diff options
author | Peter Kim <pk15950@gmail.com> | 2022-09-08 07:00:12 +0300 |
---|---|---|
committer | Peter Kim <pk15950@gmail.com> | 2022-09-08 07:00:12 +0300 |
commit | 00dcfdf916c69672210b006e62d966f1bc2fbeb7 (patch) | |
tree | 0cbb1b91fe26c750197126085b74224a795a103c /source/blender/editors/uvedit/uvedit_select.c | |
parent | a39532670f6b668da7be5810fb1f844b82feeba3 (diff) | |
parent | d5934974219135102f364f57c45a8b1465e2b8d9 (diff) |
Merge branch 'master' into xr-devxr-dev
Diffstat (limited to 'source/blender/editors/uvedit/uvedit_select.c')
-rw-r--r-- | source/blender/editors/uvedit/uvedit_select.c | 981 |
1 files changed, 894 insertions, 87 deletions
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index cea2bb05547..cecf0ff7914 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -12,6 +12,7 @@ #include "MEM_guardedalloc.h" #include "DNA_image_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" @@ -22,6 +23,7 @@ #include "BLI_blenlib.h" #include "BLI_hash.h" #include "BLI_kdopbvh.h" +#include "BLI_kdtree.h" #include "BLI_lasso_2d.h" #include "BLI_math.h" #include "BLI_polyfill_2d.h" @@ -31,6 +33,7 @@ #include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_layer.h" +#include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_report.h" @@ -75,6 +78,17 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSettings *ts, Object *obedit); +typedef enum { + UV_SSIM_AREA_UV = 1000, + UV_SSIM_AREA_3D, + UV_SSIM_FACE, + UV_SSIM_LENGTH_UV, + UV_SSIM_LENGTH_3D, + UV_SSIM_SIDES, + UV_SSIM_PIN, + UV_SSIM_MATERIAL, +} eUVSelectSimilar; + /* -------------------------------------------------------------------- */ /** \name Active Selection Tracking * @@ -193,7 +207,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(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); } } } @@ -251,7 +265,7 @@ void uvedit_face_select_set_with_sticky(const Scene *scene, const ToolSettings *ts = scene->toolsettings; const char sticky = ts->uv_sticky; if (ts->uv_flag & UV_SYNC_SELECTION) { - uvedit_face_select_set(scene, em, efa, select, do_history, cd_loop_uv_offset); + uvedit_face_select_set(scene, em->bm, efa, select, do_history, cd_loop_uv_offset); return; } if (!uvedit_face_visible_test(scene, efa)) { @@ -261,7 +275,7 @@ void uvedit_face_select_set_with_sticky(const Scene *scene, * (not part of any face selections). This now uses the sticky location mode logic instead. */ switch (sticky) { case SI_STICKY_DISABLE: { - uvedit_face_select_set(scene, em, efa, select, do_history, cd_loop_uv_offset); + uvedit_face_select_set(scene, em->bm, efa, select, do_history, cd_loop_uv_offset); break; } default: { @@ -299,32 +313,30 @@ void uvedit_face_select_shared_vert(const Scene *scene, } void uvedit_face_select_set(const Scene *scene, - BMEditMesh *em, + BMesh *bm, BMFace *efa, const bool select, const bool do_history, const int cd_loop_uv_offset) { if (select) { - uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset); + uvedit_face_select_enable(scene, bm, efa, do_history, cd_loop_uv_offset); } else { - uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); + uvedit_face_select_disable(scene, bm, efa, cd_loop_uv_offset); } } -void uvedit_face_select_enable(const Scene *scene, - BMEditMesh *em, - BMFace *efa, - const bool do_history, - const int cd_loop_uv_offset) +void uvedit_face_select_enable( + const Scene *scene, BMesh *bm, BMFace *efa, const bool do_history, const int cd_loop_uv_offset) { + BLI_assert(cd_loop_uv_offset >= 0); const ToolSettings *ts = scene->toolsettings; if (ts->uv_flag & UV_SYNC_SELECTION) { - BM_face_select_set(em->bm, efa, true); + BM_face_select_set(bm, efa, true); if (do_history) { - BM_select_history_store(em->bm, (BMElem *)efa); + BM_select_history_store(bm, (BMElem *)efa); } } else { @@ -340,14 +352,15 @@ void uvedit_face_select_enable(const Scene *scene, } void uvedit_face_select_disable(const Scene *scene, - BMEditMesh *em, + BMesh *bm, BMFace *efa, const int cd_loop_uv_offset) { + BLI_assert(cd_loop_uv_offset >= 0); const ToolSettings *ts = scene->toolsettings; if (ts->uv_flag & UV_SYNC_SELECTION) { - BM_face_select_set(em->bm, efa, false); + BM_face_select_set(bm, efa, false); } else { BMLoop *l; @@ -393,11 +406,11 @@ void uvedit_edge_select_set_with_sticky(const Scene *scene, BMLoop *l, const bool select, const bool do_history, - const uint cd_loop_uv_offset) + const int 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); + uvedit_edge_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset); return; } @@ -405,7 +418,7 @@ void uvedit_edge_select_set_with_sticky(const Scene *scene, switch (sticky) { case SI_STICKY_DISABLE: { if (uvedit_face_visible_test(scene, l->f)) { - uvedit_edge_select_set(scene, em, l, select, do_history, cd_loop_uv_offset); + uvedit_edge_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset); } break; } @@ -487,7 +500,7 @@ void uvedit_edge_select_set_noflush(const Scene *scene, } void uvedit_edge_select_set(const Scene *scene, - BMEditMesh *em, + BMesh *bm, BMLoop *l, const bool select, const bool do_history, @@ -495,36 +508,33 @@ void uvedit_edge_select_set(const Scene *scene, { if (select) { - uvedit_edge_select_enable(scene, em, l, do_history, cd_loop_uv_offset); + uvedit_edge_select_enable(scene, bm, l, do_history, cd_loop_uv_offset); } else { - uvedit_edge_select_disable(scene, em, l, cd_loop_uv_offset); + uvedit_edge_select_disable(scene, bm, l, cd_loop_uv_offset); } } -void uvedit_edge_select_enable(const Scene *scene, - BMEditMesh *em, - BMLoop *l, - const bool do_history, - const int cd_loop_uv_offset) +void uvedit_edge_select_enable( + const Scene *scene, BMesh *bm, BMLoop *l, const bool do_history, const int cd_loop_uv_offset) { const ToolSettings *ts = scene->toolsettings; if (ts->uv_flag & UV_SYNC_SELECTION) { if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, true); + BM_face_select_set(bm, l->f, true); } else if (ts->selectmode & SCE_SELECT_EDGE) { - BM_edge_select_set(em->bm, l->e, true); + BM_edge_select_set(bm, l->e, true); } else { - BM_vert_select_set(em->bm, l->e->v1, true); - BM_vert_select_set(em->bm, l->e->v2, true); + BM_vert_select_set(bm, l->e->v1, true); + BM_vert_select_set(bm, l->e->v2, true); } if (do_history) { - BM_select_history_store(em->bm, (BMElem *)l->e); + BM_select_history_store(bm, (BMElem *)l->e); } } else { @@ -538,7 +548,7 @@ void uvedit_edge_select_enable(const Scene *scene, } void uvedit_edge_select_disable(const Scene *scene, - BMEditMesh *em, + BMesh *bm, BMLoop *l, const int cd_loop_uv_offset) @@ -547,14 +557,14 @@ void uvedit_edge_select_disable(const Scene *scene, if (ts->uv_flag & UV_SYNC_SELECTION) { if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, false); + BM_face_select_set(bm, l->f, false); } else if (ts->selectmode & SCE_SELECT_EDGE) { - BM_edge_select_set(em->bm, l->e, false); + BM_edge_select_set(bm, l->e, false); } else { - BM_vert_select_set(em->bm, l->e->v1, false); - BM_vert_select_set(em->bm, l->e->v2, false); + BM_vert_select_set(bm, l->e->v1, false); + BM_vert_select_set(bm, l->e->v2, false); } } else { @@ -586,12 +596,25 @@ 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); } + if (ts->selectmode & SCE_SELECT_EDGE) { + /* Are you looking for `uvedit_edge_select_test(...)` instead? */ + } return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT); } MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (ts->selectmode & SCE_SELECT_FACE) { + /* Are you looking for `uvedit_face_select_test(...)` instead? */ + } + + if (ts->selectmode & SCE_SELECT_EDGE) { + /* Are you looking for `uvedit_edge_select_test(...)` instead? */ + } + 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); @@ -602,11 +625,11 @@ void uvedit_uv_select_set_with_sticky(const Scene *scene, BMLoop *l, const bool select, const bool do_history, - const uint cd_loop_uv_offset) + const int 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); + uvedit_uv_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset); return; } @@ -614,7 +637,7 @@ void uvedit_uv_select_set_with_sticky(const Scene *scene, switch (sticky) { case SI_STICKY_DISABLE: { if (uvedit_face_visible_test(scene, l->f)) { - uvedit_uv_select_set(scene, em, l, select, do_history, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset); } break; } @@ -668,7 +691,8 @@ void uvedit_uv_select_shared_vert(const Scene *scene, } if (do_select) { - uvedit_uv_select_set(scene, em, l_radial_iter, select, do_history, cd_loop_uv_offset); + uvedit_uv_select_set( + scene, em->bm, l_radial_iter, select, do_history, cd_loop_uv_offset); } } } @@ -677,38 +701,39 @@ void uvedit_uv_select_shared_vert(const Scene *scene, } void uvedit_uv_select_set(const Scene *scene, - BMEditMesh *em, + BMesh *bm, BMLoop *l, const bool select, const bool do_history, const int cd_loop_uv_offset) { if (select) { - uvedit_uv_select_enable(scene, em, l, do_history, cd_loop_uv_offset); + uvedit_uv_select_enable(scene, bm, l, do_history, cd_loop_uv_offset); } else { - uvedit_uv_select_disable(scene, em, l, cd_loop_uv_offset); + uvedit_uv_select_disable(scene, bm, l, cd_loop_uv_offset); } } -void uvedit_uv_select_enable(const Scene *scene, - BMEditMesh *em, - BMLoop *l, - const bool do_history, - const int cd_loop_uv_offset) +void uvedit_uv_select_enable( + const Scene *scene, BMesh *bm, BMLoop *l, const bool do_history, const int cd_loop_uv_offset) { const ToolSettings *ts = scene->toolsettings; + if (ts->selectmode & SCE_SELECT_EDGE) { + /* Are you looking for `uvedit_edge_select_set(...)` instead? */ + } + if (ts->uv_flag & UV_SYNC_SELECTION) { if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, true); + BM_face_select_set(bm, l->f, true); } else { - BM_vert_select_set(em->bm, l->v, true); + BM_vert_select_set(bm, l->v, true); } if (do_history) { - BM_select_history_store(em->bm, (BMElem *)l->v); + BM_select_history_store(bm, (BMElem *)l->v); } } else { @@ -718,7 +743,7 @@ void uvedit_uv_select_enable(const Scene *scene, } void uvedit_uv_select_disable(const Scene *scene, - BMEditMesh *em, + BMesh *bm, BMLoop *l, const int cd_loop_uv_offset) { @@ -726,10 +751,10 @@ void uvedit_uv_select_disable(const Scene *scene, if (ts->uv_flag & UV_SYNC_SELECTION) { if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, false); + BM_face_select_set(bm, l->f, false); } else { - BM_vert_select_set(em->bm, l->v, false); + BM_vert_select_set(bm, l->v, false); } } else { @@ -1109,7 +1134,7 @@ BMLoop *uv_find_nearest_loop_from_vert(struct Scene *scene, 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); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BMIter liter; BMLoop *l; @@ -1137,7 +1162,8 @@ BMLoop *uv_find_nearest_loop_from_edge(struct Scene *scene, 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); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + BLI_assert(cd_loop_uv_offset >= 0); BMIter eiter; BMLoop *l; @@ -1391,7 +1417,7 @@ static BMLoop *bm_select_edgeloop_single_side_next(const Scene *scene, scene, l_step, v_from_next, cd_loop_uv_offset); } -/* TODO(campbell): support this in the BMesh API, as we have for clearing other types. */ +/* TODO(@campbellbarton): support this in the BMesh API, as we have for clearing other types. */ static void bm_loop_tags_clear(BMesh *bm) { BMIter iter; @@ -1944,7 +1970,7 @@ static void uv_select_linked_multi(Scene *scene, BM_face_select_set(em->bm, efa, value); \ } \ else { \ - uvedit_face_select_set(scene, em, efa, value, false, cd_loop_uv_offset); \ + uvedit_face_select_set(scene, em->bm, efa, value, false, cd_loop_uv_offset); \ } \ (void)0 @@ -2905,12 +2931,14 @@ void UV_OT_select_edge_ring(wmOperatorType *ot) 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( + PropertyRNA *prop; + prop = RNA_def_boolean(ot->srna, + "extend", + 0, + "Extend", + "Extend selection rather than clearing the existing selection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_float_vector( ot->srna, "location", 2, @@ -2921,6 +2949,7 @@ void UV_OT_select_edge_ring(wmOperatorType *ot) "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /** \} */ @@ -3213,7 +3242,7 @@ static void uv_select_flush_from_tag_sticky_loc_internal(const Scene *scene, UvMapVert *start_vlist = NULL, *vlist_iter; BMFace *efa_vlist; - uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); @@ -3231,7 +3260,6 @@ static void uv_select_flush_from_tag_sticky_loc_internal(const Scene *scene, vlist_iter = start_vlist; while (vlist_iter) { - if (vlist_iter != start_vlist && vlist_iter->separate) { break; } @@ -3244,7 +3272,7 @@ static void uv_select_flush_from_tag_sticky_loc_internal(const 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(scene, em, l_other, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l_other, select, false, cd_loop_uv_offset); } vlist_iter = vlist_iter->next; } @@ -3311,7 +3339,7 @@ static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, co else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset); + uvedit_face_select_set(scene, em->bm, efa, select, false, cd_loop_uv_offset); } } } @@ -3360,7 +3388,7 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co 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(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); } } } @@ -3389,7 +3417,7 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co 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(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); } } } @@ -3549,6 +3577,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) } } else if (use_edge && !pinned) { + bool do_second_pass = true; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (!uvedit_face_visible_test(scene, efa)) { continue; @@ -3563,11 +3592,35 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) uvedit_edge_select_set_with_sticky( scene, em, l_prev, select, false, cd_loop_uv_offset); changed = true; + do_second_pass = false; } l_prev = l; luv_prev = luv; } } + /* Do a second pass if no complete edges could be selected. + * This matches wire-frame edit-mesh selection in the 3D view. */ + if (do_second_pass) { + /* Second pass to check if edges partially overlap with the selection area (box). */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; + MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset); + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (BLI_rctf_isect_segment(&rectf, luv_prev->uv, luv->uv)) { + uvedit_edge_select_set_with_sticky( + scene, em, l_prev, select, false, cd_loop_uv_offset); + changed = true; + } + l_prev = l; + luv_prev = luv; + } + } + } } else { /* other selection modes */ @@ -3585,14 +3638,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(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, 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(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); } } @@ -3659,9 +3712,9 @@ void UV_OT_select_box(wmOperatorType *ot) /** \name Circle Select Operator * \{ */ -static int uv_circle_select_is_point_inside(const float uv[2], - const float offset[2], - const float ellipse[2]) +static bool uv_circle_select_is_point_inside(const float uv[2], + const float offset[2], + const float ellipse[2]) { /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ const float co[2] = { @@ -3671,10 +3724,10 @@ static int uv_circle_select_is_point_inside(const float uv[2], return len_squared_v2(co) < 1.0f; } -static int uv_circle_select_is_edge_inside(const float uv_a[2], - const float uv_b[2], - const float offset[2], - const float ellipse[2]) +static bool uv_circle_select_is_edge_inside(const float uv_a[2], + const float uv_b[2], + const float offset[2], + const float ellipse[2]) { /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ const float co_a[2] = { @@ -3805,7 +3858,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(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); has_selected = true; } @@ -3887,6 +3940,24 @@ static bool do_lasso_select_mesh_uv_is_point_inside(const ARegion *region, return false; } +static bool do_lasso_select_mesh_uv_is_edge_inside(const ARegion *region, + const rcti *clip_rect, + const int mcoords[][2], + const int mcoords_len, + const float co_test_a[2], + const float co_test_b[2]) +{ + int co_screen_a[2], co_screen_b[2]; + if (UI_view2d_view_to_region_segment_clip( + ®ion->v2d, co_test_a, co_test_b, co_screen_a, co_screen_b) && + BLI_rcti_isect_segment(clip_rect, co_screen_a, co_screen_b) && + BLI_lasso_is_edge_inside( + mcoords, mcoords_len, UNPACK2(co_screen_a), UNPACK2(co_screen_b), V2D_IS_CLIPPED)) { + return true; + } + return false; +} + static bool do_lasso_select_mesh_uv(bContext *C, const int mcoords[][2], const int mcoords_len, @@ -3955,6 +4026,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, } } else if (use_edge) { + bool do_second_pass = true; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (!uvedit_face_visible_test(scene, efa)) { continue; @@ -3971,12 +4043,37 @@ static bool do_lasso_select_mesh_uv(bContext *C, region, &rect, mcoords, mcoords_len, luv_prev->uv)) { uvedit_edge_select_set_with_sticky( scene, em, l_prev, select, false, cd_loop_uv_offset); + do_second_pass = false; changed = true; } l_prev = l; luv_prev = luv; } } + /* Do a second pass if no complete edges could be selected. + * This matches wire-frame edit-mesh selection in the 3D view. */ + if (do_second_pass) { + /* Second pass to check if edges partially overlap with the selection area (lasso). */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; + MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset); + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (do_lasso_select_mesh_uv_is_edge_inside( + region, &rect, mcoords, mcoords_len, luv->uv, luv_prev->uv)) { + uvedit_edge_select_set_with_sticky( + scene, em, l_prev, select, false, cd_loop_uv_offset); + changed = true; + } + l_prev = l; + luv_prev = luv; + } + } + } } else { /* Vert Selection. */ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); @@ -3991,7 +4088,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(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); changed = true; BM_elem_flag_enable(l->v, BM_ELEM_TAG); has_selected = true; @@ -4111,7 +4208,7 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *op) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (luv->flag & MLOOPUV_PINNED) { - uvedit_uv_select_enable(scene, em, l, false, cd_loop_uv_offset); + uvedit_uv_select_enable(scene, em->bm, l, false, cd_loop_uv_offset); changed = true; } } @@ -4364,8 +4461,8 @@ static int uv_select_overlap(bContext *C, const bool extend) /* Main tri-tri overlap test. */ const float endpoint_bias = -1e-4f; if (overlap_tri_tri_uv_test(o_a->tri, o_b->tri, endpoint_bias)) { - uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a); - uvedit_face_select_enable(scene, em_b, face_b, false, cd_loop_uv_offset_b); + uvedit_face_select_enable(scene, em_a->bm, face_a, false, cd_loop_uv_offset_a); + uvedit_face_select_enable(scene, em_b->bm, face_b, false, cd_loop_uv_offset_b); } } @@ -4412,6 +4509,716 @@ void UV_OT_select_overlap(wmOperatorType *ot) } /** \} */ +/** \name Select Similar Operator + * \{ */ + +static float get_uv_vert_needle(const eUVSelectSimilar type, + BMVert *vert, + const float ob_m3[3][3], + MLoopUV *luv, + const int cd_loop_uv_offset) +{ + float result = 0.0f; + switch (type) { + case UV_SSIM_AREA_UV: { + BMFace *f; + BMIter iter; + BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) { + result += BM_face_calc_area_uv(f, cd_loop_uv_offset); + } + } break; + case UV_SSIM_AREA_3D: { + BMFace *f; + BMIter iter; + BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) { + result += BM_face_calc_area_with_mat3(f, ob_m3); + } + } break; + case UV_SSIM_SIDES: { + BMEdge *e; + BMIter iter; + BM_ITER_ELEM (e, &iter, vert, BM_EDGES_OF_VERT) { + result += 1.0f; + } + } break; + case UV_SSIM_PIN: + return (luv->flag & MLOOPUV_PINNED) ? 1.0f : 0.0f; + default: + BLI_assert_unreachable(); + return false; + } + + return result; +} + +static float get_uv_edge_needle(const eUVSelectSimilar type, + BMEdge *edge, + const float ob_m3[3][3], + MLoopUV *luv_a, + MLoopUV *luv_b, + const int cd_loop_uv_offset) +{ + float result = 0.0f; + switch (type) { + case UV_SSIM_AREA_UV: { + BMFace *f; + BMIter iter; + BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) { + result += BM_face_calc_area_uv(f, cd_loop_uv_offset); + } + } break; + case UV_SSIM_AREA_3D: { + BMFace *f; + BMIter iter; + BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) { + result += BM_face_calc_area_with_mat3(f, ob_m3); + } + } break; + case UV_SSIM_LENGTH_UV: + return len_v2v2(luv_a->uv, luv_b->uv); + case UV_SSIM_LENGTH_3D: + return len_v3v3(edge->v1->co, edge->v2->co); + case UV_SSIM_SIDES: { + BMEdge *e; + BMIter iter; + BM_ITER_ELEM (e, &iter, edge, BM_FACES_OF_EDGE) { + result += 1.0f; + } + } break; + case UV_SSIM_PIN: + if (luv_a->flag & MLOOPUV_PINNED) { + result += 1.0f; + } + if (luv_b->flag & MLOOPUV_PINNED) { + result += 1.0f; + } + break; + default: + BLI_assert_unreachable(); + return false; + } + + return result; +} + +static float get_uv_face_needle(const eUVSelectSimilar type, + BMFace *face, + const float ob_m3[3][3], + const int cd_loop_uv_offset) +{ + float result = 0.0f; + switch (type) { + case UV_SSIM_AREA_UV: + return BM_face_calc_area_uv(face, cd_loop_uv_offset); + case UV_SSIM_AREA_3D: + return BM_face_calc_area_with_mat3(face, ob_m3); + case UV_SSIM_SIDES: + return face->len; + case UV_SSIM_PIN: { + BMLoop *l; + BMIter liter; + BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (luv->flag & MLOOPUV_PINNED) { + result += 1.0f; + } + } + } break; + case UV_SSIM_MATERIAL: + return face->mat_nr; + default: + BLI_assert_unreachable(); + return false; + } + return result; +} + +static float get_uv_island_needle(const eUVSelectSimilar type, + const struct FaceIsland *island, + const float ob_m3[3][3], + const int cd_loop_uv_offset) + +{ + float result = 0.0f; + switch (type) { + case UV_SSIM_AREA_UV: + for (int i = 0; i < island->faces_len; i++) { + result += BM_face_calc_area_uv(island->faces[i], cd_loop_uv_offset); + } + break; + case UV_SSIM_AREA_3D: + for (int i = 0; i < island->faces_len; i++) { + result += BM_face_calc_area_with_mat3(island->faces[i], ob_m3); + } + break; + case UV_SSIM_FACE: + return island->faces_len; + default: + BLI_assert_unreachable(); + return false; + } + return result; +} + +static int uv_select_similar_vert_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type"); + const float threshold = RNA_float_get(op->ptr, "threshold"); + const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare"); + + 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 max_verts_selected_all = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + max_verts_selected_all += face->len; + } + /* TODO: Get a tighter bounds */ + } + + int tree_index = 0; + KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_verts_selected_all); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + if (bm->totvertsel == 0) { + continue; + } + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + BMLoop *l; + BMIter liter; + BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { + if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + continue; + } + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset); + BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); + } + } + } + + if (tree_1d != NULL) { + BLI_kdtree_1d_deduplicate(tree_1d); + BLI_kdtree_1d_balance(tree_1d); + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + if (bm->totvertsel == 0) { + continue; + } + + bool changed = false; + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + BMLoop *l; + BMIter liter; + BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + continue; /* Already selected. */ + } + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + const float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset); + bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); + if (select) { + uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); + changed = true; + } + } + if (changed) { + uv_select_tag_update_for_object(depsgraph, ts, ob); + } + } + } + + MEM_SAFE_FREE(objects); + BLI_kdtree_1d_free(tree_1d); + return OPERATOR_FINISHED; +} + +static int uv_select_similar_edge_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type"); + const float threshold = RNA_float_get(op->ptr, "threshold"); + const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare"); + + 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 max_edges_selected_all = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + max_edges_selected_all += face->len; + } + /* TODO: Get a tighter bounds. */ + } + + int tree_index = 0; + KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_edges_selected_all); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + if (bm->totvertsel == 0) { + continue; + } + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + BMLoop *l; + BMIter liter; + BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { + if (!uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) { + continue; + } + + MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset); + if (tree_1d) { + BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); + } + } + } + } + + if (tree_1d != NULL) { + BLI_kdtree_1d_deduplicate(tree_1d); + BLI_kdtree_1d_balance(tree_1d); + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + if (bm->totvertsel == 0) { + continue; + } + + bool changed = false; + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + BMLoop *l; + BMIter liter; + BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { + if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) { + continue; /* Already selected. */ + } + + MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset); + bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); + if (select) { + uvedit_edge_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); + changed = true; + } + } + if (changed) { + uv_select_tag_update_for_object(depsgraph, ts, ob); + } + } + } + + MEM_SAFE_FREE(objects); + BLI_kdtree_1d_free(tree_1d); + return OPERATOR_FINISHED; +} + +static int uv_select_similar_face_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type"); + const float threshold = RNA_float_get(op->ptr, "threshold"); + const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare"); + + 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 max_faces_selected_all = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + max_faces_selected_all += em->bm->totfacesel; + /* TODO: Get a tighter bounds */ + } + + int tree_index = 0; + KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_faces_selected_all); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + if (!uvedit_face_select_test(scene, face, cd_loop_uv_offset)) { + continue; + } + + float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset); + if (tree_1d) { + BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); + } + } + } + + if (tree_1d != NULL) { + BLI_kdtree_1d_deduplicate(tree_1d); + BLI_kdtree_1d_balance(tree_1d); + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + bool changed = false; + bool do_history = false; + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + float ob_m3[3][3]; + copy_m3_m4(ob_m3, ob->obmat); + + BMFace *face; + BMIter iter; + BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, face)) { + continue; + } + if (uvedit_face_select_test(scene, face, cd_loop_uv_offset)) { + continue; + } + + float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset); + + bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); + if (select) { + uvedit_face_select_set(scene, em->bm, face, select, do_history, cd_loop_uv_offset); + changed = true; + } + } + if (changed) { + uv_select_tag_update_for_object(depsgraph, ts, ob); + } + } + + MEM_SAFE_FREE(objects); + BLI_kdtree_1d_free(tree_1d); + return OPERATOR_FINISHED; +} + +static bool uv_island_selected(const Scene *scene, struct FaceIsland *island) +{ + BLI_assert(island && island->faces_len); + return uvedit_face_select_test(scene, island->faces[0], island->cd_loop_uv_offset); +} + +static int uv_select_similar_island_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type"); + const float threshold = RNA_float_get(op->ptr, "threshold"); + const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare"); + + 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); + + ListBase *island_list_ptr = MEM_callocN(sizeof(*island_list_ptr) * objects_len, __func__); + int island_list_len = 0; + + const bool face_selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + if (cd_loop_uv_offset == -1) { + continue; + } + + float aspect_y = 1.0f; /* Placeholder value, aspect doesn't change connectivity. */ + island_list_len += bm_mesh_calc_uv_islands(scene, + em->bm, + &island_list_ptr[ob_index], + face_selected, + false, + false, + aspect_y, + cd_loop_uv_offset); + } + + struct FaceIsland **island_array = MEM_callocN(sizeof(*island_array) * island_list_len, + __func__); + + int tree_index = 0; + KDTree_1d *tree_1d = BLI_kdtree_1d_new(island_list_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + if (cd_loop_uv_offset == -1) { + continue; + } + + float ob_m3[3][3]; + copy_m3_m4(ob_m3, obedit->obmat); + + int index; + LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) { + island_array[index] = island; + if (!uv_island_selected(scene, island)) { + continue; + } + float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset); + if (tree_1d) { + BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); + } + } + } + + if (tree_1d != NULL) { + BLI_kdtree_1d_deduplicate(tree_1d); + BLI_kdtree_1d_balance(tree_1d); + } + + int tot_island_index = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + if (cd_loop_uv_offset == -1) { + continue; + } + float ob_m3[3][3]; + copy_m3_m4(ob_m3, obedit->obmat); + + bool changed = false; + int index; + LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) { + island_array[tot_island_index++] = island; /* To deallocate later. */ + if (uv_island_selected(scene, island)) { + continue; + } + float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset); + bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); + if (!select) { + continue; + } + bool do_history = false; + for (int j = 0; j < island->faces_len; j++) { + uvedit_face_select_set( + scene, em->bm, island->faces[j], select, do_history, island->cd_loop_uv_offset); + } + changed = true; + } + + if (changed) { + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + + BLI_assert(tot_island_index == island_list_len); + for (int i = 0; i < island_list_len; i++) { + MEM_SAFE_FREE(island_array[i]->faces); + MEM_SAFE_FREE(island_array[i]); + } + + MEM_SAFE_FREE(island_array); + MEM_SAFE_FREE(island_list_ptr); + MEM_SAFE_FREE(objects); + BLI_kdtree_1d_free(tree_1d); + + return OPERATOR_FINISHED; +} + +/* Select similar UV faces/edges/verts based on current selection. */ +static int uv_select_similar_exec(bContext *C, wmOperator *op) +{ + ToolSettings *ts = CTX_data_tool_settings(C); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold"); + + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set(op->ptr, prop, ts->select_thresh); + } + else { + ts->select_thresh = RNA_property_float_get(op->ptr, prop); + } + + int selectmode = (ts->uv_flag & UV_SYNC_SELECTION) ? ts->selectmode : ts->uv_selectmode; + if (selectmode & UV_SELECT_EDGE) { + return uv_select_similar_edge_exec(C, op); + } + if (selectmode & UV_SELECT_FACE) { + return uv_select_similar_face_exec(C, op); + } + if (selectmode & UV_SELECT_ISLAND) { + return uv_select_similar_island_exec(C, op); + } + + return uv_select_similar_vert_exec(C, op); +} + +static EnumPropertyItem prop_vert_similar_types[] = {{UV_SSIM_PIN, "PIN", 0, "Pinned", ""}, {0}}; + +static EnumPropertyItem prop_edge_similar_types[] = { + {UV_SSIM_LENGTH_UV, "LENGTH", 0, "Length", ""}, + {UV_SSIM_LENGTH_3D, "LENGTH_3D", 0, "Length 3D", ""}, + {UV_SSIM_PIN, "PIN", 0, "Pinned", ""}, + {0}}; + +static EnumPropertyItem prop_face_similar_types[] = { + {UV_SSIM_AREA_UV, "AREA", 0, "Area", ""}, + {UV_SSIM_AREA_3D, "AREA_3D", 0, "Area 3D", ""}, + {UV_SSIM_SIDES, "SIDES", 0, "Polygon Sides", ""}, + {UV_SSIM_MATERIAL, "MATERIAL", 0, "Material", ""}, + {0}}; + +static EnumPropertyItem prop_island_similar_types[] = { + {UV_SSIM_AREA_UV, "AREA", 0, "Area", ""}, + {UV_SSIM_AREA_3D, "AREA_3D", 0, "Area 3D", ""}, + {UV_SSIM_FACE, "FACE", 0, "Amount of Faces in Island", ""}, + {0}}; + +static EnumPropertyItem prop_similar_compare_types[] = {{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""}, + {SIM_CMP_GT, "GREATER", 0, "Greater", ""}, + {SIM_CMP_LT, "LESS", 0, "Less", ""}, + {0}}; + +static const EnumPropertyItem *uv_select_similar_type_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *UNUSED(r_free)) +{ + const ToolSettings *ts = CTX_data_tool_settings(C); + if (ts) { + int selectmode = (ts->uv_flag & UV_SYNC_SELECTION) ? ts->selectmode : ts->uv_selectmode; + if (selectmode & UV_SELECT_EDGE) { + return prop_edge_similar_types; + } + if (selectmode & UV_SELECT_FACE) { + return prop_face_similar_types; + } + if (selectmode & UV_SELECT_ISLAND) { + return prop_island_similar_types; + } + } + + return prop_vert_similar_types; +} +void UV_OT_select_similar(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Similar"; + ot->description = "Select similar UVs by property types"; + ot->idname = "UV_OT_select_similar"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = uv_select_similar_exec; + ot->poll = ED_operator_uvedit_space_image; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + PropertyRNA *prop = ot->prop = RNA_def_enum( + ot->srna, "type", prop_vert_similar_types, SIMVERT_NORMAL, "Type", ""); + RNA_def_enum_funcs(prop, uv_select_similar_type_itemf); + RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", ""); + RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f); +} + +/** \} */ /* -------------------------------------------------------------------- */ /** \name Selected Elements as Arrays (Vertex, Edge & Faces) @@ -4577,12 +5384,12 @@ 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, true, false, false, true); + UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, false, false, true); if (elementmap == NULL) { return; } - int num_islands = elementmap->totalIslands; + int num_islands = elementmap->total_islands; /* Boolean array that tells if island with index i is completely selected or not. */ bool *is_island_not_selected = MEM_callocN(sizeof(bool) * (num_islands), __func__); @@ -4674,7 +5481,7 @@ void ED_uvedit_selectmode_clean(const Scene *scene, Object *obedit) if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); } - uvedit_face_select_set(scene, em, efa, false, false, cd_loop_uv_offset); + uvedit_face_select_set(scene, em->bm, efa, false, false, cd_loop_uv_offset); } } uv_select_flush_from_tag_face(scene, obedit, true); |