diff options
author | Campbell Barton <ideasman42@gmail.com> | 2018-04-16 17:27:55 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2018-04-16 18:56:50 +0300 |
commit | bfc9d426bb95e2bc0dd4541d6b4c5f802909149c (patch) | |
tree | 37702887bc3185309a13612613efd2752ebe0639 /source/blender/editors/uvedit | |
parent | 80bb4254c6fb638cee0d33868c81c76c104817bf (diff) |
Multi-Object Editing
This adds initial multi-object editing support.
- Selected objects are used when entering edit & pose modes.
- Selection & tools work on all objects however many tools need porting
See: T54641 for remaining tasks.
Indentation will be done separately.
See patch: D3101
Diffstat (limited to 'source/blender/editors/uvedit')
-rw-r--r-- | source/blender/editors/uvedit/uvedit_draw.c | 18 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_intern.h | 11 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_ops.c | 312 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_unwrap_ops.c | 251 |
4 files changed, 475 insertions, 117 deletions
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 3fcc89d0973..328ab3f1a8d 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -51,6 +51,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_editmesh.h" #include "BKE_material.h" +#include "BKE_layer.h" #include "BKE_scene.h" @@ -1100,12 +1101,21 @@ void ED_uvedit_draw_main( draw_uv_shadows_get(sima, obact, obedit, &show_uvshadow, &show_texpaint_uvshadow); if (show_uvedit || show_uvshadow || show_texpaint_uvshadow) { - if (show_uvshadow) + if (show_uvshadow) { draw_uvs_shadow(obedit); - else if (show_uvedit) - draw_uvs(sima, scene, view_layer, obedit, depsgraph); - else + } + else if (show_uvedit) { + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + draw_uvs(sima, scene, view_layer, ob_iter, depsgraph); + } + MEM_SAFE_FREE(objects); + } + else { draw_uvs_texpaint(sima, scene, view_layer, obact); + } if (show_uvedit && !(toolsettings->use_uv_sculpt)) ED_image_draw_cursor(ar, sima->cursor); diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index c5f16d6fb14..e3db0162f10 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -51,6 +51,8 @@ void uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_off /* find nearest */ typedef struct UvNearestHit { + /** Only for `*_multi(..)` versions of functions. */ + struct Object *ob; /** Always set if we have a hit. */ struct BMFace *efa; struct BMLoop *l; @@ -66,14 +68,23 @@ typedef struct UvNearestHit { bool uv_find_nearest_vert( struct Scene *scene, struct Image *ima, struct Object *obedit, const float co[2], const float penalty_dist, struct UvNearestHit *hit_final); +bool uv_find_nearest_vert_multi( + struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len, + const float co[2], const float penalty_dist, struct UvNearestHit *hit_final); bool uv_find_nearest_edge( struct Scene *scene, struct Image *ima, struct Object *obedit, const float co[2], struct UvNearestHit *hit_final); +bool uv_find_nearest_edge_multi( + struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len, + const float co[2], struct UvNearestHit *hit_final); bool uv_find_nearest_face( struct Scene *scene, struct Image *ima, struct Object *obedit, const float co[2], struct UvNearestHit *hit_final); +bool uv_find_nearest_face_multi( + struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len, + const float co[2], struct UvNearestHit *hit_final); /* utility tool functions */ diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 9df0c7c89ed..c2e8c2b5786 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -66,6 +66,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "DEG_depsgraph.h" @@ -89,7 +90,10 @@ #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_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select); @@ -794,6 +798,21 @@ bool uv_find_nearest_edge( 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( Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final) @@ -837,6 +856,21 @@ bool uv_find_nearest_face( 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( const BMLoop *l, const float co[2], const int cd_loop_uv_offset) @@ -918,6 +952,21 @@ bool uv_find_nearest_vert( 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]) { BMEditMesh *em = BKE_editmesh_from_object(obedit); @@ -1043,9 +1092,10 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, } 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) { + BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; BMIter iter, liter; BMLoop *l; @@ -1064,7 +1114,7 @@ static int uv_select_edgeloop( BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); 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); @@ -1147,10 +1197,17 @@ static int uv_select_edgeloop( /** \name Select Linked * \{ */ -static void uv_select_linked( - Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, const float limit[2], +static void uv_select_linked_multi( + Scene *scene, Image *ima, Object **objects, const uint objects_len, const float limit[2], 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; BMLoop *l; BMIter iter, liter; @@ -1161,6 +1218,7 @@ static void uv_select_linked( unsigned int a; char *flag; + BMEditMesh *em = BKE_editmesh_from_object(obedit); 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 */ @@ -1336,6 +1394,7 @@ static void uv_select_linked( MEM_freeN(stack); MEM_freeN(flag); BM_uv_vert_map_free(vmap); + } } /* WATCH IT: this returns first selected UV, @@ -1957,9 +2016,53 @@ static void UV_OT_weld(wmOperatorType *ot) /** \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; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + 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); + 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; +} + +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; @@ -1967,8 +2070,11 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEd const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - if (ts->uv_flag & UV_SYNC_SELECTION) { + 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) { case SEL_TOGGLE: EDBM_select_toggle_all(em); @@ -1986,24 +2092,6 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEd } } 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) { if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; @@ -2027,18 +2115,38 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEd } } +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) { Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(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"); - uv_select_all_perform(scene, ima, obedit, em, action); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + 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); + } + + MEM_SAFE_FREE(objects); return OPERATOR_FINISHED; } @@ -2087,14 +2195,14 @@ static bool uv_sticky_select(float *limit, int hitv[], int v, float *hituv[], fl return false; } -static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loop) +static int uv_mouse_select_multi( + bContext *C, Object **objects, uint objects_len, + const float co[2], bool extend, bool loop) { SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); ToolSettings *ts = scene->toolsettings; - Object *obedit = CTX_data_edit_object(C); Image *ima = CTX_data_edit_image(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; BMLoop *l; BMIter iter, liter; @@ -2105,8 +2213,6 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo 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; - 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 * 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 @@ -2143,7 +2249,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo /* find nearest element */ if (loop) { /* 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; } @@ -2151,7 +2257,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo } else if (selectmode == UV_SELECT_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; } @@ -2167,7 +2273,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo } else if (selectmode == UV_SELECT_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; } @@ -2185,10 +2291,13 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo } else if (selectmode == UV_SELECT_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; } + BMEditMesh *em = BKE_editmesh_from_object(hit.ob); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + /* make active */ BM_mesh_active_face_set(em->bm, hit.efa); @@ -2205,7 +2314,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo hitlen = hit.efa->len; } 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; } @@ -2216,12 +2325,24 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo 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 */ 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) { - 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) { if (selectmode == UV_SELECT_VERTEX) { @@ -2271,7 +2392,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo } else { /* 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) { /* select vertex */ @@ -2339,6 +2460,15 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; } +static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loop) +{ + ViewLayer *view_layer = CTX_data_view_layer(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 ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, loop); + MEM_freeN(objects); + return ret; +} static int uv_select_exec(bContext *C, wmOperator *op) { @@ -2443,9 +2573,8 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); 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); - BMEditMesh *em = BKE_editmesh_from_object(obedit); float limit[2]; int extend; bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); @@ -2460,6 +2589,9 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent extend = RNA_boolean_get(op->ptr, "extend"); uvedit_pixel_to_float(sima, limit, 0.05f); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len); + if (pick) { float co[2]; @@ -2475,15 +2607,32 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent 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; } } - 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); + } - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + 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); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_SAFE_FREE(objects_free); return OPERATOR_FINISHED; } @@ -2879,23 +3028,20 @@ static int uv_border_select_exec(bContext *C, wmOperator *op) SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); 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); ARegion *ar = CTX_wm_region(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; BMLoop *l; BMIter iter, liter; MLoopUV *luv; rctf rectf; - bool changed, pinned, select, extend; + bool pinned, select, extend; const bool use_face_center = ( (ts->uv_flag & UV_SYNC_SELECTION) ? (ts->selectmode == SCE_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 */ WM_operator_properties_border_to_rctf(op, &rectf); UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf); @@ -2905,8 +3051,22 @@ static int uv_border_select_exec(bContext *C, wmOperator *op) extend = RNA_boolean_get(op->ptr, "extend"); 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_unique_data_with_uvs(view_layer, &objects_len); + + /* 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) - 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 */ if (use_face_center && !pinned) { @@ -2972,12 +3132,17 @@ static int uv_border_select_exec(bContext *C, wmOperator *op) if (ts->uv_flag & UV_SYNC_SELECTION) { WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } - - return OPERATOR_FINISHED; + } + changed_multi |= changed; } + MEM_SAFE_FREE(objects); + + if (changed_multi) { + return OPERATOR_FINISHED; + } return OPERATOR_CANCELLED; -} +} static void UV_OT_select_border(wmOperatorType *ot) { @@ -3131,36 +3296,46 @@ static void UV_OT_circle_select(wmOperatorType *ot) /** \name Lasso Select Operator * \{ */ -static bool do_lasso_select_mesh_uv( - bContext *C, const int mcords[][2], short moves, - const bool select, const bool extend) +static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves, + const bool select, const bool extend) { SpaceImage *sima = CTX_wm_space_image(C); Image *ima = CTX_data_edit_image(C); ARegion *ar = CTX_wm_region(C); - Object *obedit = CTX_data_edit_object(C); Scene *scene = CTX_data_scene(C); ToolSettings *ts = scene->toolsettings; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); const bool use_face_center = ( (ts->uv_flag & UV_SYNC_SELECTION) ? (ts->selectmode == SCE_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; BMFace *efa; BMLoop *l; int screen_uv[2]; - bool changed = false; + bool changed_multi = false; rcti rect; BLI_lasso_boundbox(&rect, mcords, moves); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len); + + /* 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) { - 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 */ @@ -3223,7 +3398,10 @@ static bool do_lasso_select_mesh_uv( } } - return changed; + changed_multi |= changed; + } + + return changed_multi; } static int uv_lasso_select_exec(bContext *C, wmOperator *op) @@ -4175,7 +4353,7 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *op) me->drawflag |= ME_DRAWSEAMS; 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); WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 4f28d1f9eea..0e5f4886f3e 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -61,6 +61,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "DEG_depsgraph.h" @@ -202,6 +203,21 @@ static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, bool implicit) return false; } +static bool uvedit_have_selection_multi( + Scene *scene, Object **objects, const uint objects_len, bool implicit) +{ + bool have_select = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (uvedit_have_selection(scene, em, implicit)) { + have_select = true; + break; + } + } + return have_select; +} + void ED_uvedit_get_aspect(Scene *scene, Object *ob, BMesh *bm, float *aspx, float *aspy) { bool sloppy = true; @@ -258,9 +274,11 @@ static void construct_param_handle_face_add(ParamHandle *handle, Scene *scene, param_face_add(handle, key, i, vkeys, co, uv, pin, select, efa->no); } -static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm, - const bool implicit, const bool fill, const bool sel, - const bool correct_aspect) +/* See: construct_param_handle_multi to handle multiple objects at once. */ +static ParamHandle *construct_param_handle( + Scene *scene, Object *ob, BMesh *bm, + const bool implicit, const bool fill, const bool sel, + const bool correct_aspect) { ParamHandle *handle; BMFace *efa; @@ -324,6 +342,89 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm, return handle; } +/** + * Version of #construct_param_handle_single that handles multiple objects. + */ +static ParamHandle *construct_param_handle_multi( + Scene *scene, Object **objects, const uint objects_len, + const bool implicit, const bool fill, const bool sel, + const bool correct_aspect) +{ + ParamHandle *handle; + BMFace *efa; + BMLoop *l; + BMEdge *eed; + BMIter iter, liter; + int i; + + + handle = param_construct_begin(); + + if (correct_aspect) { + Object *ob = objects[0]; + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; + float aspx, aspy; + + ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy); + if (aspx != aspy) { + param_aspect_ratio(handle, aspx, aspy); + } + } + + /* we need the vert indices */ + EDBM_mesh_elem_index_ensure_multi(objects, objects_len, BM_VERT); + + int offset = 0; + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { + + if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || (sel && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) { + continue; + } + + if (implicit) { + bool is_loopsel = false; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + is_loopsel = true; + break; + } + } + if (is_loopsel == false) { + continue; + } + } + + construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset); + } + + if (!implicit) { + BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) { + ParamKey vkeys[2]; + vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1); + vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2); + param_edge_set_seam(handle, vkeys); + } + } + } + offset += bm->totface; + } + + param_construct_end(handle, fill, implicit); + + return handle; +} + static void texface_from_original_index(BMFace *efa, int index, float **uv, ParamBool *pin, ParamBool *select, Scene *scene, const int cd_loop_uv_offset) @@ -715,6 +816,7 @@ void UV_OT_minimize_stretch(wmOperatorType *ot) /* ******************** Pack Islands operator **************** */ + void ED_uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm, bool selected, bool correct_aspect, bool do_rotate) { ParamHandle *handle; @@ -724,14 +826,29 @@ void ED_uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm, bool selected, param_delete(handle); } +void ED_uvedit_pack_islands_multi( + Scene *scene, Object **objects, const uint objects_len, + bool selected, bool correct_aspect, bool do_rotate) +{ + ParamHandle *handle; + handle = construct_param_handle_multi( + scene, objects, objects_len, true, false, selected, correct_aspect); + param_pack(handle, scene->toolsettings->uvcalc_margin, do_rotate); + param_flush(handle); + param_delete(handle); +} + static int pack_islands_exec(bContext *C, wmOperator *op) { + ViewLayer *view_layer = CTX_data_view_layer(C); Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); bool do_rotate = RNA_boolean_get(op->ptr, "rotate"); - if (!uvedit_have_selection(scene, em, true)) { + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len); + + if (!uvedit_have_selection_multi(scene, objects, objects_len, true)) { + MEM_SAFE_FREE(objects); return OPERATOR_CANCELLED; } @@ -740,10 +857,15 @@ static int pack_islands_exec(bContext *C, wmOperator *op) else RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin); - ED_uvedit_pack_islands(scene, obedit, em->bm, true, true, do_rotate); - - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + ED_uvedit_pack_islands_multi(scene, objects, objects_len, true, true, do_rotate); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + + MEM_SAFE_FREE(objects); return OPERATOR_FINISHED; } @@ -856,7 +978,7 @@ void ED_uvedit_live_unwrap(Scene *scene, Object *obedit) if (scene->toolsettings->edge_mode_live_unwrap && CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) { - ED_unwrap_lscm(scene, obedit, false); /* unwrap all not just sel */ + ED_unwrap_lscm(scene, obedit, false, false); /* unwrap all not just sel */ } } @@ -1178,7 +1300,7 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOper /* ******************** Unwrap operator **************** */ /* assumes UV Map is checked, doesn't run update funcs */ -void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel) +void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel, const bool pack) { BMEditMesh *em = BKE_editmesh_from_object(obedit); ParamHandle *handle; @@ -1199,7 +1321,10 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel) param_lscm_end(handle); param_average(handle); - param_pack(handle, scene->toolsettings->uvcalc_margin, false); + + if (pack) { + param_pack(handle, scene->toolsettings->uvcalc_margin, false); + } param_flush(handle); @@ -1208,33 +1333,48 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel) static int unwrap_exec(bContext *C, wmOperator *op) { + ViewLayer *view_layer = CTX_data_view_layer(C); Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); int method = RNA_enum_get(op->ptr, "method"); const bool fill_holes = RNA_boolean_get(op->ptr, "fill_holes"); const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"); const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data"); - bool use_subsurf_final; float obsize[3]; bool implicit = false; - if (!uvedit_have_selection(scene, em, implicit)) { + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + + if (!uvedit_have_selection_multi(scene, objects, objects_len, implicit)) { + MEM_SAFE_FREE(objects); return OPERATOR_CANCELLED; } - + /* add uvs if they don't exist yet */ - if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { - return OPERATOR_CANCELLED; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + bool use_subsurf_final; + + if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { + continue; + } - mat4_to_size(obsize, obedit->obmat); - if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f)) - BKE_report(op->reports, RPT_INFO, - "Object has non-uniform scale, unwrap will operate on a non-scaled version of the mesh"); - else if (is_negative_m4(obedit->obmat)) - BKE_report(op->reports, RPT_INFO, - "Object has negative scale, unwrap will operate on a non-flipped version of the mesh"); + mat4_to_size(obsize, obedit->obmat); + if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f)) + BKE_report(op->reports, RPT_INFO, + "Object has non-uniform scale, unwrap will operate on a non-scaled version of the mesh"); + else if (is_negative_m4(obedit->obmat)) + BKE_report(op->reports, RPT_INFO, + "Object has negative scale, unwrap will operate on a non-flipped version of the mesh"); + + + /* double up the check here but better keep ED_unwrap_lscm interface simple and not + * pass operator for warning append */ + modifier_unwrap_state(obedit, scene, &use_subsurf_final); + if (use_subsurf != use_subsurf_final) { + BKE_report(op->reports, RPT_INFO, "Subdivision Surface modifier needs to be first to work with unwrap"); + } + } /* remember last method for live unwrap */ if (RNA_struct_property_is_set(op->ptr, "method")) @@ -1257,17 +1397,17 @@ static int unwrap_exec(bContext *C, wmOperator *op) if (use_subsurf) scene->toolsettings->uvcalc_flag |= UVCALC_USESUBSURF; else scene->toolsettings->uvcalc_flag &= ~UVCALC_USESUBSURF; - /* double up the check here but better keep ED_unwrap_lscm interface simple and not - * pass operator for warning append */ - modifier_unwrap_state(obedit, scene, &use_subsurf_final); - if (use_subsurf != use_subsurf_final) - BKE_report(op->reports, RPT_INFO, "Subdivision Surface modifier needs to be first to work with unwrap"); - /* execute unwrap */ - ED_unwrap_lscm(scene, obedit, true); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ED_unwrap_lscm(scene, obedit, true, false); + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + ED_uvedit_pack_islands_multi(scene, objects, objects_len, true, true, true); + + MEM_SAFE_FREE(objects); return OPERATOR_FINISHED; } @@ -1322,9 +1462,8 @@ static int uv_from_view_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE static int uv_from_view_exec(bContext *C, wmOperator *op) { + ViewLayer *view_layer = CTX_data_view_layer(C); Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -1334,15 +1473,22 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) BMIter iter, liter; MLoopUV *luv; float rotmat[4][4]; + bool changed_multi = false; - int cd_loop_uv_offset; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + + 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; /* add uvs if they don't exist yet */ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { - return OPERATOR_CANCELLED; + continue; } - 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); if (RNA_boolean_get(op->ptr, "orthographic")) { uv_map_rotation_matrix(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f); @@ -1355,6 +1501,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); BLI_uvproject_from_view_ortho(luv->uv, l->v->co, rotmat); } + changed = true; } } else if (camera) { @@ -1372,6 +1519,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); BLI_uvproject_from_camera(luv->uv, l->v->co, uci); } + changed = true; } MEM_freeN(uci); @@ -1388,15 +1536,26 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); BLI_uvproject_from_view(luv->uv, l->v->co, rv3d->persmat, rotmat, ar->winx, ar->winy); } + changed = true; } } - uv_map_clip_correct(scene, obedit, em, op); + if (changed) { + uv_map_clip_correct(scene, obedit, em, op); - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + changed_multi = true; + } + } + MEM_SAFE_FREE(objects); - return OPERATOR_FINISHED; + if (changed_multi) { + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } static int uv_from_view_poll(bContext *C) |