Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2020-07-30 07:21:49 +0300
committerCampbell Barton <ideasman42@gmail.com>2020-07-30 07:21:49 +0300
commit1f48e67002159a149ef17e57c615814f7e8c29f3 (patch)
tree0eae764b6e42b6fb260f280f982594980baf1110
parent422e5e372ed3546273adc2415aa3bb49444dcb3a (diff)
parent69ec7ab873f3e75d46077f303396b194c728479e (diff)
Merge branch 'blender-v2.90-release' into master
-rw-r--r--source/blender/editors/include/ED_uvedit.h3
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h9
-rw-r--r--source/blender/editors/uvedit/uvedit_path.c264
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c144
4 files changed, 300 insertions, 120 deletions
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index c89a9fe0e99..935b99ba8e8 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -217,6 +217,9 @@ struct BMLoop *ED_uvedit_active_vert_loop_get(struct BMesh *bm);
void ED_uvedit_active_edge_loop_set(struct BMesh *bm, struct BMLoop *l);
struct BMLoop *ED_uvedit_active_edge_loop_get(struct BMesh *bm);
+char ED_uvedit_select_mode_get(const Scene *scene);
+void ED_uvedit_select_sync_flush(const ToolSettings *ts, struct BMEditMesh *em, const bool select);
+
/* uvedit_unwrap_ops.c */
void ED_uvedit_live_unwrap_begin(struct Scene *scene, struct Object *obedit);
void ED_uvedit_live_unwrap_re_solve(void);
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index d4f284a1619..5ccc6e29026 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -88,6 +88,15 @@ bool uv_find_nearest_face_multi(struct Scene *scene,
const float co[2],
struct UvNearestHit *hit_final);
+BMLoop *uv_find_nearest_loop_from_vert(struct Scene *scene,
+ struct Object *obedit,
+ struct BMVert *v,
+ const float co[2]);
+BMLoop *uv_find_nearest_loop_from_edge(struct Scene *scene,
+ struct Object *obedit,
+ struct BMEdge *e,
+ const float co[2]);
+
/* utility tool functions */
void uvedit_live_unwrap_update(struct SpaceImage *sima,
diff --git a/source/blender/editors/uvedit/uvedit_path.c b/source/blender/editors/uvedit/uvedit_path.c
index 1c7da7af0f4..546aad078aa 100644
--- a/source/blender/editors/uvedit/uvedit_path.c
+++ b/source/blender/editors/uvedit/uvedit_path.c
@@ -69,9 +69,6 @@
#include "bmesh_tools.h"
-/* TODO(campbell): region filling, matching mesh selection. */
-#define USE_FILL
-
/* -------------------------------------------------------------------- */
/** \name Local Utilities
* \{ */
@@ -84,8 +81,12 @@
*
* While the code below is a bit awkward, it's significantly less overhead than
* adding full edge selection which is nearly the same as vertex path in the case of UV's.
+ *
+ * \param use_nearest: When false use the post distant pair of loops,
+ * use when filling a region as we want both verts from each edge to be included in the region.
*/
-static void bm_loop_calc_vert_pair_from_edge_pair(const int cd_loop_uv_offset,
+static void bm_loop_calc_vert_pair_from_edge_pair(const bool use_nearest,
+ const int cd_loop_uv_offset,
const float aspect_y,
BMElem **ele_src_p,
BMElem **ele_dst_p,
@@ -116,8 +117,15 @@ static void bm_loop_calc_vert_pair_from_edge_pair(const int cd_loop_uv_offset,
};
int i_best = 0;
for (int i = 1; i < ARRAY_SIZE(tests); i++) {
- if (tests[i].len_sq < tests[i_best].len_sq) {
- i_best = i;
+ if (use_nearest) {
+ if (tests[i].len_sq < tests[i_best].len_sq) {
+ i_best = i;
+ }
+ }
+ else {
+ if (tests[i].len_sq > tests[i_best].len_sq) {
+ i_best = i;
+ }
}
}
@@ -139,14 +147,13 @@ struct PathSelectParams {
bool track_active;
bool use_topology_distance;
bool use_face_step;
-#ifdef USE_FILL
bool use_fill;
-#endif
struct CheckerIntervalParams interval_params;
};
struct UserData_UV {
Scene *scene;
+ BMEditMesh *em;
uint cd_loop_uv_offset;
};
@@ -162,13 +169,11 @@ static void path_select_properties(wmOperatorType *ot)
false,
"Topology Distance",
"Find the minimum number of steps, ignoring spatial distance");
-#ifdef USE_FILL
RNA_def_boolean(ot->srna,
"use_fill",
false,
"Fill Region",
"Select all paths between the source/destination elements");
-#endif
WM_operator_properties_checker_interval(ot, true);
}
@@ -177,9 +182,7 @@ static void path_select_params_from_op(wmOperator *op, struct PathSelectParams *
{
op_params->track_active = false;
op_params->use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
-#ifdef USE_FILL
op_params->use_fill = RNA_boolean_get(op->ptr, "use_fill");
-#endif
op_params->use_topology_distance = RNA_boolean_get(op->ptr, "use_topology_distance");
WM_operator_properties_checker_interval_from_op(op, &op_params->interval_params);
}
@@ -200,6 +203,7 @@ static bool looptag_test_cb(BMLoop *l, void *user_data_v)
{
/* All connected loops are selected or we return false. */
struct UserData_UV *user_data = user_data_v;
+ const Scene *scene = user_data->scene;
const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
BMIter iter;
@@ -208,7 +212,7 @@ static bool looptag_test_cb(BMLoop *l, void *user_data_v)
if (looptag_filter_cb(l_iter, user_data)) {
const MLoopUV *luv_iter = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
if (equals_v2v2(luv->uv, luv_iter->uv)) {
- if ((luv_iter->flag & MLOOPUV_VERTSEL) == 0) {
+ if (!uvedit_uv_select_test(scene, l_iter, cd_loop_uv_offset)) {
return false;
}
}
@@ -219,6 +223,8 @@ static bool looptag_test_cb(BMLoop *l, void *user_data_v)
static void looptag_set_cb(BMLoop *l, bool val, void *user_data_v)
{
struct UserData_UV *user_data = user_data_v;
+ const Scene *scene = user_data->scene;
+ BMEditMesh *em = user_data->em;
const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
BMIter iter;
@@ -227,28 +233,56 @@ static void looptag_set_cb(BMLoop *l, bool val, void *user_data_v)
if (looptag_filter_cb(l_iter, user_data)) {
MLoopUV *luv_iter = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
if (equals_v2v2(luv->uv, luv_iter->uv)) {
- SET_FLAG_FROM_TEST(luv_iter->flag, val, MLOOPUV_VERTSEL);
+ uvedit_uv_select_set(scene, em, l_iter, val, false, cd_loop_uv_offset);
}
}
}
}
-static void mouse_mesh_uv_shortest_path_vert(Scene *scene,
- Object *obedit,
- const struct PathSelectParams *op_params,
- BMLoop *l_src,
- BMLoop *l_dst,
- BMLoop *l_dst_add_to_path,
- const float aspect_y,
- const int cd_loop_uv_offset)
+static int mouse_mesh_uv_shortest_path_vert(Scene *scene,
+ Object *obedit,
+ const struct PathSelectParams *op_params,
+ BMLoop *l_src,
+ BMLoop *l_dst,
+ const float aspect_y,
+ const int cd_loop_uv_offset)
{
- const ToolSettings *ts = scene->toolsettings;
- const bool use_fake_edge_select = (ts->uv_selectmode & UV_SELECT_EDGE);
+ const char uv_selectmode = ED_uvedit_select_mode_get(scene);
+ const bool use_fake_edge_select = (uv_selectmode & UV_SELECT_EDGE);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
+ int flush = 0;
+
+ /* Variables to use when `use_fake_edge_select` is set. */
+ struct {
+ BMLoop *l_dst_activate;
+ BMLoop *l_dst_add_to_path;
+ } fake_edge_select = {NULL};
+
+ if (use_fake_edge_select) {
+ fake_edge_select.l_dst_activate = l_dst;
+
+ /* Use most distant when doing region selection.
+ * without this we get dangling edges outside the region. */
+ bool use_neaerst = (op_params->use_fill == false);
+ BMElem *ele_src = (BMElem *)l_src;
+ BMElem *ele_dst = (BMElem *)l_dst;
+ BMElem *ele_dst_final = NULL;
+ bm_loop_calc_vert_pair_from_edge_pair(
+ use_neaerst, cd_loop_uv_offset, aspect_y, &ele_src, &ele_dst, &ele_dst_final);
+
+ if (op_params->use_fill == false) {
+ /* Always activate the item under the cursor. */
+ fake_edge_select.l_dst_add_to_path = (BMLoop *)ele_dst_final;
+ }
+
+ l_src = (BMLoop *)ele_src;
+ l_dst = (BMLoop *)ele_dst;
+ }
struct UserData_UV user_data = {
.scene = scene,
+ .em = em,
.cd_loop_uv_offset = cd_loop_uv_offset,
};
@@ -280,11 +314,14 @@ static void mouse_mesh_uv_shortest_path_vert(Scene *scene,
BMLoop *l_dst_last = l_dst;
if (path) {
- if ((l_dst_add_to_path != NULL) && (BLI_linklist_index(path, l_dst_add_to_path) == -1)) {
- /* Append, this isn't optimal compared to #BLI_linklist_append, it's a one-off lookup. */
- LinkNode *path_last = BLI_linklist_find_last(path);
- BLI_linklist_insert_after(&path_last, l_dst_add_to_path);
- BLI_assert(BLI_linklist_find_last(path)->link == l_dst_add_to_path);
+ if (use_fake_edge_select) {
+ if ((fake_edge_select.l_dst_add_to_path != NULL) &&
+ (BLI_linklist_index(path, fake_edge_select.l_dst_add_to_path) == -1)) {
+ /* Append, this isn't optimal compared to #BLI_linklist_append, it's a one-off lookup. */
+ LinkNode *path_last = BLI_linklist_find_last(path);
+ BLI_linklist_insert_after(&path_last, fake_edge_select.l_dst_add_to_path);
+ BLI_assert(BLI_linklist_find_last(path)->link == fake_edge_select.l_dst_add_to_path);
+ }
}
/* toggle the flag */
@@ -310,6 +347,7 @@ static void mouse_mesh_uv_shortest_path_vert(Scene *scene,
} while ((void)depth++, (node = node->next));
BLI_linklist_free(path, NULL);
+ flush = all_set ? -1 : 1;
}
else {
const bool is_act = !looptag_test_cb(l_dst, &user_data);
@@ -319,12 +357,17 @@ static void mouse_mesh_uv_shortest_path_vert(Scene *scene,
if (op_params->track_active) {
/* Fake edge selection. */
if (use_fake_edge_select) {
- ED_uvedit_active_edge_loop_set(bm, l_dst_last);
+ BMLoop *l_dst_activate = fake_edge_select.l_dst_activate;
+ /* TODO(campbell): Search for an active loop attached to 'l_dst'.
+ * when `BLI_linklist_index(path, l_dst_activate) == -1`
+ * In practice this rarely happens though. */
+ ED_uvedit_active_edge_loop_set(bm, l_dst_activate);
}
else {
ED_uvedit_active_vert_loop_set(bm, l_dst_last);
}
}
+ return flush;
}
/** \} */
@@ -343,12 +386,12 @@ static bool facetag_test_cb(BMFace *f, void *user_data_v)
{
/* All connected loops are selected or we return false. */
struct UserData_UV *user_data = user_data_v;
+ const Scene *scene = user_data->scene;
const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
BMIter iter;
BMLoop *l_iter;
BM_ITER_ELEM (l_iter, &iter, f, BM_LOOPS_OF_FACE) {
- const MLoopUV *luv_iter = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
- if ((luv_iter->flag & MLOOPUV_VERTSEL) == 0) {
+ if (!uvedit_uv_select_test(scene, l_iter, cd_loop_uv_offset)) {
return false;
}
}
@@ -357,28 +400,27 @@ static bool facetag_test_cb(BMFace *f, void *user_data_v)
static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
{
struct UserData_UV *user_data = user_data_v;
+ const Scene *scene = user_data->scene;
+ BMEditMesh *em = user_data->em;
const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
- BMIter iter;
- BMLoop *l_iter;
- BM_ITER_ELEM (l_iter, &iter, f, BM_LOOPS_OF_FACE) {
- MLoopUV *luv_iter = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv_iter->flag, val, MLOOPUV_VERTSEL);
- }
+ uvedit_face_select_set(scene, em, f, val, false, cd_loop_uv_offset);
}
-static void mouse_mesh_uv_shortest_path_face(Scene *scene,
- Object *obedit,
- const struct PathSelectParams *op_params,
- BMFace *f_src,
- BMFace *f_dst,
- const float aspect_y,
- const int cd_loop_uv_offset)
+static int mouse_mesh_uv_shortest_path_face(Scene *scene,
+ Object *obedit,
+ const struct PathSelectParams *op_params,
+ BMFace *f_src,
+ BMFace *f_dst,
+ const float aspect_y,
+ const int cd_loop_uv_offset)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
+ int flush = 0;
struct UserData_UV user_data = {
.scene = scene,
+ .em = em,
.cd_loop_uv_offset = cd_loop_uv_offset,
};
@@ -433,6 +475,7 @@ static void mouse_mesh_uv_shortest_path_face(Scene *scene,
} while ((void)depth++, (node = node->next));
BLI_linklist_free(path, NULL);
+ flush = all_set ? -1 : 1;
}
else {
const bool is_act = !facetag_test_cb(f_dst, &user_data);
@@ -443,6 +486,7 @@ static void mouse_mesh_uv_shortest_path_face(Scene *scene,
/* Unlike other types, we can track active without it being selected. */
BM_mesh_active_face_set(bm, f_dst_last);
}
+ return flush;
}
/** \} */
@@ -462,44 +506,56 @@ static bool uv_shortest_path_pick_ex(Scene *scene,
const float aspect_y,
const int cd_loop_uv_offset)
{
+ const ToolSettings *ts = scene->toolsettings;
+ const char uv_selectmode = ED_uvedit_select_mode_get(scene);
bool ok = false;
+ int flush = 0;
if (ELEM(NULL, ele_src, ele_dst) || (ele_src->head.htype != ele_dst->head.htype)) {
/* pass */
}
else if (ele_src->head.htype == BM_FACE) {
- mouse_mesh_uv_shortest_path_face(scene,
- obedit,
- op_params,
- (BMFace *)ele_src,
- (BMFace *)ele_dst,
- aspect_y,
- cd_loop_uv_offset);
+ flush = mouse_mesh_uv_shortest_path_face(scene,
+ obedit,
+ op_params,
+ (BMFace *)ele_src,
+ (BMFace *)ele_dst,
+ aspect_y,
+ cd_loop_uv_offset);
ok = true;
}
else if (ele_src->head.htype == BM_LOOP) {
- const ToolSettings *ts = scene->toolsettings;
- BMElem *ele_dst_final = NULL;
- if (ts->uv_selectmode & UV_SELECT_EDGE) {
- if (op_params->use_fill == false) {
- bm_loop_calc_vert_pair_from_edge_pair(
- cd_loop_uv_offset, aspect_y, &ele_src, &ele_dst, &ele_dst_final);
- }
- }
- mouse_mesh_uv_shortest_path_vert(scene,
- obedit,
- op_params,
- (BMLoop *)ele_src,
- (BMLoop *)ele_dst,
- (BMLoop *)ele_dst_final,
- aspect_y,
- cd_loop_uv_offset);
+ flush = mouse_mesh_uv_shortest_path_vert(scene,
+ obedit,
+ op_params,
+ (BMLoop *)ele_src,
+ (BMLoop *)ele_dst,
+ aspect_y,
+ cd_loop_uv_offset);
ok = true;
}
if (ok) {
- Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
- BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT);
+ if (flush != 0) {
+ const bool select = (flush == 1);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (uv_selectmode & UV_SELECT_EDGE) {
+ /* Special case as we don't use true edge selection,
+ * flush the selection from the vertices. */
+ BM_mesh_select_mode_flush_ex(em->bm, SCE_SELECT_VERTEX);
+ }
+ }
+ ED_uvedit_select_sync_flush(scene->toolsettings, em, select);
+ }
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ }
+ else {
+ Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
+ BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT);
+ }
/* Only for region redraw. */
WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
}
@@ -511,13 +567,9 @@ static int uv_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEve
{
Scene *scene = CTX_data_scene(C);
const ToolSettings *ts = scene->toolsettings;
+ const char uv_selectmode = ED_uvedit_select_mode_get(scene);
/* We could support this, it needs further testing. */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BKE_report(op->reports, RPT_ERROR, "Sync selection doesn't support path select");
- return OPERATOR_CANCELLED;
- }
-
if (RNA_struct_property_is_set(op->ptr, "index")) {
return uv_shortest_path_pick_exec(C, op);
}
@@ -550,7 +602,7 @@ static int uv_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEve
BMElem *ele_src = NULL, *ele_dst = NULL;
- if (ts->uv_selectmode & UV_SELECT_FACE) {
+ if (uv_selectmode == UV_SELECT_FACE) {
UvNearestHit hit = UV_NEAREST_HIT_INIT;
if (!uv_find_nearest_face(scene, obedit, co, &hit)) {
return OPERATOR_CANCELLED;
@@ -562,21 +614,30 @@ static int uv_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEve
ele_src = (BMElem *)f_src;
ele_dst = (BMElem *)hit.efa;
}
- else if (ts->uv_selectmode & UV_SELECT_EDGE) {
+
+ else if (uv_selectmode & UV_SELECT_EDGE) {
UvNearestHit hit = UV_NEAREST_HIT_INIT;
if (!uv_find_nearest_edge(scene, obedit, co, &hit)) {
return OPERATOR_CANCELLED;
}
- BMLoop *l_src = ED_uvedit_active_edge_loop_get(bm);
- if (l_src != NULL) {
- const MLoopUV *luv_src_v1 = BM_ELEM_CD_GET_VOID_P(l_src, cd_loop_uv_offset);
- const MLoopUV *luv_src_v2 = BM_ELEM_CD_GET_VOID_P(l_src->next, cd_loop_uv_offset);
- if ((luv_src_v1->flag & MLOOPUV_VERTSEL) == 0 && (luv_src_v2->flag & MLOOPUV_VERTSEL) == 0) {
- l_src = NULL;
+ BMLoop *l_src = NULL;
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BMEdge *e_src = BM_mesh_active_edge_get(bm);
+ if (e_src != NULL) {
+ l_src = uv_find_nearest_loop_from_edge(scene, obedit, e_src, co);
+ }
+ }
+ else {
+ l_src = ED_uvedit_active_edge_loop_get(bm);
+ if (l_src != NULL) {
+ if ((!uvedit_uv_select_test(scene, l_src, cd_loop_uv_offset)) &&
+ (!uvedit_uv_select_test(scene, l_src->next, cd_loop_uv_offset))) {
+ l_src = NULL;
+ }
+ ele_src = (BMElem *)l_src;
}
}
-
ele_src = (BMElem *)l_src;
ele_dst = (BMElem *)hit.l;
}
@@ -586,14 +647,21 @@ static int uv_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEve
return OPERATOR_CANCELLED;
}
- BMLoop *l_src = ED_uvedit_active_vert_loop_get(bm);
- if (l_src != NULL) {
- const MLoopUV *luv_src = BM_ELEM_CD_GET_VOID_P(l_src, cd_loop_uv_offset);
- if ((luv_src->flag & MLOOPUV_VERTSEL) == 0) {
- l_src = NULL;
+ BMLoop *l_src = NULL;
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BMVert *v_src = BM_mesh_active_vert_get(bm);
+ if (v_src != NULL) {
+ l_src = uv_find_nearest_loop_from_vert(scene, obedit, v_src, co);
+ }
+ }
+ else {
+ l_src = ED_uvedit_active_vert_loop_get(bm);
+ if (l_src != NULL) {
+ if (!uvedit_uv_select_test(scene, l_src, cd_loop_uv_offset)) {
+ l_src = NULL;
+ }
}
}
-
ele_src = (BMElem *)l_src;
ele_dst = (BMElem *)hit.l;
}
@@ -607,11 +675,11 @@ static int uv_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEve
/* To support redo. */
int index;
- if (ts->uv_selectmode & UV_SELECT_FACE) {
+ if (uv_selectmode & UV_SELECT_FACE) {
BM_mesh_elem_index_ensure(bm, BM_FACE);
index = BM_elem_index_get(ele_dst);
}
- else if (ts->uv_selectmode & UV_SELECT_EDGE) {
+ else if (uv_selectmode & UV_SELECT_EDGE) {
BM_mesh_elem_index_ensure(bm, BM_LOOP);
index = BM_elem_index_get(ele_dst);
}
@@ -628,7 +696,7 @@ static int uv_shortest_path_pick_exec(bContext *C, wmOperator *op)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
+ const char uv_selectmode = ED_uvedit_select_mode_get(scene);
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
@@ -645,7 +713,7 @@ static int uv_shortest_path_pick_exec(bContext *C, wmOperator *op)
BMElem *ele_src, *ele_dst;
- if (ts->uv_selectmode & UV_SELECT_FACE) {
+ if (uv_selectmode & UV_SELECT_FACE) {
if (index < 0 || index >= bm->totface) {
return OPERATOR_CANCELLED;
}
@@ -654,7 +722,7 @@ static int uv_shortest_path_pick_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
}
- else if (ts->uv_selectmode & UV_SELECT_EDGE) {
+ else if (uv_selectmode & UV_SELECT_EDGE) {
if (index < 0 || index >= bm->totloop) {
return OPERATOR_CANCELLED;
}
@@ -720,7 +788,7 @@ static int uv_shortest_path_select_exec(bContext *C, wmOperator *op)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
+ const char uv_selectmode = ED_uvedit_select_mode_get(scene);
bool found_valid_elements = false;
float aspect_y;
@@ -746,10 +814,10 @@ static int uv_shortest_path_select_exec(bContext *C, wmOperator *op)
{
BMElem **ele_array = NULL;
int ele_array_len = 0;
- if (ts->uv_selectmode & UV_SELECT_FACE) {
+ if (uv_selectmode & UV_SELECT_FACE) {
ele_array = (BMElem **)ED_uvedit_selected_faces(scene, bm, 3, &ele_array_len);
}
- else if (ts->uv_selectmode & UV_SELECT_EDGE) {
+ else if (uv_selectmode & UV_SELECT_EDGE) {
ele_array = (BMElem **)ED_uvedit_selected_edges(scene, bm, 3, &ele_array_len);
}
else {
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 6699f247288..4c354ab5940 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -145,6 +145,59 @@ BMLoop *ED_uvedit_active_edge_loop_get(BMesh *bm)
* \{ */
/**
+ * Intentionally don't return #UV_SELECT_ISLAND as it's not an element type.
+ * In this case return #UV_SELECT_VERTEX as a fallback.
+ */
+char ED_uvedit_select_mode_get(const Scene *scene)
+{
+ const ToolSettings *ts = scene->toolsettings;
+ char uv_selectmode = UV_SELECT_VERTEX;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_VERTEX) {
+ uv_selectmode = UV_SELECT_VERTEX;
+ }
+ else if (ts->selectmode & SCE_SELECT_EDGE) {
+ uv_selectmode = UV_SELECT_EDGE;
+ }
+ else if (ts->selectmode & SCE_SELECT_FACE) {
+ uv_selectmode = UV_SELECT_FACE;
+ }
+ }
+ else {
+ if (ts->uv_selectmode & UV_SELECT_VERTEX) {
+ uv_selectmode = UV_SELECT_VERTEX;
+ }
+ else if (ts->uv_selectmode & UV_SELECT_EDGE) {
+ uv_selectmode = UV_SELECT_EDGE;
+ }
+ else if (ts->uv_selectmode & UV_SELECT_FACE) {
+ uv_selectmode = UV_SELECT_FACE;
+ }
+ }
+ return uv_selectmode;
+}
+
+void ED_uvedit_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const bool select)
+{
+ /* bmesh API handles flushing but not on de-select */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode != SCE_SELECT_FACE) {
+ if (select == false) {
+ EDBM_deselect_flush(em);
+ }
+ else {
+ EDBM_select_flush(em);
+ }
+ }
+
+ if (select == false) {
+ BM_select_history_validate(em->bm);
+ }
+ }
+}
+
+/**
* Apply a penalty to elements that are already selected
* so elements that aren't already selected are prioritized.
*
@@ -857,6 +910,72 @@ bool ED_uvedit_nearest_uv_multi(const Scene *scene,
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Find Nearest to Element
+ *
+ * These functions are quite specialized, useful when sync select is enabled
+ * and we want to pick an active UV vertex/edge from the active element which may
+ * have multiple UV's split out.
+ * \{ */
+
+BMLoop *uv_find_nearest_loop_from_vert(struct Scene *scene,
+ struct Object *obedit,
+ struct BMVert *v,
+ 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);
+
+ BMIter liter;
+ BMLoop *l;
+ BMLoop *l_found = NULL;
+ float dist_best_sq = FLT_MAX;
+
+ BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+ if (!uvedit_face_visible_test(scene, l->f)) {
+ continue;
+ }
+
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const float dist_test_sq = len_squared_v2v2(co, luv->uv);
+ if (dist_test_sq < dist_best_sq) {
+ dist_best_sq = dist_test_sq;
+ l_found = l;
+ }
+ }
+ return l_found;
+}
+
+BMLoop *uv_find_nearest_loop_from_edge(struct Scene *scene,
+ struct Object *obedit,
+ struct BMEdge *e,
+ 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);
+
+ BMIter eiter;
+ BMLoop *l;
+ BMLoop *l_found = NULL;
+ float dist_best_sq = FLT_MAX;
+
+ BM_ITER_ELEM (l, &eiter, e, BM_LOOPS_OF_EDGE) {
+ if (!uvedit_face_visible_test(scene, l->f)) {
+ continue;
+ }
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
+ if (dist_test_sq < dist_best_sq) {
+ dist_best_sq = dist_test_sq;
+ l_found = l;
+ }
+ }
+ return l_found;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Edge Loop Select
* \{ */
@@ -2383,25 +2502,6 @@ void UV_OT_select_split(wmOperatorType *ot)
ot->poll = ED_operator_uvedit; /* requires space image */
}
-static void uv_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const short select)
-{
- /* bmesh API handles flushing but not on de-select */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode != SCE_SELECT_FACE) {
- if (select == false) {
- EDBM_deselect_flush(em);
- }
- else {
- EDBM_select_flush(em);
- }
- }
-
- if (select == false) {
- BM_select_history_validate(em->bm);
- }
- }
-}
-
static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
const ToolSettings *ts,
Object *obedit)
@@ -2806,7 +2906,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
if (changed || use_pre_deselect) {
changed_multi = true;
- uv_select_sync_flush(ts, em, select);
+ ED_uvedit_select_sync_flush(ts, em, select);
uv_select_tag_update_for_object(depsgraph, ts, obedit);
}
}
@@ -3026,7 +3126,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
if (changed || use_pre_deselect) {
changed_multi = true;
- uv_select_sync_flush(ts, em, select);
+ ED_uvedit_select_sync_flush(ts, em, select);
uv_select_tag_update_for_object(depsgraph, ts, obedit);
}
}
@@ -3221,7 +3321,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
if (changed || use_pre_deselect) {
changed_multi = true;
- uv_select_sync_flush(ts, em, select);
+ ED_uvedit_select_sync_flush(ts, em, select);
uv_select_tag_update_for_object(depsgraph, ts, obedit);
}
}