[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