Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/uvedit/uvedit_ops.c
| Show First 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | |||||
| #include "BKE_library.h" | #include "BKE_library.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_material.h" | #include "BKE_material.h" | ||||
| #include "BKE_mesh_mapping.h" | #include "BKE_mesh_mapping.h" | ||||
| #include "BKE_node.h" | #include "BKE_node.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "BKE_scene.h" | #include "BKE_scene.h" | ||||
| #include "BKE_editmesh.h" | #include "BKE_editmesh.h" | ||||
| #include "BKE_layer.h" | |||||
| #include "DEG_depsgraph.h" | #include "DEG_depsgraph.h" | ||||
| #include "ED_image.h" | #include "ED_image.h" | ||||
| #include "ED_mesh.h" | #include "ED_mesh.h" | ||||
| #include "ED_node.h" | #include "ED_node.h" | ||||
| #include "ED_uvedit.h" | #include "ED_uvedit.h" | ||||
| #include "ED_object.h" | #include "ED_object.h" | ||||
| #include "ED_screen.h" | #include "ED_screen.h" | ||||
| #include "ED_transform.h" | #include "ED_transform.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "RNA_define.h" | #include "RNA_define.h" | ||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "UI_resources.h" | #include "UI_resources.h" | ||||
| #include "UI_view2d.h" | #include "UI_view2d.h" | ||||
| #include "uvedit_intern.h" | #include "uvedit_intern.h" | ||||
| static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, int action); | static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit); | ||||
| static bool uv_select_is_any_selected_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len); | |||||
| static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action); | |||||
| static void uv_select_all_perform_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len, int action); | |||||
| static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select); | static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select); | ||||
| static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select); | static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select); | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name State Testing | /** \name State Testing | ||||
| * \{ */ | * \{ */ | ||||
| bool ED_uvedit_test(Object *obedit) | bool ED_uvedit_test(Object *obedit) | ||||
| ▲ Show 20 Lines • Show All 688 Lines • ▼ Show 20 Lines | BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { | ||||
| hit->dist_sq = dist_test_sq; | hit->dist_sq = dist_test_sq; | ||||
| found = true; | found = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return found; | return found; | ||||
| } | } | ||||
| bool uv_find_nearest_edge_multi( | |||||
| Scene *scene, Image *ima, Object **objects, const uint objects_len, | |||||
| const float co[2], UvNearestHit *hit_final) | |||||
| { | |||||
| bool found = false; | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) { | |||||
| hit_final->ob = obedit; | |||||
| found = true; | |||||
| } | |||||
| } | |||||
| return found; | |||||
| } | |||||
| bool uv_find_nearest_face( | bool uv_find_nearest_face( | ||||
| Scene *scene, Image *ima, Object *obedit, const float co[2], | Scene *scene, Image *ima, Object *obedit, const float co[2], | ||||
| UvNearestHit *hit_final) | UvNearestHit *hit_final) | ||||
| { | { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| bool found = false; | bool found = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | ||||
| Show All 27 Lines | if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { | ||||
| } | } | ||||
| } | } | ||||
| if (found) { | if (found) { | ||||
| *hit_final = hit; | *hit_final = hit; | ||||
| } | } | ||||
| return found; | return found; | ||||
| } | } | ||||
| bool uv_find_nearest_face_multi( | |||||
| Scene *scene, Image *ima, Object **objects, const uint objects_len, | |||||
| const float co[2], UvNearestHit *hit_final) | |||||
| { | |||||
| bool found = false; | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) { | |||||
| hit_final->ob = obedit; | |||||
| found = true; | |||||
| } | |||||
| } | |||||
| return found; | |||||
| } | |||||
| static bool uv_nearest_between( | static bool uv_nearest_between( | ||||
| const BMLoop *l, const float co[2], | const BMLoop *l, const float co[2], | ||||
| const int cd_loop_uv_offset) | const int cd_loop_uv_offset) | ||||
| { | { | ||||
| const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv; | const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv; | ||||
| const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv; | const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv; | ||||
| const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv; | const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv; | ||||
| ▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | bool uv_find_nearest_vert( | ||||
| if (found) { | if (found) { | ||||
| *hit_final = hit; | *hit_final = hit; | ||||
| } | } | ||||
| return found; | return found; | ||||
| } | } | ||||
| bool uv_find_nearest_vert_multi( | |||||
| Scene *scene, Image *ima, Object **objects, const uint objects_len, | |||||
| float const co[2], const float penalty_dist, UvNearestHit *hit_final) | |||||
| { | |||||
| bool found = false; | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) { | |||||
| hit_final->ob = obedit; | |||||
| found = true; | |||||
| } | |||||
| } | |||||
| return found; | |||||
| } | |||||
| bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float co[2], float r_uv[2]) | bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float co[2], float r_uv[2]) | ||||
| { | { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | MLoopUV *luv; | ||||
| float mindist, dist; | float mindist, dist; | ||||
| ▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | for (iterv2 = first2; iterv2; iterv2 = iterv2->next) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| static int uv_select_edgeloop( | static int uv_select_edgeloop( | ||||
| Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, UvNearestHit *hit, | Scene *scene, Image *ima, Object *obedit, UvNearestHit *hit, | ||||
| const float limit[2], const bool extend) | const float limit[2], const bool extend) | ||||
| { | { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | |||||
| BMFace *efa; | BMFace *efa; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| UvVertMap *vmap; | UvVertMap *vmap; | ||||
| UvMapVert *iterv_curr; | UvMapVert *iterv_curr; | ||||
| UvMapVert *iterv_next; | UvMapVert *iterv_next; | ||||
| int starttotf; | int starttotf; | ||||
| bool looking, select; | bool looking, select; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | ||||
| /* setup */ | /* setup */ | ||||
| BM_mesh_elem_table_ensure(em->bm, BM_FACE); | BM_mesh_elem_table_ensure(em->bm, BM_FACE); | ||||
| vmap = BM_uv_vert_map_create(em->bm, limit, false, false); | vmap = BM_uv_vert_map_create(em->bm, limit, false, false); | ||||
| BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); | BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); | ||||
| if (!extend) { | if (!extend) { | ||||
| uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT); | uv_select_all_perform(scene, ima, obedit, SEL_DESELECT); | ||||
| } | } | ||||
| BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); | BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); | ||||
| /* set flags for first face and verts */ | /* set flags for first face and verts */ | ||||
| iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); | iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); | ||||
| iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); | iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); | ||||
| uv_select_edgeloop_vertex_loop_flag(iterv_curr); | uv_select_edgeloop_vertex_loop_flag(iterv_curr); | ||||
| ▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Select Linked | /** \name Select Linked | ||||
| * \{ */ | * \{ */ | ||||
| static void uv_select_linked( | static void uv_select_linked_multi( | ||||
| Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, const float limit[2], | Scene *scene, Image *ima, Object **objects, const uint objects_len, const float limit[2], | ||||
| UvNearestHit *hit_final, bool extend, bool select_faces) | UvNearestHit *hit_final, bool extend, bool select_faces) | ||||
| { | { | ||||
| /* loop over objects, or just use hit_final->ob */ | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| if (hit_final && ob_index != 0) { | |||||
| break; | |||||
| } | |||||
| Object *obedit = hit_final ? hit_final->ob : objects[ob_index]; | |||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | MLoopUV *luv; | ||||
| UvVertMap *vmap; | UvVertMap *vmap; | ||||
| UvMapVert *vlist, *iterv, *startv; | UvMapVert *vlist, *iterv, *startv; | ||||
| int i, stacksize = 0, *stack; | int i, stacksize = 0, *stack; | ||||
| unsigned int a; | unsigned int a; | ||||
| char *flag; | char *flag; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | |||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | ||||
| BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */ | BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */ | ||||
| /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320 | /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320 | ||||
| * this made *every* projection split the island into front/back islands. | * this made *every* projection split the island into front/back islands. | ||||
| * Keep 'use_winding' to false, see: T50970. | * Keep 'use_winding' to false, see: T50970. | ||||
| * | * | ||||
| ▲ Show 20 Lines • Show All 159 Lines • ▼ Show 20 Lines | else { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(stack); | MEM_freeN(stack); | ||||
| MEM_freeN(flag); | MEM_freeN(flag); | ||||
| BM_uv_vert_map_free(vmap); | BM_uv_vert_map_free(vmap); | ||||
| } /* objects */ | |||||
| } | } | ||||
| /* WATCH IT: this returns first selected UV, | /* WATCH IT: this returns first selected UV, | ||||
| * not ideal in many cases since there could be multiple */ | * not ideal in many cases since there could be multiple */ | ||||
| static float *uv_sel_co_from_eve(Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve) | static float *uv_sel_co_from_eve(Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve) | ||||
| { | { | ||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| ▲ Show 20 Lines • Show All 605 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name (De)Select All Operator | /** \name (De)Select All Operator | ||||
| * \{ */ | * \{ */ | ||||
| static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, int action) | |||||
| static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit) | |||||
| { | { | ||||
| ToolSettings *ts = scene->toolsettings; | ToolSettings *ts = scene->toolsettings; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | |||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | MLoopUV *luv; | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | |||||
| return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel); | |||||
| } | |||||
| else { | |||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | |||||
| if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { | |||||
| continue; | |||||
| } | |||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | |||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| if (luv->flag & MLOOPUV_VERTSEL) { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | static bool uv_select_is_any_selected_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len) | ||||
| { | |||||
| bool found = false; | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| if (uv_select_is_any_selected(scene, ima, obedit)) { | |||||
| found = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| return found; | |||||
| } | |||||
| static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action) | |||||
| { | |||||
| ToolSettings *ts = scene->toolsettings; | |||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | |||||
| BMFace *efa; | |||||
| BMLoop *l; | |||||
| BMIter iter, liter; | |||||
| MLoopUV *luv; | |||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | |||||
| if (action == SEL_TOGGLE) { | |||||
| action = uv_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT; | |||||
| } | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | |||||
| switch (action) { | switch (action) { | ||||
| case SEL_TOGGLE: | case SEL_TOGGLE: | ||||
| EDBM_select_toggle_all(em); | EDBM_select_toggle_all(em); | ||||
| break; | break; | ||||
| case SEL_SELECT: | case SEL_SELECT: | ||||
| EDBM_flag_enable_all(em, BM_ELEM_SELECT); | EDBM_flag_enable_all(em, BM_ELEM_SELECT); | ||||
| break; | break; | ||||
| case SEL_DESELECT: | case SEL_DESELECT: | ||||
| EDBM_flag_disable_all(em, BM_ELEM_SELECT); | EDBM_flag_disable_all(em, BM_ELEM_SELECT); | ||||
| break; | break; | ||||
| case SEL_INVERT: | case SEL_INVERT: | ||||
| EDBM_select_swap(em); | EDBM_select_swap(em); | ||||
| EDBM_selectmode_flush(em); | EDBM_selectmode_flush(em); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if (action == SEL_TOGGLE) { | |||||
| action = SEL_SELECT; | |||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | |||||
| if (!uvedit_face_visible_test(scene, obedit, ima, efa)) | |||||
| continue; | |||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | |||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| if (luv->flag & MLOOPUV_VERTSEL) { | |||||
| action = SEL_DESELECT; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| 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, obedit, ima, efa)) | if (!uvedit_face_visible_test(scene, obedit, ima, efa)) | ||||
| continue; | continue; | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | ||||
| switch (action) { | switch (action) { | ||||
| case SEL_SELECT: | case SEL_SELECT: | ||||
| luv->flag |= MLOOPUV_VERTSEL; | luv->flag |= MLOOPUV_VERTSEL; | ||||
| break; | break; | ||||
| case SEL_DESELECT: | case SEL_DESELECT: | ||||
| luv->flag &= ~MLOOPUV_VERTSEL; | luv->flag &= ~MLOOPUV_VERTSEL; | ||||
| break; | break; | ||||
| case SEL_INVERT: | case SEL_INVERT: | ||||
| luv->flag ^= MLOOPUV_VERTSEL; | luv->flag ^= MLOOPUV_VERTSEL; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void uv_select_all_perform_multi( | |||||
| Scene *scene, Image *ima, Object **objects, const uint objects_len, int action) | |||||
| { | |||||
| if (action == SEL_TOGGLE) { | |||||
| action = uv_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT : SEL_SELECT; | |||||
| } | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| uv_select_all_perform(scene, ima, obedit, action); | |||||
| } | |||||
| } | |||||
| static int uv_select_all_exec(bContext *C, wmOperator *op) | static int uv_select_all_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| Object *obedit = CTX_data_edit_object(C); | |||||
| Image *ima = CTX_data_edit_image(C); | Image *ima = CTX_data_edit_image(C); | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| int action = RNA_enum_get(op->ptr, "action"); | int action = RNA_enum_get(op->ptr, "action"); | ||||
| uv_select_all_perform(scene, ima, obedit, em, action); | uint objects_len = 0; | ||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( | |||||
| view_layer, &objects_len, | |||||
| .filter_fn = BKE_view_layer_filter_edit_mesh_has_uvs, | |||||
| .no_dupe_data = true); | |||||
| uv_select_all_perform_multi(scene, ima, objects, objects_len, action); | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | |||||
| MEM_SAFE_FREE(objects); | |||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static void UV_OT_select_all(wmOperatorType *ot) | static void UV_OT_select_all(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "(De)select All"; | ot->name = "(De)select All"; | ||||
| Show All 37 Lines | static bool uv_sticky_select(float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen) | ||||
| return false; | return false; | ||||
| } | } | ||||
| static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loop) | static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loop) | ||||
| { | { | ||||
| SpaceImage *sima = CTX_wm_space_image(C); | SpaceImage *sima = CTX_wm_space_image(C); | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ToolSettings *ts = scene->toolsettings; | ToolSettings *ts = scene->toolsettings; | ||||
| Object *obedit = CTX_data_edit_object(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| Image *ima = CTX_data_edit_image(C); | Image *ima = CTX_data_edit_image(C); | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | |||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | MLoopUV *luv; | ||||
| UvNearestHit hit = UV_NEAREST_HIT_INIT; | UvNearestHit hit = UV_NEAREST_HIT_INIT; | ||||
| int i, selectmode, sticky, sync, *hitv = NULL; | int i, selectmode, sticky, sync, *hitv = NULL; | ||||
| bool select = true; | bool select = true; | ||||
| int flush = 0, hitlen = 0; /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ | int flush = 0, hitlen = 0; /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ | ||||
| float limit[2], **hituv = NULL; | float limit[2], **hituv = NULL; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | // BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| // const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | |||||
| /* notice 'limit' is the same no matter the zoom level, since this is like | /* notice 'limit' is the same no matter the zoom level, since this is like | ||||
| * remove doubles and could annoying if it joined points when zoomed out. | * remove doubles and could annoying if it joined points when zoomed out. | ||||
| * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and | * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and | ||||
| * shift-selecting can consider an adjacent point close enough to add to | * shift-selecting can consider an adjacent point close enough to add to | ||||
| * the selection rather than de-selecting the closest. */ | * the selection rather than de-selecting the closest. */ | ||||
| float penalty_dist; | float penalty_dist; | ||||
| Show All 18 Lines | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| sticky = SI_STICKY_DISABLE; | sticky = SI_STICKY_DISABLE; | ||||
| } | } | ||||
| else { | else { | ||||
| sync = 0; | sync = 0; | ||||
| selectmode = ts->uv_selectmode; | selectmode = ts->uv_selectmode; | ||||
| sticky = (sima) ? sima->sticky : 1; | sticky = (sima) ? sima->sticky : 1; | ||||
| } | } | ||||
| uint objects_len = 0; | |||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( | |||||
| view_layer, &objects_len, | |||||
| .filter_fn = BKE_view_layer_filter_edit_mesh_has_uvs, | |||||
| .no_dupe_data = true); | |||||
| /* find nearest element */ | /* find nearest element */ | ||||
| if (loop) { | if (loop) { | ||||
| /* find edge */ | /* find edge */ | ||||
| if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { | if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| hitlen = 0; | hitlen = 0; | ||||
| } | } | ||||
| else if (selectmode == UV_SELECT_VERTEX) { | else if (selectmode == UV_SELECT_VERTEX) { | ||||
| /* find vertex */ | /* find vertex */ | ||||
| if (!uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, &hit)) { | if (!uv_find_nearest_vert_multi(scene, ima, objects, objects_len, co, penalty_dist, &hit)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* mark 1 vertex as being hit */ | /* mark 1 vertex as being hit */ | ||||
| hitv = BLI_array_alloca(hitv, hit.efa->len); | hitv = BLI_array_alloca(hitv, hit.efa->len); | ||||
| hituv = BLI_array_alloca(hituv, hit.efa->len); | hituv = BLI_array_alloca(hituv, hit.efa->len); | ||||
| copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); | copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); | ||||
| hitv[hit.lindex] = BM_elem_index_get(hit.l->v); | hitv[hit.lindex] = BM_elem_index_get(hit.l->v); | ||||
| hituv[hit.lindex] = hit.luv->uv; | hituv[hit.lindex] = hit.luv->uv; | ||||
| hitlen = hit.efa->len; | hitlen = hit.efa->len; | ||||
| } | } | ||||
| else if (selectmode == UV_SELECT_EDGE) { | else if (selectmode == UV_SELECT_EDGE) { | ||||
| /* find edge */ | /* find edge */ | ||||
| if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { | if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* mark 2 edge vertices as being hit */ | /* mark 2 edge vertices as being hit */ | ||||
| hitv = BLI_array_alloca(hitv, hit.efa->len); | hitv = BLI_array_alloca(hitv, hit.efa->len); | ||||
| hituv = BLI_array_alloca(hituv, hit.efa->len); | hituv = BLI_array_alloca(hituv, hit.efa->len); | ||||
| copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); | copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); | ||||
| hitv[hit.lindex] = BM_elem_index_get(hit.l->v); | hitv[hit.lindex] = BM_elem_index_get(hit.l->v); | ||||
| hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v); | hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v); | ||||
| hituv[hit.lindex] = hit.luv->uv; | hituv[hit.lindex] = hit.luv->uv; | ||||
| hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv; | hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv; | ||||
| hitlen = hit.efa->len; | hitlen = hit.efa->len; | ||||
| } | } | ||||
| else if (selectmode == UV_SELECT_FACE) { | else if (selectmode == UV_SELECT_FACE) { | ||||
| /* find face */ | /* find face */ | ||||
| if (!uv_find_nearest_face(scene, ima, obedit, co, &hit)) { | if (!uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| BMEditMesh *em = BKE_editmesh_from_object(hit.ob); | |||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | |||||
| /* make active */ | /* make active */ | ||||
| BM_mesh_active_face_set(em->bm, hit.efa); | BM_mesh_active_face_set(em->bm, hit.efa); | ||||
| /* mark all face vertices as being hit */ | /* mark all face vertices as being hit */ | ||||
| hitv = BLI_array_alloca(hitv, hit.efa->len); | hitv = BLI_array_alloca(hitv, hit.efa->len); | ||||
| hituv = BLI_array_alloca(hituv, hit.efa->len); | hituv = BLI_array_alloca(hituv, hit.efa->len); | ||||
| BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) { | BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | ||||
| hituv[i] = luv->uv; | hituv[i] = luv->uv; | ||||
| hitv[i] = BM_elem_index_get(l->v); | hitv[i] = BM_elem_index_get(l->v); | ||||
| } | } | ||||
| hitlen = hit.efa->len; | hitlen = hit.efa->len; | ||||
| } | } | ||||
| else if (selectmode == UV_SELECT_ISLAND) { | else if (selectmode == UV_SELECT_ISLAND) { | ||||
| if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { | if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| hitlen = 0; | hitlen = 0; | ||||
| } | } | ||||
| else { | else { | ||||
| hitlen = 0; | hitlen = 0; | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| Object *obedit = hit.ob; | |||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | |||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | |||||
| /* do selection */ | /* do selection */ | ||||
| if (loop) { | if (loop) { | ||||
| flush = uv_select_edgeloop(scene, ima, obedit, em, &hit, limit, extend); | if (!extend) { | ||||
| /* TODO(MULTI_EDIT): We only need to de-select non-active */ | |||||
| uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); | |||||
| } | |||||
| flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend); | |||||
| } | } | ||||
| else if (selectmode == UV_SELECT_ISLAND) { | else if (selectmode == UV_SELECT_ISLAND) { | ||||
| uv_select_linked(scene, ima, obedit, em, limit, &hit, extend, false); | if (!extend) { | ||||
| /* TODO(MULTI_EDIT): We only need to de-select non-active */ | |||||
| uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); | |||||
| } | |||||
| uv_select_linked_multi(scene, ima, objects, objects_len, limit, &hit, extend, false); | |||||
| } | } | ||||
| else if (extend) { | else if (extend) { | ||||
| if (selectmode == UV_SELECT_VERTEX) { | if (selectmode == UV_SELECT_VERTEX) { | ||||
| /* (de)select uv vertex */ | /* (de)select uv vertex */ | ||||
| select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); | select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); | ||||
| uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); | uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); | ||||
| flush = 1; | flush = 1; | ||||
| } | } | ||||
| Show All 33 Lines | if (sticky != SI_STICKY_DISABLE) { | ||||
| } | } | ||||
| } | } | ||||
| flush = select ? 1 : -1; | flush = select ? 1 : -1; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* deselect all */ | /* deselect all */ | ||||
| uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT); | uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); | ||||
| if (selectmode == UV_SELECT_VERTEX) { | if (selectmode == UV_SELECT_VERTEX) { | ||||
| /* select vertex */ | /* select vertex */ | ||||
| uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); | uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); | ||||
| flush = 1; | flush = 1; | ||||
| } | } | ||||
| else if (selectmode == UV_SELECT_EDGE) { | else if (selectmode == UV_SELECT_EDGE) { | ||||
| /* select edge */ | /* select edge */ | ||||
| ▲ Show 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | |||||
| /** \name Select Linked Operator | /** \name Select Linked Operator | ||||
| * \{ */ | * \{ */ | ||||
| static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, int pick) | static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, int pick) | ||||
| { | { | ||||
| SpaceImage *sima = CTX_wm_space_image(C); | SpaceImage *sima = CTX_wm_space_image(C); | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ToolSettings *ts = scene->toolsettings; | ToolSettings *ts = scene->toolsettings; | ||||
| Object *obedit = CTX_data_edit_object(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| Image *ima = CTX_data_edit_image(C); | Image *ima = CTX_data_edit_image(C); | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | |||||
| float limit[2]; | float limit[2]; | ||||
| int extend; | int extend; | ||||
| bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); | bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); | ||||
| UvNearestHit hit = UV_NEAREST_HIT_INIT; | UvNearestHit hit = UV_NEAREST_HIT_INIT; | ||||
| if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) { | if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Select linked only works in face select mode when sync selection is enabled"); | BKE_report(op->reports, RPT_ERROR, "Select linked only works in face select mode when sync selection is enabled"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| extend = RNA_boolean_get(op->ptr, "extend"); | extend = RNA_boolean_get(op->ptr, "extend"); | ||||
| uvedit_pixel_to_float(sima, limit, 0.05f); | uvedit_pixel_to_float(sima, limit, 0.05f); | ||||
| uint objects_len = 0; | |||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( | |||||
| view_layer, &objects_len, | |||||
| .filter_fn = BKE_view_layer_filter_edit_mesh_has_uvs, | |||||
| .no_dupe_data = true); | |||||
| if (pick) { | if (pick) { | ||||
| float co[2]; | float co[2]; | ||||
| if (event) { | if (event) { | ||||
| /* invoke */ | /* invoke */ | ||||
| ARegion *ar = CTX_wm_region(C); | ARegion *ar = CTX_wm_region(C); | ||||
| UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); | UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); | ||||
| RNA_float_set_array(op->ptr, "location", co); | RNA_float_set_array(op->ptr, "location", co); | ||||
| } | } | ||||
| else { | else { | ||||
| /* exec */ | /* exec */ | ||||
| RNA_float_get_array(op->ptr, "location", co); | RNA_float_get_array(op->ptr, "location", co); | ||||
| } | } | ||||
| if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { | if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { | ||||
| MEM_SAFE_FREE(objects); | |||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| } | } | ||||
| uv_select_linked(scene, ima, obedit, em, limit, pick ? &hit : NULL, extend, select_faces); | if (!extend) { | ||||
| uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); | |||||
| } | |||||
| uv_select_linked_multi(scene, ima, objects, objects_len, limit, pick ? &hit : NULL, extend, select_faces); | |||||
| /* weak!, but works */ | |||||
| Object **objects_free = objects; | |||||
| if (pick) { | |||||
| objects = &hit.ob; | |||||
| objects_len = 1; | |||||
| } | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| DEG_id_tag_update(obedit->data, 0); | DEG_id_tag_update(obedit->data, 0); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | |||||
| MEM_SAFE_FREE(objects_free); | |||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int uv_select_linked_exec(bContext *C, wmOperator *op) | static int uv_select_linked_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| return uv_select_linked_internal(C, op, NULL, 0); | return uv_select_linked_internal(C, op, NULL, 0); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 379 Lines • ▼ Show 20 Lines | |||||
| /** \name Border Select Operator | /** \name Border Select Operator | ||||
| * \{ */ | * \{ */ | ||||
| static int uv_border_select_exec(bContext *C, wmOperator *op) | static int uv_border_select_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| SpaceImage *sima = CTX_wm_space_image(C); | SpaceImage *sima = CTX_wm_space_image(C); | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ToolSettings *ts = scene->toolsettings; | ToolSettings *ts = scene->toolsettings; | ||||
| Object *obedit = CTX_data_edit_object(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| Image *ima = CTX_data_edit_image(C); | Image *ima = CTX_data_edit_image(C); | ||||
| ARegion *ar = CTX_wm_region(C); | ARegion *ar = CTX_wm_region(C); | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | |||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | MLoopUV *luv; | ||||
| rctf rectf; | rctf rectf; | ||||
| bool changed, pinned, select, extend; | bool pinned, select, extend; | ||||
| const bool use_face_center = ( | const bool use_face_center = ( | ||||
| (ts->uv_flag & UV_SYNC_SELECTION) ? | (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 int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | |||||
| /* get rectangle from operator */ | /* get rectangle from operator */ | ||||
| WM_operator_properties_border_to_rctf(op, &rectf); | WM_operator_properties_border_to_rctf(op, &rectf); | ||||
| UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf); | UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf); | ||||
| /* figure out what to select/deselect */ | /* figure out what to select/deselect */ | ||||
| select = !RNA_boolean_get(op->ptr, "deselect"); | select = !RNA_boolean_get(op->ptr, "deselect"); | ||||
| extend = RNA_boolean_get(op->ptr, "extend"); | extend = RNA_boolean_get(op->ptr, "extend"); | ||||
| pinned = RNA_boolean_get(op->ptr, "pinned"); | pinned = RNA_boolean_get(op->ptr, "pinned"); | ||||
| bool changed_multi = false; | |||||
| uint objects_len = 0; | |||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( | |||||
| view_layer, &objects_len, | |||||
| .filter_fn = BKE_view_layer_filter_edit_mesh_has_uvs, | |||||
| .no_dupe_data = true); | |||||
| /* don't indent to avoid diff noise! */ | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | |||||
| bool changed = false; | |||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | |||||
| if (!extend) | if (!extend) | ||||
| uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT); | uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); | ||||
| /* do actual selection */ | /* do actual selection */ | ||||
| if (use_face_center && !pinned) { | if (use_face_center && !pinned) { | ||||
| /* handle face selection mode */ | /* handle face selection mode */ | ||||
| float cent[2]; | float cent[2]; | ||||
| changed = false; | changed = false; | ||||
| ▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | static int uv_border_select_exec(bContext *C, wmOperator *op) | ||||
| } | } | ||||
| if (changed) { | if (changed) { | ||||
| uv_select_sync_flush(ts, em, select); | uv_select_sync_flush(ts, em, select); | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| } | |||||
| changed_multi |= changed; | |||||
| return OPERATOR_FINISHED; | |||||
| } | } | ||||
| MEM_SAFE_FREE(objects); | |||||
| if (changed_multi) { | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| static void UV_OT_select_border(wmOperatorType *ot) | static void UV_OT_select_border(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Border Select"; | ot->name = "Border Select"; | ||||
| ot->description = "Select UV vertices using border selection"; | ot->description = "Select UV vertices using border selection"; | ||||
| ot->idname = "UV_OT_select_border"; | ot->idname = "UV_OT_select_border"; | ||||
| ▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Lasso Select Operator | /** \name Lasso Select Operator | ||||
| * \{ */ | * \{ */ | ||||
| static bool do_lasso_select_mesh_uv( | static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves, | ||||
| bContext *C, const int mcords[][2], short moves, | |||||
| const bool select, const bool extend) | const bool select, const bool extend) | ||||
| { | { | ||||
| SpaceImage *sima = CTX_wm_space_image(C); | SpaceImage *sima = CTX_wm_space_image(C); | ||||
| Image *ima = CTX_data_edit_image(C); | Image *ima = CTX_data_edit_image(C); | ||||
| ARegion *ar = CTX_wm_region(C); | ARegion *ar = CTX_wm_region(C); | ||||
| Object *obedit = CTX_data_edit_object(C); | |||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ToolSettings *ts = scene->toolsettings; | ToolSettings *ts = scene->toolsettings; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| const bool use_face_center = ( | const bool use_face_center = ( | ||||
| (ts->uv_flag & UV_SYNC_SELECTION) ? | (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 int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | |||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| int screen_uv[2]; | int screen_uv[2]; | ||||
| bool changed = false; | bool changed_multi = false; | ||||
| rcti rect; | rcti rect; | ||||
| BLI_lasso_boundbox(&rect, mcords, moves); | BLI_lasso_boundbox(&rect, mcords, moves); | ||||
| uint objects_len = 0; | |||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( | |||||
| view_layer, &objects_len, | |||||
| .filter_fn = BKE_view_layer_filter_edit_mesh_has_uvs, | |||||
| .no_dupe_data = true); | |||||
| /* don't indent to avoid diff noise! */ | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| bool changed = false; | |||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | |||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | |||||
| if (!extend && select) { | if (!extend && select) { | ||||
| uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT); | uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); | ||||
| } | } | ||||
| if (use_face_center) { /* Face Center Sel */ | if (use_face_center) { /* Face Center Sel */ | ||||
| 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); | BM_elem_flag_disable(efa, BM_ELEM_TAG); | ||||
| /* assume not touched */ | /* assume not touched */ | ||||
| if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { | if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { | ||||
| float cent[2]; | float cent[2]; | ||||
| ▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves, | ||||
| if (changed) { | if (changed) { | ||||
| uv_select_sync_flush(scene->toolsettings, em, select); | uv_select_sync_flush(scene->toolsettings, em, select); | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| } | } | ||||
| return changed; | changed_multi |= changed; | ||||
| } /* objects */ | |||||
| return changed_multi; | |||||
| } | } | ||||
| static int uv_lasso_select_exec(bContext *C, wmOperator *op) | static int uv_lasso_select_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| int mcords_tot; | int mcords_tot; | ||||
| const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); | const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); | ||||
| if (mcords) { | if (mcords) { | ||||
| ▲ Show 20 Lines • Show All 935 Lines • ▼ Show 20 Lines | BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set); | BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| me->drawflag |= ME_DRAWSEAMS; | me->drawflag |= ME_DRAWSEAMS; | ||||
| if (scene->toolsettings->edge_mode_live_unwrap) | if (scene->toolsettings->edge_mode_live_unwrap) | ||||
| ED_unwrap_lscm(scene, ob, false); | ED_unwrap_lscm(scene, ob, false, false); | ||||
| DEG_id_tag_update(&me->id, 0); | DEG_id_tag_update(&me->id, 0); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); | WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int uv_mark_seam_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | static int uv_mark_seam_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | ||||
| ▲ Show 20 Lines • Show All 177 Lines • Show Last 20 Lines | |||||