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:
Diffstat (limited to 'source/blender/editors/uvedit/uvedit_select.c')
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c237
1 files changed, 183 insertions, 54 deletions
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index ece0158bc9b..149c5cf1f96 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.
*
@@ -529,7 +582,7 @@ void uvedit_uv_select_enable(const Scene *scene,
}
if (do_history) {
- BM_select_history_remove(em->bm, (BMElem *)l->v);
+ BM_select_history_store(em->bm, (BMElem *)l->v);
}
}
else {
@@ -671,7 +724,7 @@ bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNea
}
float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
+ BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
const float dist_test_sq = len_squared_v2v2(co, cent);
@@ -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
* \{ */
@@ -1144,11 +1263,13 @@ static void uv_select_linked_multi(Scene *scene,
Object **objects,
const uint objects_len,
UvNearestHit *hit_final,
- bool extend,
+ const bool extend,
bool deselect,
- bool toggle,
- bool select_faces)
+ const bool toggle,
+ const bool select_faces)
{
+ const bool uv_sync_select = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
+
/* loop over objects, or just use hit_final->ob */
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
if (hit_final && ob_index != 0) {
@@ -1159,7 +1280,6 @@ static void uv_select_linked_multi(Scene *scene,
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MLoopUV *luv;
UvVertMap *vmap;
UvMapVert *vlist, *iterv, *startv;
int i, stacksize = 0, *stack;
@@ -1177,7 +1297,7 @@ static void uv_select_linked_multi(Scene *scene,
*
* Better solve this by having a delimit option for select-linked operator,
* keeping island-select working as is. */
- vmap = BM_uv_vert_map_create(em->bm, !select_faces, false);
+ vmap = BM_uv_vert_map_create(em->bm, !uv_sync_select, false);
if (vmap == NULL) {
continue;
@@ -1199,14 +1319,42 @@ static void uv_select_linked_multi(Scene *scene,
}
else {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ bool add_to_stack = true;
+ if (uv_sync_select && !select_faces) {
+ /* Special case, vertex/edge & sync select being enabled.
+ *
+ * Without this, a second linked select will 'grow' each time as each new
+ * selection reaches the boundaries of islands that share vertices but not UV's.
+ *
+ * Rules applied here:
+ * - This loops face isn't selected.
+ * - The only other fully selected face is connected or,
+ * - There are no connected fully selected faces UV-connected to this loop.
+ */
+ if (uvedit_face_select_test(scene, l->f, cd_loop_uv_offset)) {
+ /* pass */
+ }
+ else {
+ BMIter liter_other;
+ BMLoop *l_other;
+ BM_ITER_ELEM (l_other, &liter_other, l->v, BM_LOOPS_OF_VERT) {
+ if ((l != l_other) &&
+ !BM_loop_uv_share_vert_check(l, l_other, cd_loop_uv_offset) &&
+ uvedit_face_select_test(scene, l_other->f, cd_loop_uv_offset)) {
+ add_to_stack = false;
+ break;
+ }
+ }
+ }
+ }
- break;
+ if (add_to_stack) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+ break;
+ }
}
}
}
@@ -1275,10 +1423,9 @@ static void uv_select_linked_multi(Scene *scene,
}
else {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
found_selected = true;
+ break;
}
}
@@ -1295,10 +1442,7 @@ static void uv_select_linked_multi(Scene *scene,
BM_face_select_set(em->bm, efa, value); \
} \
else { \
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \
- luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \
- } \
+ uvedit_face_select_set(scene, em, efa, value, false, cd_loop_uv_offset); \
} \
(void)0
@@ -1323,6 +1467,17 @@ static void uv_select_linked_multi(Scene *scene,
MEM_freeN(stack);
MEM_freeN(flag);
BM_uv_vert_map_free(vmap);
+
+ if (uv_sync_select) {
+ if (deselect) {
+ EDBM_deselect_flush(em);
+ }
+ else {
+ if (!select_faces) {
+ EDBM_selectmode_flush(em);
+ }
+ }
+ }
}
}
@@ -2144,13 +2299,6 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
UvNearestHit hit = UV_NEAREST_HIT_INIT;
- if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
- BKE_report(op->reports,
- RPT_ERROR,
- "Select linked only works in face select mode when sync selection is enabled");
- return OPERATOR_CANCELLED;
- }
-
if (pick) {
extend = RNA_boolean_get(op->ptr, "extend");
deselect = RNA_boolean_get(op->ptr, "deselect");
@@ -2181,7 +2329,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
}
}
- if (!extend) {
+ if (!extend && !deselect) {
uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
}
@@ -2383,25 +2531,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)
@@ -2712,7 +2841,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
BM_elem_flag_disable(efa, BM_ELEM_TAG);
if (uvedit_face_visible_test(scene, efa)) {
- uv_poly_center(efa, cent, cd_loop_uv_offset);
+ BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
if (BLI_rctf_isect_pt_v(&rectf, cent)) {
BM_elem_flag_enable(efa, BM_ELEM_TAG);
changed = true;
@@ -2806,7 +2935,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);
}
}
@@ -2943,7 +3072,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
/* assume not touched */
if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
+ BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
if (uv_circle_select_is_point_inside(cent, offset, ellipse)) {
BM_elem_flag_enable(efa, BM_ELEM_TAG);
changed = true;
@@ -3026,7 +3155,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);
}
}
@@ -3134,7 +3263,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
/* assume not touched */
if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
+ BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcoords, mcoords_len, cent)) {
BM_elem_flag_enable(efa, BM_ELEM_TAG);
changed = true;
@@ -3221,7 +3350,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);
}
}