diff options
Diffstat (limited to 'source/blender/editors/uvedit')
-rw-r--r-- | source/blender/editors/uvedit/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_buttons.c | 20 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_draw.c | 831 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_intern.h | 19 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_ops.c | 1259 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_smart_stitch.c | 160 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_unwrap_ops.c | 683 |
7 files changed, 1643 insertions, 1330 deletions
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt index 543ef0e0663..a933717fe98 100644 --- a/source/blender/editors/uvedit/CMakeLists.txt +++ b/source/blender/editors/uvedit/CMakeLists.txt @@ -24,6 +24,7 @@ set(INC ../../blenlib ../../blentranslation ../../bmesh + ../../depsgraph ../../gpu ../../makesdna ../../makesrna diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c index 2eb2d8bc80d..b37703d03dd 100644 --- a/source/blender/editors/uvedit/uvedit_buttons.c +++ b/source/blender/editors/uvedit/uvedit_buttons.c @@ -61,22 +61,19 @@ /* UV Utilities */ -static int uvedit_center(Scene *scene, BMEditMesh *em, Image *ima, float center[2]) +static int uvedit_center(Scene *scene, Object *obedit, BMEditMesh *em, Image *ima, float center[2]) { BMFace *f; BMLoop *l; BMIter iter, liter; - MTexPoly *tf; MLoopUV *luv; int tot = 0; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); zero_v2(center); BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(f, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, f, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, f)) continue; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { @@ -96,20 +93,17 @@ static int uvedit_center(Scene *scene, BMEditMesh *em, Image *ima, float center[ return tot; } -static void uvedit_translate(Scene *scene, BMEditMesh *em, Image *ima, float delta[2]) +static void uvedit_translate(Scene *scene, Object *obedit, BMEditMesh *em, Image *ima, float delta[2]) { BMFace *f; BMLoop *l; BMIter iter, liter; MLoopUV *luv; - MTexPoly *tf; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(f, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, f, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, f)) continue; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { @@ -140,7 +134,7 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block) em = BKE_editmesh_from_object(obedit); - if (uvedit_center(scene, em, ima, center)) { + if (uvedit_center(scene, obedit, em, ima, center)) { float range_xy[2][2] = { {-10.0f, 10.0f}, {-10.0f, 10.0f}, @@ -196,7 +190,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) em = BKE_editmesh_from_object(obedit); ED_space_image_get_size(sima, &imx, &imy); - uvedit_center(scene, em, ima, center); + uvedit_center(scene, obedit, em, ima, center); if (sima->flag & SI_COORDFLOATS) { delta[0] = uvedit_old_center[0] - center[0]; @@ -207,7 +201,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) delta[1] = uvedit_old_center[1] / imy - center[1]; } - uvedit_translate(scene, em, ima, delta); + uvedit_translate(scene, obedit, em, ima, delta); WM_event_add_notifier(C, NC_IMAGE, sima->image); } diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index a9f650a6d7a..08df08dafb4 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -33,6 +33,8 @@ #include <stdlib.h> #include <string.h> +#include "MEM_guardedalloc.h" + #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -49,12 +51,21 @@ #include "BKE_DerivedMesh.h" #include "BKE_editmesh.h" #include "BKE_material.h" +#include "BKE_layer.h" #include "BKE_scene.h" -#include "BIF_gl.h" #include "BIF_glutil.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "GPU_batch.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_state.h" + #include "ED_image.h" #include "ED_mesh.h" #include "ED_uvedit.h" @@ -65,12 +76,7 @@ #include "uvedit_intern.h" -#include "GPU_basic_shader.h" - -/* use editmesh tessface */ -#define USE_EDBM_LOOPTRIS - -static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset); +static void draw_uvs_lineloop_bmfaces(BMesh *bm, const int cd_loop_uv_offset, const uint shdr_pos); void ED_image_draw_cursor(ARegion *ar, const float cursor[2]) { @@ -82,37 +88,60 @@ void ED_image_draw_cursor(ARegion *ar, const float cursor[2]) x_fac = zoom[0]; y_fac = zoom[1]; - cpack(0xFFFFFF); - glTranslate2fv(cursor); - fdrawline(-0.05f * x_fac, 0, 0, 0.05f * y_fac); - fdrawline(0, 0.05f * y_fac, 0.05f * x_fac, 0.0f); - fdrawline(0.05f * x_fac, 0.0f, 0.0f, -0.05f * y_fac); - fdrawline(0.0f, -0.05f * y_fac, -0.05f * x_fac, 0.0f); - - setlinestyle(4); - cpack(0xFF); - fdrawline(-0.05f * x_fac, 0.0f, 0.0f, 0.05f * y_fac); - fdrawline(0.0f, 0.05f * y_fac, 0.05f * x_fac, 0.0f); - fdrawline(0.05f * x_fac, 0.0f, 0.0f, -0.05f * y_fac); - fdrawline(0.0f, -0.05f * y_fac, -0.05f * x_fac, 0.0f); - - - setlinestyle(0.0f); - cpack(0x0); - fdrawline(-0.020f * x_fac, 0.0f, -0.1f * x_fac, 0.0f); - fdrawline(0.1f * x_fac, 0.0f, 0.020f * x_fac, 0.0f); - fdrawline(0.0f, -0.020f * y_fac, 0.0f, -0.1f * y_fac); - fdrawline(0.0f, 0.1f * y_fac, 0.0f, 0.020f * y_fac); - - setlinestyle(1); - cpack(0xFFFFFF); - fdrawline(-0.020f * x_fac, 0.0f, -0.1f * x_fac, 0.0f); - fdrawline(0.1f * x_fac, 0.0f, 0.020f * x_fac, 0.0f); - fdrawline(0.0f, -0.020f * y_fac, 0.0f, -0.1f * y_fac); - fdrawline(0.0f, 0.1f * y_fac, 0.0f, 0.020f * y_fac); - - glTranslatef(-cursor[0], -cursor[1], 0.0); - setlinestyle(0); + GPU_line_width(1.0f); + + gpuTranslate2fv(cursor); + + const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + GPU_viewport_size_getf(viewport_size); + immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + + immUniform1i("num_colors", 2); /* "advanced" mode */ + immUniformArray4fv("colors", (float *)(float[][4]){{1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2); + immUniform1f("dash_width", 8.0f); + + immBegin(GWN_PRIM_LINES, 8); + + immVertex2f(shdr_pos, -0.05f * x_fac, 0.0f); + immVertex2f(shdr_pos, 0.0f, 0.05f * y_fac); + + immVertex2f(shdr_pos, 0.0f, 0.05f * y_fac); + immVertex2f(shdr_pos, 0.05f * x_fac, 0.0f); + + immVertex2f(shdr_pos, 0.05f * x_fac, 0.0f); + immVertex2f(shdr_pos, 0.0f, -0.05f * y_fac); + + immVertex2f(shdr_pos, 0.0f, -0.05f * y_fac); + immVertex2f(shdr_pos, -0.05f * x_fac, 0.0f); + + immEnd(); + + immUniformArray4fv("colors", (float *)(float[][4]){{1.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}, 2); + immUniform1f("dash_width", 2.0f); + + immBegin(GWN_PRIM_LINES, 8); + + immVertex2f(shdr_pos, -0.020f * x_fac, 0.0f); + immVertex2f(shdr_pos, -0.1f * x_fac, 0.0f); + + immVertex2f(shdr_pos, 0.1f * x_fac, 0.0f); + immVertex2f(shdr_pos, 0.020f * x_fac, 0.0f); + + immVertex2f(shdr_pos, 0.0f, -0.020f * y_fac); + immVertex2f(shdr_pos, 0.0f, -0.1f * y_fac); + + immVertex2f(shdr_pos, 0.0f, 0.1f * y_fac); + immVertex2f(shdr_pos, 0.0f, 0.020f * y_fac); + + immEnd(); + + immUnbindProgram(); + + gpuTranslate2f(-cursor[0], -cursor[1]); } static int draw_uvs_face_check(Scene *scene) @@ -136,46 +165,33 @@ static void draw_uvs_shadow(Object *obedit) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; - BMFace *efa; - BMIter iter; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - /* draws the mesh when painting */ - UI_ThemeColor(TH_UV_SHADOW); + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset); - } -} + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); -static int draw_uvs_dm_shadow(DerivedMesh *dm) -{ - /* draw shadow mesh - this is the mesh with the modifier applied */ + /* draws the mesh when painting */ + immUniformThemeColor(TH_UV_SHADOW); - if (dm && dm->drawUVEdges && CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { - UI_ThemeColor(TH_UV_SHADOW); - dm->drawUVEdges(dm); - return 1; - } + draw_uvs_lineloop_bmfaces(bm, cd_loop_uv_offset, pos); - return 0; + immUnbindProgram(); } -static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTexPoly *activetf) +static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, Object *obedit, BMEditMesh *em, const BMFace *efa_act) { BMesh *bm = em->bm; BMFace *efa; BMLoop *l; BMIter iter, liter; - MTexPoly *tf; MLoopUV *luv; Image *ima = sima->image; float aspx, aspy, col[4]; int i; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY); BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); BLI_buffer_declare_static(vec2f, tf_uvorig_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); @@ -191,7 +207,6 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe const int efa_len = efa->len; float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len); float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len); - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); @@ -203,28 +218,37 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe totarea += BM_face_calc_area(efa); totuvarea += area_poly_v2(tf_uv, efa->len); - if (uvedit_face_visible_test(scene, ima, efa, tf)) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); } else { - if (tf == activetf) - activetf = NULL; + if (efa == efa_act) { + efa_act = NULL; + } BM_elem_flag_disable(efa, BM_ELEM_TAG); } } + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + if (totarea < FLT_EPSILON || totuvarea < FLT_EPSILON) { col[0] = 1.0; col[1] = col[2] = 0.0; - glColor3fv(col); + + immUniformColor3fv(col); + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - glBegin(GL_POLYGON); + immBegin(GWN_PRIM_TRI_FAN, efa->len); + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } - glEnd(); + + immEnd(); } } } @@ -254,18 +278,23 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe areadiff = 1.0f - (area / uvarea); weight_to_rgb(col, areadiff); - glColor3fv(col); + immUniformColor3fv(col); + + /* TODO: use editmesh tessface */ + immBegin(GWN_PRIM_TRI_FAN, efa->len); - /* TODO: USE_EDBM_LOOPTRIS */ - glBegin(GL_POLYGON); BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } - glEnd(); + + immEnd(); } } } + + immUnbindProgram(); + break; } case SI_UVDT_STRETCH_ANGLE: @@ -279,10 +308,14 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe col[3] = 0.5f; /* hard coded alpha, not that nice */ - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - if (uvedit_face_visible_test(scene, ima, efa, tf)) { + immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { const int efa_len = efa->len; float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len); float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len); @@ -319,24 +352,26 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe ang[i] = angle_normalized_v3v3(av[i], av[(i + 1) % efa_len]); } - /* TODO: USE_EDBM_LOOPTRIS */ - glBegin(GL_POLYGON); + /* TODO: use editmesh tessface */ + immBegin(GWN_PRIM_TRI_FAN, efa->len); BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); a = fabsf(uvang[i] - ang[i]) / (float)M_PI; weight_to_rgb(col, 1.0f - pow2f(1.0f - a)); - glColor3fv(col); - glVertex2fv(luv->uv); + immAttrib3fv(color, col); + immVertex2fv(pos, luv->uv); } - glEnd(); + immEnd(); } else { - if (tf == activetf) - activetf = NULL; + if (efa == efa_act) + efa_act = NULL; BM_elem_flag_disable(efa, BM_ELEM_TAG); } } + immUnbindProgram(); + BLI_buffer_free(&uvang_buf); BLI_buffer_free(&ang_buf); BLI_buffer_free(&av_buf); @@ -350,58 +385,58 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe BLI_buffer_free(&tf_uvorig_buf); } -static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset) +static void draw_uvs_lineloop_bmfaces(BMesh *bm, const int cd_loop_uv_offset, const uint shdr_pos) { - BMIter liter; + BMIter iter, liter; + BMFace *efa; BMLoop *l; MLoopUV *luv; - glBegin(GL_LINE_LOOP); - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - glVertex2fv(luv->uv); + /* For more efficiency first transfer the entire buffer to vram. */ + Gwn_Batch *loop_batch = immBeginBatchAtMost(GWN_PRIM_LINE_LOOP, bm->totloop); + + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + immVertex2fv(shdr_pos, luv->uv); + } } - glEnd(); + immEnd(); + + /* Then draw each face contour separately. */ + GWN_batch_program_use_begin(loop_batch); + unsigned int index = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + GWN_batch_draw_range_ex(loop_batch, index, efa->len, false); + index += efa->len; + } + GWN_batch_program_use_end(loop_batch); + GWN_batch_discard(loop_batch); } -static void draw_uvs_lineloop_mpoly(Mesh *me, MPoly *mpoly) +static void draw_uvs_lineloop_mpoly(Mesh *me, MPoly *mpoly, unsigned int pos) { MLoopUV *mloopuv; int i; - glBegin(GL_LINE_LOOP); + immBegin(GWN_PRIM_LINE_LOOP, mpoly->totloop); + mloopuv = &me->mloopuv[mpoly->loopstart]; for (i = mpoly->totloop; i != 0; i--, mloopuv++) { - glVertex2fv(mloopuv->uv); + immVertex2fv(pos, mloopuv->uv); } - glEnd(); -} - -static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage, const int other_uv_filter) -{ - Mesh *me = ob->data; - MPoly *mpoly = me->mpoly; - MTexPoly *mtpoly = me->mtpoly; - int a; - - if (me->mloopuv == NULL) { - return; - } - - for (a = me->totpoly; a != 0; a--, mpoly++, mtpoly++) { - if (other_uv_filter == SI_FILTER_ALL) { - /* Nothing to compare, all UV faces are visible. */ - } - else if (other_uv_filter == SI_FILTER_SAME_IMAGE) { - if (mtpoly->tpage != curimage) { - continue; - } - } - draw_uvs_lineloop_mpoly(me, mpoly); - } + immEnd(); } -static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage, const int other_uv_filter) + +static void draw_uvs_other_mesh(Object *ob, const Image *curimage, + const int other_uv_filter, unsigned int pos) { Mesh *me = ob->data; MPoly *mpoly = me->mpoly; @@ -453,53 +488,42 @@ static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage, c } } - draw_uvs_lineloop_mpoly(me, mpoly); - } -} -static void draw_uvs_other_mesh(Object *ob, const Image *curimage, const bool new_shading_nodes, - const int other_uv_filter) -{ - if (new_shading_nodes) { - draw_uvs_other_mesh_new_shading(ob, curimage, other_uv_filter); - } - else { - draw_uvs_other_mesh_texface(ob, curimage, other_uv_filter); + draw_uvs_lineloop_mpoly(me, mpoly, pos); } } -static void draw_uvs_other(Scene *scene, Object *obedit, const Image *curimage, const bool new_shading_nodes, +static void draw_uvs_other(ViewLayer *view_layer, Object *obedit, const Image *curimage, const int other_uv_filter) { - Base *base; + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - UI_ThemeColor(TH_UV_OTHERS); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - for (base = scene->base.first; base; base = base->next) { - Object *ob = base->object; + immUniformThemeColor(TH_UV_OTHERS); - if (!(base->flag & SELECT)) continue; - if (!(base->lay & scene->lay)) continue; - if (ob->restrictflag & OB_RESTRICT_VIEW) continue; - - if ((ob->type == OB_MESH) && (ob != obedit) && ((Mesh *)ob->data)->mloopuv) { - draw_uvs_other_mesh(ob, curimage, new_shading_nodes, other_uv_filter); + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (((base->flag & BASE_SELECTED) != 0) && + ((base->flag & BASE_VISIBLE) != 0)) + { + Object *ob = base->object; + if ((ob->type == OB_MESH) && (ob != obedit) && ((Mesh *)ob->data)->mloopuv) { + draw_uvs_other_mesh(ob, curimage, other_uv_filter, pos); + } } } + immUnbindProgram(); } -static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob) +static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Object *ob) { - const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); Image *curimage = ED_space_image(sima); Mesh *me = ob->data; Material *ma; if (sima->flag & SI_DRAW_OTHER) { - draw_uvs_other(scene, ob, curimage, new_shading_nodes, sima->other_uv_filter); + draw_uvs_other(view_layer, ob, curimage, sima->other_uv_filter); } - UI_ThemeColor(TH_UV_SHADOW); - ma = give_current_material(ob, ob->actcol); if (me->mloopuv) { @@ -512,24 +536,33 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob) mloopuv = me->mloopuv; } + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformThemeColor(TH_UV_SHADOW); + mloopuv_base = mloopuv; for (a = me->totpoly; a > 0; a--, mpoly++) { if ((scene->toolsettings->uv_flag & UV_SHOW_SAME_IMAGE) && mpoly->mat_nr != ob->actcol - 1) continue; - glBegin(GL_LINE_LOOP); + + immBegin(GWN_PRIM_LINE_LOOP, mpoly->totloop); mloopuv = mloopuv_base + mpoly->loopstart; for (b = 0; b < mpoly->totloop; b++, mloopuv++) { - glVertex2fv(mloopuv->uv); + immVertex2fv(pos, mloopuv->uv); } - glEnd(); + + immEnd(); } + + immUnbindProgram(); } } -#ifdef USE_EDBM_LOOPTRIS -static void draw_uvs_looptri(BMEditMesh *em, unsigned int *r_loop_index, const int cd_loop_uv_offset) +static void draw_uvs_looptri(BMEditMesh *em, unsigned int *r_loop_index, const int cd_loop_uv_offset, unsigned int pos) { unsigned int i = *r_loop_index; BMFace *f = em->looptris[i][0]->f; @@ -537,43 +570,34 @@ static void draw_uvs_looptri(BMEditMesh *em, unsigned int *r_loop_index, const i unsigned int j; for (j = 0; j < 3; j++) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(em->looptris[i][j], cd_loop_uv_offset); - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } i++; } while (i != em->tottri && (f == em->looptris[i][0]->f)); *r_loop_index = i - 1; } -#endif /* draws uv's in the image space */ -static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) +static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Object *obedit, Depsgraph *depsgraph) { - const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); ToolSettings *ts; Mesh *me = obedit->data; BMEditMesh *em = me->edit_btmesh; BMesh *bm = em->bm; BMFace *efa, *efa_act; -#ifndef USE_EDBM_LOOPTRIS - BMFace *activef; -#endif BMLoop *l; BMIter iter, liter; - MTexPoly *tf, *activetf = NULL; MLoopUV *luv; - DerivedMesh *finaldm, *cagedm; - unsigned char col1[4], col2[4]; + float col1[4], col2[4]; float pointsize; int drawfaces, interpedges; Image *ima = sima->image; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY); - efa_act = EDBM_uv_active_face_get(em, false, false, &activetf); /* will be set to NULL if hidden */ -#ifndef USE_EDBM_LOOPTRIS - activef = BM_mesh_active_face_get(bm, false, false); -#endif + unsigned int pos, color; + + efa_act = EDBM_uv_active_face_get(em, false, false); /* will be set to NULL if hidden */ ts = scene->toolsettings; drawfaces = draw_uvs_face_check(scene); @@ -586,325 +610,362 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) if (sima->flag & SI_DRAW_OTHER) { Image *curimage; - if (new_shading_nodes) { - if (efa_act) { - ED_object_get_active_image(obedit, efa_act->mat_nr + 1, &curimage, NULL, NULL, NULL); - } - else { - curimage = ima; - } + if (efa_act) { + ED_object_get_active_image(obedit, efa_act->mat_nr + 1, &curimage, NULL, NULL, NULL); } else { - curimage = (activetf) ? activetf->tpage : ima; + curimage = ima; } - draw_uvs_other(scene, obedit, curimage, new_shading_nodes, sima->other_uv_filter); + draw_uvs_other(view_layer, obedit, curimage, sima->other_uv_filter); } /* 1. draw shadow mesh */ if (sima->flag & SI_DRAWSHADOW) { - DM_update_materials(em->derivedFinal, obedit); - /* first try existing derivedmesh */ - if (!draw_uvs_dm_shadow(em->derivedFinal)) { - /* create one if it does not exist */ - cagedm = editbmesh_get_derived_cage_and_final( - scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH | CD_MASK_MTFACE, - &finaldm); - - /* when sync selection is enabled, all faces are drawn (except for hidden) - * so if cage is the same as the final, theres no point in drawing this */ - if (!((ts->uv_flag & UV_SYNC_SELECTION) && (cagedm == finaldm))) - draw_uvs_dm_shadow(finaldm); - - /* release derivedmesh again */ - if (cagedm != finaldm) cagedm->release(cagedm); - finaldm->release(finaldm); + Object *ob_cage_eval = DEG_get_evaluated_object(depsgraph, obedit); + /* XXX TODO: Need to check if shadow mesh is different than original mesh. */ + bool is_cage_like_final_meshes = (ob_cage_eval == obedit); + + /* When sync selection is enabled, all faces are drawn (except for hidden) + * so if cage is the same as the final, there is no point in drawing this. */ + if (((ts->uv_flag & UV_SYNC_SELECTION) == 0) || is_cage_like_final_meshes) { + draw_uvs_shadow(ob_cage_eval); } } /* 2. draw colored faces */ if (sima->flag & SI_DRAW_STRETCH) { - draw_uvs_stretch(sima, scene, em, activetf); + draw_uvs_stretch(sima, scene, obedit, em, efa_act); } - else if (!(sima->flag & SI_NO_DRAWFACES)) { - /* draw transparent faces */ - UI_GetThemeColor4ubv(TH_FACE, col1); - UI_GetThemeColor4ubv(TH_FACE_SELECT, col2); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - -#ifdef USE_EDBM_LOOPTRIS - { - unsigned int i; - for (i = 0; i < em->tottri; i++) { + else { + unsigned int tri_count = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + tri_count += efa->len - 2; + } + else { + BM_elem_flag_disable(efa, BM_ELEM_TAG); + } + } + + if (tri_count && !(sima->flag & SI_NO_DRAWFACES)) { + /* draw transparent faces */ + UI_GetThemeColor4fv(TH_FACE, col1); + UI_GetThemeColor4fv(TH_FACE_SELECT, col2); + GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + GPU_blend(true); + + Gwn_VertFormat *format = immVertexFormat(); + pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + + Gwn_Batch *face_batch = immBeginBatch(GWN_PRIM_TRIS, tri_count * 3); + for (unsigned int i = 0; i < em->tottri; i++) { efa = em->looptris[i][0]->f; - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (uvedit_face_visible_test(scene, ima, efa, tf)) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { const bool is_select = uvedit_face_select_test(scene, efa, cd_loop_uv_offset); - BM_elem_flag_enable(efa, BM_ELEM_TAG); - if (tf == activetf) { + if (efa == efa_act) { /* only once */ - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE); - UI_ThemeColor4(TH_EDITMESH_ACTIVE); + float tmp_col[4]; + UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, tmp_col); + immAttrib4fv(color, tmp_col); } else { - glColor4ubv((GLubyte *)(is_select ? col2 : col1)); + immAttrib4fv(color, is_select ? col2 : col1); } - glBegin(GL_TRIANGLES); - draw_uvs_looptri(em, &i, cd_loop_uv_offset); - glEnd(); - - if (tf == activetf) { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } - } - else { - BM_elem_flag_disable(efa, BM_ELEM_TAG); + draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos); } } - } -#else - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (uvedit_face_visible_test(scene, ima, efa, tf)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - if (tf == activetf) continue; /* important the temp boolean is set above */ - - if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) - glColor4ubv((GLubyte *)col2); - else - glColor4ubv((GLubyte *)col1); + immEnd(); - glBegin(GL_POLYGON); - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - glVertex2fv(luv->uv); - } - glEnd(); - } - else { - if (tf == activetf) - activetf = NULL; - BM_elem_flag_disable(efa, BM_ELEM_TAG); - } - } -#endif - glDisable(GL_BLEND); - } - else { - /* would be nice to do this within a draw loop but most below are optional, so it would involve too many checks */ + /* XXX performance: we should not create and throw away result. */ + GWN_batch_draw(face_batch); + GWN_batch_program_use_end(face_batch); + GWN_batch_discard(face_batch); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); + immUnbindProgram(); - if (uvedit_face_visible_test(scene, ima, efa, tf)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - } - else { - if (tf == activetf) - activetf = NULL; - BM_elem_flag_disable(efa, BM_ELEM_TAG); + GPU_blend(false); + } + else { + if (efa_act && !uvedit_face_visible_test(scene, obedit, ima, efa_act)) { + efa_act = NULL; } } - } /* 3. draw active face stippled */ -#ifndef USE_EDBM_LOOPTRIS - if (activef) { - tf = BM_ELEM_CD_GET_VOID_P(activef, cd_poly_tex_offset); - if (uvedit_face_visible_test(scene, ima, activef, tf)) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - UI_ThemeColor4(TH_EDITMESH_ACTIVE); - - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE); - - glBegin(GL_POLYGON); - BM_ITER_ELEM (l, &liter, activef, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - glVertex2fv(luv->uv); - } - glEnd(); - - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - glDisable(GL_BLEND); - } - } -#endif + /* (removed during OpenGL upgrade, reimplement if needed) */ /* 4. draw edges */ if (sima->flag & SI_SMOOTH_UV) { - glEnable(GL_LINE_SMOOTH); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GPU_line_smooth(true); + GPU_blend(true); + GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); } - glLineWidth(1); + pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); switch (sima->dt_uv) { case SI_UVDT_DASH: - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - - if (tf) { - cpack(0x111111); - - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset); + { + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); - setlinestyle(2); - cpack(0x909090); + float viewport_size[4]; + GPU_viewport_size_getf(viewport_size); + immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset); + immUniform1i("num_colors", 2); /* "advanced" mode */ + immUniformArray4fv("colors", (float *)(float[][4]){{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}}, 2); + immUniform1f("dash_width", 4.0f); + GPU_line_width(1.0f); - setlinestyle(0); - } - } break; + } case SI_UVDT_BLACK: /* black/white */ case SI_UVDT_WHITE: - if (sima->dt_uv == SI_UVDT_WHITE) glColor3f(1.0f, 1.0f, 1.0f); - else glColor3f(0.0f, 0.0f, 0.0f); - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + if (sima->dt_uv == SI_UVDT_WHITE) { + immUniformColor3f(1.0f, 1.0f, 1.0f); + } + else { + immUniformColor3f(0.0f, 0.0f, 0.0f); } + GPU_line_width(1.0f); + break; case SI_UVDT_OUTLINE: - glLineWidth(3); - cpack(0x0); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + imm_cpack(0x0); + GPU_line_width(3.0f); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; + break; + } + + /* For more efficiency first transfer the entire buffer to vram. */ + Gwn_Batch *loop_batch = immBeginBatchAtMost(GWN_PRIM_LINE_LOOP, bm->totloop); + Gwn_VertBuf *loop_vbo = loop_batch->verts[0]; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + immVertex2fv(pos, luv->uv); + } + } + immEnd(); + + /* Then draw each face contour separately. */ + if (loop_vbo->vertex_ct != 0) { + GWN_batch_program_use_begin(loop_batch); + unsigned int index = 0, loop_vbo_count; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + GWN_batch_draw_range_ex(loop_batch, index, efa->len, false); + index += efa->len; + } + loop_vbo_count = index; + GWN_batch_program_use_end(loop_batch); + immUnbindProgram(); - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset); - } - glLineWidth(1); - UI_GetThemeColor4ubv(TH_WIRE_EDIT, col2); - glColor4ubv((unsigned char *)col2); + if (sima->dt_uv == SI_UVDT_OUTLINE) { + GPU_line_width(1.0f); + UI_GetThemeColor4fv(TH_WIRE_EDIT, col2); if (me->drawflag & ME_DRAWEDGES) { - int sel, lastsel = -1; - UI_GetThemeColor4ubv(TH_EDGE_SELECT, col1); + int sel; + UI_GetThemeColor4fv(TH_EDGE_SELECT, col1); if (interpedges) { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + /* Create a color buffer. */ + static Gwn_VertFormat format = { 0 }; + static uint shdr_col; + if (format.attrib_ct == 0) { + shdr_col = GWN_vertformat_attr_add(&format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); + } + + Gwn_VertBuf *vbo_col = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo_col, loop_vbo_count); + + index = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; - glBegin(GL_LINE_LOOP); - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); - glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); - - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - glVertex2fv(luv->uv); + GWN_vertbuf_attr_set(vbo_col, shdr_col, index++, sel ? col1 : col2); } - glEnd(); } + /* Reuse the UV buffer and add the color buffer. */ + GWN_batch_vertbuf_add_ex(loop_batch, vbo_col, true); + + /* Now draw each face contour separately with another builtin program. */ + GWN_batch_program_set_builtin(loop_batch, GPU_SHADER_2D_SMOOTH_COLOR); + gpuBindMatrices(loop_batch->interface); + + GWN_batch_program_use_begin(loop_batch); + index = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + GWN_batch_draw_range_ex(loop_batch, index, efa->len, false); + index += efa->len; + } + GWN_batch_program_use_end(loop_batch); } else { - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + Gwn_VertFormat *format = immVertexFormat(); + pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + + /* Use batch here to avoid problems with `IMM_BUFFER_SIZE`. */ + Gwn_Batch *flat_edges_batch = immBeginBatchAtMost(GWN_PRIM_LINES, loop_vbo_count * 2); + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; - glBegin(GL_LINES); - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { sel = uvedit_edge_select_test(scene, l, cd_loop_uv_offset); - if (sel != lastsel) { - glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); - lastsel = sel; - } + immAttrib4fv(color, sel ? col1 : col2); + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); luv = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } - glEnd(); } + immEnd(); + + GWN_batch_draw(flat_edges_batch); + GWN_batch_discard(flat_edges_batch); + + immUnbindProgram(); } } else { + GWN_batch_uniform_4fv(loop_batch, "color", col2); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* no nice edges */ - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + GWN_batch_program_use_begin(loop_batch); + index = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset); + GWN_batch_draw_range_ex(loop_batch, index, efa->len, false); + index += efa->len; } + GWN_batch_program_use_end(loop_batch); + immUnbindProgram(); } - - break; + } } + else { + immUnbindProgram(); + } + + GWN_batch_discard(loop_batch); if (sima->flag & SI_SMOOTH_UV) { - glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); + GPU_line_smooth(false); + GPU_blend(false); } /* 5. draw face centers */ if (drawfaces) { float cent[2]; + bool col_set = false; + + Gwn_VertFormat *format = immVertexFormat(); + pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); pointsize = UI_GetThemeValuef(TH_FACEDOT_SIZE); - glPointSize(pointsize); + GPU_point_size(pointsize); - glBegin(GL_POINTS); + immBeginAtMost(GWN_PRIM_POINTS, bm->totface); /* unselected faces */ - UI_ThemeColor(TH_WIRE); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + /* Only set color for the first face */ + if (!col_set) { + UI_GetThemeColor3fv(TH_WIRE, col1); + immAttrib3fv(color, col1); + + col_set = true; + } + uv_poly_center(efa, cent, cd_loop_uv_offset); - glVertex2fv(cent); + immVertex2fv(pos, cent); } } + col_set = false; + /* selected faces */ - UI_ThemeColor(TH_FACE_DOT); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + /* Only set color for the first face */ + if (!col_set) { + UI_GetThemeColor3fv(TH_FACE_DOT, col1); + immAttrib3fv(color, col1); + + col_set = true; + } + uv_poly_center(efa, cent, cd_loop_uv_offset); - glVertex2fv(cent); + immVertex2fv(pos, cent); } } - glEnd(); + immEnd(); + + immUnbindProgram(); } /* 6. draw uv vertices */ if (drawfaces != 2) { /* 2 means Mesh Face Mode */ + pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* unselected uvs */ - UI_ThemeColor(TH_VERTEX); + immUniformThemeColor(TH_VERTEX); pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE); - glPointSize(pointsize); + GPU_point_size(pointsize); + + immBeginAtMost(GWN_PRIM_POINTS, bm->totloop); - glBegin(GL_POINTS); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; @@ -912,17 +973,19 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } } - glEnd(); + + immEnd(); /* pinned uvs */ /* give odd pointsizes odd pin pointsizes */ - glPointSize(pointsize * 2 + (((int)pointsize % 2) ? (-1) : 0)); - cpack(0xFF); + GPU_point_size(pointsize * 2 + (((int)pointsize % 2) ? (-1) : 0)); + imm_cpack(0xFF); + + immBeginAtMost(GWN_PRIM_POINTS, bm->totloop); - glBegin(GL_POINTS); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; @@ -931,16 +994,18 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (luv->flag & MLOOPUV_PINNED) - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } } - glEnd(); + + immEnd(); /* selected uvs */ - UI_ThemeColor(TH_VERTEX_SELECT); - glPointSize(pointsize); + immUniformThemeColor(TH_VERTEX_SELECT); + GPU_point_size(pointsize); + + immBeginAtMost(GWN_PRIM_POINTS, bm->totloop); - glBegin(GL_POINTS); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; @@ -949,15 +1014,20 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) - glVertex2fv(luv->uv); + immVertex2fv(pos, luv->uv); } } - glEnd(); + + immEnd(); + + immUnbindProgram(); } } -static void draw_uv_shadows_get(SpaceImage *sima, Object *ob, Object *obedit, bool *show_shadow, bool *show_texpaint) +static void draw_uv_shadows_get( + SpaceImage *sima, Object *ob, Object *obedit, + bool *show_shadow, bool *show_texpaint) { *show_shadow = *show_texpaint = false; @@ -973,7 +1043,9 @@ static void draw_uv_shadows_get(SpaceImage *sima, Object *ob, Object *obedit, bo *show_texpaint = (ob && ob->type == OB_MESH && ob->mode == OB_MODE_TEXTURE_PAINT); } -void ED_uvedit_draw_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit, Object *obact) +void ED_uvedit_draw_main( + SpaceImage *sima, + ARegion *ar, Scene *scene, ViewLayer *view_layer, Object *obedit, Object *obact, Depsgraph *depsgraph) { ToolSettings *toolsettings = scene->toolsettings; bool show_uvedit, show_uvshadow, show_texpaint_uvshadow; @@ -982,12 +1054,21 @@ void ED_uvedit_draw_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *ob 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, obedit); - else - draw_uvs_texpaint(sima, scene, obact); + } + 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_freeN(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 a9162d26d72..eed9d68f39c 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -32,7 +32,6 @@ #ifndef __UVEDIT_INTERN_H__ #define __UVEDIT_INTERN_H__ -struct MTexPoly; struct Image; struct Object; struct Scene; @@ -52,9 +51,10 @@ 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 MTexPoly *tf; struct BMLoop *l; struct MLoopUV *luv, *luv_next; /** Index of loop within face. */ @@ -66,15 +66,24 @@ typedef struct UvNearestHit { #define UV_NEAREST_HIT_INIT { .dist_sq = FLT_MAX, } bool uv_find_nearest_vert( - struct Scene *scene, struct Image *ima, struct BMEditMesh *em, + 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 BMEditMesh *em, + 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 BMEditMesh *em, + 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 0fa5fb9a48d..e3d2537c040 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -29,6 +29,7 @@ * \ingroup eduv */ + #include <stdlib.h> #include <string.h> #include <math.h> @@ -56,7 +57,6 @@ #include "BKE_context.h" #include "BKE_customdata.h" -#include "BKE_depsgraph.h" #include "BKE_image.h" #include "BKE_library.h" #include "BKE_main.h" @@ -66,6 +66,9 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" + +#include "DEG_depsgraph.h" #include "ED_image.h" #include "ED_mesh.h" @@ -87,7 +90,10 @@ #include "uvedit_intern.h" -static void uv_select_all_perform(Scene *scene, Image *ima, 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); @@ -189,144 +195,6 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i //#define USE_SWITCH_ASPECT -void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, Image *ima, Image *previma) -{ - BMEditMesh *em; - BMIter iter; - MTexPoly *tf; - bool update = false; - const bool selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION); - - /* skip assigning these procedural images... */ - if (ima && (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE)) - return; - - /* verify we have a mesh we can work with */ - if (!obedit || (obedit->type != OB_MESH)) - return; - - em = BKE_editmesh_from_object(obedit); - if (!em || !em->bm->totface) { - return; - } - - if (BKE_scene_use_new_shading_nodes(scene)) { - /* new shading system, do not assign anything */ - } - else { - BMFace *efa; - - int cd_loop_uv_offset; - int cd_poly_tex_offset; - - /* old shading system, assign image to selected faces */ -#ifdef USE_SWITCH_ASPECT - float prev_aspect[2], fprev_aspect; - float aspect[2], faspect; - - ED_image_get_uv_aspect(previma, prev_aspect, prev_aspect + 1); - ED_image_get_uv_aspect(ima, aspect, aspect + 1); - - fprev_aspect = prev_aspect[0] / prev_aspect[1]; - faspect = aspect[0] / aspect[1]; -#endif - - /* ensure we have a uv map */ - if (!CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY)) { - BM_data_layer_add(em->bm, &em->bm->pdata, CD_MTEXPOLY); - BM_data_layer_add(em->bm, &em->bm->ldata, CD_MLOOPUV); - /* make UVs all nice 0-1 */ - ED_mesh_uv_loop_reset_ex(obedit->data, CustomData_get_active_layer(&em->bm->pdata, CD_MTEXPOLY)); - update = true; - } - - cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); - - /* now assign to all visible faces */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - - if (uvedit_face_visible_test(scene, previma, efa, tf) && - (selected == true || uvedit_face_select_test(scene, efa, cd_loop_uv_offset))) - { - if (ima) { - tf->tpage = ima; - - if (ima->id.us == 0) id_us_plus(&ima->id); - else id_lib_extern(&ima->id); - -#ifdef USE_SWITCH_ASPECT - /* we also need to correct the aspect of uvs */ - if (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) { - /* do nothing */ - } - else { - BMIter liter; - BMLoop *l; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - luv->uv[0] *= fprev_aspect; - luv->uv[0] /= faspect; - } - } -#endif - } - else { - tf->tpage = NULL; - } - - update = true; - } - } - - /* and update depdency graph */ - if (update) { - DAG_id_tag_update(obedit->data, 0); - } - } - -} - -/* dotile - 1, set the tile flag (from the space image) - * 2, set the tile index for the faces. */ -static bool uvedit_set_tile(Object *obedit, Image *ima, int curtile) -{ - BMEditMesh *em; - BMFace *efa; - BMIter iter; - MTexPoly *tf; - int cd_poly_tex_offset; - - /* verify if we have something to do */ - if (!ima || !ED_uvedit_test(obedit)) - return false; - - if ((ima->tpageflag & IMA_TILES) == 0) - return false; - - /* skip assigning these procedural images... */ - if (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE) - return false; - - em = BKE_editmesh_from_object(obedit); - - cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - - if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) - tf->tile = curtile; /* set tile index */ - } - - DAG_id_tag_update(obedit->data, 0); - - return true; -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -380,14 +248,18 @@ bool uvedit_face_visible_nolocal(Scene *scene, BMFace *efa) return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); } -bool uvedit_face_visible_test(Scene *scene, Image *ima, BMFace *efa, MTexPoly *tf) +bool uvedit_face_visible_test(Scene *scene, Object *obedit, Image *ima, BMFace *efa) { ToolSettings *ts = scene->toolsettings; - if (ts->uv_flag & UV_SHOW_SAME_IMAGE) - return (tf->tpage == ima) ? uvedit_face_visible_nolocal(scene, efa) : false; - else + if (ts->uv_flag & UV_SHOW_SAME_IMAGE) { + Image *face_image; + ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL); + return (face_image == ima) ? uvedit_face_visible_nolocal(scene, efa) : false; + } + else { return uvedit_face_visible_nolocal(scene, efa); + } } bool uvedit_face_select_test( @@ -695,38 +567,45 @@ void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float as } } -bool ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2]) +bool ED_uvedit_minmax_multi( + Scene *scene, Image *ima, Object **objects_edit, uint objects_len, + float r_min[2], float r_max[2]) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MTexPoly *tf; - MLoopUV *luv; bool changed = false; + INIT_MINMAX2(r_min, r_max); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects_edit[ob_index]; - INIT_MINMAX2(r_min, r_max); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) - continue; + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - minmax_v2v2_v2(r_min, r_max, luv->uv); - changed = true; + 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) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + minmax_v2v2_v2(r_min, r_max, luv->uv); + changed = true; + } } } } - return changed; } +bool ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2]) +{ + return ED_uvedit_minmax_multi(scene, ima, &obedit, 1, r_min, r_max); +} + /* Be careful when using this, it bypasses all synchronization options */ void ED_uvedit_select_all(BMesh *bm) { @@ -745,30 +624,32 @@ void ED_uvedit_select_all(BMesh *bm) } } -static bool ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[2]) +static bool ED_uvedit_median_multi(Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2]) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MTexPoly *tf; - MLoopUV *luv; unsigned int sel = 0; + zero_v2(co); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects_edit[ob_index]; - zero_v2(co); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) - continue; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - add_v2_v2(co, luv->uv); - sel++; + 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 (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + add_v2_v2(co, luv->uv); + sel++; + } } } } @@ -778,19 +659,24 @@ static bool ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[ return (sel != 0); } -static bool uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], char mode) +static bool UNUSED_FUNCTION(ED_uvedit_median)(Scene *scene, Image *ima, Object *obedit, float co[2]) +{ + return ED_uvedit_median_multi(scene, ima, &obedit, 1, co); +} + +bool ED_uvedit_center_multi(Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float cent[2], char mode) { bool changed = false; if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */ float min[2], max[2]; - if (ED_uvedit_minmax(scene, ima, obedit, min, max)) { + if (ED_uvedit_minmax_multi(scene, ima, objects_edit, objects_len, min, max)) { mid_v2_v2v2(cent, min, max); changed = true; } } else { - if (ED_uvedit_median(scene, ima, obedit, cent)) { + if (ED_uvedit_median_multi(scene, ima, objects_edit, objects_len, cent)) { changed = true; } } @@ -798,6 +684,11 @@ static bool uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2 return changed; } +bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], char mode) +{ + return ED_uvedit_center_multi(scene, ima, &obedit, 1, cent, mode); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -805,10 +696,10 @@ static bool uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2 * \{ */ bool uv_find_nearest_edge( - Scene *scene, Image *ima, BMEditMesh *em, const float co[2], + Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit) { - MTexPoly *tf; + BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; BMLoop *l; BMIter iter, liter; @@ -817,13 +708,11 @@ bool uv_find_nearest_edge( bool found = false; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); BM_mesh_elem_index_ensure(em->bm, BM_VERT); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { continue; } BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { @@ -833,7 +722,6 @@ bool uv_find_nearest_edge( const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv); if (dist_test_sq < hit->dist_sq) { - hit->tf = tf; hit->efa = efa; hit->l = l; @@ -849,19 +737,34 @@ 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, BMEditMesh *em, const float co[2], + Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final) { + BMEditMesh *em = BKE_editmesh_from_object(obedit); bool found = false; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); /* this will fill in hit.vert1 and hit.vert2 */ float dist_sq_init = hit_final->dist_sq; UvNearestHit hit = *hit_final; - if (uv_find_nearest_edge(scene, ima, em, co, &hit)) { + if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { hit.dist_sq = dist_sq_init; hit.l = NULL; hit.luv = hit.luv_next = NULL; @@ -870,8 +773,7 @@ bool uv_find_nearest_face( BMFace *efa; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { continue; } @@ -893,6 +795,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) @@ -906,7 +823,7 @@ static bool uv_nearest_between( } bool uv_find_nearest_vert( - Scene *scene, Image *ima, BMEditMesh *em, + Scene *scene, Image *ima, Object *obedit, float const co[2], const float penalty_dist, UvNearestHit *hit_final) { bool found = false; @@ -914,23 +831,22 @@ bool uv_find_nearest_vert( /* this will fill in hit.vert1 and hit.vert2 */ float dist_sq_init = hit_final->dist_sq; UvNearestHit hit = *hit_final; - if (uv_find_nearest_edge(scene, ima, em, co, &hit)) { + if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { hit.dist_sq = dist_sq_init; hit.l = NULL; hit.luv = hit.luv_next = NULL; + BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; BMIter iter; BM_mesh_elem_index_ensure(em->bm, BM_VERT); const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { continue; } @@ -975,26 +891,38 @@ 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); BMFace *efa; BMLoop *l; BMIter iter, liter; - MTexPoly *tf; MLoopUV *luv; float mindist, dist; bool found = false; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); mindist = 1e10f; copy_v2_v2(r_uv, co); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1103,13 +1031,13 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, } static int uv_select_edgeloop( - Scene *scene, Image *ima, 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; - MTexPoly *tf; UvVertMap *vmap; UvMapVert *iterv_curr; UvMapVert *iterv_next; @@ -1117,7 +1045,6 @@ static int uv_select_edgeloop( bool looking, select; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); /* setup */ BM_mesh_elem_table_ensure(em->bm, BM_FACE); @@ -1126,7 +1053,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, 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); @@ -1150,9 +1077,7 @@ static int uv_select_edgeloop( /* find correct valence edges which are not tagged yet, but connect to tagged one */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - - if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, ima, efa, tf)) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, obedit, ima, efa)) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { /* check face not hidden and not tagged */ if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) @@ -1211,190 +1136,193 @@ static int uv_select_edgeloop( /** \name Select Linked * \{ */ -static void uv_select_linked( - Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], UvNearestHit *hit_final, - bool extend, bool deselect, bool toggle, bool select_faces) +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 deselect, bool toggle, bool select_faces) { - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - UvVertMap *vmap; - UvMapVert *vlist, *iterv, *startv; - int i, stacksize = 0, *stack; - unsigned int a; - char *flag; + /* 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]; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + UvVertMap *vmap; + UvMapVert *vlist, *iterv, *startv; + int i, stacksize = 0, *stack; + unsigned int a; + char *flag; - BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */ + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - /* 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. - * Keep 'use_winding' to false, see: T50970. - * - * Better solve this by having a delimit option for select-linked operator, - * keeping island-select working as is. */ - vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false); + BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */ - if (vmap == NULL) - return; + /* 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. + * Keep 'use_winding' to false, see: T50970. + * + * Better solve this by having a delimit option for select-linked operator, + * keeping island-select working as is. */ + vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false); - stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack"); - flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag"); + if (vmap == NULL) + return; - if (hit_final == NULL) { - /* Use existing selection */ - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); + stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack"); + flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag"); - if (uvedit_face_visible_test(scene, ima, efa, tf)) { - if (select_faces) { - if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - stack[stacksize] = a; - stacksize++; - flag[a] = 1; - } - } - else { - 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) { + if (hit_final == NULL) { + /* Use existing selection */ + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (select_faces) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { stack[stacksize] = a; stacksize++; flag[a] = 1; + } + } + else { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - break; + if (luv->flag & MLOOPUV_VERTSEL) { + stack[stacksize] = a; + stacksize++; + flag[a] = 1; + + break; + } } } } } } - } - else { - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - if (efa == hit_final->efa) { - stack[stacksize] = a; - stacksize++; - flag[a] = 1; - break; + else { + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { + if (efa == hit_final->efa) { + stack[stacksize] = a; + stacksize++; + flag[a] = 1; + break; + } } } - } - while (stacksize > 0) { + while (stacksize > 0) { - stacksize--; - a = stack[stacksize]; + stacksize--; + a = stack[stacksize]; - efa = BM_face_at_index(em->bm, a); + efa = BM_face_at_index(em->bm, a); - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { + BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - /* make_uv_vert_map_EM sets verts tmp.l to the indices */ - vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); + /* make_uv_vert_map_EM sets verts tmp.l to the indices */ + vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); - startv = vlist; + startv = vlist; - for (iterv = vlist; iterv; iterv = iterv->next) { - if (iterv->separate) - startv = iterv; - if (iterv->f == a) - break; - } + for (iterv = vlist; iterv; iterv = iterv->next) { + if (iterv->separate) + startv = iterv; + if (iterv->f == a) + break; + } - for (iterv = startv; iterv; iterv = iterv->next) { - if ((startv != iterv) && (iterv->separate)) - break; - else if (!flag[iterv->f]) { - flag[iterv->f] = 1; - stack[stacksize] = iterv->f; - stacksize++; + for (iterv = startv; iterv; iterv = iterv->next) { + if ((startv != iterv) && (iterv->separate)) + break; + else if (!flag[iterv->f]) { + flag[iterv->f] = 1; + stack[stacksize] = iterv->f; + stacksize++; + } } } } - } - - /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */ - if ((toggle == true) && (extend == false) && (deselect == false)) { - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - bool found_selected = false; - if (!flag[a]) { - continue; - } - if (select_faces) { - if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - found_selected = true; + /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */ + if ((toggle == true) && (extend == false) && (deselect == false)) { + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { + bool found_selected = false; + if (!flag[a]) { + continue; } - } - else { - 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) { + if (select_faces) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { found_selected = true; } } + else { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (found_selected) { - deselect = true; - break; + if (luv->flag & MLOOPUV_VERTSEL) { + found_selected = true; + } + } + + if (found_selected) { + deselect = true; + break; + } } } } - } #define SET_SELECTION(value) \ - if (select_faces) { \ - BM_face_select_set(em->bm, efa, value); \ - } \ - else { \ - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \ - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \ - luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \ + if (select_faces) { \ + BM_face_select_set(em->bm, efa, value); \ } \ - } (void)0 + else { \ + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \ + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \ + luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \ + } \ + } (void)0 - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - if (!flag[a]) { - if (!extend && !deselect && !toggle) { - SET_SELECTION(false); + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { + if (!flag[a]) { + if (!extend && !deselect && !toggle) { + SET_SELECTION(false); + } + continue; } - continue; - } - if (!deselect) { - SET_SELECTION(true); - } - else { - SET_SELECTION(false); + if (!deselect) { + SET_SELECTION(true); + } + else { + SET_SELECTION(false); + } } - } #undef SET_SELECTION - MEM_freeN(stack); - MEM_freeN(flag); - BM_uv_vert_map_free(vmap); + MEM_freeN(stack); + MEM_freeN(flag); + BM_uv_vert_map_free(vmap); + } } /* WATCH IT: this returns first selected UV, * not ideal in many cases since there could be multiple */ -static float *uv_sel_co_from_eve(Scene *scene, 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; BMLoop *l; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { - MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(l->f, cd_poly_tex_offset); - - if (!uvedit_face_visible_test(scene, ima, l->f, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) continue; if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { @@ -1426,7 +1354,6 @@ static int uv_select_more_less(bContext *C, const bool select) ToolSettings *ts = scene->toolsettings; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); if (ts->uv_flag & UV_SYNC_SELECTION) { if (select) { @@ -1435,7 +1362,7 @@ static int uv_select_more_less(bContext *C, const bool select) else { EDBM_select_less(em, true); } - + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -1447,9 +1374,7 @@ static int uv_select_more_less(bContext *C, const bool select) /* mark loops to be selected */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - - if (uvedit_face_visible_test(scene, ima, efa, tf)) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { #define IS_SEL 1 #define IS_UNSEL 2 @@ -1492,9 +1417,7 @@ static int uv_select_more_less(bContext *C, const bool select) /* mark loops to be selected */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - - if (uvedit_face_visible_test(scene, ima, efa, tf)) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); @@ -1511,6 +1434,7 @@ static int uv_select_more_less(bContext *C, const bool select) uv_select_flush_from_tag_loop(sima, scene, obedit, select); } + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -1565,11 +1489,9 @@ static void uv_weld_align(bContext *C, int tool) SpaceImage *sima; Scene *scene; Image *ima; - MTexPoly *tf; float cent[2], min[2], max[2]; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); scene = CTX_data_scene(C); ima = CTX_data_edit_image(C); @@ -1583,9 +1505,7 @@ static void uv_weld_align(bContext *C, int tool) BMLoop *l; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - - if (!uvedit_face_visible_test(scene, ima, efa, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1599,7 +1519,7 @@ static void uv_weld_align(bContext *C, int tool) tool = (max[0] - min[0] >= max[1] - min[1]) ? 'y' : 'x'; } - uvedit_center(scene, ima, obedit, cent, 0); + ED_uvedit_center(scene, ima, obedit, cent, 0); if (tool == 'x' || tool == 'w') { BMIter iter, liter; @@ -1607,8 +1527,7 @@ static void uv_weld_align(bContext *C, int tool) BMLoop *l; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1627,8 +1546,7 @@ static void uv_weld_align(bContext *C, int tool) BMLoop *l; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1654,9 +1572,7 @@ static void uv_weld_align(bContext *C, int tool) /* tag verts with a selected UV */ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { - tf = BM_ELEM_CD_GET_VOID_P(l->f, cd_poly_tex_offset); - - if (!uvedit_face_visible_test(scene, ima, l->f, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) continue; if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { @@ -1725,8 +1641,10 @@ static void uv_weld_align(bContext *C, int tool) if (BLI_array_len(eve_line) > 2) { /* we know the returns from these must be valid */ - const float *uv_start = uv_sel_co_from_eve(scene, ima, em, eve_line[0]); - const float *uv_end = uv_sel_co_from_eve(scene, ima, em, eve_line[BLI_array_len(eve_line) - 1]); + const float *uv_start = uv_sel_co_from_eve( + scene, obedit, ima, em, eve_line[0]); + const float *uv_end = uv_sel_co_from_eve( + scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]); /* For t & u modes */ float a = 0.0f; @@ -1746,9 +1664,7 @@ static void uv_weld_align(bContext *C, int tool) /* go over all verts except for endpoints */ for (i = 0; i < BLI_array_len(eve_line); i++) { BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) { - tf = BM_ELEM_CD_GET_VOID_P(l->f, cd_poly_tex_offset); - - if (!uvedit_face_visible_test(scene, ima, l->f, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) continue; if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { @@ -1782,7 +1698,7 @@ static void uv_weld_align(bContext *C, int tool) uvedit_live_unwrap_update(sima, scene, obedit); - DAG_id_tag_update(obedit->data, 0); + DEG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); } @@ -1839,7 +1755,6 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); Image *ima; - MTexPoly *tf; int uv_a_index; int uv_b_index; float *uv_a; @@ -1850,7 +1765,6 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) BMLoop *l; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); sima = CTX_wm_space_image(C); scene = CTX_data_scene(C); @@ -1864,8 +1778,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) /* TODO, use kd-tree as with MESH_OT_remove_doubles, this isn't optimal */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1927,8 +1840,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) BLI_array_declare(loop_arr_unselected); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1965,7 +1877,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) } uvedit_live_unwrap_update(sima, scene, obedit); - DAG_id_tag_update(obedit->data, 0); + DEG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); return OPERATOR_FINISHED; @@ -2020,20 +1932,65 @@ static void UV_OT_weld(wmOperatorType *ot) /** \name (De)Select All Operator * \{ */ -static void uv_select_all_perform(Scene *scene, Image *ima, 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; - MTexPoly *tf; MLoopUV *luv; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); - 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); @@ -2051,30 +2008,8 @@ static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int } } else { - if (action == SEL_TOGGLE) { - action = SEL_SELECT; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - - if (!uvedit_face_visible_test(scene, ima, efa, tf)) - 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) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - - if (!uvedit_face_visible_test(scene, ima, efa, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -2096,18 +2031,39 @@ static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int } } +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, 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]; + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -2156,18 +2112,17 @@ 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; - MTexPoly *tf; MLoopUV *luv; UvNearestHit hit = UV_NEAREST_HIT_INIT; int i, selectmode, sticky, sync, *hitv = NULL; @@ -2175,9 +2130,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); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); - /* 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 @@ -2214,7 +2166,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, em, co, &hit)) { + if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { return OPERATOR_CANCELLED; } @@ -2222,7 +2174,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, em, co, penalty_dist, &hit)) { + if (!uv_find_nearest_vert_multi(scene, ima, objects, objects_len, co, penalty_dist, &hit)) { return OPERATOR_CANCELLED; } @@ -2238,7 +2190,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, em, co, &hit)) { + if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { return OPERATOR_CANCELLED; } @@ -2256,10 +2208,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, em, 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); @@ -2276,7 +2231,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, em, co, &hit)) { + if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { return OPERATOR_CANCELLED; } @@ -2287,13 +2242,25 @@ 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, 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) { + 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); + } /* Current behavior of 'extend' is actually toggling, so pass extend flag as 'toggle' here */ - uv_select_linked(scene, ima, em, limit, &hit, false, false, extend, false); + uv_select_linked_multi(scene, ima, objects, objects_len, limit, &hit, false, false, extend, false); } else if (extend) { if (selectmode == UV_SELECT_VERTEX) { @@ -2328,8 +2295,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo BM_mesh_elem_index_ensure(em->bm, BM_VERT); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -2344,7 +2310,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, em, SEL_DESELECT); + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); if (selectmode == UV_SELECT_VERTEX) { /* select vertex */ @@ -2364,8 +2330,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo /* select sticky uvs */ if (sticky != SI_STICKY_DISABLE) { BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -2408,11 +2373,20 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo #endif } - DAG_id_tag_update(obedit->data, 0); + DEG_id_tag_update(obedit->data, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); 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) { @@ -2517,9 +2491,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, deselect; bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); @@ -2535,6 +2508,9 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent deselect = RNA_boolean_get(op->ptr, "deselect"); 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]; @@ -2550,15 +2526,34 @@ 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, em, co, &hit)) { + if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { + MEM_freeN(objects); return OPERATOR_CANCELLED; } } - uv_select_linked(scene, ima, em, limit, pick ? &hit : NULL, extend, deselect, false, select_faces); + if (!extend) { + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + } - DAG_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, deselect, false, 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, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_SAFE_FREE(objects_free); return OPERATOR_FINISHED; } @@ -2632,12 +2627,10 @@ static int uv_select_split_exec(bContext *C, wmOperator *op) BMFace *efa; BMLoop *l; BMIter iter, liter; - MTexPoly *tf; MLoopUV *luv; bool changed = false; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY); if (ts->uv_flag & UV_SYNC_SELECTION) { BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled"); @@ -2649,9 +2642,8 @@ static int uv_select_split_exec(bContext *C, wmOperator *op) BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { bool is_sel = false; bool is_unsel = false; - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; /* are we all selected? */ @@ -2796,7 +2788,6 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object BMFace *efa; BMLoop *l; BMIter iter, liter; - /* MTexPoly *tf; */ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) { @@ -2882,7 +2873,6 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object BMFace *efa; BMLoop *l; BMIter iter, liter; - /* MTexPoly *tf; */ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); @@ -2960,25 +2950,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; - MTexPoly *tf; 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); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); - /* get rectangle from operator */ WM_operator_properties_border_to_rctf(op, &rectf); UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf); @@ -2988,80 +2973,96 @@ static int uv_border_select_exec(bContext *C, wmOperator *op) extend = RNA_boolean_get(op->ptr, "extend"); pinned = RNA_boolean_get(op->ptr, "pinned"); - if (!extend) - uv_select_all_perform(scene, ima, em, SEL_DESELECT); + bool changed_multi = false; - /* do actual selection */ - if (use_face_center && !pinned) { - /* handle face selection mode */ - float cent[2]; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len); - changed = false; + /* 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); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - /* assume not touched */ - BM_elem_flag_disable(efa, BM_ELEM_TAG); + bool changed = false; - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (uvedit_face_visible_test(scene, ima, efa, tf)) { - uv_poly_center(efa, cent, cd_loop_uv_offset); - if (BLI_rctf_isect_pt_v(&rectf, cent)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - changed = true; + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (!extend) + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + + /* do actual selection */ + if (use_face_center && !pinned) { + /* handle face selection mode */ + float cent[2]; + + changed = false; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + /* assume not touched */ + BM_elem_flag_disable(efa, BM_ELEM_TAG); + + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + uv_poly_center(efa, cent, cd_loop_uv_offset); + if (BLI_rctf_isect_pt_v(&rectf, cent)) { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + changed = true; + } } } - } - /* (de)selects all tagged faces and deals with sticky modes */ - if (changed) { - uv_select_flush_from_tag_face(sima, scene, obedit, select); + /* (de)selects all tagged faces and deals with sticky modes */ + if (changed) { + uv_select_flush_from_tag_face(sima, scene, obedit, select); + } } - } - else { - /* other selection modes */ - changed = true; - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + else { + /* other selection modes */ + changed = true; + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tf)) - continue; - 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 (!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 (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) { + if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) { - /* UV_SYNC_SELECTION - can't do pinned selection */ - if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - BM_elem_flag_enable(l->v, BM_ELEM_TAG); + /* UV_SYNC_SELECTION - can't do pinned selection */ + if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } } - } - else if (pinned) { - if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - BM_elem_flag_enable(l->v, BM_ELEM_TAG); + else if (pinned) { + if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } } } } - } - if (sima->sticky == SI_STICKY_VERTEX) { - uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } } - } - if (changed) { - uv_select_sync_flush(ts, em, select); + if (changed) { + changed_multi = true; - if (ts->uv_flag & UV_SYNC_SELECTION) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } + uv_select_sync_flush(ts, em, select); - return OPERATOR_FINISHED; + if (ts->uv_flag & UV_SYNC_SELECTION) { + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + } } - return OPERATOR_CANCELLED; + MEM_freeN(objects); + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } static void UV_OT_select_border(wmOperatorType *ot) @@ -3183,6 +3184,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) if (changed) { uv_select_sync_flush(ts, em, select); + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } @@ -3216,102 +3218,113 @@ 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); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); BMIter iter, liter; BMFace *efa; BMLoop *l; - MTexPoly *tf; int screen_uv[2]; - bool changed = false; + bool changed_multi = false; rcti rect; BLI_lasso_boundbox(&rect, mcords, moves); - if (!extend && select) { - uv_select_all_perform(scene, ima, em, SEL_DESELECT); - } + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len); - if (use_face_center) { /* Face Center Sel */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_elem_flag_disable(efa, BM_ELEM_TAG); - /* assume not touched */ - if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { - float cent[2]; - uv_poly_center(efa, cent, cd_loop_uv_offset); + /* don't indent to avoid diff noise! */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; - if (UI_view2d_view_to_region_clip(&ar->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) && - BLI_rcti_isect_pt_v(&rect, screen_uv) && - BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) - { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - changed = true; + 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_multi(scene, ima, objects, objects_len, SEL_DESELECT); + } + + if (use_face_center) { /* Face Center Sel */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_elem_flag_disable(efa, BM_ELEM_TAG); + /* assume not touched */ + if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + float cent[2]; + uv_poly_center(efa, cent, cd_loop_uv_offset); + + if (UI_view2d_view_to_region_clip(&ar->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) && + BLI_rcti_isect_pt_v(&rect, screen_uv) && + BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) + { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + changed = true; + } } } - } - /* (de)selects all tagged faces and deals with sticky modes */ - if (changed) { - uv_select_flush_from_tag_face(sima, scene, obedit, select); + /* (de)selects all tagged faces and deals with sticky modes */ + if (changed) { + uv_select_flush_from_tag_face(sima, scene, obedit, select); + } } - } - else { /* Vert Sel */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + else { /* Vert Sel */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (uvedit_face_visible_test(scene, ima, efa, tf)) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (UI_view2d_view_to_region_clip( - &ar->v2d, - luv->uv[0], luv->uv[1], - &screen_uv[0], &screen_uv[1]) && - BLI_rcti_isect_pt_v(&rect, screen_uv) && - BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) - { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - changed = true; - BM_elem_flag_enable(l->v, BM_ELEM_TAG); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (UI_view2d_view_to_region_clip( + &ar->v2d, + luv->uv[0], luv->uv[1], + &screen_uv[0], &screen_uv[1]) && + BLI_rcti_isect_pt_v(&rect, screen_uv) && + BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) + { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + changed = true; + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } } } } } - } - if (sima->sticky == SI_STICKY_VERTEX) { - uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } } - } - if (changed) { - uv_select_sync_flush(scene->toolsettings, em, select); + if (changed) { + changed_multi = true; - if (ts->uv_flag & UV_SYNC_SELECTION) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + uv_select_sync_flush(scene->toolsettings, em, select); + + if (ts->uv_flag & UV_SYNC_SELECTION) { + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } } } - return changed; + return changed_multi; } static int uv_lasso_select_exec(bContext *C, wmOperator *op) @@ -3374,17 +3387,16 @@ static void uv_snap_cursor_to_pixels(SpaceImage *sima) uv_snap_to_pixel(sima->cursor, width, height); } -static bool uv_snap_cursor_to_selection(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima) +static bool uv_snap_cursor_to_selection( + Scene *scene, Image *ima, Object **objects_edit, uint objects_len, SpaceImage *sima) { - return uvedit_center(scene, ima, obedit, sima->cursor, sima->around); + return ED_uvedit_center_multi(scene, ima, objects_edit, objects_len, sima->cursor, sima->around); } static int uv_snap_cursor_exec(bContext *C, wmOperator *op) { SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - Image *ima = CTX_data_edit_image(C); + bool changed = false; switch (RNA_enum_get(op->ptr, "target")) { @@ -3393,8 +3405,18 @@ static int uv_snap_cursor_exec(bContext *C, wmOperator *op) changed = true; break; case 1: - changed = uv_snap_cursor_to_selection(scene, ima, obedit, sima); + { + Scene *scene = CTX_data_scene(C); + Image *ima = CTX_data_edit_image(C); + 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); + changed = uv_snap_cursor_to_selection(scene, ima, objects, objects_len, sima); + MEM_freeN(objects); break; + } } if (!changed) @@ -3438,16 +3460,13 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, cons BMFace *efa; BMLoop *l; BMIter iter, liter; - MTexPoly *tface; MLoopUV *luv; bool changed = false; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tface = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tface)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -3468,16 +3487,13 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f BMFace *efa; BMLoop *l; BMIter iter, liter; - MTexPoly *mtexpoly; MLoopUV *luv; bool changed = false; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - mtexpoly = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, mtexpoly)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -3499,17 +3515,14 @@ static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object BMFace *f; BMLoop *l, *lsub; BMIter iter, liter, lsubiter; - MTexPoly *tface; MLoopUV *luv; bool changed = false; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY); /* index every vert that has a selected UV using it, but only once so as to * get unique indices and to count how much to malloc */ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - tface = BM_ELEM_CD_GET_VOID_P(f, cd_poly_tex_offset); - if (uvedit_face_visible_test(scene, ima, f, tface)) { + if (uvedit_face_visible_test(scene, obedit, ima, f)) { BM_elem_flag_enable(f, BM_ELEM_TAG); BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset)); @@ -3557,22 +3570,19 @@ static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit BMFace *efa; BMLoop *l; BMIter iter, liter; - MTexPoly *tface; MLoopUV *luv; int width = 0, height = 0; float w, h; bool changed = false; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); ED_space_image_get_size(sima, &width, &height); w = (float)width; h = (float)height; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tface = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tface)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -3606,7 +3616,7 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op) case 2: { float center[2]; - if (uvedit_center(scene, ima, obedit, center, sima->around)) { + if (ED_uvedit_center(scene, ima, obedit, center, sima->around)) { float offset[2]; sub_v2_v2v2(offset, sima->cursor, center); changed = uv_snap_uvs_offset(scene, ima, obedit, offset); @@ -3622,7 +3632,7 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; uvedit_live_unwrap_update(sima, scene, obedit); - DAG_id_tag_update(obedit->data, 0); + DEG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); return OPERATOR_FINISHED; @@ -3666,16 +3676,13 @@ static int uv_pin_exec(bContext *C, wmOperator *op) BMFace *efa; BMLoop *l; BMIter iter, liter; - MTexPoly *tface; MLoopUV *luv; const bool clear = RNA_boolean_get(op->ptr, "clear"); const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tface = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tface)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -3728,15 +3735,12 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) BMFace *efa; BMLoop *l; BMIter iter, liter; - MTexPoly *tface; MLoopUV *luv; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tface = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - if (!uvedit_face_visible_test(scene, ima, efa, tface)) + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) continue; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -3747,6 +3751,7 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) } } + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -3805,16 +3810,16 @@ static int uv_hide_exec(bContext *C, wmOperator *op) BMLoop *l; BMIter iter, liter; MLoopUV *luv; - MTexPoly *tf; const bool swap = RNA_boolean_get(op->ptr, "unselected"); Image *ima = sima ? sima->image : NULL; const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE); const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); if (ts->uv_flag & UV_SYNC_SELECTION) { EDBM_mesh_hide(em, swap); + + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -3823,9 +3828,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op) BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { int hide = 0; - tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - - if (!uvedit_face_visible_test(scene, ima, efa, tf)) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { continue; } @@ -3885,6 +3888,8 @@ static int uv_hide_exec(bContext *C, wmOperator *op) EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX | SCE_SELECT_EDGE); BM_select_history_validate(em->bm); + + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -3938,6 +3943,7 @@ static int uv_reveal_exec(bContext *C, wmOperator *op) /* call the mesh function if we are in mesh sync sel */ if (ts->uv_flag & UV_SYNC_SELECTION) { EDBM_mesh_reveal(em, select); + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -4027,6 +4033,7 @@ static int uv_reveal_exec(bContext *C, wmOperator *op) /* re-select tagged faces */ BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG); + DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -4117,76 +4124,6 @@ static void UV_OT_cursor_set(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Set Tile Operator - * \{ */ - -static int set_tile_exec(bContext *C, wmOperator *op) -{ - Image *ima = CTX_data_edit_image(C); - int tile[2]; - Object *obedit = CTX_data_edit_object(C); - - RNA_int_get_array(op->ptr, "tile", tile); - - if (uvedit_set_tile(obedit, ima, tile[0] + ima->xrep * tile[1])) { - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL); - - return OPERATOR_FINISHED; - } - - return OPERATOR_CANCELLED; -} - -static int set_tile_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); - ARegion *ar = CTX_wm_region(C); - float fx, fy; - int tile[2]; - - if (!ima || !(ima->tpageflag & IMA_TILES)) - return OPERATOR_CANCELLED; - - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy); - - if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) { - fx = fx * ima->xrep; - fy = fy * ima->yrep; - - tile[0] = fx; - tile[1] = fy; - - sima->curtile = tile[1] * ima->xrep + tile[0]; - RNA_int_set_array(op->ptr, "tile", tile); - } - - return set_tile_exec(C, op); -} - -static void UV_OT_tile_set(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Set Tile"; - ot->description = "Set UV image tile coordinates"; - ot->idname = "UV_OT_tile_set"; - - /* api callbacks */ - ot->exec = set_tile_exec; - ot->invoke = set_tile_invoke; - ot->poll = ED_operator_image_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_int_vector(ot->srna, "tile", 2, NULL, 0, INT_MAX, "Tile", "Tile coordinate", 0, 10); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Seam from UV Islands Operator * \{ */ @@ -4299,7 +4236,7 @@ static int uv_seams_from_islands_exec(bContext *C, wmOperator *op) BM_uv_vert_map_free(vmap); - DAG_id_tag_update(&me->id, 0); + DEG_id_tag_update(&me->id, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); return OPERATOR_FINISHED; @@ -4355,9 +4292,9 @@ 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); - DAG_id_tag_update(&me->id, 0); + DEG_id_tag_update(&me->id, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); return OPERATOR_FINISHED; @@ -4450,7 +4387,6 @@ void ED_operatortypes_uvedit(void) WM_operatortype_append(UV_OT_hide); WM_operatortype_append(UV_OT_cursor_set); - WM_operatortype_append(UV_OT_tile_set); } void ED_keymap_uvedit(wmKeyConfig *keyconf) @@ -4513,7 +4449,7 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "UV_OT_select_pinned", PKEY, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_weldalign", WKEY, KM_PRESS, 0, 0); + WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_weldalign", WKEY, KM_PRESS, KM_SHIFT, 0); /* uv operations */ WM_keymap_add_item(keymap, "UV_OT_stitch", VKEY, KM_PRESS, 0, 0); @@ -4538,7 +4474,6 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf) /* cursor */ WM_keymap_add_item(keymap, "UV_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "UV_OT_tile_set", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0); /* menus */ WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_snap", SKEY, KM_PRESS, KM_SHIFT, 0); diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index e4452af4790..9091f3eff0b 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -52,10 +52,11 @@ #include "BKE_context.h" #include "BKE_customdata.h" -#include "BKE_depsgraph.h" #include "BKE_mesh_mapping.h" #include "BKE_editmesh.h" +#include "DEG_depsgraph.h" + #include "UI_interface.h" #include "ED_mesh.h" @@ -63,6 +64,9 @@ #include "ED_screen.h" #include "ED_space_api.h" +#include "GPU_batch.h" +#include "GPU_state.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -154,6 +158,8 @@ typedef struct StitchState { bool snap_islands; /* stitch at midpoints or at islands */ bool midpoints; + /* object for editmesh */ + Object *obedit; /* editmesh, cached for use in modal handler */ BMEditMesh *em; /* clear seams of stitched edges after stitch */ @@ -286,7 +292,7 @@ static void stitch_update_header(StitchState *state, bContext *C) state->limit_dist, WM_bool_as_string(state->use_limit)); - ED_area_headerprint(sa, msg); + ED_workspace_status_text(C, msg); } } @@ -1538,63 +1544,126 @@ static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *no normalize_v2(normal); } +/** + */ +static void stitch_draw_vbo(Gwn_VertBuf *vbo, Gwn_PrimType prim_type, const float col[4]) +{ + Gwn_Batch *batch = GWN_batch_create_ex(prim_type, vbo, NULL, GWN_BATCH_OWNS_VBO); + GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR); + GWN_batch_uniform_4fv(batch, "color", col); + GWN_batch_draw(batch); + GWN_batch_discard(batch); +} + +/* TODO make things pretier : store batches inside StitchPreviewer instead of the bare verts pos */ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) { - int i, index = 0; + int j, index = 0; + unsigned int num_line = 0, num_tri, tri_idx = 0, line_idx = 0; StitchState *state = (StitchState *)arg; StitchPreviewer *stitch_preview = state->stitch_preview; + Gwn_VertBuf *vbo, *vbo_line; + float col[4]; + + static Gwn_VertFormat format = { 0 }; + static unsigned int pos_id; + if (format.attrib_ct == 0) { + pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + + GPU_blend(true); + + /* Static Tris */ + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_ACTIVE, col); + vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, stitch_preview->num_static_tris * 3); + for (int i = 0; i < stitch_preview->num_static_tris * 3; i++) { + GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->static_tris[i * 2]); + } + stitch_draw_vbo(vbo, GWN_PRIM_TRIS, col); + - glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); - glEnableClientState(GL_VERTEX_ARRAY); + /* Preview Polys */ + for (int i = 0; i < stitch_preview->num_polys; i++) + num_line += stitch_preview->uvs_per_polygon[i]; - glEnable(GL_BLEND); + num_tri = num_line - 2 * stitch_preview->num_polys; - UI_ThemeColor4(TH_STITCH_PREVIEW_ACTIVE); - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->static_tris); - glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_static_tris * 3); + /* we need to convert the polys into triangles / lines */ + vbo = GWN_vertbuf_create_with_format(&format); + vbo_line = GWN_vertbuf_create_with_format(&format); - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_polys); - for (i = 0; i < stitch_preview->num_polys; i++) { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - UI_ThemeColor4(TH_STITCH_PREVIEW_FACE); - glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - UI_ThemeColor4(TH_STITCH_PREVIEW_EDGE); - glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]); -#if 0 - glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); - UI_ThemeColor4(TH_STITCH_PREVIEW_VERT); - glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]); -#endif + GWN_vertbuf_data_alloc(vbo, num_tri * 3); + GWN_vertbuf_data_alloc(vbo_line, num_line * 2); - index += stitch_preview->uvs_per_polygon[i]; + for (int i = 0; i < stitch_preview->num_polys; i++) { + BLI_assert(stitch_preview->uvs_per_polygon[i] >= 3); + + /* Start line */ + GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]); + GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + 2]); + + for (j = 1; j < stitch_preview->uvs_per_polygon[i] - 1; ++j) { + GWN_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]); + GWN_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]); + GWN_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]); + + GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]); + GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]); + } + + /* Closing line */ + GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]); + /* j = uvs_per_polygon[i] - 1*/ + GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + j * 2]); + + index += stitch_preview->uvs_per_polygon[i] * 2; } - glDisable(GL_BLEND); + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_FACE, col); + stitch_draw_vbo(vbo, GWN_PRIM_TRIS, col); + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_EDGE, col); + stitch_draw_vbo(vbo_line, GWN_PRIM_LINES, col); + + GPU_blend(false); - /* draw vert preview */ + + /* draw stitch vert/lines preview */ if (state->mode == STITCH_VERT) { - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f); + GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f); - UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE); - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable); - glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable); + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col); + vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable); + for (int i = 0; i < stitch_preview->num_stitchable; i++) { + GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]); + } + stitch_draw_vbo(vbo, GWN_PRIM_POINTS, col); - UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE); - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable); - glDrawArrays(GL_POINTS, 0, stitch_preview->num_unstitchable); + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col); + vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable); + for (int i = 0; i < stitch_preview->num_unstitchable; i++) { + GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]); + } + stitch_draw_vbo(vbo, GWN_PRIM_POINTS, col); } else { - UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE); - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable); - glDrawArrays(GL_LINES, 0, 2 * stitch_preview->num_stitchable); + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col); + vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable * 2); + for (int i = 0; i < stitch_preview->num_stitchable * 2; i++) { + GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]); + } + stitch_draw_vbo(vbo, GWN_PRIM_LINES, col); - UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE); - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable); - glDrawArrays(GL_LINES, 0, 2 * stitch_preview->num_unstitchable); + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col); + vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable * 2); + for (int i = 0; i < stitch_preview->num_unstitchable * 2; i++) { + GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]); + } + stitch_draw_vbo(vbo, GWN_PRIM_LINES, col); } - - glPopClientAttrib(); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } static UvEdge *uv_edge_get(BMLoop *l, StitchState *state) @@ -1653,6 +1722,7 @@ static int stitch_init(bContext *C, wmOperator *op) /* initialize state */ state->use_limit = RNA_boolean_get(op->ptr, "use_limit"); state->limit_dist = RNA_float_get(op->ptr, "limit"); + state->obedit = obedit; state->em = em; state->snap_islands = RNA_boolean_get(op->ptr, "snap_islands"); state->static_island = RNA_int_get(op->ptr, "static_island"); @@ -2020,11 +2090,11 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished) } if (sa) - ED_area_headerprint(sa, NULL); + ED_workspace_status_text(C, NULL); ED_region_draw_cb_exit(CTX_wm_region(C)->type, state->draw_handle); - DAG_id_tag_update(obedit->data, 0); + DEG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); state_delete(state); @@ -2066,7 +2136,7 @@ static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, Stitc if (state->mode == STITCH_VERT) { if (uv_find_nearest_vert( - scene, ima, state->em, co, 0.0f, &hit)) + scene, ima, state->obedit, co, 0.0f, &hit)) { /* Add vertex to selection, deselect all common uv's of vert other * than selected and update the preview. This behavior was decided so that @@ -2080,7 +2150,7 @@ static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, Stitc } else { if (uv_find_nearest_edge( - scene, ima, state->em, co, &hit)) + scene, ima, state->obedit, co, &hit)) { UvEdge *edge = uv_edge_get(hit.l, state); stitch_select_edge(edge, state, false); diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index dbe8796ba8b..eb14ca9ae2d 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); @@ -563,14 +656,14 @@ 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); + DEG_id_tag_update(ms->obedit->data, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ms->obedit->data); } } @@ -580,8 +673,9 @@ static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel) MinStretch *ms = op->customdata; ScrArea *sa = CTX_wm_area(C); - if (sa) - ED_area_headerprint(sa, NULL); + ED_area_status_text(sa, NULL); + ED_workspace_status_text(C, NULL); + if (ms->timer) WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ms->timer); @@ -593,7 +687,7 @@ 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); + DEG_id_tag_update(ms->obedit->data, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ms->obedit->data); MEM_freeN(ms); @@ -714,6 +808,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 +818,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 +849,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); - 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]; + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -784,7 +899,7 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op)) param_flush(handle); param_delete(handle); - DAG_id_tag_update(obedit->data, 0); + DEG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); return OPERATOR_FINISHED; @@ -855,7 +970,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 +1018,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 +1040,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: @@ -1108,7 +1223,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 +1234,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 +1283,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 +1333,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 +1345,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; - 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"); + 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"); + + + /* 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 +1409,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); + } - DAG_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_freeN(objects); return OPERATOR_FINISHED; } @@ -1321,9 +1474,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 +1485,98 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) BMIter iter, liter; MLoopUV *luv; float rotmat[4][4]; + bool changed_multi = false; + + /* 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); + 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; + } - int cd_loop_uv_offset; - - /* add uvs if they don't exist yet */ - if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { - return OPERATOR_CANCELLED; - } + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - 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); - if (RNA_boolean_get(op->ptr, "orthographic")) { - uv_map_rotation_matrix(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f); + 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_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; + } - 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); + MEM_freeN(uci); } } - } - 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); + else { + copy_m4_m4(rotmat, obedit->obmat); - 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); + BLI_uvproject_from_view(luv->uv, l->v->co, rv3d->persmat, rotmat, ar->winx, ar->winy); } + changed = true; } - - MEM_freeN(uci); } - } - 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_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); - } + 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 int uv_from_view_poll(bContext *C) @@ -1435,18 +1616,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 +1674,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 +1706,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_clip_correct(scene, obedit, em, op); + uv_map_mirror(em, efa); + } - 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; } @@ -1594,46 +1794,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 +1870,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 +1907,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; + + if (!RNA_property_is_set(op->ptr, prop_cube_size)) { + bounds_buf = bounds; + } + + 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); + ED_uvedit_unwrap_cube_project(em->bm, cube_size, true, center); - 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; } |