[Bf-blender-cvs] [d6e02d92e13] soc-2021-uv-editor-improvements-edge-selection: UV: Extend edge selection support

Siddhartha Jejurkar noreply at git.blender.org
Thu Aug 5 13:08:35 CEST 2021


Commit: d6e02d92e13383b73f305cd7cd2162143f647507
Author: Siddhartha Jejurkar
Date:   Mon Aug 2 09:50:50 2021 +0530
Branches: soc-2021-uv-editor-improvements-edge-selection
https://developer.blender.org/rBd6e02d92e13383b73f305cd7cd2162143f647507

UV: Extend edge selection support

- Add edge selection support for operators: mouse select, box select,
  circle select, lasso select, (de)select all, invert selection and
  select more/less
- Flush selections between UV verts and edges
- Fix: prevent deselection of neighbouring edges when deselecting an
  edge in sticky location + edge select mode

===================================================================

M	source/blender/editors/uvedit/uvedit_intern.h
M	source/blender/editors/uvedit/uvedit_select.c

===================================================================

diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index ea72b859f7c..b0ab34b6b02 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -125,6 +125,14 @@ BMLoop *uv_find_nearest_loop_from_edge(struct Scene *scene,
                                        struct BMEdge *e,
                                        const float co[2]);
 
+/* flush uv selection */
+void uv_flush_vert_to_edge(struct Scene *scene,
+                           struct Object *obedit,
+                           const int cd_loop_uv_offset);
+void uv_flush_edge_to_vert(struct Scene *scene,
+                           struct Object *obedit,
+                           const int cd_loop_uv_offset);
+
 /* utility tool functions */
 
 void uvedit_live_unwrap_update(struct SpaceImage *sima,
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index fe505f865b6..0e8022b0289 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -91,6 +91,18 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
                                             const ToolSettings *ts,
                                             Object *obedit);
 
+static bool uvedit_vert_is_any_other_edge_selected(const Scene *scene,
+                                                   BMLoop *l,
+                                                   const int cd_loop_uv_offset);
+static bool uvedit_vert_is_any_other_face_selected(const Scene *scene,
+                                                   BMLoop *l,
+                                                   BMVert *v,
+                                                   const int cd_loop_uv_offset);
+static bool uvedit_vert_is_any_other_not_face_selected(const Scene *scene,
+                                                       BMLoop *l,
+                                                       BMVert *v,
+                                                       const int cd_loop_uv_offset);
+
 /* -------------------------------------------------------------------- */
 /** \name Active Selection Tracking
  *
@@ -469,17 +481,37 @@ void uvedit_edge_select_set_with_sticky(const struct SpaceImage *sima,
     default: {
       /* SI_STICKY_LOC
        * Fallback to SI_STICKY_LOC, in case sima->sticky is invalid */
-      uvedit_edge_select_shared_location(
-          scene, em, l, select, false, do_history, cd_loop_uv_offset);
-
-      /* NOTE (Design tradeoff): This is a case where we deviate from the logic of: "EDGE
-       * SELECTION MODE SHOULD IMPLY ONLY EDGES MUST BE SELECTED". The UV vertex selections done
-       * below are to avoid the cases of edge selections breaking away (/become separate
-       * entities) from the vertices/edges they were connected to */
-      uvedit_uv_select_shared_location(scene, em, l, select, false, do_history, cd_loop_uv_offset);
-      uvedit_uv_select_shared_location(
-          scene, em, l->next, select, false, do_history, cd_loop_uv_offset);
+      if (select) {
+        uvedit_edge_select_shared_location(
+            scene, em, l, select, false, do_history, cd_loop_uv_offset);
+
+        /* NOTE (Design tradeoff): This is a case where we deviate from the logic of: "EDGE
+         * SELECTION MODE SHOULD IMPLY ONLY EDGES MUST BE SELECTED". The UV vertex selections done
+         * below are to avoid the cases of edge selections breaking away (/become separate
+         * entities) from the vertices/edges they were connected to */
+        uvedit_uv_select_shared_location(
+            scene, em, l, select, false, do_history, cd_loop_uv_offset);
+        uvedit_uv_select_shared_location(
+            scene, em, l->next, select, false, do_history, cd_loop_uv_offset);
+      }
+      else {
+        BMLoop *l_radial_iter = l;
+        do {
+          if (BM_loop_uv_share_edge_check(l, l_radial_iter, cd_loop_uv_offset)) {
+            MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_radial_iter, cd_loop_uv_offset);
+            luv->flag &= ~MLOOPUV_EDGESEL;
+          }
+        } while ((l_radial_iter = l_radial_iter->radial_next) != l);
 
+        if (!uvedit_vert_is_any_other_edge_selected(scene, l, cd_loop_uv_offset)) {
+          uvedit_uv_select_shared_location(
+              scene, em, l, select, false, do_history, cd_loop_uv_offset);
+        }
+        if (!uvedit_vert_is_any_other_edge_selected(scene, l->next, cd_loop_uv_offset)) {
+          uvedit_uv_select_shared_location(
+              scene, em, l->next, select, false, do_history, cd_loop_uv_offset);
+        }
+      }
       break;
     }
   }
