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:
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h27
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c228
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c14
4 files changed, 156 insertions, 117 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 5ef9d4a6499..7b636530d61 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, em, co, NULL, &hit);
+ uv_find_nearest_vert(scene, ima, em, 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 e028c08091c..b5ff46e9219 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -51,18 +51,31 @@ 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 MTexPoly *tf;
struct BMLoop *l;
struct MLoopUV *luv, *luv_next;
- int lindex; /* index of loop within face */
-} NearestHit;
+ /** Index of loop within face. */
+ int lindex;
+ /** Needs to be set before calling nearest functions. */
+ float dist_sq;
+} UvNearestHit;
-void uv_find_nearest_vert(struct Scene *scene, struct Image *ima, 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 BMEditMesh *em,
- const float co[2], struct NearestHit *hit);
+#define UV_NEAREST_HIT_INIT { .dist_sq = FLT_MAX, }
+
+bool uv_find_nearest_vert(
+ struct Scene *scene, struct Image *ima, struct BMEditMesh *em,
+ const float co[2], const float penalty_dist, struct UvNearestHit *hit_final);
+
+bool uv_find_nearest_edge(
+ struct Scene *scene, struct Image *ima, struct BMEditMesh *em,
+ const float co[2], struct UvNearestHit *hit_final);
+
+bool uv_find_nearest_face(
+ struct Scene *scene, struct Image *ima, struct BMEditMesh *em,
+ 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 bf5a06f0a1c..1ee10268be5 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -760,83 +760,93 @@ static bool uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2
/************************** find nearest ****************************/
-void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, const float co[2], NearestHit *hit)
+bool uv_find_nearest_edge(
+ Scene *scene, Image *ima, BMEditMesh *em, const float co[2],
+ UvNearestHit *hit)
{
MTexPoly *tf;
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);
const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
- 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) {
tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
+ if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
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->tf = tf;
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, BMEditMesh *em, const float co[2], NearestHit *hit)
+bool uv_find_nearest_face(
+ Scene *scene, Image *ima, BMEditMesh *em, const float co[2],
+ UvNearestHit *hit_final)
{
- MTexPoly *tf;
- BMFace *efa;
- BMIter iter;
- float mindist, dist, cent[2];
+ bool found = false;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
- 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, em, 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, 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) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
- continue;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
+ 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->tf = tf;
- 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],
@@ -850,60 +860,74 @@ 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, BMEditMesh *em,
- float const co[2], const float penalty[2], NearestHit *hit)
+bool uv_find_nearest_vert(
+ Scene *scene, Image *ima, BMEditMesh *em,
+ float const co[2], const float penalty_dist, UvNearestHit *hit_final)
{
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MTexPoly *tf;
- MLoopUV *luv;
- float mindist, dist;
- int i;
+ bool found = false;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
+ /* 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, em, co, &hit)) {
+ hit.dist_sq = dist_sq_init;
- /*this will fill in hit.vert1 and hit.vert2*/
- uv_find_nearest_edge(scene, ima, 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);
+ BMFace *efa;
+ BMIter iter;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
- 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);
+ const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
- 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) {
+ MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
+ 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->tf = tf;
- 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])
@@ -1029,8 +1053,9 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, UvMapVert *first1,
return true;
}
-static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestHit *hit,
- const float limit[2], const bool extend)
+static int uv_select_edgeloop(
+ Scene *scene, Image *ima, BMEditMesh *em, UvNearestHit *hit,
+ const float limit[2], const bool extend)
{
BMFace *efa;
BMIter iter, liter;
@@ -1133,12 +1158,13 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH
/*********************** linked select ***********************/
-static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], NearestHit *hit, bool extend, bool select_faces)
+static void uv_select_linked(
+ Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], UvNearestHit *hit_final,
+ bool extend, bool select_faces)
{
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
UvVertMap *vmap;
UvMapVert *vlist, *iterv, *startv;
@@ -1165,9 +1191,10 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
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) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
if (uvedit_face_visible_test(scene, ima, efa, tf)) {
if (select_faces) {
@@ -1195,7 +1222,7 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
}
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;
@@ -2084,12 +2111,11 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
BMIter iter, liter;
MTexPoly *tf;
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);
const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
@@ -2100,8 +2126,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) {
@@ -2125,8 +2156,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, em, co, &hit);
- if (hit.efa == NULL) {
+ if (!uv_find_nearest_edge(scene, ima, em, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2134,8 +2164,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, em, co, penalty, &hit);
- if (hit.efa == NULL) {
+ if (!uv_find_nearest_vert(scene, ima, em, co, penalty_dist, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2151,8 +2180,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, em, co, &hit);
- if (hit.efa == NULL) {
+ if (!uv_find_nearest_edge(scene, ima, em, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2170,11 +2198,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, em, co, &hit);
- if (hit.efa == NULL) {
+ if (!uv_find_nearest_face(scene, ima, em, co, &hit)) {
return OPERATOR_CANCELLED;
}
-
+
/* make active */
BM_mesh_active_face_set(em->bm, hit.efa);
@@ -2191,9 +2218,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, em, co, &hit);
-
- if (hit.efa == NULL) {
+ if (!uv_find_nearest_edge(scene, ima, em, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2432,7 +2457,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");
@@ -2457,11 +2482,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, em, co, &hit);
- hit_p = &hit;
+ if (!uv_find_nearest_edge(scene, ima, em, co, &hit)) {
+ return OPERATOR_CANCELLED;
+ }
}
- uv_select_linked(scene, ima, em, limit, hit_p, extend, select_faces);
+ uv_select_linked(scene, ima, em, limit, pick ? &hit : NULL, extend, select_faces);
DAG_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 da36170310a..057417b898f 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -2058,16 +2058,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->em, co, NULL, &hit);
-
- if (hit.efa) {
+ if (uv_find_nearest_vert(
+ scene, ima, state->em, 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 */
@@ -2079,9 +2079,9 @@ static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, Stitc
}
}
else {
- uv_find_nearest_edge(scene, ima, state->em, co, &hit);
-
- if (hit.efa) {
+ if (uv_find_nearest_edge(
+ scene, ima, state->em, co, &hit))
+ {
UvEdge *edge = uv_edge_get(hit.l, state);
stitch_select_edge(edge, state, false);
}