[Bf-blender-cvs] [613d314251f] master: UV: support region fill for path select

Campbell Barton noreply at git.blender.org
Wed Jul 15 15:21:11 CEST 2020


Commit: 613d314251f32f32d9f634d073ce0d6993c22754
Author: Campbell Barton
Date:   Wed Jul 15 17:35:57 2020 +1000
Branches: master
https://developer.blender.org/rB613d314251f32f32d9f634d073ce0d6993c22754

UV: support region fill for path select

This matches edit-mesh region selection (Ctrl-Shift-Select).

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

M	release/scripts/presets/keyconfig/keymap_data/blender_default.py
M	source/blender/bmesh/CMakeLists.txt
M	source/blender/bmesh/bmesh_tools.h
A	source/blender/bmesh/tools/bmesh_path_region_uv.c
A	source/blender/bmesh/tools/bmesh_path_region_uv.h
M	source/blender/editors/uvedit/uvedit_path.c

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

diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 3a885837444..fae247b30a5 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -850,7 +850,10 @@ def km_uv_editor(params):
          {"properties": [("extend", False)]}),
         ("uv.select_loop", {"type": params.select_mouse, "value": params.select_mouse_value, "shift": True, "alt": True},
          {"properties": [("extend", True)]}),
-        ("uv.shortest_path_pick", {"type": params.select_mouse, "value": params.select_mouse_value, "ctrl": True}, None),
+        ("uv.shortest_path_pick", {"type": params.select_mouse, "value": params.select_mouse_value, "ctrl": True},
+         {"properties": [("use_fill", False)]}),
+        ("uv.shortest_path_pick", {"type": params.select_mouse, "value": params.select_mouse_value, "ctrl": True, "shift": True},
+         {"properties": [("use_fill", True)]}),
         ("uv.select_split", {"type": 'Y', "value": 'PRESS'}, None),
         ("uv.select_box", {"type": 'B', "value": 'PRESS'},
          {"properties": [("pinned", False)]}),
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 0943b4a9c2a..fca411e594f 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -155,6 +155,8 @@ set(SRC
   tools/bmesh_path_region.h
   tools/bmesh_path_uv.c
   tools/bmesh_path_uv.h
+  tools/bmesh_path_region_uv.c
+  tools/bmesh_path_region_uv.h
   tools/bmesh_region_match.c
   tools/bmesh_region_match.h
   tools/bmesh_separate.c
diff --git a/source/blender/bmesh/bmesh_tools.h b/source/blender/bmesh/bmesh_tools.h
index a0dc6abf009..4593f34792b 100644
--- a/source/blender/bmesh/bmesh_tools.h
+++ b/source/blender/bmesh/bmesh_tools.h
@@ -36,6 +36,7 @@ extern "C" {
 #include "tools/bmesh_edgesplit.h"
 #include "tools/bmesh_path.h"
 #include "tools/bmesh_path_region.h"
+#include "tools/bmesh_path_region_uv.h"
 #include "tools/bmesh_path_uv.h"
 #include "tools/bmesh_region_match.h"
 #include "tools/bmesh_separate.h"
diff --git a/source/blender/bmesh/tools/bmesh_path_region_uv.c b/source/blender/bmesh/tools/bmesh_path_region_uv.c
new file mode 100644
index 00000000000..d036c20d0e4
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_path_region_uv.c
@@ -0,0 +1,502 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bmesh
+ *
+ * Find the region defined by the path(s) between 2 UV elements.
+ * (path isn't ordered).
+ *
+ * \note This uses the same behavior as bmesh_path_region.c
+ * however walking UV's causes enough differences that it's
+ * impractical to share the code.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_alloca.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_utildefines_stack.h"
+
+#include "bmesh.h"
+#include "bmesh_path_region_uv.h" /* own include */
+
+/**
+ * Special handling of vertices with 2 edges
+ * (act as if the edge-chain is a single edge).
+ *
+ * \note Regarding manifold edge stepping: #BM_vert_is_edge_pair_manifold usage.
+ * Logic to skip a chain of vertices is not applied at boundaries because it gives
+ * strange behavior from a user perspective especially with boundary quads, see: T52701
+ *
+ * Restrict walking over a vertex chain to cases where the edges share the same faces.
+ * This is more typical of what a user would consider a vertex chain.
+ */
+#define USE_EDGE_CHAIN
+
+#ifdef USE_EDGE_CHAIN
+/**
+ * Takes a vertex with 2 edge users and assigns the vertices at each end-point,
+ *
+ * \return Success when \a l_end_pair values are set or false if the edges loop back on themselves.
+ */
+static bool bm_loop_pair_ends(BMLoop *l_pivot, BMLoop *l_end_pair[2])
+{
+  int j;
+  for (j = 0; j < 2; j++) {
+    BMLoop *l_other = j ? l_pivot->next : l_pivot->prev;
+    while (BM_vert_is_edge_pair_manifold(l_other->v)) {
+      l_other = j ? l_other->next : l_other->prev;
+      if (l_other == l_pivot) {
+        return false;
+      }
+    }
+    l_end_pair[j] = l_other;
+  }
+  BLI_assert(j == 2);
+  return true;
+}
+#endif /* USE_EDGE_CHAIN */
+
+/** \name Loop Vertex in Region Checks
+ * \{ */
+
+static bool bm_loop_region_test(BMLoop *l, int *const depths[2], const int pass)
+{
+  const int index = BM_elem_index_get(l);
+  return (((depths[0][index] != -1) && (depths[1][index] != -1)) &&
+          ((depths[0][index] + depths[1][index]) < pass));
+}
+
+#ifdef USE_EDGE_CHAIN
+static bool bm_loop_region_test_chain(BMLoop *l, int *const depths[2], const int pass)
+{
+  BMLoop *l_end_pair[2];
+  if (bm_loop_region_test(l, depths, pass)) {
+    return true;
+  }
+  if (BM_vert_is_edge_pair_manifold(l->v) && bm_loop_pair_ends(l, l_end_pair) &&
+      bm_loop_region_test(l_end_pair[0], depths, pass) &&
+      bm_loop_region_test(l_end_pair[1], depths, pass)) {
+    return true;
+  }
+
+  return false;
+}
+#else
+static bool bm_loop_region_test_chain(BMLoop *l, int *const depths[2], const int pass)
+{
+  return bm_loop_region_test(l, depths, pass);
+}
+#endif
+
+/** \} */
+
+/**
+ * Main logic for calculating region between 2 elements.
+ *
+ * This method works walking (breadth first) over all vertices,
+ * keeping track of topological distance from the source.
+ *
+ * This is done in both directions, after that each vertices 'depth' is added to check
+ * if its less than the number of passes needed to complete the search.
+ * When it is, we know the path is one of possible paths
+ * that have the minimum topological distance.
+ *
+ * \note Only verts without BM_ELEM_TAG will be walked over.
+ */
+static LinkNode *mesh_calc_path_region_elem(BMesh *bm,
+                                            BMElem *ele_src,
+                                            BMElem *ele_dst,
+                                            const uint cd_loop_uv_offset,
+                                            const char path_htype)
+{
+  int ele_loops_len[2];
+  BMLoop **ele_loops[2];
+
+  /* Get vertices from any `ele_src/ele_dst` elements. */
+  for (int side = 0; side < 2; side++) {
+    BMElem *ele = side ? ele_dst : ele_src;
+    int j = 0;
+
+    if (ele->head.htype == BM_FACE) {
+      BMFace *f = (BMFace *)ele;
+      ele_loops[side] = BLI_array_alloca(ele_loops[side], f->len);
+
+      BMLoop *l_first, *l_iter;
+      l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+      do {
+        ele_loops[side][j++] = l_iter;
+      } while ((l_iter = l_iter->next) != l_first);
+    }
+    else if (ele->head.htype == BM_LOOP) {
+      if (path_htype == BM_EDGE) {
+        BMLoop *l = (BMLoop *)ele;
+        ele_loops[side] = BLI_array_alloca(ele_loops[side], 2);
+        ele_loops[side][j++] = l;
+        ele_loops[side][j++] = l->next;
+      }
+      else if (path_htype == BM_VERT) {
+        BMLoop *l = (BMLoop *)ele;
+        ele_loops[side] = BLI_array_alloca(ele_loops[side], 1);
+
+        ele_loops[side][j++] = l;
+      }
+      else {
+        BLI_assert(0);
+      }
+    }
+    else {
+      BLI_assert(0);
+    }
+    ele_loops_len[side] = j;
+  }
+
+  int *depths[2] = {NULL};
+  int pass = 0;
+
+  BMLoop **stack = MEM_mallocN(sizeof(*stack) * bm->totloop, __func__);
+  BMLoop **stack_other = MEM_mallocN(sizeof(*stack_other) * bm->totloop, __func__);
+
+  STACK_DECLARE(stack);
+  STACK_INIT(stack, bm->totloop);
+
+  STACK_DECLARE(stack_other);
+  STACK_INIT(stack_other, bm->totloop);
+
+  BM_mesh_elem_index_ensure(bm, BM_LOOP);
+
+  /* After exhausting all possible elements, we should have found all elements on the 'side_other'.
+   * otherwise, exit early. */
+  bool found_all = false;
+
+  for (int side = 0; side < 2; side++) {
+    const int side_other = !side;
+
+    /* initialize depths to -1 (un-touched), fill in with the depth as we walk over the edges. */
+    depths[side] = MEM_mallocN(sizeof(*depths[side]) * bm->totloop, __func__);
+    copy_vn_i(depths[side], bm->totloop, -1);
+
+    /* needed for second side */
+    STACK_CLEAR(stack);
+    STACK_CLEAR(stack_other);
+
+    for (int i = 0; i < ele_loops_len[side]; i++) {
+      BMLoop *l = ele_loops[side][i];
+      depths[side][BM_elem_index_get(l)] = 0;
+      if (!BM_elem_flag_test(l, BM_ELEM_TAG)) {
+        STACK_PUSH(stack, l);
+      }
+    }
+
+#ifdef USE_EDGE_CHAIN
+    /* Expand initial state to end-point vertices when they only have 2x edges,
+     * this prevents odd behavior when source or destination are in the middle
+     * of a long chain of edges. */
+    if (ELEM(path_htype, BM_VERT, BM_EDGE)) {
+      for (int i = 0; i < ele_loops_len[side]; i++) {
+        BMLoop *l = ele_loops[side][i];
+        BMLoop *l_end_pair[2];
+        if (BM_vert_is_edge_pair_manifold(l->v) && bm_loop_pair_ends(l, l_end_pair)) {
+          for (int j = 0; j < 2; j++) {
+            const int l_end_index = BM_elem_index_get(l_end_pair[j]);
+            if (depths[side][l_end_index] == -1) {
+              depths[side][l_end_index] = 0;
+              if (!BM_elem_flag_test(l_end_pair[j], BM_ELEM_TAG)) {
+                STACK_PUSH(stack, l_end_pair[j]);
+              }
+            }
+          }
+        }
+      }
+    }
+#endif /* USE_EDGE_CHAIN */
+
+    /* Keep walking over connected geometry until we find all the vertices in
+     * `ele_loops[side_other]`, or exit the loop when there's no connection. */
+    found_all = false;
+    for (pass = 1; (STACK_SIZE(stack) != 0); pass++) {
+      while (STACK_S

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list