diff options
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_uv.c | 4 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_intern.h | 31 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_ops.c | 217 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_smart_stitch.c | 14 |
4 files changed, 153 insertions, 113 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index 700b0969277..6928610f280 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -650,9 +650,9 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm /* we need to find the active island here */ if (do_island_optimization) { UvElement *element; - NearestHit hit; + UvNearestHit hit = UV_NEAREST_HIT_INIT; Image *ima = CTX_data_edit_image(C); - uv_find_nearest_vert(scene, ima, obedit, em, co, NULL, &hit); + uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit); element = BM_uv_element_get(data->elementMap, hit.efa, hit.l); island_index = element->island; diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index eb92f17544f..c5f16d6fb14 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -50,19 +50,30 @@ void uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_off /* find nearest */ -typedef struct NearestHit { +typedef struct UvNearestHit { + /** Always set if we have a hit. */ struct BMFace *efa; struct BMLoop *l; struct MLoopUV *luv, *luv_next; - int lindex; /* index of loop within face */ -} NearestHit; - -void uv_find_nearest_vert( - struct Scene *scene, struct Image *ima, struct Object *obedit, struct BMEditMesh *em, - const float co[2], const float penalty[2], struct NearestHit *hit); -void uv_find_nearest_edge( - struct Scene *scene, struct Image *ima, struct Object *obedit, struct BMEditMesh *em, - const float co[2], struct NearestHit *hit); + /** Index of loop within face. */ + int lindex; + /** Needs to be set before calling nearest functions. */ + float dist_sq; +} UvNearestHit; + +#define UV_NEAREST_HIT_INIT { .dist_sq = FLT_MAX, } + +bool uv_find_nearest_vert( + struct Scene *scene, struct Image *ima, struct Object *obedit, + const float co[2], const float penalty_dist, struct UvNearestHit *hit_final); + +bool uv_find_nearest_edge( + struct Scene *scene, struct Image *ima, struct Object *obedit, + const float co[2], struct UvNearestHit *hit_final); + +bool uv_find_nearest_face( + struct Scene *scene, struct Image *ima, struct Object *obedit, + const float co[2], struct UvNearestHit *hit_final); /* utility tool functions */ diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 61e0004915d..1c54ea0ebc1 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -707,76 +707,89 @@ bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], c /************************** find nearest ****************************/ -void uv_find_nearest_edge(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, const float co[2], NearestHit *hit) +bool uv_find_nearest_edge( + Scene *scene, Image *ima, Object *obedit, const float co[2], + UvNearestHit *hit) { + BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; BMLoop *l; BMIter iter, liter; MLoopUV *luv, *luv_next; - float mindist_squared, dist_squared; int i; + bool found = false; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - mindist_squared = 1e10f; - memset(hit, 0, sizeof(*hit)); - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { continue; - + } BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { 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); - dist_squared = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv); + const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv); - if (dist_squared < mindist_squared) { + if (dist_test_sq < hit->dist_sq) { hit->efa = efa; - + hit->l = l; hit->luv = luv; hit->luv_next = luv_next; hit->lindex = i; - mindist_squared = dist_squared; + hit->dist_sq = dist_test_sq; + found = true; } } } + return found; } -static void uv_find_nearest_face( - Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, const float co[2], NearestHit *hit) +bool uv_find_nearest_face( + Scene *scene, Image *ima, Object *obedit, const float co[2], + UvNearestHit *hit_final) { - BMFace *efa; - BMIter iter; - float mindist, dist, cent[2]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + bool found = false; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - mindist = 1e10f; - memset(hit, 0, sizeof(*hit)); + /* this will fill in hit.vert1 and hit.vert2 */ + float dist_sq_init = hit_final->dist_sq; + UvNearestHit hit = *hit_final; + if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { + hit.dist_sq = dist_sq_init; + hit.l = NULL; + hit.luv = hit.luv_next = NULL; - /*this will fill in hit.vert1 and hit.vert2*/ - uv_find_nearest_edge(scene, ima, obedit, em, co, hit); - hit->l = NULL; - hit->luv = hit->luv_next = NULL; + BMIter iter; + BMFace *efa; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) - continue; + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } - uv_poly_center(efa, cent, cd_loop_uv_offset); + float cent[2]; + uv_poly_center(efa, cent, cd_loop_uv_offset); - dist = len_manhattan_v2v2(co, cent); + const float dist_test_sq = len_squared_v2v2(co, cent); - if (dist < mindist) { - hit->efa = efa; - mindist = dist; + if (dist_test_sq < hit.dist_sq) { + hit.efa = efa; + hit.dist_sq = dist_test_sq; + found = true; + } } } + if (found) { + *hit_final = hit; + } + return found; } static bool uv_nearest_between(const BMLoop *l, const float co[2], @@ -790,57 +803,73 @@ static bool uv_nearest_between(const BMLoop *l, const float co[2], (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f)); } -void uv_find_nearest_vert( - Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, - float const co[2], const float penalty[2], NearestHit *hit) +bool uv_find_nearest_vert( + Scene *scene, Image *ima, Object *obedit, + float const co[2], const float penalty_dist, UvNearestHit *hit_final) { - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - float mindist, dist; - int i; + bool found = false; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + /* this will fill in hit.vert1 and hit.vert2 */ + float dist_sq_init = hit_final->dist_sq; + UvNearestHit hit = *hit_final; + if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { + hit.dist_sq = dist_sq_init; - /*this will fill in hit.vert1 and hit.vert2*/ - uv_find_nearest_edge(scene, ima, obedit, em, co, hit); - hit->l = NULL; - hit->luv = hit->luv_next = NULL; + hit.l = NULL; + hit.luv = hit.luv_next = NULL; - mindist = 1e10f; - memset(hit, 0, sizeof(*hit)); - - BM_mesh_elem_index_ensure(em->bm, BM_VERT); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMIter iter; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) - continue; + BM_mesh_elem_index_ensure(em->bm, BM_VERT); - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (penalty && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) - dist = len_manhattan_v2v2(co, luv->uv) + len_manhattan_v2(penalty); - else - dist = len_manhattan_v2v2(co, luv->uv); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - if (dist <= mindist) { - if (dist == mindist) { - if (!uv_nearest_between(l, co, cd_loop_uv_offset)) { - continue; - } + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + BMIter liter; + BMLoop *l; + int i; + BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { + float dist_test_sq; + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist; + dist_test_sq = SQUARE(dist_test_sq); + } + else { + dist_test_sq = len_squared_v2v2(co, luv->uv); } - mindist = dist; + if (dist_test_sq <= hit.dist_sq) { + if (dist_test_sq == hit.dist_sq) { + if (!uv_nearest_between(l, co, cd_loop_uv_offset)) { + continue; + } + } - hit->l = l; - hit->luv = luv; - hit->luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - hit->efa = efa; - hit->lindex = i; + hit.dist_sq = dist_test_sq; + + hit.l = l; + hit.luv = luv; + hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + hit.efa = efa; + hit.lindex = i; + found = true; + } } } } + + if (found) { + *hit_final = hit; + } + + return found; } bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float co[2], float r_uv[2]) @@ -964,7 +993,7 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, } static int uv_select_edgeloop( - Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, NearestHit *hit, + Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, UvNearestHit *hit, const float limit[2], const bool extend) { BMFace *efa; @@ -1065,8 +1094,8 @@ static int uv_select_edgeloop( /*********************** linked select ***********************/ static void uv_select_linked( - Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, - const float limit[2], NearestHit *hit, bool extend, bool select_faces) + Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, const float limit[2], + UvNearestHit *hit_final, bool extend, bool select_faces) { BMFace *efa; BMLoop *l; @@ -1096,7 +1125,8 @@ static void uv_select_linked( stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack"); flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag"); - if (!hit) { + if (hit_final == NULL) { + /* Use existing selection */ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { if (uvedit_face_visible_test(scene, obedit, ima, efa)) { if (select_faces) { @@ -1124,7 +1154,7 @@ static void uv_select_linked( } else { BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - if (efa == hit->efa) { + if (efa == hit_final->efa) { stack[stacksize] = a; stacksize++; flag[a] = 1; @@ -1986,12 +2016,11 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo BMLoop *l; BMIter iter, liter; MLoopUV *luv; - NearestHit hit; + UvNearestHit hit = UV_NEAREST_HIT_INIT; int i, selectmode, sticky, sync, *hitv = NULL; bool select = true; int flush = 0, hitlen = 0; /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ float limit[2], **hituv = NULL; - float penalty[2]; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); @@ -2001,8 +2030,13 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo * shift-selecting can consider an adjacent point close enough to add to * the selection rather than de-selecting the closest. */ - uvedit_pixel_to_float(sima, limit, 0.05f); - uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f)); + float penalty_dist; + { + float penalty[2]; + uvedit_pixel_to_float(sima, limit, 0.05f); + uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f)); + penalty_dist = len_v2(penalty); + } /* retrieve operation mode */ if (ts->uv_flag & UV_SYNC_SELECTION) { @@ -2026,8 +2060,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo /* find nearest element */ if (loop) { /* find edge */ - uv_find_nearest_edge(scene, ima, obedit, em, co, &hit); - if (hit.efa == NULL) { + if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { return OPERATOR_CANCELLED; } @@ -2035,8 +2068,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo } else if (selectmode == UV_SELECT_VERTEX) { /* find vertex */ - uv_find_nearest_vert(scene, ima, obedit, em, co, penalty, &hit); - if (hit.efa == NULL) { + if (!uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, &hit)) { return OPERATOR_CANCELLED; } @@ -2052,8 +2084,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo } else if (selectmode == UV_SELECT_EDGE) { /* find edge */ - uv_find_nearest_edge(scene, ima, obedit, em, co, &hit); - if (hit.efa == NULL) { + if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { return OPERATOR_CANCELLED; } @@ -2071,11 +2102,10 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo } else if (selectmode == UV_SELECT_FACE) { /* find face */ - uv_find_nearest_face(scene, ima, obedit, em, co, &hit); - if (hit.efa == NULL) { + if (!uv_find_nearest_face(scene, ima, obedit, co, &hit)) { return OPERATOR_CANCELLED; } - + /* make active */ BM_mesh_active_face_set(em->bm, hit.efa); @@ -2092,9 +2122,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo hitlen = hit.efa->len; } else if (selectmode == UV_SELECT_ISLAND) { - uv_find_nearest_edge(scene, ima, obedit, em, co, &hit); - - if (hit.efa == NULL) { + if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { return OPERATOR_CANCELLED; } @@ -2331,7 +2359,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent int extend; bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); - NearestHit hit, *hit_p = NULL; + 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"); @@ -2356,11 +2384,12 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent RNA_float_get_array(op->ptr, "location", co); } - uv_find_nearest_edge(scene, ima, obedit, em, co, &hit); - hit_p = &hit; + if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { + return OPERATOR_CANCELLED; + } } - uv_select_linked(scene, ima, obedit, em, limit, hit_p, extend, select_faces); + uv_select_linked(scene, ima, obedit, em, limit, pick ? &hit : NULL, extend, select_faces); DEG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 9cd34c46874..4c205818329 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -2127,16 +2127,16 @@ static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, Stitc { /* add uv under mouse to processed uv's */ float co[2]; - NearestHit hit; + UvNearestHit hit = UV_NEAREST_HIT_INIT; ARegion *ar = CTX_wm_region(C); Image *ima = CTX_data_edit_image(C); UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); if (state->mode == STITCH_VERT) { - uv_find_nearest_vert(scene, ima, state->obedit, state->em, co, NULL, &hit); - - if (hit.efa) { + if (uv_find_nearest_vert( + scene, ima, state->obedit, co, 0.0f, &hit)) + { /* Add vertex to selection, deselect all common uv's of vert other * than selected and update the preview. This behavior was decided so that * you can do stuff like deselect the opposite stitchable vertex and the initial still gets deselected */ @@ -2148,9 +2148,9 @@ static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, Stitc } } else { - uv_find_nearest_edge(scene, ima, state->obedit, state->em, co, &hit); - - if (hit.efa) { + if (uv_find_nearest_edge( + scene, ima, state->obedit, co, &hit)) + { UvEdge *edge = uv_edge_get(hit.l, state); stitch_select_edge(edge, state, false); } |