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:
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user