Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/uvedit/uvedit_ops.c
| Context not available. | |||||
| #include "BLI_blenlib.h" | #include "BLI_blenlib.h" | ||||
| #include "BLI_array.h" | #include "BLI_array.h" | ||||
| #include "BLI_kdtree.h" | #include "BLI_kdtree.h" | ||||
| #include "BLI_kdopbvh.h" | |||||
| #include "BLI_polyfill_2d.h" | |||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| Context not available. | |||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Select Overlapping Operator | |||||
| * \{ */ | |||||
| BLI_INLINE unsigned int overlap_hash(const void *overlap_v) | |||||
| { | |||||
| const BVHTreeOverlap *overlap = overlap_v; | |||||
| return (unsigned int)overlap->indexA + (unsigned int)overlap->indexB; | |||||
| } | |||||
| BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v) | |||||
| { | |||||
| const BVHTreeOverlap *a = a_v; | |||||
| const BVHTreeOverlap *b = b_v; | |||||
| return !((a->indexA == b->indexA && a->indexB == b->indexB) || (a->indexA == b->indexB && a->indexB == b->indexA)); | |||||
| } | |||||
| static int uv_select_overlapping(bContext *C, const bool extend) | |||||
| { | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | |||||
| SpaceImage *sima = CTX_wm_space_image(C); | |||||
| Image *ima = CTX_data_edit_image(C); | |||||
| uint objects_len = 0; | |||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len); | |||||
| int *object_face_watermark = MEM_mallocN(sizeof(int) * objects_len, "UV select overlap face counts"); | |||||
| /* Setup meshes, calculate maximum number of tree nodes, and track a per-object face-index watermark */ | |||||
| int uv_maxtri = 0; | |||||
| int face_watermark = 0; | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | |||||
| BM_mesh_elem_table_ensure(em->bm, BM_FACE); | |||||
| BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); | |||||
| BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); | |||||
| if (!extend) { | |||||
| uv_select_all_perform(scene, ima, obedit, SEL_DESELECT); | |||||
| } | |||||
| uv_maxtri += em->tottri; | |||||
| face_watermark += em->bm->totface; | |||||
| object_face_watermark[ob_index] = face_watermark - 1; | |||||
| } | |||||
| BVHTree *uv_tree = BLI_bvhtree_new(uv_maxtri, 0.0001f, 4, 26); | |||||
| int face_base_index = 0; | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| BMIter iter, liter; | |||||
| BMFace *efa; | |||||
| BMLoop *l; | |||||
| 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); | |||||
| /* | |||||
| Triangulate each face and store it inside the bvh | |||||
| A global face-index will be used as the bvh index | |||||
| */ | |||||
| int face_index; | |||||
| BM_ITER_MESH_INDEX(efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) { | |||||
| const int vert_count = efa->len; | |||||
| const int triangle_count = vert_count - 2; | |||||
| const int tree_index = face_base_index + face_index; | |||||
| float(*uv_verts)[2] = MEM_mallocN(sizeof(*uv_verts) * vert_count, "UV select overlap coords"); | |||||
| unsigned int(*indices)[3] = MEM_mallocN(sizeof(*indices) * triangle_count, "UV select overlap triangulation"); | |||||
| int vert_index; | |||||
| BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) { | |||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| printf("%d:[%4.2f, %4.2f] ", tree_index, luv->uv[0], luv->uv[1]); | |||||
| uv_verts[vert_index][0] = luv->uv[0]; | |||||
| uv_verts[vert_index][1] = luv->uv[1]; | |||||
| } | |||||
| printf("\n"); | |||||
| BLI_polyfill_calc(uv_verts, (unsigned int)vert_count, 0, indices); | |||||
| for (int t = 0; t < triangle_count; t++) { | |||||
| const float tri[3][3] = { | |||||
| { UNPACK2(uv_verts[indices[t][0]]), 0 }, | |||||
| { UNPACK2(uv_verts[indices[t][1]]), 0 }, | |||||
| { UNPACK2(uv_verts[indices[t][2]]), 0 }, | |||||
| }; | |||||
| BLI_bvhtree_insert(uv_tree, tree_index, (const float *)tri, 3); | |||||
| } | |||||
| MEM_freeN(indices); | |||||
| MEM_freeN(uv_verts); | |||||
| } | |||||
| face_base_index += em->bm->totface; | |||||
| } | |||||
| BLI_bvhtree_balance(uv_tree); | |||||
| uint tree_overlap_tot; | |||||
| BVHTreeOverlap *overlap = BLI_bvhtree_overlap(uv_tree, uv_tree, &tree_overlap_tot, NULL, NULL); | |||||
| if (overlap) { | |||||
| GSet *pair_test = BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, tree_overlap_tot); | |||||
| for (int i = 0; i < tree_overlap_tot; i++) { | |||||
| /* skip overlaps that have already been tested */ | |||||
| if (!BLI_gset_add(pair_test, &overlap[i])) { | |||||
| continue; | |||||
| } | |||||
| /* skip overlaps with the same face-index */ | |||||
| if (overlap[i].indexA == overlap[i].indexB) { | |||||
| continue; | |||||
| } | |||||
| printf("indexA=%d indexB=%d\n", overlap[i].indexA, overlap[i].indexB); | |||||
| /* find which object the face in question belongs too */ | |||||
| int ob_index_a = 0; | |||||
| int ob_index_b = 0; | |||||
| for (int o = 0; o < objects_len; o++) { | |||||
| if (overlap[i].indexA <= object_face_watermark[o]) { | |||||
| ob_index_a = o; | |||||
| break; | |||||
| } | |||||
| } | |||||
| for (int o = 0; o < objects_len; o++) { | |||||
| if (overlap[i].indexB <= object_face_watermark[o]) { | |||||
| ob_index_b = o; | |||||
| break; | |||||
| } | |||||
| } | |||||
| const int face_index_a = overlap[i].indexA - (ob_index_a == 0 ? 0 : object_face_watermark[ob_index_a - 1] + 1); | |||||
| const int face_index_b = overlap[i].indexB - (ob_index_b == 0 ? 0 : object_face_watermark[ob_index_b - 1] + 1); | |||||
| Object *obedit_a = objects[ob_index_a]; | |||||
| Object *obedit_b = objects[ob_index_b]; | |||||
| BMEditMesh *emA = BKE_editmesh_from_object(obedit_a); | |||||
| BMEditMesh *emB = BKE_editmesh_from_object(obedit_b); | |||||
| BMFace *face_a = emA->bm->ftable[face_index_a]; | |||||
| BMFace *face_b = emB->bm->ftable[face_index_b]; | |||||
| /* if the faces belong to the same object double check to see if it's a true intersection; skip if not */ | |||||
| if (ob_index_a == ob_index_b) { | |||||
| /* TODO: Not sure how to do this... */ | |||||
| } | |||||
| /* a valid overlap, select both faces */ | |||||
| const int cd_loop_uv_offset_a = CustomData_get_offset(&emA->bm->ldata, CD_MLOOPUV); | |||||
| const int cd_loop_uv_offset_b = CustomData_get_offset(&emB->bm->ldata, CD_MLOOPUV); | |||||
| uvedit_face_select_enable(scene, emA, face_a, false, cd_loop_uv_offset_a); | |||||
| uvedit_face_select_enable(scene, emB, face_b, false, cd_loop_uv_offset_b); | |||||
| DEG_id_tag_update(obedit_a->data, DEG_TAG_SELECT_UPDATE); | |||||
| DEG_id_tag_update(obedit_b->data, DEG_TAG_SELECT_UPDATE); | |||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit_a->data); | |||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit_b->data); | |||||
| } | |||||
| BLI_gset_free(pair_test, NULL); | |||||
| MEM_freeN(overlap); | |||||
| } | |||||
| BLI_bvhtree_free(uv_tree); | |||||
| MEM_freeN(object_face_watermark); | |||||
| MEM_freeN(objects); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| static int uv_select_overlapping_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| bool extend = RNA_boolean_get(op->ptr, "extend"); | |||||
| return uv_select_overlapping(C, extend); | |||||
| } | |||||
| static void UV_OT_select_overlapping(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Select Overlapping"; | |||||
| ot->description = "Select all UV faces which overlap each other"; | |||||
| ot->idname = "UV_OT_select_overlapping"; | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| /* api callbacks */ | |||||
| ot->exec = uv_select_overlapping_exec; | |||||
| ot->poll = ED_operator_uvedit; | |||||
| /* properties */ | |||||
| RNA_def_boolean(ot->srna, "extend", 0, | |||||
| "Extend", "Extend selection rather than clearing the existing selection"); | |||||
| } | |||||
| /** \} */ | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Weld Align Operator | /** \name Weld Align Operator | ||||
| * \{ */ | * \{ */ | ||||
| Context not available. | |||||
| WM_operatortype_append(UV_OT_circle_select); | WM_operatortype_append(UV_OT_circle_select); | ||||
| WM_operatortype_append(UV_OT_select_more); | WM_operatortype_append(UV_OT_select_more); | ||||
| WM_operatortype_append(UV_OT_select_less); | WM_operatortype_append(UV_OT_select_less); | ||||
| WM_operatortype_append(UV_OT_select_overlapping); | |||||
| WM_operatortype_append(UV_OT_snap_cursor); | WM_operatortype_append(UV_OT_snap_cursor); | ||||
| WM_operatortype_append(UV_OT_snap_selected); | WM_operatortype_append(UV_OT_snap_selected); | ||||
| Context not available. | |||||