diff options
author | Chris Blackbourn <chrisbblend@gmail.com> | 2022-07-30 14:20:13 +0300 |
---|---|---|
committer | Chris Blackbourn <chrisbblend@gmail.com> | 2022-07-30 14:24:11 +0300 |
commit | a5814607289a7e01d4844ee5ef724e6388cf044e (patch) | |
tree | 32db74c27e02e493c20fba2e6d97c15ea56a747e /source/blender/editors/uvedit/uvedit_select.c | |
parent | d31886b3fe3b939fb86079d5fb607e80103078da (diff) |
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
Diffstat (limited to 'source/blender/editors/uvedit/uvedit_select.c')
-rw-r--r-- | source/blender/editors/uvedit/uvedit_select.c | 169 |
1 files changed, 168 insertions, 1 deletions
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index d59dcb4f4ed..b1ed00e2c57 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -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; |