diff options
author | Campbell Barton <ideasman42@gmail.com> | 2021-01-20 08:57:02 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2021-01-20 09:07:20 +0300 |
commit | 908b383b7d2199c0c614d085ff65a03eb7852274 (patch) | |
tree | 955c797b1100c3af5232bbba4a00f711a33f3eee /source/blender/editors/uvedit | |
parent | 9f337bef80d2e7259a9e7fec0b8ec8cd807881ae (diff) |
UV: tweak face select behavior
When the mouse cursor is inside the UV face,
extend the selection threshold.
This means when zoomed in, a face can always be selected when the cursor
is inside it.
In the case of multiple overlapping faces - the face with the closest
center is used.
----
Prior to 246efd7286f6187e4dd4b3edcc79cccb1746bb1d, the UV selection
threshold was scaled by the zoom level, so selecting a face when zoomed
in close would often often select faces even when the on-screen center
was outside the intended threshold.
Having a zoom-independent threshold may require more precision than
users are used to.
This change addresses this.
Diffstat (limited to 'source/blender/editors/uvedit')
-rw-r--r-- | source/blender/editors/uvedit/uvedit_intern.h | 11 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_select.c | 49 |
2 files changed, 56 insertions, 4 deletions
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 45d65e7070e..cd8fbd00316 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -93,10 +93,21 @@ bool uv_find_nearest_edge_multi(struct Scene *scene, const float co[2], struct UvNearestHit *hit); +bool uv_find_nearest_face_ex(struct Scene *scene, + struct Object *obedit, + const float co[2], + struct UvNearestHit *hit, + const bool only_in_face); bool uv_find_nearest_face(struct Scene *scene, struct Object *obedit, const float co[2], struct UvNearestHit *hit); +bool uv_find_nearest_face_multi_ex(struct Scene *scene, + struct Object **objects, + const uint objects_len, + const float co[2], + struct UvNearestHit *hit, + const bool only_in_face); bool uv_find_nearest_face_multi(struct Scene *scene, struct Object **objects, const uint objects_len, diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index 394bdd14166..c69900678db 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -719,7 +719,17 @@ bool uv_find_nearest_edge_multi( return found; } -bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit) +/** + * \param only_in_face: when true, only hit faces which `co` is inside. + * This gives users a result they might expect, especially when zoomed in. + * + * \note Concave faces can cause odd behavior, although in practice this isn't often an issue. + * The center can be outside the face, in this case the distance to the center + * could cause the face to be considered too far away. + * If this becomes an issue we could track the distance to the faces closest edge. + */ +bool uv_find_nearest_face_ex( + Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit, const bool only_in_face) { BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f)); BMEditMesh *em = BKE_editmesh_from_object(obedit); @@ -745,6 +755,13 @@ bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNea const float dist_test_sq = len_squared_v2(delta); if (dist_test_sq < hit->dist_sq) { + + if (only_in_face) { + if (!BM_face_uv_point_inside_test(efa, co, cd_loop_uv_offset)) { + continue; + } + } + hit->ob = obedit; hit->efa = efa; hit->dist_sq = dist_test_sq; @@ -754,19 +771,34 @@ bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNea return found; } -bool uv_find_nearest_face_multi( - Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit) +bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit) +{ + return uv_find_nearest_face_ex(scene, obedit, co, hit, NULL); +} + +bool uv_find_nearest_face_multi_ex(Scene *scene, + Object **objects, + const uint objects_len, + const float co[2], + UvNearestHit *hit, + const bool only_in_face) { bool found = false; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - if (uv_find_nearest_face(scene, obedit, co, hit)) { + if (uv_find_nearest_face_ex(scene, obedit, co, hit, only_in_face)) { found = true; } } return found; } +bool uv_find_nearest_face_multi( + Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit) +{ + return uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, hit, false); +} + static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset) { const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv; @@ -1934,6 +1966,15 @@ static int uv_mouse_select_multi(bContext *C, else if (selectmode == UV_SELECT_FACE) { /* find face */ found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit); + + if (!found_item) { + /* Fallback, perform a second pass without a limited threshold, + * which succeeds as long as the cursor is inside the UV face. + * Useful when zoomed in, to select faces with distant screen-space face centers. */ + hit.dist_sq = FLT_MAX; + found_item = uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, &hit, true); + } + if (found_item) { BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm; BM_mesh_active_face_set(bm, hit.efa); |