forked from blender/blender
WIP: uv-simple-select (Version2) #2
@ -86,7 +86,6 @@ bool ED_uvedit_test(struct Object *obedit);
|
|||||||
|
|
||||||
/* Visibility and selection tests. */
|
/* Visibility and selection tests. */
|
||||||
|
|
||||||
bool uvedit_face_visible_test_ex(const struct ToolSettings *ts, struct BMFace *efa);
|
|
||||||
bool uvedit_face_select_test_ex(const struct ToolSettings *ts,
|
bool uvedit_face_select_test_ex(const struct ToolSettings *ts,
|
||||||
struct BMFace *efa,
|
struct BMFace *efa,
|
||||||
BMUVOffsets offsets);
|
BMUVOffsets offsets);
|
||||||
@ -194,30 +193,6 @@ void uvedit_uv_select_set_with_sticky(const struct Scene *scene,
|
|||||||
bool do_history,
|
bool do_history,
|
||||||
BMUVOffsets offsets);
|
BMUVOffsets offsets);
|
||||||
|
|
||||||
/* Low level functions for sticky element selection (sticky mode independent). Type of sticky
|
|
||||||
* selection is specified explicitly (using sticky_flag, except for face selection). */
|
|
||||||
|
|
||||||
void uvedit_face_select_shared_vert(const struct Scene *scene,
|
|
||||||
struct BMEditMesh *em,
|
|
||||||
struct BMFace *efa,
|
|
||||||
const bool select,
|
|
||||||
const bool do_history,
|
|
||||||
BMUVOffsets offsets);
|
|
||||||
void uvedit_edge_select_shared_vert(const struct Scene *scene,
|
|
||||||
struct BMEditMesh *em,
|
|
||||||
struct BMLoop *l,
|
|
||||||
const bool select,
|
|
||||||
const int sticky_flag,
|
|
||||||
const bool do_history,
|
|
||||||
BMUVOffsets offsets);
|
|
||||||
void uvedit_uv_select_shared_vert(const struct Scene *scene,
|
|
||||||
struct BMEditMesh *em,
|
|
||||||
struct BMLoop *l,
|
|
||||||
const bool select,
|
|
||||||
const int sticky_flag,
|
|
||||||
const bool do_history,
|
|
||||||
BMUVOffsets offsets);
|
|
||||||
|
|
||||||
/* Sets required UV edge flags as specified by the sticky_flag. */
|
/* Sets required UV edge flags as specified by the sticky_flag. */
|
||||||
void uvedit_edge_select_set_noflush(const struct Scene *scene,
|
void uvedit_edge_select_set_noflush(const struct Scene *scene,
|
||||||
struct BMLoop *l,
|
struct BMLoop *l,
|
||||||
@ -259,19 +234,6 @@ bool ED_uvedit_nearest_uv_multi(const struct View2D *v2d,
|
|||||||
float *dist_sq,
|
float *dist_sq,
|
||||||
float r_uv[2]);
|
float r_uv[2]);
|
||||||
|
|
||||||
struct BMFace **ED_uvedit_selected_faces(const struct Scene *scene,
|
|
||||||
struct BMesh *bm,
|
|
||||||
int len_max,
|
|
||||||
int *r_faces_len);
|
|
||||||
struct BMLoop **ED_uvedit_selected_edges(const struct Scene *scene,
|
|
||||||
struct BMesh *bm,
|
|
||||||
int len_max,
|
|
||||||
int *r_edges_len);
|
|
||||||
struct BMLoop **ED_uvedit_selected_verts(const struct Scene *scene,
|
|
||||||
struct BMesh *bm,
|
|
||||||
int len_max,
|
|
||||||
int *r_verts_len);
|
|
||||||
|
|
||||||
void ED_uvedit_get_aspect(struct Object *obedit, float *r_aspx, float *r_aspy);
|
void ED_uvedit_get_aspect(struct Object *obedit, float *r_aspx, float *r_aspy);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,7 +18,7 @@ struct Scene;
|
|||||||
struct SpaceImage;
|
struct SpaceImage;
|
||||||
struct wmOperatorType;
|
struct wmOperatorType;
|
||||||
|
|
||||||
/* find nearest */
|
/* UV Find Nearest */
|
||||||
|
|
||||||
typedef struct UvNearestHit {
|
typedef struct UvNearestHit {
|
||||||
/** Only for `*_multi(..)` versions of functions. */
|
/** Only for `*_multi(..)` versions of functions. */
|
||||||
@ -30,9 +30,9 @@ typedef struct UvNearestHit {
|
|||||||
* Needs to be set before calling nearest functions.
|
* Needs to be set before calling nearest functions.
|
||||||
*
|
*
|
||||||
* \note When #UV_NEAREST_HIT_INIT_DIST_PX or #UV_NEAREST_HIT_INIT_MAX are used,
|
* \note When #UV_NEAREST_HIT_INIT_DIST_PX or #UV_NEAREST_HIT_INIT_MAX are used,
|
||||||
* this value is pixels squared.
|
* Units are pixels.
|
||||||
*/
|
*/
|
||||||
float dist_sq;
|
float dist;
|
||||||
|
|
||||||
/** Scale the UVs to account for aspect ratio from the image view. */
|
/** Scale the UVs to account for aspect ratio from the image view. */
|
||||||
float scale[2];
|
float scale[2];
|
||||||
@ -40,7 +40,7 @@ typedef struct UvNearestHit {
|
|||||||
|
|
||||||
#define UV_NEAREST_HIT_INIT_DIST_PX(v2d, dist_px) \
|
#define UV_NEAREST_HIT_INIT_DIST_PX(v2d, dist_px) \
|
||||||
{ \
|
{ \
|
||||||
.dist_sq = square_f(U.pixelsize * dist_px), \
|
.dist = U.pixelsize * dist_px, \
|
||||||
.scale = { \
|
.scale = { \
|
||||||
UI_view2d_scale_get_x(v2d), \
|
UI_view2d_scale_get_x(v2d), \
|
||||||
UI_view2d_scale_get_y(v2d), \
|
UI_view2d_scale_get_y(v2d), \
|
||||||
@ -49,7 +49,7 @@ typedef struct UvNearestHit {
|
|||||||
|
|
||||||
#define UV_NEAREST_HIT_INIT_MAX(v2d) \
|
#define UV_NEAREST_HIT_INIT_MAX(v2d) \
|
||||||
{ \
|
{ \
|
||||||
.dist_sq = FLT_MAX, \
|
.dist = FLT_MAX, \
|
||||||
.scale = { \
|
.scale = { \
|
||||||
UI_view2d_scale_get_x(v2d), \
|
UI_view2d_scale_get_x(v2d), \
|
||||||
UI_view2d_scale_get_y(v2d), \
|
UI_view2d_scale_get_y(v2d), \
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -787,6 +787,156 @@ void UV_OT_shortest_path_pick(wmOperatorType *ot)
|
|||||||
/** \name Select Path Between Existing Selection
|
/** \name Select Path Between Existing Selection
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Selected Elements as Arrays (Vertex, Edge & Faces)
|
||||||
|
*
|
||||||
|
* These functions return single elements per connected vertex/edge.
|
||||||
|
* So an edge that has two connected edge loops only assigns one loop in the array.
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
static BMFace **ED_uvedit_selected_faces(const Scene *scene,
|
||||||
|
BMesh *bm,
|
||||||
|
int len_max,
|
||||||
|
int *r_faces_len)
|
||||||
|
{
|
||||||
|
const BMUVOffsets offsets = BM_uv_map_get_offsets(bm);
|
||||||
|
|
||||||
|
int faces_len = 0;
|
||||||
|
BMFace **faces = MEM_mallocN(sizeof(*faces) * len_max, __func__);
|
||||||
|
|
||||||
|
BMIter iter;
|
||||||
|
BMFace *f;
|
||||||
|
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||||
|
if (uvedit_face_visible_test(scene, f) && uvedit_face_select_test(scene, f, offsets)) {
|
||||||
|
faces[faces_len++] = f;
|
||||||
|
if (faces_len == len_max) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*r_faces_len = faces_len;
|
||||||
|
return faces;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BMLoop **ED_uvedit_selected_edges(const Scene *scene,
|
||||||
|
BMesh *bm,
|
||||||
|
int len_max,
|
||||||
|
int *r_edges_len)
|
||||||
|
{
|
||||||
|
const BMUVOffsets offsets = BM_uv_map_get_offsets(bm);
|
||||||
|
BLI_assert(offsets.uv >= 0);
|
||||||
|
|
||||||
|
CLAMP_MAX(len_max, bm->totloop);
|
||||||
|
int edges_len = 0;
|
||||||
|
BMLoop **edges = MEM_mallocN(sizeof(*edges) * len_max, __func__);
|
||||||
|
|
||||||
|
BMIter iter;
|
||||||
|
BMFace *f;
|
||||||
|
|
||||||
|
/* Clear tag. */
|
||||||
|
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||||
|
BMIter liter;
|
||||||
|
BMLoop *l_iter;
|
||||||
|
BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
|
||||||
|
BM_elem_flag_disable(l_iter, BM_ELEM_TAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||||
|
if (uvedit_face_visible_test(scene, f)) {
|
||||||
|
BMIter liter;
|
||||||
|
BMLoop *l_iter;
|
||||||
|
BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
|
||||||
|
if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
|
||||||
|
if (uvedit_edge_select_test(scene, l_iter, offsets)) {
|
||||||
|
BM_elem_flag_enable(l_iter, BM_ELEM_TAG);
|
||||||
|
|
||||||
|
edges[edges_len++] = l_iter;
|
||||||
|
if (edges_len == len_max) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tag other connected loops so we don't consider them separate edges. */
|
||||||
|
if (l_iter != l_iter->radial_next) {
|
||||||
|
BMLoop *l_radial_iter = l_iter->radial_next;
|
||||||
|
do {
|
||||||
|
if (BM_loop_uv_share_edge_check(l_iter, l_radial_iter, offsets.uv)) {
|
||||||
|
BM_elem_flag_enable(l_radial_iter, BM_ELEM_TAG);
|
||||||
|
}
|
||||||
|
} while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finally:
|
||||||
|
*r_edges_len = edges_len;
|
||||||
|
return edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BMLoop **ED_uvedit_selected_verts(const Scene *scene,
|
||||||
|
BMesh *bm,
|
||||||
|
int len_max,
|
||||||
|
int *r_verts_len)
|
||||||
|
{
|
||||||
|
const BMUVOffsets offsets = BM_uv_map_get_offsets(bm);
|
||||||
|
BLI_assert(offsets.select_vert >= 0);
|
||||||
|
BLI_assert(offsets.uv >= 0);
|
||||||
|
|
||||||
|
CLAMP_MAX(len_max, bm->totloop);
|
||||||
|
int verts_len = 0;
|
||||||
|
BMLoop **verts = MEM_mallocN(sizeof(*verts) * len_max, __func__);
|
||||||
|
|
||||||
|
BMIter iter;
|
||||||
|
BMFace *f;
|
||||||
|
|
||||||
|
/* Clear tag. */
|
||||||
|
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||||
|
BMIter liter;
|
||||||
|
BMLoop *l_iter;
|
||||||
|
BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
|
||||||
|
BM_elem_flag_disable(l_iter, BM_ELEM_TAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||||
|
if (uvedit_face_visible_test(scene, f)) {
|
||||||
|
BMIter liter;
|
||||||
|
BMLoop *l_iter;
|
||||||
|
BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
|
||||||
|
if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
|
||||||
|
if (BM_ELEM_CD_GET_BOOL(l_iter, offsets.select_vert)) {
|
||||||
|
BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
|
||||||
|
|
||||||
|
verts[verts_len++] = l_iter;
|
||||||
|
if (verts_len == len_max) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tag other connected loops so we don't consider them separate vertices. */
|
||||||
|
BMIter liter_disk;
|
||||||
|
BMLoop *l_disk_iter;
|
||||||
|
BM_ITER_ELEM (l_disk_iter, &liter_disk, l_iter->v, BM_LOOPS_OF_VERT) {
|
||||||
|
if (BM_loop_uv_share_vert_check(l_iter, l_disk_iter, offsets.uv)) {
|
||||||
|
BM_elem_flag_enable(l_disk_iter, BM_ELEM_TAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finally:
|
||||||
|
*r_verts_len = verts_len;
|
||||||
|
return verts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
static int uv_shortest_path_select_exec(bContext *C, wmOperator *op)
|
static int uv_shortest_path_select_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||||
|
@ -5,43 +5,22 @@
|
|||||||
* \ingroup eduv
|
* \ingroup eduv
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <math.h>
|
#include "BKE_context.h"
|
||||||
#include <stdlib.h>
|
#include "BKE_editmesh.h"
|
||||||
#include <string.h>
|
#include "BKE_layer.h"
|
||||||
|
#include "BKE_mesh.h"
|
||||||
|
#include "BKE_mesh_mapping.h"
|
||||||
|
#include "BKE_report.h"
|
||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
|
||||||
|
|
||||||
#include "DNA_image_types.h"
|
|
||||||
#include "DNA_material_types.h"
|
|
||||||
#include "DNA_meshdata_types.h"
|
|
||||||
#include "DNA_node_types.h"
|
|
||||||
#include "DNA_object_types.h"
|
|
||||||
#include "DNA_scene_types.h"
|
|
||||||
#include "DNA_space_types.h"
|
|
||||||
|
|
||||||
#include "BLI_alloca.h"
|
|
||||||
#include "BLI_blenlib.h"
|
|
||||||
#include "BLI_hash.h"
|
#include "BLI_hash.h"
|
||||||
#include "BLI_heap.h"
|
#include "BLI_heap.h"
|
||||||
#include "BLI_kdopbvh.h"
|
#include "BLI_kdopbvh.h"
|
||||||
#include "BLI_kdtree.h"
|
#include "BLI_kdtree.h"
|
||||||
#include "BLI_lasso_2d.h"
|
#include "BLI_lasso_2d.h"
|
||||||
#include "BLI_math.h"
|
|
||||||
#include "BLI_memarena.h"
|
#include "BLI_memarena.h"
|
||||||
#include "BLI_polyfill_2d.h"
|
#include "BLI_polyfill_2d.h"
|
||||||
#include "BLI_polyfill_2d_beautify.h"
|
#include "BLI_polyfill_2d_beautify.h"
|
||||||
#include "BLI_utildefines.h"
|
|
||||||
|
|
||||||
#include "BKE_context.h"
|
|
||||||
#include "BKE_customdata.h"
|
|
||||||
#include "BKE_editmesh.h"
|
|
||||||
#include "BKE_layer.h"
|
|
||||||
#include "BKE_material.h"
|
|
||||||
#include "BKE_mesh.h"
|
|
||||||
#include "BKE_mesh_mapping.h"
|
|
||||||
#include "BKE_report.h"
|
|
||||||
|
|
||||||
#include "DEG_depsgraph.h"
|
|
||||||
#include "DEG_depsgraph_query.h"
|
#include "DEG_depsgraph_query.h"
|
||||||
|
|
||||||
#include "ED_image.h"
|
#include "ED_image.h"
|
||||||
@ -50,28 +29,19 @@
|
|||||||
#include "ED_select_utils.h"
|
#include "ED_select_utils.h"
|
||||||
#include "ED_uvedit.h"
|
#include "ED_uvedit.h"
|
||||||
|
|
||||||
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
#include "RNA_access.h"
|
#include "RNA_access.h"
|
||||||
#include "RNA_define.h"
|
#include "RNA_define.h"
|
||||||
#include "RNA_enum_types.h"
|
#include "RNA_enum_types.h"
|
||||||
|
|
||||||
#include "WM_api.h"
|
|
||||||
#include "WM_types.h"
|
|
||||||
|
|
||||||
#include "UI_view2d.h"
|
#include "UI_view2d.h"
|
||||||
|
|
||||||
#include "uvedit_intern.h"
|
#include "uvedit_intern.h"
|
||||||
|
|
||||||
static void uv_select_all_perform(const Scene *scene, Object *obedit, int action);
|
#include "WM_api.h"
|
||||||
|
|
||||||
static void uv_select_all_perform_multi_ex(const Scene *scene,
|
static void uv_select_all_perform(const Scene *scene, Object *obedit, int action);
|
||||||
Object **objects,
|
|
||||||
const uint objects_len,
|
|
||||||
int action,
|
|
||||||
const Object *ob_exclude);
|
|
||||||
static void uv_select_all_perform_multi(const Scene *scene,
|
|
||||||
Object **objects,
|
|
||||||
const uint objects_len,
|
|
||||||
int action);
|
|
||||||
|
|
||||||
static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, const bool select);
|
static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, const bool select);
|
||||||
static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, const bool select);
|
static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, const bool select);
|
||||||
@ -81,6 +51,30 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
|
|||||||
const ToolSettings *ts,
|
const ToolSettings *ts,
|
||||||
Object *obedit);
|
Object *obedit);
|
||||||
|
|
||||||
|
/* Low level functions for sticky element selection (sticky mode independent). Type of sticky
|
||||||
|
* selection is specified explicitly (using sticky_flag, except for face selection). */
|
||||||
|
|
||||||
|
static void uvedit_face_select_shared_vert(const struct Scene *scene,
|
||||||
|
struct BMEditMesh *em,
|
||||||
|
struct BMFace *efa,
|
||||||
|
const bool select,
|
||||||
|
const bool do_history,
|
||||||
|
BMUVOffsets offsets);
|
||||||
|
static void uvedit_edge_select_shared_vert(const struct Scene *scene,
|
||||||
|
struct BMEditMesh *em,
|
||||||
|
struct BMLoop *l,
|
||||||
|
const bool select,
|
||||||
|
const int sticky_flag,
|
||||||
|
const bool do_history,
|
||||||
|
BMUVOffsets offsets);
|
||||||
|
static void uvedit_uv_select_shared_vert(const struct Scene *scene,
|
||||||
|
struct BMEditMesh *em,
|
||||||
|
struct BMLoop *l,
|
||||||
|
const bool select,
|
||||||
|
const int sticky_flag,
|
||||||
|
const bool do_history,
|
||||||
|
BMUVOffsets offsets);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UV_SSIM_AREA_UV = 1000,
|
UV_SSIM_AREA_UV = 1000,
|
||||||
UV_SSIM_AREA_3D,
|
UV_SSIM_AREA_3D,
|
||||||
@ -153,32 +147,47 @@ BMLoop *ED_uvedit_active_edge_loop_get(BMesh *bm)
|
|||||||
|
|
||||||
char ED_uvedit_select_mode_get(const Scene *scene)
|
char ED_uvedit_select_mode_get(const Scene *scene)
|
||||||
{
|
{
|
||||||
|
/* Returns a single element selection mode (Vertex, Edge or Face) based on
|
||||||
|
* Sync Selection, and potentially multiple selected modes in the UI. */
|
||||||
const ToolSettings *ts = scene->toolsettings;
|
const ToolSettings *ts = scene->toolsettings;
|
||||||
char uv_selectmode = UV_SELECT_VERTEX;
|
char uv_select_mode = ts->uv_selectmode; /* i.e. Default from UV Editor. */
|
||||||
|
|
||||||
if (ts->uv_flag & UV_SYNC_SELECTION) {
|
if (ts->uv_flag & UV_SYNC_SELECTION) {
|
||||||
|
/* We're in Sync-Selection mode.
|
||||||
|
* Convert the selection mode options from the 3D Viewport
|
||||||
|
* into their closest UV Editor equivalents. */
|
||||||
|
|
||||||
|
uv_select_mode = 0;
|
||||||
if (ts->selectmode & SCE_SELECT_VERTEX) {
|
if (ts->selectmode & SCE_SELECT_VERTEX) {
|
||||||
uv_selectmode = UV_SELECT_VERTEX;
|
uv_select_mode |= UV_SELECT_VERTEX;
|
||||||
}
|
}
|
||||||
else if (ts->selectmode & SCE_SELECT_EDGE) {
|
if (ts->selectmode & SCE_SELECT_EDGE) {
|
||||||
uv_selectmode = UV_SELECT_EDGE;
|
uv_select_mode |= UV_SELECT_EDGE;
|
||||||
}
|
}
|
||||||
else if (ts->selectmode & SCE_SELECT_FACE) {
|
if (ts->selectmode & SCE_SELECT_FACE) {
|
||||||
uv_selectmode = UV_SELECT_FACE;
|
uv_select_mode |= UV_SELECT_FACE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if (ts->uv_selectmode & UV_SELECT_VERTEX) {
|
/* Order is important here, as more than one type of selection element could be enabled. */
|
||||||
uv_selectmode = UV_SELECT_VERTEX;
|
if (uv_select_mode & UV_SELECT_VERTEX) {
|
||||||
|
return UV_SELECT_VERTEX; /* Vertex selection is enabled, use Vertex mode. */
|
||||||
}
|
}
|
||||||
else if (ts->uv_selectmode & UV_SELECT_EDGE) {
|
if (uv_select_mode & UV_SELECT_EDGE) {
|
||||||
uv_selectmode = UV_SELECT_EDGE;
|
return UV_SELECT_EDGE; /* Edge selection is enabled, use Edge mode. */
|
||||||
}
|
}
|
||||||
else if (ts->uv_selectmode & UV_SELECT_FACE) {
|
if (uv_select_mode & UV_SELECT_FACE) {
|
||||||
uv_selectmode = UV_SELECT_FACE;
|
return UV_SELECT_FACE; /* Face selection is enabled, use Face mode. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (uv_select_mode & UV_SELECT_ISLAND) {
|
||||||
|
/* Island selection is stored as Vertex selection internally. */
|
||||||
|
return UV_SELECT_VERTEX; /* Not UV_SELECT_ISLAND ! */
|
||||||
}
|
}
|
||||||
return uv_selectmode;
|
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
|
||||||
|
return UV_SELECT_VERTEX; /* Should never happen. */
|
||||||
}
|
}
|
||||||
|
|
||||||
void ED_uvedit_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const bool select)
|
void ED_uvedit_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const bool select)
|
||||||
@ -202,7 +211,7 @@ void ED_uvedit_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const b
|
|||||||
|
|
||||||
static void uvedit_vertex_select_tagged(BMEditMesh *em,
|
static void uvedit_vertex_select_tagged(BMEditMesh *em,
|
||||||
Scene *scene,
|
Scene *scene,
|
||||||
bool select,
|
const bool select,
|
||||||
const BMUVOffsets offsets)
|
const BMUVOffsets offsets)
|
||||||
{
|
{
|
||||||
BMFace *efa;
|
BMFace *efa;
|
||||||
@ -218,16 +227,18 @@ static void uvedit_vertex_select_tagged(BMEditMesh *em,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool uvedit_face_visible_test_ex(const ToolSettings *ts, BMFace *efa)
|
|
||||||
{
|
|
||||||
if (ts->uv_flag & UV_SYNC_SELECTION) {
|
|
||||||
return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
|
|
||||||
}
|
|
||||||
return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
|
|
||||||
}
|
|
||||||
bool uvedit_face_visible_test(const Scene *scene, BMFace *efa)
|
bool uvedit_face_visible_test(const Scene *scene, BMFace *efa)
|
||||||
{
|
{
|
||||||
return uvedit_face_visible_test_ex(scene->toolsettings, efa);
|
if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
|
||||||
|
/* Face Hidden flag always applies to both 3D viewport *and* UV Editor. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
|
||||||
|
/* UV Sync Selection mode, ignore 3D Viewport selection for visibility in UV Editor. */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/* No sync-selection, only *selected* faces in 3D Viewport are visible in UV Editor. */
|
||||||
|
return BM_elem_flag_test(efa, BM_ELEM_SELECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const BMUVOffsets offsets)
|
bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const BMUVOffsets offsets)
|
||||||
@ -807,6 +818,33 @@ static BMLoop *uvedit_loop_find_other_boundary_loop_with_visible_face(const Scen
|
|||||||
/** \name Find Nearest Elements
|
/** \name Find Nearest Elements
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
|
static bool uv_nearest_was_updated(const UvNearestHit *hit)
|
||||||
|
{
|
||||||
|
return hit->efa;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uv_nearest_hit_update(
|
||||||
|
UvNearestHit *hit, Object *ob, BMFace *efa, BMLoop *l, const float dist)
|
||||||
|
{
|
||||||
|
BLI_assert(ob != NULL);
|
||||||
|
BLI_assert(efa != NULL);
|
||||||
|
BLI_assert(dist >= 0.0f);
|
||||||
|
if (dist < hit->dist) {
|
||||||
|
hit->ob = ob;
|
||||||
|
hit->efa = efa;
|
||||||
|
hit->l = l; /* Can be NULL. */
|
||||||
|
hit->dist = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static float uv_nearest_calc_dist(const UvNearestHit *hit, const float co[2], const float uv[2])
|
||||||
|
{
|
||||||
|
float delta[2];
|
||||||
|
sub_v2_v2v2(delta, co, uv);
|
||||||
|
mul_v2_v2(delta, hit->scale);
|
||||||
|
return len_v2(delta);
|
||||||
|
}
|
||||||
|
|
||||||
bool uv_find_nearest_edge(
|
bool uv_find_nearest_edge(
|
||||||
Scene *scene, Object *obedit, const float co[2], const float penalty, UvNearestHit *hit)
|
Scene *scene, Object *obedit, const float co[2], const float penalty, UvNearestHit *hit)
|
||||||
{
|
{
|
||||||
@ -817,7 +855,6 @@ bool uv_find_nearest_edge(
|
|||||||
BMIter iter, liter;
|
BMIter iter, liter;
|
||||||
float *luv, *luv_next;
|
float *luv, *luv_next;
|
||||||
int i;
|
int i;
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||||
BLI_assert(offsets.uv >= 0);
|
BLI_assert(offsets.uv >= 0);
|
||||||
@ -834,29 +871,17 @@ bool uv_find_nearest_edge(
|
|||||||
|
|
||||||
float delta[2];
|
float delta[2];
|
||||||
closest_to_line_segment_v2(delta, co, luv, luv_next);
|
closest_to_line_segment_v2(delta, co, luv, luv_next);
|
||||||
|
float dist_test = uv_nearest_calc_dist(hit, co, delta);
|
||||||
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
|
/* Ensures that successive selection attempts will select other edges sharing the same
|
||||||
* UV coordinates as the previous selection. */
|
* UV coordinates as the previous selection. */
|
||||||
if ((penalty != 0.0f) && uvedit_edge_select_test(scene, l, offsets)) {
|
if ((penalty != 0.0f) && uvedit_edge_select_test(scene, l, offsets)) {
|
||||||
dist_test_sq = square_f(sqrtf(dist_test_sq) + penalty);
|
dist_test += penalty;
|
||||||
}
|
}
|
||||||
if (dist_test_sq < hit->dist_sq) {
|
uv_nearest_hit_update(hit, obedit, efa, l, dist_test);
|
||||||
hit->ob = obedit;
|
|
||||||
hit->efa = efa;
|
|
||||||
|
|
||||||
hit->l = l;
|
|
||||||
|
|
||||||
hit->dist_sq = dist_test_sq;
|
|
||||||
found = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return uv_nearest_was_updated(hit);
|
||||||
return found;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool uv_find_nearest_edge_multi(Scene *scene,
|
bool uv_find_nearest_edge_multi(Scene *scene,
|
||||||
@ -866,85 +891,64 @@ bool uv_find_nearest_edge_multi(Scene *scene,
|
|||||||
const float penalty,
|
const float penalty,
|
||||||
UvNearestHit *hit)
|
UvNearestHit *hit)
|
||||||
{
|
{
|
||||||
bool found = false;
|
|
||||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||||
Object *obedit = objects[ob_index];
|
uv_find_nearest_edge(scene, objects[ob_index], co, penalty, hit);
|
||||||
if (uv_find_nearest_edge(scene, obedit, co, penalty, hit)) {
|
|
||||||
found = true;
|
|
||||||
}
|
}
|
||||||
}
|
return uv_nearest_was_updated(hit);
|
||||||
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_dist, 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);
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_PROP_FLOAT2);
|
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||||
|
|
||||||
BMIter iter;
|
BMIter iter;
|
||||||
BMFace *efa;
|
BMFace *efa;
|
||||||
|
|
||||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||||
if (!uvedit_face_visible_test(scene, efa)) {
|
if (!uvedit_face_visible_test(scene, efa)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float cent[2];
|
/* Ensures that successive selection attempts will select other edges sharing the same
|
||||||
BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
|
* UV coordinates as the previous selection. */
|
||||||
|
const float face_penalty_dist = uvedit_face_select_test(scene, efa, offsets) ? penalty_dist :
|
||||||
|
0.0f;
|
||||||
|
|
||||||
float delta[2];
|
if (BM_face_uv_point_inside_test(efa, co, offsets.uv)) {
|
||||||
sub_v2_v2v2(delta, co, cent);
|
uv_nearest_hit_update(hit, obedit, efa, NULL, face_penalty_dist);
|
||||||
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BMLoop *l;
|
||||||
|
BMIter liter;
|
||||||
|
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||||
|
float *luv = BM_ELEM_CD_GET_VOID_P(l, offsets.uv);
|
||||||
|
float *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, offsets.uv);
|
||||||
|
|
||||||
|
float delta[2];
|
||||||
|
closest_to_line_segment_v2(delta, co, luv, luv_next);
|
||||||
|
sub_v2_v2(delta, co);
|
||||||
|
mul_v2_v2(delta, hit->scale);
|
||||||
|
uv_nearest_hit_update(hit, obedit, efa, NULL, len_v2(delta) + face_penalty_dist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uv_nearest_was_updated(hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
hit->ob = obedit;
|
bool uv_find_nearest_face_multi(Scene *scene,
|
||||||
hit->efa = efa;
|
|
||||||
hit->dist_sq = dist_test_sq;
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit)
|
|
||||||
{
|
|
||||||
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_dist,
|
||||||
const bool only_in_face)
|
UvNearestHit *hit)
|
||||||
{
|
{
|
||||||
bool found = false;
|
for (int ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
uv_find_nearest_face(scene, objects[ob_index], co, penalty_dist, hit);
|
||||||
Object *obedit = objects[ob_index];
|
|
||||||
if (uv_find_nearest_face_ex(scene, obedit, co, hit, only_in_face)) {
|
|
||||||
found = true;
|
|
||||||
}
|
}
|
||||||
}
|
return uv_nearest_was_updated(hit);
|
||||||
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)
|
||||||
@ -961,7 +965,6 @@ bool uv_find_nearest_vert(
|
|||||||
Scene *scene, Object *obedit, float const co[2], const float penalty_dist, UvNearestHit *hit)
|
Scene *scene, Object *obedit, float const co[2], const float penalty_dist, 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));
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||||
BMFace *efa;
|
BMFace *efa;
|
||||||
@ -981,39 +984,30 @@ bool uv_find_nearest_vert(
|
|||||||
BMLoop *l;
|
BMLoop *l;
|
||||||
int i;
|
int i;
|
||||||
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
|
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
|
||||||
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
const float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||||
|
float dist_test = uv_nearest_calc_dist(hit, co, luv);
|
||||||
float delta[2];
|
|
||||||
|
|
||||||
sub_v2_v2v2(delta, co, luv);
|
|
||||||
mul_v2_v2(delta, hit->scale);
|
|
||||||
|
|
||||||
float dist_test_sq = len_squared_v2(delta);
|
|
||||||
|
|
||||||
/* Ensures that successive selection attempts will select other vertices sharing the same
|
/* Ensures that successive selection attempts will select other vertices sharing the same
|
||||||
* UV coordinates */
|
* UV coordinates */
|
||||||
if ((penalty_dist != 0.0f) && uvedit_uv_select_test(scene, l, offsets)) {
|
if ((penalty_dist != 0.0f) && uvedit_uv_select_test(scene, l, offsets)) {
|
||||||
dist_test_sq = square_f(sqrtf(dist_test_sq) + penalty_dist);
|
dist_test += penalty_dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dist_test_sq <= hit->dist_sq) {
|
if (dist_test == hit->dist) {
|
||||||
if (dist_test_sq == hit->dist_sq) {
|
/* Special case to break ties. */
|
||||||
if (!uv_nearest_between(l, co, offsets.uv)) {
|
if (uv_nearest_between(l, co, offsets.uv)) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hit->dist_sq = dist_test_sq;
|
|
||||||
|
|
||||||
hit->ob = obedit;
|
hit->ob = obedit;
|
||||||
hit->efa = efa;
|
hit->efa = efa;
|
||||||
hit->l = l;
|
hit->l = l;
|
||||||
found = true;
|
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uv_nearest_hit_update(hit, obedit, efa, l, dist_test);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return found;
|
return uv_nearest_was_updated(hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool uv_find_nearest_vert_multi(Scene *scene,
|
bool uv_find_nearest_vert_multi(Scene *scene,
|
||||||
@ -2433,8 +2427,8 @@ static bool uv_mouse_select_multi(bContext *C,
|
|||||||
Scene *scene = CTX_data_scene(C);
|
Scene *scene = CTX_data_scene(C);
|
||||||
const ToolSettings *ts = scene->toolsettings;
|
const ToolSettings *ts = scene->toolsettings;
|
||||||
UvNearestHit hit = UV_NEAREST_HIT_INIT_DIST_PX(®ion->v2d, 75.0f);
|
UvNearestHit hit = UV_NEAREST_HIT_INIT_DIST_PX(®ion->v2d, 75.0f);
|
||||||
int selectmode, sticky;
|
int selectmode = ts->uv_selectmode;
|
||||||
bool found_item = false;
|
int sticky = ts->uv_sticky;
|
||||||
/* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */
|
/* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */
|
||||||
int flush = 0;
|
int flush = 0;
|
||||||
|
|
||||||
@ -2456,16 +2450,11 @@ static bool uv_mouse_select_multi(bContext *C,
|
|||||||
|
|
||||||
sticky = SI_STICKY_DISABLE;
|
sticky = SI_STICKY_DISABLE;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
selectmode = ts->uv_selectmode;
|
|
||||||
sticky = ts->uv_sticky;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find nearest element */
|
/* find nearest element */
|
||||||
if (selectmode == UV_SELECT_VERTEX) {
|
if (selectmode == UV_SELECT_VERTEX) {
|
||||||
/* find vertex */
|
/* find vertex */
|
||||||
found_item = uv_find_nearest_vert_multi(scene, objects, objects_len, co, penalty_dist, &hit);
|
if (uv_find_nearest_vert_multi(scene, objects, objects_len, co, penalty_dist, &hit)) {
|
||||||
if (found_item) {
|
|
||||||
if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
|
if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
|
||||||
BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm;
|
BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm;
|
||||||
ED_uvedit_active_vert_loop_set(bm, hit.l);
|
ED_uvedit_active_vert_loop_set(bm, hit.l);
|
||||||
@ -2474,8 +2463,7 @@ static bool uv_mouse_select_multi(bContext *C,
|
|||||||
}
|
}
|
||||||
else if (selectmode == UV_SELECT_EDGE) {
|
else if (selectmode == UV_SELECT_EDGE) {
|
||||||
/* find edge */
|
/* find edge */
|
||||||
found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, penalty_dist, &hit);
|
if (uv_find_nearest_edge_multi(scene, objects, objects_len, co, penalty_dist, &hit)) {
|
||||||
if (found_item) {
|
|
||||||
if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
|
if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
|
||||||
BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm;
|
BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm;
|
||||||
ED_uvedit_active_edge_loop_set(bm, hit.l);
|
ED_uvedit_active_edge_loop_set(bm, hit.l);
|
||||||
@ -2484,33 +2472,18 @@ 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);
|
const bool 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);
|
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 = uv_nearest_was_updated(&hit);
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
bool is_selected = false;
|
bool is_selected = false;
|
||||||
@ -2528,9 +2501,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 {
|
||||||
@ -3494,6 +3466,32 @@ static void uv_select_flush_from_loop_edge_flag(const Scene *scene, BMEditMesh *
|
|||||||
/** \name Box Select Operator
|
/** \name Box Select Operator
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
|
static bool uv_box_select_is_face_touching(Scene *scene,
|
||||||
|
BMFace *efa,
|
||||||
|
rctf rectf,
|
||||||
|
const int cd_loop_uv_offset)
|
||||||
|
{
|
||||||
|
/* First, are we visible? */
|
||||||
|
if (!uvedit_face_visible_test(scene, efa)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next, are any of the edges inside the rectangle? */
|
||||||
|
BMLoop *l;
|
||||||
|
BMIter iter;
|
||||||
|
BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) {
|
||||||
|
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset);
|
||||||
|
float *luv_next = BM_ELEM_CD_GET_FLOAT_P(l->next, cd_loop_uv_offset);
|
||||||
|
if (BLI_rctf_isect_segment(&rectf, luv_next, luv)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Last, is an arbitrary point of the rectangle in the interior of the face? */
|
||||||
|
float rectangle_corner[2] = {rectf.xmin, rectf.ymin};
|
||||||
|
return BM_face_uv_point_inside_test(efa, rectangle_corner, cd_loop_uv_offset);
|
||||||
|
}
|
||||||
|
|
||||||
static int uv_box_select_exec(bContext *C, wmOperator *op)
|
static int uv_box_select_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||||
@ -3506,8 +3504,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
|
|||||||
BMIter iter, liter;
|
BMIter iter, liter;
|
||||||
float *luv;
|
float *luv;
|
||||||
rctf rectf;
|
rctf rectf;
|
||||||
bool pinned;
|
const bool use_face_touch = ((ts->uv_flag & UV_SYNC_SELECTION) ?
|
||||||
const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
|
|
||||||
(ts->selectmode == SCE_SELECT_FACE) :
|
(ts->selectmode == SCE_SELECT_FACE) :
|
||||||
(ts->uv_selectmode == UV_SELECT_FACE));
|
(ts->uv_selectmode == UV_SELECT_FACE));
|
||||||
const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
|
const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
|
||||||
@ -3524,7 +3521,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
|
|||||||
const bool select = (sel_op != SEL_OP_SUB);
|
const bool select = (sel_op != SEL_OP_SUB);
|
||||||
const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
|
const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
|
||||||
|
|
||||||
pinned = RNA_boolean_get(op->ptr, "pinned");
|
const bool pinned = RNA_boolean_get(op->ptr, "pinned");
|
||||||
|
|
||||||
bool changed_multi = false;
|
bool changed_multi = false;
|
||||||
|
|
||||||
@ -3536,7 +3533,6 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
|
|||||||
uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
|
uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* don't indent to avoid diff noise! */
|
|
||||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||||
Object *obedit = objects[ob_index];
|
Object *obedit = objects[ob_index];
|
||||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||||
@ -3549,22 +3545,13 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
|
|||||||
BM_uv_map_ensure_pin_attr(em->bm, active_uv_name);
|
BM_uv_map_ensure_pin_attr(em->bm, active_uv_name);
|
||||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||||
|
|
||||||
/* do actual selection */
|
/* Do actual selection. */
|
||||||
if (use_face_center && !pinned) {
|
if (use_face_touch && !pinned) {
|
||||||
/* handle face selection mode */
|
/* Handle face selection mode. */
|
||||||
float cent[2];
|
|
||||||
|
|
||||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||||
/* assume not touched */
|
const bool touched = uv_box_select_is_face_touching(scene, efa, rectf, offsets.uv);
|
||||||
BM_elem_flag_disable(efa, BM_ELEM_TAG);
|
BM_elem_flag_set(efa, BM_ELEM_TAG, touched);
|
||||||
|
changed |= touched;
|
||||||
if (uvedit_face_visible_test(scene, efa)) {
|
|
||||||
BM_face_uv_calc_center_median(efa, offsets.uv, cent);
|
|
||||||
if (BLI_rctf_isect_pt_v(&rectf, cent)) {
|
|
||||||
BM_elem_flag_enable(efa, BM_ELEM_TAG);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (de)selects all tagged faces and deals with sticky modes */
|
/* (de)selects all tagged faces and deals with sticky modes */
|
||||||
@ -3735,6 +3722,26 @@ static bool uv_circle_select_is_edge_inside(const float uv_a[2],
|
|||||||
return dist_squared_to_line_segment_v2((const float[2]){0.0f, 0.0f}, co_a, co_b) < 1.0f;
|
return dist_squared_to_line_segment_v2((const float[2]){0.0f, 0.0f}, co_a, co_b) < 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool uv_circle_select_is_face_touching(BMFace *efa,
|
||||||
|
const float offset[2],
|
||||||
|
const float ellipse[2],
|
||||||
|
const int cd_loop_uv_offset)
|
||||||
|
{
|
||||||
|
/* First, are any of the edges inside the solid ellipse? */
|
||||||
|
BMLoop *l;
|
||||||
|
BMIter iter;
|
||||||
|
BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) {
|
||||||
|
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset);
|
||||||
|
float *luv_next = BM_ELEM_CD_GET_FLOAT_P(l->next, cd_loop_uv_offset);
|
||||||
|
if (uv_circle_select_is_edge_inside(luv, luv_next, offset, ellipse)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Also, is the center of the ellipse in the interior of the face? */
|
||||||
|
return BM_face_uv_point_inside_test(efa, offset, cd_loop_uv_offset);
|
||||||
|
}
|
||||||
|
|
||||||
static int uv_circle_select_exec(bContext *C, wmOperator *op)
|
static int uv_circle_select_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||||
@ -3751,9 +3758,6 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
|
|||||||
float zoomx, zoomy;
|
float zoomx, zoomy;
|
||||||
float offset[2], ellipse[2];
|
float offset[2], ellipse[2];
|
||||||
|
|
||||||
const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
|
|
||||||
(ts->selectmode == SCE_SELECT_FACE) :
|
|
||||||
(ts->uv_selectmode == UV_SELECT_FACE));
|
|
||||||
const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
|
const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
|
||||||
(ts->selectmode == SCE_SELECT_EDGE) :
|
(ts->selectmode == SCE_SELECT_EDGE) :
|
||||||
(ts->uv_selectmode == UV_SELECT_EDGE));
|
(ts->uv_selectmode == UV_SELECT_EDGE));
|
||||||
@ -3801,19 +3805,13 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
|
|||||||
BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name);
|
BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name);
|
||||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||||
|
|
||||||
/* do selection */
|
/* Do selection. */
|
||||||
if (use_face_center) {
|
if (ED_uvedit_select_mode_get(scene) == UV_SELECT_FACE) {
|
||||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||||
BM_elem_flag_disable(efa, BM_ELEM_TAG);
|
const bool touched = select != uvedit_face_select_test(scene, efa, offsets) &&
|
||||||
/* assume not touched */
|
uv_circle_select_is_face_touching(efa, offset, ellipse, offsets.uv);
|
||||||
if (select != uvedit_face_select_test(scene, efa, offsets)) {
|
BM_elem_flag_set(efa, BM_ELEM_TAG, touched);
|
||||||
float cent[2];
|
changed |= touched;
|
||||||
BM_face_uv_calc_center_median(efa, offsets.uv, cent);
|
|
||||||
if (uv_circle_select_is_point_inside(cent, offset, ellipse)) {
|
|
||||||
BM_elem_flag_enable(efa, BM_ELEM_TAG);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (de)selects all tagged faces and deals with sticky modes */
|
/* (de)selects all tagged faces and deals with sticky modes */
|
||||||
@ -3944,14 +3942,35 @@ static bool do_lasso_select_mesh_uv_is_edge_inside(const ARegion *region,
|
|||||||
const float co_test_b[2])
|
const float co_test_b[2])
|
||||||
{
|
{
|
||||||
int co_screen_a[2], co_screen_b[2];
|
int co_screen_a[2], co_screen_b[2];
|
||||||
if (UI_view2d_view_to_region_segment_clip(
|
return UI_view2d_view_to_region_segment_clip(
|
||||||
®ion->v2d, co_test_a, co_test_b, co_screen_a, co_screen_b) &&
|
®ion->v2d, co_test_a, co_test_b, co_screen_a, co_screen_b) &&
|
||||||
BLI_rcti_isect_segment(clip_rect, co_screen_a, co_screen_b) &&
|
BLI_rcti_isect_segment(clip_rect, co_screen_a, co_screen_b) &&
|
||||||
BLI_lasso_is_edge_inside(
|
BLI_lasso_is_edge_inside(
|
||||||
mcoords, mcoords_len, UNPACK2(co_screen_a), UNPACK2(co_screen_b), V2D_IS_CLIPPED)) {
|
mcoords, mcoords_len, UNPACK2(co_screen_a), UNPACK2(co_screen_b), V2D_IS_CLIPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool uv_lasso_select_is_face_touching(BMFace *efa,
|
||||||
|
const ARegion *region,
|
||||||
|
const rcti *clip_rect,
|
||||||
|
const int mcoords[][2],
|
||||||
|
const int mcoords_len,
|
||||||
|
const int cd_loop_uv_offset)
|
||||||
|
{
|
||||||
|
/* First, are any of the face edges inside the lasso? */
|
||||||
|
BMLoop *l;
|
||||||
|
BMIter iter;
|
||||||
|
BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) {
|
||||||
|
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset);
|
||||||
|
float *luv_next = BM_ELEM_CD_GET_FLOAT_P(l->next, cd_loop_uv_offset);
|
||||||
|
if (do_lasso_select_mesh_uv_is_edge_inside(
|
||||||
|
region, clip_rect, mcoords, mcoords_len, luv, luv_next)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
/* Also, is an arbitrary point of the lasso in the interior of the face? */
|
||||||
|
float lasso_corner[2] = {mcoords[0][0], mcoords[0][1]};
|
||||||
|
return BM_face_uv_point_inside_test(efa, lasso_corner, cd_loop_uv_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool do_lasso_select_mesh_uv(bContext *C,
|
static bool do_lasso_select_mesh_uv(bContext *C,
|
||||||
@ -3964,9 +3983,6 @@ static bool do_lasso_select_mesh_uv(bContext *C,
|
|||||||
Scene *scene = CTX_data_scene(C);
|
Scene *scene = CTX_data_scene(C);
|
||||||
const ToolSettings *ts = scene->toolsettings;
|
const ToolSettings *ts = scene->toolsettings;
|
||||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||||
const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
|
|
||||||
(ts->selectmode == SCE_SELECT_FACE) :
|
|
||||||
(ts->uv_selectmode == UV_SELECT_FACE));
|
|
||||||
const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
|
const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
|
||||||
(ts->selectmode == SCE_SELECT_EDGE) :
|
(ts->selectmode == SCE_SELECT_EDGE) :
|
||||||
(ts->uv_selectmode == UV_SELECT_EDGE));
|
(ts->uv_selectmode == UV_SELECT_EDGE));
|
||||||
@ -4005,18 +4021,13 @@ static bool do_lasso_select_mesh_uv(bContext *C,
|
|||||||
BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name);
|
BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name);
|
||||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||||
|
|
||||||
if (use_face_center) { /* Face Center Select. */
|
if (ED_uvedit_select_mode_get(scene) == UV_SELECT_FACE) { /* Face Touch Select. */
|
||||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||||
BM_elem_flag_disable(efa, BM_ELEM_TAG);
|
const bool touched = select != uvedit_face_select_test(scene, efa, offsets) &&
|
||||||
/* assume not touched */
|
uv_lasso_select_is_face_touching(
|
||||||
if (select != uvedit_face_select_test(scene, efa, offsets)) {
|
efa, region, &rect, mcoords, mcoords_len, offsets.uv);
|
||||||
float cent[2];
|
BM_elem_flag_set(efa, BM_ELEM_TAG, touched);
|
||||||
BM_face_uv_calc_center_median(efa, offsets.uv, cent);
|
changed |= touched;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (de)selects all tagged faces and deals with sticky modes */
|
/* (de)selects all tagged faces and deals with sticky modes */
|
||||||
@ -4341,7 +4352,7 @@ static int uv_select_overlap(bContext *C, const bool extend)
|
|||||||
BMIter iter;
|
BMIter iter;
|
||||||
BMFace *efa;
|
BMFace *efa;
|
||||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||||
if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) {
|
if (!uvedit_face_visible_test(scene, efa)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uv_tri_len += efa->len - 2;
|
uv_tri_len += efa->len - 2;
|
||||||
@ -4375,7 +4386,7 @@ static int uv_select_overlap(bContext *C, const bool extend)
|
|||||||
int face_index;
|
int face_index;
|
||||||
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) {
|
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) {
|
||||||
|
|
||||||
if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) {
|
if (!uvedit_face_visible_test(scene, efa)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5245,160 +5256,6 @@ void UV_OT_select_similar(wmOperatorType *ot)
|
|||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name Selected Elements as Arrays (Vertex, Edge & Faces)
|
|
||||||
*
|
|
||||||
* These functions return single elements per connected vertex/edge.
|
|
||||||
* So an edge that has two connected edge loops only assigns one loop in the array.
|
|
||||||
* \{ */
|
|
||||||
|
|
||||||
BMFace **ED_uvedit_selected_faces(const Scene *scene, BMesh *bm, int len_max, int *r_faces_len)
|
|
||||||
{
|
|
||||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(bm);
|
|
||||||
|
|
||||||
CLAMP_MAX(len_max, bm->totface);
|
|
||||||
int faces_len = 0;
|
|
||||||
BMFace **faces = MEM_mallocN(sizeof(*faces) * len_max, __func__);
|
|
||||||
|
|
||||||
BMIter iter;
|
|
||||||
BMFace *f;
|
|
||||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
|
||||||
if (uvedit_face_visible_test(scene, f)) {
|
|
||||||
if (uvedit_face_select_test(scene, f, offsets)) {
|
|
||||||
faces[faces_len++] = f;
|
|
||||||
if (faces_len == len_max) {
|
|
||||||
goto finally;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
finally:
|
|
||||||
*r_faces_len = faces_len;
|
|
||||||
if (faces_len != len_max) {
|
|
||||||
faces = MEM_reallocN(faces, sizeof(*faces) * faces_len);
|
|
||||||
}
|
|
||||||
return faces;
|
|
||||||
}
|
|
||||||
|
|
||||||
BMLoop **ED_uvedit_selected_edges(const Scene *scene, BMesh *bm, int len_max, int *r_edges_len)
|
|
||||||
{
|
|
||||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(bm);
|
|
||||||
BLI_assert(offsets.uv >= 0);
|
|
||||||
|
|
||||||
CLAMP_MAX(len_max, bm->totloop);
|
|
||||||
int edges_len = 0;
|
|
||||||
BMLoop **edges = MEM_mallocN(sizeof(*edges) * len_max, __func__);
|
|
||||||
|
|
||||||
BMIter iter;
|
|
||||||
BMFace *f;
|
|
||||||
|
|
||||||
/* Clear tag. */
|
|
||||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
|
||||||
BMIter liter;
|
|
||||||
BMLoop *l_iter;
|
|
||||||
BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
|
|
||||||
BM_elem_flag_disable(l_iter, BM_ELEM_TAG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
|
||||||
if (uvedit_face_visible_test(scene, f)) {
|
|
||||||
BMIter liter;
|
|
||||||
BMLoop *l_iter;
|
|
||||||
BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
|
|
||||||
if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
|
|
||||||
if (uvedit_edge_select_test(scene, l_iter, offsets)) {
|
|
||||||
BM_elem_flag_enable(l_iter, BM_ELEM_TAG);
|
|
||||||
|
|
||||||
edges[edges_len++] = l_iter;
|
|
||||||
if (edges_len == len_max) {
|
|
||||||
goto finally;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tag other connected loops so we don't consider them separate edges. */
|
|
||||||
if (l_iter != l_iter->radial_next) {
|
|
||||||
BMLoop *l_radial_iter = l_iter->radial_next;
|
|
||||||
do {
|
|
||||||
if (BM_loop_uv_share_edge_check(l_iter, l_radial_iter, offsets.uv)) {
|
|
||||||
BM_elem_flag_enable(l_radial_iter, BM_ELEM_TAG);
|
|
||||||
}
|
|
||||||
} while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
finally:
|
|
||||||
*r_edges_len = edges_len;
|
|
||||||
if (edges_len != len_max) {
|
|
||||||
edges = MEM_reallocN(edges, sizeof(*edges) * edges_len);
|
|
||||||
}
|
|
||||||
return edges;
|
|
||||||
}
|
|
||||||
|
|
||||||
BMLoop **ED_uvedit_selected_verts(const Scene *scene, BMesh *bm, int len_max, int *r_verts_len)
|
|
||||||
{
|
|
||||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(bm);
|
|
||||||
BLI_assert(offsets.select_vert >= 0);
|
|
||||||
BLI_assert(offsets.uv >= 0);
|
|
||||||
|
|
||||||
CLAMP_MAX(len_max, bm->totloop);
|
|
||||||
int verts_len = 0;
|
|
||||||
BMLoop **verts = MEM_mallocN(sizeof(*verts) * len_max, __func__);
|
|
||||||
|
|
||||||
BMIter iter;
|
|
||||||
BMFace *f;
|
|
||||||
|
|
||||||
/* Clear tag. */
|
|
||||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
|
||||||
BMIter liter;
|
|
||||||
BMLoop *l_iter;
|
|
||||||
BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
|
|
||||||
BM_elem_flag_disable(l_iter, BM_ELEM_TAG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
|
||||||
if (uvedit_face_visible_test(scene, f)) {
|
|
||||||
BMIter liter;
|
|
||||||
BMLoop *l_iter;
|
|
||||||
BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
|
|
||||||
if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
|
|
||||||
if (BM_ELEM_CD_GET_BOOL(l_iter, offsets.select_vert)) {
|
|
||||||
BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
|
|
||||||
|
|
||||||
verts[verts_len++] = l_iter;
|
|
||||||
if (verts_len == len_max) {
|
|
||||||
goto finally;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tag other connected loops so we don't consider them separate vertices. */
|
|
||||||
BMIter liter_disk;
|
|
||||||
BMLoop *l_disk_iter;
|
|
||||||
BM_ITER_ELEM (l_disk_iter, &liter_disk, l_iter->v, BM_LOOPS_OF_VERT) {
|
|
||||||
if (BM_loop_uv_share_vert_check(l_iter, l_disk_iter, offsets.uv)) {
|
|
||||||
BM_elem_flag_enable(l_disk_iter, BM_ELEM_TAG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
finally:
|
|
||||||
*r_verts_len = verts_len;
|
|
||||||
if (verts_len != len_max) {
|
|
||||||
verts = MEM_reallocN(verts, sizeof(*verts) * verts_len);
|
|
||||||
}
|
|
||||||
return verts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/** \name Select Mode UV Vert/Edge/Face/Island Operator
|
/** \name Select Mode UV Vert/Edge/Face/Island Operator
|
||||||
* \{ */
|
* \{ */
|
||||||
|
Loading…
Reference in New Issue
Block a user