UV: Add options for uv select similar in island mode

In island selection mode, add new options for uv select similar:

* Area UV
* Area 3D
* Face (number of faces in island)

See also https://developer.blender.org/T47437
Differential Revision: https://developer.blender.org/D15553
This commit is contained in:
Chris Blackbourn
2022-07-30 23:20:13 +12:00
parent d31886b3fe
commit a581460728
3 changed files with 199 additions and 24 deletions

View File

@@ -305,6 +305,29 @@ void ED_uvedit_buttons_register(struct ARegionType *art);
/* uvedit_islands.c */
struct FaceIsland {
struct FaceIsland *next;
struct FaceIsland *prev;
struct BMFace **faces;
int faces_len;
rctf bounds_rect;
/**
* \note While this is duplicate information,
* it allows islands from multiple meshes to be stored in the same list.
*/
uint cd_loop_uv_offset;
float aspect_y;
};
int bm_mesh_calc_uv_islands(const Scene *scene,
struct BMesh *bm,
ListBase *island_list,
const bool only_selected_faces,
const bool only_selected_uvs,
const bool use_seams,
const float aspect_y,
const uint cd_loop_uv_offset);
struct UVMapUDIM_Params {
const struct Image *image;
/** Copied from #SpaceImage.tile_grid_shape */

View File

@@ -309,23 +309,8 @@ static float uv_nearest_grid_tile_distance(const int udim_grid[2],
/* -------------------------------------------------------------------- */
/** \name Calculate UV Islands
*
* \note Currently this is a private API/type, it could be made public.
* \{ */
struct FaceIsland {
struct FaceIsland *next, *prev;
BMFace **faces;
int faces_len;
rctf bounds_rect;
/**
* \note While this is duplicate information,
* it allows islands from multiple meshes to be stored in the same list.
*/
uint cd_loop_uv_offset;
float aspect_y;
};
struct SharedUVLoopData {
uint cd_loop_uv_offset;
bool use_seams;
@@ -347,14 +332,14 @@ static bool bm_loop_uv_shared_edge_check(const BMLoop *l_a, const BMLoop *l_b, v
/**
* Calculate islands and add them to \a island_list returning the number of items added.
*/
static int bm_mesh_calc_uv_islands(const Scene *scene,
BMesh *bm,
ListBase *island_list,
const bool only_selected_faces,
const bool only_selected_uvs,
const bool use_seams,
const float aspect_y,
const uint cd_loop_uv_offset)
int bm_mesh_calc_uv_islands(const Scene *scene,
BMesh *bm,
ListBase *island_list,
const bool only_selected_faces,
const bool only_selected_uvs,
const bool use_seams,
const float aspect_y,
const uint cd_loop_uv_offset)
{
int island_added = 0;
BM_mesh_elem_table_ensure(bm, BM_FACE);

View File

@@ -81,6 +81,7 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
typedef enum {
UV_SSIM_AREA_UV = 1000,
UV_SSIM_AREA_3D,
UV_SSIM_FACE,
UV_SSIM_LENGTH_UV,
UV_SSIM_LENGTH_3D,
UV_SSIM_SIDES,
@@ -4638,6 +4639,33 @@ static float get_uv_face_needle(const eUVSelectSimilar type,
return result;
}
static float get_uv_island_needle(const eUVSelectSimilar type,
const struct FaceIsland *island,
const float ob_m3[3][3],
const int cd_loop_uv_offset)
{
float result = 0.0f;
switch (type) {
case UV_SSIM_AREA_UV:
for (int i = 0; i < island->faces_len; i++) {
result += BM_face_calc_area_uv(island->faces[i], cd_loop_uv_offset);
}
break;
case UV_SSIM_AREA_3D:
for (int i = 0; i < island->faces_len; i++) {
result += BM_face_calc_area_with_mat3(island->faces[i], ob_m3);
}
break;
case UV_SSIM_FACE:
return island->faces_len;
default:
BLI_assert_unreachable();
return false;
}
return result;
}
static int uv_select_similar_vert_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -4969,6 +4997,136 @@ static int uv_select_similar_face_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static bool uv_island_selected(const Scene *scene, struct FaceIsland *island)
{
BLI_assert(island && island->faces_len);
return uvedit_face_select_test(scene, island->faces[0], island->cd_loop_uv_offset);
}
static int uv_select_similar_island_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ToolSettings *ts = CTX_data_tool_settings(C);
const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
const float threshold = RNA_float_get(op->ptr, "threshold");
const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
ListBase *island_list_ptr = MEM_callocN(sizeof(*island_list_ptr) * objects_len, __func__);
int island_list_len = 0;
const bool face_selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
if (cd_loop_uv_offset == -1) {
continue;
}
float aspect_y = 1.0f; /* Placeholder value, aspect doesn't change connectivity. */
island_list_len += bm_mesh_calc_uv_islands(scene,
em->bm,
&island_list_ptr[ob_index],
face_selected,
false,
false,
aspect_y,
cd_loop_uv_offset);
}
struct FaceIsland **island_array = MEM_callocN(sizeof(*island_array) * island_list_len,
__func__);
int tree_index = 0;
KDTree_1d *tree_1d = BLI_kdtree_1d_new(island_list_len);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
if (cd_loop_uv_offset == -1) {
continue;
}
float ob_m3[3][3];
copy_m3_m4(ob_m3, obedit->obmat);
int index;
LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) {
island_array[index] = island;
if (!uv_island_selected(scene, island)) {
continue;
}
float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset);
if (tree_1d) {
BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
}
}
}
if (tree_1d != NULL) {
BLI_kdtree_1d_deduplicate(tree_1d);
BLI_kdtree_1d_balance(tree_1d);
}
int tot_island_index = 0;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
if (cd_loop_uv_offset == -1) {
continue;
}
float ob_m3[3][3];
copy_m3_m4(ob_m3, obedit->obmat);
bool changed = false;
int index;
LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) {
island_array[tot_island_index++] = island; /* To deallocate later. */
if (uv_island_selected(scene, island)) {
continue;
}
float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset);
bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
if (!select) {
continue;
}
bool do_history = false;
for (int j = 0; j < island->faces_len; j++) {
uvedit_face_select_set(
scene, em, island->faces[j], select, do_history, island->cd_loop_uv_offset);
}
changed = true;
}
if (changed) {
uv_select_tag_update_for_object(depsgraph, ts, obedit);
}
}
BLI_assert(tot_island_index == island_list_len);
for (int i = 0; i < island_list_len; i++) {
MEM_SAFE_FREE(island_array[i]->faces);
MEM_SAFE_FREE(island_array[i]);
}
MEM_SAFE_FREE(island_array);
MEM_SAFE_FREE(island_list_ptr);
MEM_SAFE_FREE(objects);
BLI_kdtree_1d_free(tree_1d);
return OPERATOR_FINISHED;
}
/* Select similar UV faces/edges/verts based on current selection. */
static int uv_select_similar_exec(bContext *C, wmOperator *op)
{
@@ -4990,7 +5148,7 @@ static int uv_select_similar_exec(bContext *C, wmOperator *op)
return uv_select_similar_face_exec(C, op);
}
if (selectmode & UV_SELECT_ISLAND) {
// return uv_select_similar_island_exec(C, op);
return uv_select_similar_island_exec(C, op);
}
return uv_select_similar_vert_exec(C, op);
@@ -5011,6 +5169,12 @@ static EnumPropertyItem prop_face_similar_types[] = {
{UV_SSIM_MATERIAL, "MATERIAL", 0, "Material", ""},
{0}};
static EnumPropertyItem prop_island_similar_types[] = {
{UV_SSIM_AREA_UV, "AREA", 0, "Area", ""},
{UV_SSIM_AREA_3D, "AREA_3D", 0, "Area 3D", ""},
{UV_SSIM_FACE, "FACE", 0, "Amount of Faces in Island", ""},
{0}};
static EnumPropertyItem prop_similar_compare_types[] = {{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
{SIM_CMP_GT, "GREATER", 0, "Greater", ""},
{SIM_CMP_LT, "LESS", 0, "Less", ""},
@@ -5030,6 +5194,9 @@ static const EnumPropertyItem *uv_select_similar_type_itemf(bContext *C,
if (selectmode & UV_SELECT_FACE) {
return prop_face_similar_types;
}
if (selectmode & UV_SELECT_ISLAND) {
return prop_island_similar_types;
}
}
return prop_vert_similar_types;