diff options
Diffstat (limited to 'source/blender/editors/uvedit/uvedit_unwrap_ops.c')
-rw-r--r-- | source/blender/editors/uvedit/uvedit_unwrap_ops.c | 839 |
1 files changed, 576 insertions, 263 deletions
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 582ba989997..2e3ff5a5065 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -55,12 +55,15 @@ #include "BKE_subsurf.h" #include "BKE_context.h" #include "BKE_customdata.h" -#include "BKE_depsgraph.h" #include "BKE_image.h" #include "BKE_main.h" +#include "BKE_material.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" + +#include "DEG_depsgraph.h" #include "PIL_time.h" @@ -100,9 +103,8 @@ static void modifier_unwrap_state(Object *obedit, Scene *scene, bool *r_use_subs *r_use_subsurf = subsurf; } -static bool ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit) +static bool ED_uvedit_ensure_uvs(bContext *C, Scene *UNUSED(scene), Object *obedit) { - Main *bmain = CTX_data_main(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; BMIter iter; @@ -116,7 +118,7 @@ static bool ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit) if (ED_uvedit_test(obedit)) return 1; - if (em && em->bm->totface && !CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY)) + if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) ED_mesh_uv_texture_add(obedit->data, NULL, true); if (!ED_uvedit_test(obedit)) @@ -146,9 +148,6 @@ static bool ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit) } } - if (ima) - ED_uvedit_assign_image(bmain, scene, obedit, ima, NULL); - /* select new UV's (ignore UV_SYNC_SELECTION in this case) */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BMIter liter; @@ -200,7 +199,22 @@ static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, bool implicit) return false; } -void ED_uvedit_get_aspect(Scene *scene, Object *ob, BMesh *bm, float *aspx, float *aspy) +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 *UNUSED(scene), Object *ob, BMesh *bm, float *aspx, float *aspy) { bool sloppy = true; bool selected = false; @@ -210,13 +224,7 @@ void ED_uvedit_get_aspect(Scene *scene, Object *ob, BMesh *bm, float *aspx, floa efa = BM_mesh_active_face_get(bm, sloppy, selected); if (efa) { - if (BKE_scene_use_new_shading_nodes(scene)) { - ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL); - } - else { - MTexPoly *tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); - ima = tf->tpage; - } + ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL); ED_image_get_uv_aspect(ima, NULL, aspx, aspy); } @@ -257,9 +265,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; @@ -323,6 +333,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) @@ -403,7 +496,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B smd.subdivType = smd_real->subdivType; initialDerived = CDDM_from_editbmesh(em, false, false); - derivedMesh = subsurf_make_derived_from_derived(initialDerived, &smd, + derivedMesh = subsurf_make_derived_from_derived(initialDerived, &smd, scene, NULL, SUBSURF_IN_EDIT_MODE); initialDerived->release(initialDerived); @@ -505,8 +598,8 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B typedef struct MinStretch { Scene *scene; - Object *obedit; - BMEditMesh *em; + Object **objects_edit; + uint objects_len; ParamHandle *handle; float blend; double lasttime; @@ -517,24 +610,28 @@ typedef struct MinStretch { static bool minimize_stretch_init(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + MinStretch *ms; const bool fill_holes = RNA_boolean_get(op->ptr, "fill_holes"); bool implicit = true; - if (!uvedit_have_selection(scene, em, implicit)) { + 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, implicit)) { + MEM_freeN(objects); return false; } ms = MEM_callocN(sizeof(MinStretch), "MinStretch"); ms->scene = scene; - ms->obedit = obedit; - ms->em = em; + ms->objects_edit = objects; + ms->objects_len = objects_len; ms->blend = RNA_float_get(op->ptr, "blend"); ms->iterations = RNA_int_get(op->ptr, "iterations"); ms->i = 0; - ms->handle = construct_param_handle(scene, obedit, em->bm, implicit, fill_holes, 1, 1); + ms->handle = construct_param_handle_multi(scene, objects, objects_len, implicit, fill_holes, true, true); ms->lasttime = PIL_check_seconds_timer(); param_stretch_begin(ms->handle); @@ -550,6 +647,9 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac { MinStretch *ms = op->customdata; ScrArea *sa = CTX_wm_area(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; param_stretch_blend(ms->handle, ms->blend); param_stretch_iter(ms->handle); @@ -563,15 +663,24 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac param_flush(ms->handle); if (sa) { - BLI_snprintf(str, sizeof(str), - IFACE_("Minimize Stretch. Blend %.2f (Press + and -, or scroll wheel to set)"), ms->blend); - ED_area_headerprint(sa, str); + BLI_snprintf(str, sizeof(str), IFACE_("Minimize Stretch. Blend %.2f"), ms->blend); + ED_area_status_text(sa, str); + ED_workspace_status_text(C, IFACE_("Press + and -, or scroll wheel to set blending")); } ms->lasttime = PIL_check_seconds_timer(); - DAG_id_tag_update(ms->obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ms->obedit->data); + for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) { + Object *obedit = ms->objects_edit[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (synced_selection && (em->bm->totfacesel == 0)) { + continue; + } + + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } } } @@ -579,9 +688,13 @@ static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel) { MinStretch *ms = op->customdata; ScrArea *sa = CTX_wm_area(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + + ED_area_status_text(sa, NULL); + ED_workspace_status_text(C, NULL); - if (sa) - ED_area_headerprint(sa, NULL); if (ms->timer) WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ms->timer); @@ -593,9 +706,19 @@ static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel) param_stretch_end(ms->handle); param_delete(ms->handle); - DAG_id_tag_update(ms->obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ms->obedit->data); + for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) { + Object *obedit = ms->objects_edit[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (synced_selection && (em->bm->totfacesel == 0)) { + continue; + } + + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + MEM_freeN(ms->objects_edit); MEM_freeN(ms); op->customdata = NULL; } @@ -714,6 +837,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; @@ -723,14 +847,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_freeN(objects); return OPERATOR_CANCELLED; } @@ -739,10 +878,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); + 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); + } - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -770,23 +914,37 @@ void UV_OT_pack_islands(wmOperatorType *ot) static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + ToolSettings *ts = scene->toolsettings; + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + const bool implicit = true; ParamHandle *handle; - bool implicit = true; - if (!uvedit_have_selection(scene, em, implicit)) { + 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, implicit)) { + MEM_freeN(objects); return OPERATOR_CANCELLED; } - handle = construct_param_handle(scene, obedit, em->bm, implicit, 0, 1, 1); + handle = construct_param_handle_multi(scene, objects, objects_len, implicit, false, true, true); param_average(handle); param_flush(handle); param_delete(handle); - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -806,10 +964,14 @@ void UV_OT_average_islands_scale(wmOperatorType *ot) /**************** Live Unwrap *****************/ -static ParamHandle *liveHandle = NULL; +static struct { + ParamHandle **handles; + uint len, len_alloc; +} g_live_unwrap = {NULL}; void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit) { + ParamHandle *handle = NULL; BMEditMesh *em = BKE_editmesh_from_object(obedit); const bool abf = (scene->toolsettings->unwrapper == 0); const bool fillholes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0; @@ -822,29 +984,49 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit) } if (use_subsurf) - liveHandle = construct_param_handle_subsurfed(scene, obedit, em, fillholes, false, true); + handle = construct_param_handle_subsurfed(scene, obedit, em, fillholes, false, true); else - liveHandle = construct_param_handle(scene, obedit, em->bm, false, fillholes, false, true); + handle = construct_param_handle(scene, obedit, em->bm, false, fillholes, false, true); + + param_lscm_begin(handle, PARAM_TRUE, abf); - param_lscm_begin(liveHandle, PARAM_TRUE, abf); + /* Create or increase size of g_live_unwrap.handles array */ + if (g_live_unwrap.handles == NULL) { + g_live_unwrap.len_alloc = 32; + g_live_unwrap.handles = MEM_mallocN(sizeof(ParamHandle *) * g_live_unwrap.len_alloc, "uvedit_live_unwrap_liveHandles"); + g_live_unwrap.len = 0; + } + if (g_live_unwrap.len >= g_live_unwrap.len_alloc) { + g_live_unwrap.len_alloc *= 2; + g_live_unwrap.handles = MEM_reallocN(g_live_unwrap.handles, sizeof(ParamHandle *) * g_live_unwrap.len_alloc); + } + g_live_unwrap.handles[g_live_unwrap.len] = handle; + g_live_unwrap.len++; } void ED_uvedit_live_unwrap_re_solve(void) { - if (liveHandle) { - param_lscm_solve(liveHandle); - param_flush(liveHandle); + if (g_live_unwrap.handles) { + for (int i = 0; i < g_live_unwrap.len; i++) { + param_lscm_solve(g_live_unwrap.handles[i]); + param_flush(g_live_unwrap.handles[i]); + } } } void ED_uvedit_live_unwrap_end(short cancel) { - if (liveHandle) { - param_lscm_end(liveHandle); - if (cancel) - param_flush_restore(liveHandle); - param_delete(liveHandle); - liveHandle = NULL; + if (g_live_unwrap.handles) { + for (int i = 0; i < g_live_unwrap.len; i++) { + param_lscm_end(g_live_unwrap.handles[i]); + if (cancel) + param_flush_restore(g_live_unwrap.handles[i]); + param_delete(g_live_unwrap.handles[i]); + } + MEM_freeN(g_live_unwrap.handles); + g_live_unwrap.handles = NULL; + g_live_unwrap.len = 0; + g_live_unwrap.len_alloc = 0; } } @@ -855,7 +1037,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 */ } } @@ -903,7 +1085,7 @@ static void uv_map_transform_center( float r_bounds[2][3]) { /* only operates on the edit object - this is all that's needed now */ - const int around = (v3d) ? v3d->around : V3D_AROUND_CENTER_BOUNDS; + const int around = (v3d) ? scene->toolsettings->transform_pivot_point : V3D_AROUND_CENTER_BOUNDS; float bounds[2][3]; INIT_MINMAX(bounds[0], bounds[1]); @@ -925,7 +1107,7 @@ static void uv_map_transform_center( case V3D_AROUND_CURSOR: /* cursor center */ { invert_m4_m4(ob->imat, ob->obmat); - mul_v3_m4v3(r_center, ob->imat, ED_view3d_cursor3d_get(scene, v3d)); + mul_v3_m4v3(r_center, ob->imat, ED_view3d_cursor3d_get(scene, v3d)->location); break; } case V3D_AROUND_ACTIVE: @@ -953,12 +1135,12 @@ static void uv_map_transform_center( } } -static void uv_map_rotation_matrix(float result[4][4], RegionView3D *rv3d, Object *ob, - float upangledeg, float sideangledeg, float radius) +static void uv_map_rotation_matrix_ex( + float result[4][4], RegionView3D *rv3d, Object *ob, + float upangledeg, float sideangledeg, float radius, float offset[4]) { float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4]; float sideangle = 0.0f, upangle = 0.0f; - int k; /* get rotation of the current view matrix */ if (rv3d) @@ -967,15 +1149,14 @@ static void uv_map_rotation_matrix(float result[4][4], RegionView3D *rv3d, Objec unit_m4(viewmatrix); /* but shifting */ - for (k = 0; k < 4; k++) - viewmatrix[3][k] = 0.0f; + copy_v4_fl(viewmatrix[3], 0.0f); /* get rotation of the current object matrix */ copy_m4_m4(rotobj, ob->obmat); /* but shifting */ - for (k = 0; k < 4; k++) - rotobj[3][k] = 0.0f; + add_v4_v4(rotobj[3], offset); + rotobj[3][3] = 0.0f; zero_m4(rotup); zero_m4(rotside); @@ -1001,6 +1182,14 @@ static void uv_map_rotation_matrix(float result[4][4], RegionView3D *rv3d, Objec mul_m4_series(result, rotup, rotside, viewmatrix, rotobj); } +static void uv_map_rotation_matrix( + float result[4][4], RegionView3D *rv3d, Object *ob, + float upangledeg, float sideangledeg, float radius) +{ + float offset[4] = {0}; + uv_map_rotation_matrix_ex(result, rv3d, ob, upangledeg, sideangledeg, radius, offset); +} + static void uv_map_transform(bContext *C, wmOperator *op, float rotmat[4][4]) { /* context checks are messy here, making it work in both 3d view and uv editor */ @@ -1108,7 +1297,7 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot) "Scale UV coordinates to bounds after unwrapping"); } -static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOperator *op) +static void uv_map_clip_correct_multi(Scene *scene, Object **objects, uint objects_len, wmOperator *op) { BMFace *efa; BMLoop *l; @@ -1119,25 +1308,46 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOper const bool clip_to_bounds = RNA_boolean_get(op->ptr, "clip_to_bounds"); const bool scale_to_bounds = RNA_boolean_get(op->ptr, "scale_to_bounds"); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + INIT_MINMAX2(min, max); - /* correct for image aspect ratio */ - if (correct_aspect) - correct_uv_aspect(scene, ob, em); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; - if (scale_to_bounds) { - INIT_MINMAX2(min, max); + BMEditMesh *em = BKE_editmesh_from_object(ob); + 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 (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) - continue; + /* correct for image aspect ratio */ + if (correct_aspect) + correct_uv_aspect(scene, ob, em); - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - minmax_v2v2_v2(min, max, luv->uv); + if (scale_to_bounds) { + /* find uv limits */ + BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) + continue; + + BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + minmax_v2v2_v2(min, max, luv->uv); + } } } + else if (clip_to_bounds) { + /* clipping and wrapping */ + BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) + continue; + BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + CLAMP(luv->uv[0], 0.0f, 1.0f); + CLAMP(luv->uv[1], 0.0f, 1.0f); + } + } + } + } + + if (scale_to_bounds) { /* rescale UV to be in 1/1 */ dx = (max[0] - min[0]); dy = (max[1] - min[1]); @@ -1147,37 +1357,36 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOper if (dy > 0.0f) dy = 1.0f / dy; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) - continue; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + BMEditMesh *em = BKE_editmesh_from_object(ob); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - luv->uv[0] = (luv->uv[0] - min[0]) * dx; - luv->uv[1] = (luv->uv[1] - min[1]) * dy; - } - } - } - else if (clip_to_bounds) { - /* clipping and wrapping */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) - continue; + BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) + continue; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - CLAMP(luv->uv[0], 0.0f, 1.0f); - CLAMP(luv->uv[1], 0.0f, 1.0f); + BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + luv->uv[0] = (luv->uv[0] - min[0]) * dx; + luv->uv[1] = (luv->uv[1] - min[1]) * dy; + } } } } } +static void uv_map_clip_correct(Scene *scene, Object *ob, wmOperator *op) +{ + uv_map_clip_correct_multi(scene, &ob, 1, op); +} + /* ******************** 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; @@ -1198,7 +1407,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); @@ -1207,33 +1419,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_freeN(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")) @@ -1256,17 +1483,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); + } + + ED_uvedit_pack_islands_multi(scene, objects, objects_len, true, true, true); - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -1321,9 +1548,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); @@ -1333,69 +1559,114 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) BMIter iter, liter; MLoopUV *luv; float rotmat[4][4]; + float objects_pos_offset[4]; + bool changed_multi = false; - int cd_loop_uv_offset; + const bool use_orthographic = RNA_boolean_get(op->ptr, "orthographic"); - /* add uvs if they don't exist yet */ - if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { - return OPERATOR_CANCELLED; - } + /* Note: objects that aren't touched are set to NULL (to skip clipping). */ + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + if (use_orthographic) { + /* Calculate average object position. */ + float objects_pos_avg[4] = {0}; - if (RNA_boolean_get(op->ptr, "orthographic")) { - uv_map_rotation_matrix(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + add_v4_v4(objects_pos_avg, objects[ob_index]->obmat[3]); + } - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) - continue; + mul_v4_fl(objects_pos_avg, 1.0f / objects_len); + negate_v4_v4(objects_pos_offset, objects_pos_avg); + } - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - BLI_uvproject_from_view_ortho(luv->uv, l->v->co, rotmat); - } + 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)) { + continue; } - } - else if (camera) { - const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds"); - struct ProjCameraInfo *uci = BLI_uvproject_camera_info(v3d->camera, obedit->obmat, - camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f, - camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f); - if (uci) { + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (use_orthographic) { + uv_map_rotation_matrix_ex(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f, objects_pos_offset); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - BLI_uvproject_from_camera(luv->uv, l->v->co, uci); + BLI_uvproject_from_view_ortho(luv->uv, l->v->co, rotmat); } + changed = true; } + } + else if (camera) { + const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds"); + struct ProjCameraInfo *uci = BLI_uvproject_camera_info( + v3d->camera, obedit->obmat, + camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f, + camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f); + + if (uci) { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) + continue; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + 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); + MEM_freeN(uci); + } } - } - else { - copy_m4_m4(rotmat, obedit->obmat); + else { + copy_m4_m4(rotmat, obedit->obmat); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) - continue; + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) + continue; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - 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); + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + 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; } } + + if (changed) { + changed_multi = true; + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + else { + ARRAY_DELETE_REORDER_LAST(objects, ob_index, 1, objects_len); + objects_len -= 1; + ob_index -= 1; + } } - uv_map_clip_correct(scene, obedit, em, op); + if (changed_multi) { + uv_map_clip_correct_multi(scene, objects, objects_len, op); + } - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + MEM_freeN(objects); - return OPERATOR_FINISHED; + if (changed_multi) { + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } static bool uv_from_view_poll(bContext *C) @@ -1435,18 +1706,30 @@ void UV_OT_project_from_view(wmOperatorType *ot) static int reset_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - Mesh *me = (Mesh *)obedit->data; - /* add uvs if they don't exist yet */ - if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { - return OPERATOR_CANCELLED; - } + 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(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + Mesh *me = (Mesh *)obedit->data; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - ED_mesh_uv_loop_reset(C, me); + if (em->bm->totfacesel == 0) { + continue; + } - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + /* add uvs if they don't exist yet */ + if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { + continue; + } + + ED_mesh_uv_loop_reset(C, me); + + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -1481,7 +1764,7 @@ static void uv_sphere_project(float target[2], float source[3], float center[3], target[0] -= 1.0f; } -static void uv_map_mirror(BMEditMesh *em, BMFace *efa, MTexPoly *UNUSED(tf)) +static void uv_map_mirror(BMEditMesh *em, BMFace *efa) { BMLoop *l; BMIter liter; @@ -1513,46 +1796,53 @@ static void uv_map_mirror(BMEditMesh *em, BMFace *efa, MTexPoly *UNUSED(tf)) static int sphere_project_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); View3D *v3d = CTX_wm_view3d(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MTexPoly *tf; - MLoopUV *luv; - float center[3], rotmat[4][4]; - int cd_loop_uv_offset; + 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(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); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; - /* add uvs if they don't exist yet */ - if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { - return OPERATOR_CANCELLED; - } + if (em->bm->totfacesel == 0) { + continue; + } - cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + /* add uvs if they don't exist yet */ + if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { + continue; + } - uv_map_transform(C, op, rotmat); - uv_map_transform_center(scene, v3d, obedit, em, center, NULL); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + float center[3], rotmat[4][4]; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) - continue; + uv_map_transform(C, op, rotmat); + uv_map_transform_center(scene, v3d, obedit, em, center, NULL); - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) + continue; - uv_sphere_project(luv->uv, l->v->co, center, rotmat); - } + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); - uv_map_mirror(em, efa, tf); - } + uv_sphere_project(luv->uv, l->v->co, center, rotmat); + } + + uv_map_mirror(em, efa); + } - uv_map_clip_correct(scene, obedit, em, op); + uv_map_clip_correct(scene, obedit, op); - DAG_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); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -1594,46 +1884,53 @@ static void uv_cylinder_project(float target[2], float source[3], float center[3 static int cylinder_project_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); View3D *v3d = CTX_wm_view3d(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MTexPoly *tf; - MLoopUV *luv; - float center[3], rotmat[4][4]; - int cd_loop_uv_offset; + 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(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); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; - /* add uvs if they don't exist yet */ - if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { - return OPERATOR_CANCELLED; - } + if (em->bm->totfacesel == 0) { + continue; + } - cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + /* add uvs if they don't exist yet */ + if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { + continue; + } - uv_map_transform(C, op, rotmat); - uv_map_transform_center(scene, v3d, obedit, em, center, NULL); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + float center[3], rotmat[4][4]; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) - continue; + uv_map_transform(C, op, rotmat); + uv_map_transform_center(scene, v3d, obedit, em, center, NULL); - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) + continue; - uv_cylinder_project(luv->uv, l->v->co, center, rotmat); - } + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); - uv_map_mirror(em, efa, tf); - } + uv_cylinder_project(luv->uv, l->v->co, center, rotmat); + } + + uv_map_mirror(em, efa); + } - uv_map_clip_correct(scene, obedit, em, op); + uv_map_clip_correct(scene, obedit, op); - DAG_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); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -1663,7 +1960,6 @@ void ED_uvedit_unwrap_cube_project(BMesh *bm, float cube_size, bool use_select, BMFace *efa; BMLoop *l; BMIter iter, liter; - /* MTexPoly *tf; */ /* UNUSED */ MLoopUV *luv; float loc[3]; int cox, coy; @@ -1701,40 +1997,57 @@ static int cube_project_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + PropertyRNA *prop_cube_size = RNA_struct_find_property(op->ptr, "cube_size"); - float cube_size = RNA_property_float_get(op->ptr, prop_cube_size); - float center[3]; - float bounds[2][3]; - float (*bounds_buf)[3] = NULL; + const float cube_size_init = RNA_property_float_get(op->ptr, prop_cube_size); - /* add uvs if they don't exist yet */ - if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { - return OPERATOR_CANCELLED; - } + 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(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); - if (!RNA_property_is_set(op->ptr, prop_cube_size)) { - bounds_buf = bounds; - } + if (em->bm->totfacesel == 0) { + continue; + } - uv_map_transform_center(scene, v3d, obedit, em, center, bounds_buf); + /* add uvs if they don't exist yet */ + if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { + continue; + } - /* calculate based on bounds */ - if (bounds_buf) { - float dims[3]; - sub_v3_v3v3(dims, bounds[1], bounds[0]); - cube_size = max_fff(UNPACK3(dims)); - cube_size = cube_size ? 2.0f / cube_size : 1.0f; - RNA_property_float_set(op->ptr, prop_cube_size, cube_size); - } + float bounds[2][3]; + float (*bounds_buf)[3] = NULL; - ED_uvedit_unwrap_cube_project(em->bm, cube_size, true, center); + if (!RNA_property_is_set(op->ptr, prop_cube_size)) { + bounds_buf = bounds; + } - uv_map_clip_correct(scene, obedit, em, op); + float center[3]; + uv_map_transform_center(scene, v3d, obedit, em, center, bounds_buf); + + /* calculate based on bounds */ + float cube_size = cube_size_init; + if (bounds_buf) { + float dims[3]; + sub_v3_v3v3(dims, bounds[1], bounds[0]); + cube_size = max_fff(UNPACK3(dims)); + cube_size = cube_size ? 2.0f / cube_size : 1.0f; + if (ob_index == 0) { + /* This doesn't fit well with, multiple objects. */ + RNA_property_float_set(op->ptr, prop_cube_size, cube_size); + } + } + + ED_uvedit_unwrap_cube_project(em->bm, cube_size, true, center); - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + uv_map_clip_correct(scene, obedit, op); + + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } |