|
|
|
|
@@ -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);
|
|
|
|
|
|