@@ -1156,13 +1188,155 @@ bool ED_uvedit_nearest_uv_multi(const Scene *scene,
 
 /** \} */
 
-/*
- * \brief Select Mode Flush
+/**
+ * For a specified vertex of a face, check if any edge connected to that vertex is selected or not
+ */
+static bool uvedit_vert_is_any_other_edge_selected(const Scene *scene,
+                                                   BMLoop *l,
+                                                   const int cd_loop_uv_offset)
+{
+  BMEdge *e_first, *e_iter;
+  e_first = e_iter = l->e;
+  do {
+    BMLoop *l_radial_iter = e_iter->l;
+    do {
+      if ((l_radial_iter->f != l->f) && uvedit_face_visible_test(scene, l_radial_iter->f)) {
+
+        if (uvedit_edge_select_test(scene, l_radial_iter, cd_loop_uv_offset)) {
+          return true;
+        }
+      }
+    } 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);
+
+  return false;
+}
+
+/**
+ * For a specified vertex of a face, check if any other face connected to that vertex is selected
+ * or not
+ */
+static bool uvedit_vert_is_any_other_face_selected(const Scene *scene,
+                                                   BMLoop *l,
+                                                   BMVert *v,
+                                                   const int cd_loop_uv_offset)
+{
+  BMEdge *e_first, *e_iter;
+  e_first = e_iter = l->e;
+  do {
+    BMLoop *l_radial_iter = e_iter->l;
+    do {
+      if ((l_radial_iter->f != l->f) && uvedit_face_visible_test(scene, l_radial_iter->f) &&
+          (l->v == l_radial_iter->v)) {
+
+        if (BM_loop_uv_share_vert_check(l, l_radial_iter, cd_loop_uv_offset) &&
+            uvedit_face_select_test(scene, l_radial_iter->f, cd_loop_uv_offset)) {
+          return true;
+        }
+      }
+    } while ((l_radial_iter = l_radial_iter->radial_next) != e_iter->l);
+  } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
+
+  return false;
+}
+
+/**
+ * For a specified vertex of a face, check if at least one face connected to that vertex is not
+ * selected
+ */
+static bool uvedit_vert_is_any_other_not_face_selected(const Scene *scene,
+                                                       BMLoop *l,
+                                                       BMVert *v,
+                                                       const int cd_loop_uv_offset)
+{
+  BMEdge *e_first, *e_iter;
+  e_first = e_iter = l->e;
+  do {
+    BMLoop *l_radial_iter = e_iter->l;
+    do {
+      if ((l_radial_iter->f != l->f) && uvedit_face_visible_test(scene, l_radial_iter->f) &&
+          (l->v == l_radial_iter->v)) {
+
+        if (BM_loop_uv_share_vert_check(l, l_radial_iter, cd_loop_uv_offset) &&
+            !uvedit_face_select_test(scene, l_radial_iter->f, cd_loop_uv_offset)) {
+          return true;
+        }
+      }
+    } while ((l_radial_iter = l_radial_iter->radial_next) != e_iter->l);
+  } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
+
+  return false;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name UV Flush selection
  *
- * TODO: Flushing selections based on current UV editor selection modes
- * Selections might need to be flushed in both directions (upwards and vice-versa - Refer invert
- * all option in UV select all operator).
+ * Utility functions to flush the uv-selection
+ * \{ */
+
+/**
+ * Flushes selection upwards (verts to edge)
  */
+void uv_flush_vert_to_edge(Scene *scene, Object *obedit, const int cd_loop_uv_offset)
+{
+  BMEditMesh *em = BKE_editmesh_from_object(obedit);
+  BMFace *efa;
+  BMLoop *l;
+  BMIter iter, liter;
+  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) {
+      MLoopUV *luv, *luv_next;
+      luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+      luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+      if ((luv->flag & MLOOPUV_VERTSEL) && (luv_next->flag & MLOOPUV_VERTSEL)) {
+        luv->flag |= MLOOPUV_EDGESEL;
+      }
+      else {
+        luv->flag &= ~MLOOPUV_EDGESEL;
+      }
+    }
+  }
+}
+
+/**
+ * Flushes selection downwards (edge to verts)
+ * Could be renamed to uv_validate_selection_state()
+ *
+ * UNUSUAL CASE : Flushing downwards
+ * Useful when edges that need to be selected are marked using MLOOPUV_EDGESEL flag
+ */
+void uv_flush_edge_to_vert(Scene *scene, Object *obedit, const int cd_loop_uv_offset)
+{
+  BMEditMesh *em = BKE_editmesh_from_object(obedit);
+  BMFace *efa;
+  BMLoop *l;
+  BMIter iter, liter;
+  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) {
+      MLoopUV *luv, *luv_next;
+      luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+      luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+      if (luv->flag & MLOOPUV_EDGESEL) {
+        luv->flag |= MLOOPUV_VERTSEL;
+        luv_next->flag |= MLOOPUV_VERTSEL;
+      }
+    }
+  }
+}
+
+/** \} */
+
+/* NOTE : UV Selection mode flushing NOT implemented for now
+ * Currently there's now way to know the instant when the user changes UV selection modes. */
 
 /* -------------------------------------------------------------------- */
 /** \name Find Nearest to Element
@@ -1581,9 +1755,9 @@ static void uv_select_linked_multi(Sc

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list