forked from blender/blender
WIP: uv-simple-select (Version2) #2
@ -80,34 +80,11 @@ bool uv_find_nearest_edge_multi(struct Scene *scene,
|
|||||||
float penalty,
|
float penalty,
|
||||||
struct UvNearestHit *hit);
|
struct UvNearestHit *hit);
|
||||||
|
|
||||||
/**
|
|
||||||
* \param only_in_face: when true, only hit faces which `co` is inside.
|
|
||||||
* This gives users a result they might expect, especially when zoomed in.
|
|
||||||
*
|
|
||||||
* \note Concave faces can cause odd behavior, although in practice this isn't often an issue.
|
|
||||||
* The center can be outside the face, in this case the distance to the center
|
|
||||||
* could cause the face to be considered too far away.
|
|
||||||
* If this becomes an issue we could track the distance to the faces closest edge.
|
|
||||||
*/
|
|
||||||
bool uv_find_nearest_face_ex(struct Scene *scene,
|
|
||||||
struct Object *obedit,
|
|
||||||
const float co[2],
|
|
||||||
struct UvNearestHit *hit,
|
|
||||||
bool only_in_face);
|
|
||||||
bool uv_find_nearest_face(struct Scene *scene,
|
|
||||||
struct Object *obedit,
|
|
||||||
const float co[2],
|
|
||||||
struct UvNearestHit *hit);
|
|
||||||
bool uv_find_nearest_face_multi_ex(struct Scene *scene,
|
|
||||||
struct Object **objects,
|
|
||||||
uint objects_len,
|
|
||||||
const float co[2],
|
|
||||||
struct UvNearestHit *hit,
|
|
||||||
bool only_in_face);
|
|
||||||
bool uv_find_nearest_face_multi(struct Scene *scene,
|
bool uv_find_nearest_face_multi(struct Scene *scene,
|
||||||
struct Object **objects,
|
struct Object **objects,
|
||||||
uint objects_len,
|
uint objects_len,
|
||||||
const float co[2],
|
const float co[2],
|
||||||
|
float penalty,
|
||||||
struct UvNearestHit *hit);
|
struct UvNearestHit *hit);
|
||||||
|
|
||||||
BMLoop *uv_find_nearest_loop_from_vert(struct Scene *scene,
|
BMLoop *uv_find_nearest_loop_from_vert(struct Scene *scene,
|
||||||
|
@ -577,7 +577,7 @@ static int uv_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEve
|
|||||||
UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(®ion->v2d);
|
UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(®ion->v2d);
|
||||||
bool hit_found = false;
|
bool hit_found = false;
|
||||||
if (uv_selectmode == UV_SELECT_FACE) {
|
if (uv_selectmode == UV_SELECT_FACE) {
|
||||||
if (uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit)) {
|
if (uv_find_nearest_face_multi(scene, objects, objects_len, co, 0.0f, &hit)) {
|
||||||
hit_found = true;
|
hit_found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -876,8 +876,8 @@ bool uv_find_nearest_edge_multi(Scene *scene,
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool uv_find_nearest_face_ex(
|
static bool uv_find_nearest_face(
|
||||||
Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit, const bool only_in_face)
|
Scene *scene, Object *obedit, const float co[2], const float penalty, UvNearestHit *hit)
|
||||||
{
|
{
|
||||||
BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f));
|
BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f));
|
||||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||||
@ -893,60 +893,63 @@ bool uv_find_nearest_face_ex(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float cent[2];
|
if (BM_face_uv_point_inside_test(efa, co, cd_loop_uv_offset)) {
|
||||||
BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
|
|
||||||
|
|
||||||
float delta[2];
|
|
||||||
sub_v2_v2v2(delta, co, cent);
|
|
||||||
mul_v2_v2(delta, hit->scale);
|
|
||||||
|
|
||||||
const float dist_test_sq = len_squared_v2(delta);
|
|
||||||
|
|
||||||
if (dist_test_sq < hit->dist_sq) {
|
|
||||||
|
|
||||||
if (only_in_face) {
|
|
||||||
if (!BM_face_uv_point_inside_test(efa, co, cd_loop_uv_offset)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hit->ob = obedit;
|
hit->ob = obedit;
|
||||||
hit->efa = efa;
|
hit->efa = efa;
|
||||||
|
hit->dist_sq = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||||
|
|
||||||
|
BMLoop *l;
|
||||||
|
BMIter liter;
|
||||||
|
int i;
|
||||||
|
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
|
||||||
|
float *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
|
||||||
|
float *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
|
||||||
|
|
||||||
|
float delta[2];
|
||||||
|
closest_to_line_segment_v2(delta, co, luv, luv_next);
|
||||||
|
|
||||||
|
sub_v2_v2(delta, co);
|
||||||
|
mul_v2_v2(delta, hit->scale);
|
||||||
|
|
||||||
|
float dist_test_sq = len_squared_v2(delta);
|
||||||
|
|
||||||
|
/* Ensures that successive selection attempts will select other edges sharing the same
|
||||||
|
* UV coordinates as the previous selection. */
|
||||||
|
if ((penalty != 0.0f) && uvedit_edge_select_test(scene, l, offsets)) {
|
||||||
|
dist_test_sq = square_f(sqrtf(dist_test_sq) + penalty);
|
||||||
|
}
|
||||||
|
if (dist_test_sq < hit->dist_sq) {
|
||||||
|
hit->ob = obedit;
|
||||||
|
hit->efa = efa;
|
||||||
|
|
||||||
|
hit->l = l;
|
||||||
|
|
||||||
hit->dist_sq = dist_test_sq;
|
hit->dist_sq = dist_test_sq;
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit)
|
bool uv_find_nearest_face_multi(Scene *scene,
|
||||||
{
|
|
||||||
return uv_find_nearest_face_ex(scene, obedit, co, hit, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool uv_find_nearest_face_multi_ex(Scene *scene,
|
|
||||||
Object **objects,
|
Object **objects,
|
||||||
const uint objects_len,
|
uint objects_len,
|
||||||
const float co[2],
|
const float co[2],
|
||||||
UvNearestHit *hit,
|
const float penalty,
|
||||||
const bool only_in_face)
|
UvNearestHit *hit)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
for (int ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||||
Object *obedit = objects[ob_index];
|
found |= uv_find_nearest_face(scene, objects[ob_index], co, penalty, hit);
|
||||||
if (uv_find_nearest_face_ex(scene, obedit, co, hit, only_in_face)) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool uv_find_nearest_face_multi(
|
|
||||||
Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit)
|
|
||||||
{
|
|
||||||
return uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, hit, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
|
static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
|
||||||
{
|
{
|
||||||
const float *uv_prev = BM_ELEM_CD_GET_FLOAT_P(l->prev, cd_loop_uv_offset);
|
const float *uv_prev = BM_ELEM_CD_GET_FLOAT_P(l->prev, cd_loop_uv_offset);
|
||||||
@ -2484,30 +2487,14 @@ static bool uv_mouse_select_multi(bContext *C,
|
|||||||
}
|
}
|
||||||
else if (selectmode == UV_SELECT_FACE) {
|
else if (selectmode == UV_SELECT_FACE) {
|
||||||
/* find face */
|
/* find face */
|
||||||
found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit);
|
found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, penalty_dist, &hit);
|
||||||
|
|
||||||
if (!found_item) {
|
|
||||||
/* Fallback, perform a second pass without a limited threshold,
|
|
||||||
* which succeeds as long as the cursor is inside the UV face.
|
|
||||||
* Useful when zoomed in, to select faces with distant screen-space face centers. */
|
|
||||||
hit.dist_sq = FLT_MAX;
|
|
||||||
found_item = uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, &hit, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found_item) {
|
if (found_item) {
|
||||||
BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm;
|
BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm;
|
||||||
BM_mesh_active_face_set(bm, hit.efa);
|
BM_mesh_active_face_set(bm, hit.efa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (selectmode == UV_SELECT_ISLAND) {
|
else if (selectmode == UV_SELECT_ISLAND) {
|
||||||
found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, 0.0f, &hit);
|
found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, penalty_dist, &hit);
|
||||||
|
|
||||||
if (!found_item) {
|
|
||||||
/* Without this, we can be within the face of an island but too far from an edge,
|
|
||||||
* see face selection comment for details. */
|
|
||||||
hit.dist_sq = FLT_MAX;
|
|
||||||
found_item = uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, &hit, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool found = found_item;
|
bool found = found_item;
|
||||||
@ -2528,9 +2515,8 @@ static bool uv_mouse_select_multi(bContext *C,
|
|||||||
is_selected = uvedit_edge_select_test(scene, hit.l, offsets);
|
is_selected = uvedit_edge_select_test(scene, hit.l, offsets);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Vertex or island. For island (if we were using #uv_find_nearest_face_multi_ex, see above),
|
/* Vertex or island. */
|
||||||
* `hit.l` is NULL, use `hit.efa` instead. */
|
if (hit.l) {
|
||||||
if (hit.l != NULL) {
|
|
||||||
is_selected = uvedit_uv_select_test(scene, hit.l, offsets);
|
is_selected = uvedit_uv_select_test(scene, hit.l, offsets);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
Loading…
Reference in New Issue
Block a user