diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/uvedit | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/uvedit')
-rw-r--r-- | source/blender/editors/uvedit/CMakeLists.txt | 48 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_buttons.c | 315 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_draw.c | 759 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_intern.h | 93 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_ops.c | 7665 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_parametrizer.c | 6861 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_parametrizer.h | 14 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_smart_stitch.c | 4920 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_unwrap_ops.c | 3645 |
9 files changed, 12421 insertions, 11899 deletions
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt index 45cd9b09de3..240cfd382a4 100644 --- a/source/blender/editors/uvedit/CMakeLists.txt +++ b/source/blender/editors/uvedit/CMakeLists.txt @@ -16,42 +16,42 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - ../include - ../../blenkernel - ../../blenlib - ../../blentranslation - ../../bmesh - ../../depsgraph - ../../gpu - ../../makesdna - ../../makesrna - ../../windowmanager - ../../../../intern/guardedalloc - ../../../../intern/eigen - ../../../../intern/glew-mx + ../include + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../bmesh + ../../depsgraph + ../../gpu + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/guardedalloc + ../../../../intern/eigen + ../../../../intern/glew-mx ) set(INC_SYS - ${GLEW_INCLUDE_PATH} + ${GLEW_INCLUDE_PATH} ) set(SRC - uvedit_buttons.c - uvedit_draw.c - uvedit_ops.c - uvedit_parametrizer.c - uvedit_smart_stitch.c - uvedit_unwrap_ops.c - - uvedit_intern.h - uvedit_parametrizer.h + uvedit_buttons.c + uvedit_draw.c + uvedit_ops.c + uvedit_parametrizer.c + uvedit_smart_stitch.c + uvedit_unwrap_ops.c + + uvedit_intern.h + uvedit_parametrizer.h ) set(LIB ) if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) endif() add_definitions(${GL_DEFINITIONS}) diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c index 6f8bfac8c57..16620436029 100644 --- a/source/blender/editors/uvedit/uvedit_buttons.c +++ b/source/blender/editors/uvedit/uvedit_buttons.c @@ -53,62 +53,63 @@ #include "WM_api.h" #include "WM_types.h" -#define B_UVEDIT_VERTEX 3 +#define B_UVEDIT_VERTEX 3 /* UV Utilities */ static int uvedit_center(Scene *scene, Object *obedit, BMEditMesh *em, Image *ima, float center[2]) { - BMFace *f; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - int tot = 0; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - zero_v2(center); - BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, f)) - continue; - - BM_ITER_ELEM (l, &liter, f, 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); - add_v2_v2(center, luv->uv); - tot++; - } - } - } - - if (tot > 0) { - center[0] /= tot; - center[1] /= tot; - } - - return tot; + BMFace *f; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + int tot = 0; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + zero_v2(center); + BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, f)) + continue; + + BM_ITER_ELEM (l, &liter, f, 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); + add_v2_v2(center, luv->uv); + tot++; + } + } + } + + if (tot > 0) { + center[0] /= tot; + center[1] /= tot; + } + + return tot; } -static void uvedit_translate(Scene *scene, Object *obedit, 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; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, f)) - continue; - - BM_ITER_ELEM (l, &liter, f, 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); - add_v2_v2(luv->uv, delta); - } - } - } + BMFace *f; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, f)) + continue; + + BM_ITER_ELEM (l, &liter, f, 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); + add_v2_v2(luv->uv, delta); + } + } + } } /* Button Functions, using an evil static variable */ @@ -117,122 +118,144 @@ static float uvedit_old_center[2]; static void uvedit_vertex_buttons(const bContext *C, uiBlock *block) { - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - Image *ima = sima->image; - BMEditMesh *em; - float center[2]; - int imx, imy, step, digits; - float width = 8 * UI_UNIT_X; - - ED_space_image_get_size(sima, &imx, &imy); - - em = BKE_editmesh_from_object(obedit); - - if (uvedit_center(scene, obedit, em, ima, center)) { - float range_xy[2][2] = { - {-10.0f, 10.0f}, - {-10.0f, 10.0f}, - }; - - copy_v2_v2(uvedit_old_center, center); - - /* expand UI range by center */ - CLAMP_MAX(range_xy[0][0], uvedit_old_center[0]); - CLAMP_MIN(range_xy[0][1], uvedit_old_center[0]); - CLAMP_MAX(range_xy[1][0], uvedit_old_center[1]); - CLAMP_MIN(range_xy[1][1], uvedit_old_center[1]); - - if (!(sima->flag & SI_COORDFLOATS)) { - uvedit_old_center[0] *= imx; - uvedit_old_center[1] *= imy; - - mul_v2_fl(range_xy[0], imx); - mul_v2_fl(range_xy[1], imy); - } - - if (sima->flag & SI_COORDFLOATS) { - step = 1; - digits = 3; - } - else { - step = 100; - digits = 2; - } - - UI_block_align_begin(block); - uiDefButF(block, UI_BTYPE_NUM, B_UVEDIT_VERTEX, IFACE_("X:"), 0, 0, width, UI_UNIT_Y, &uvedit_old_center[0], - UNPACK2(range_xy[0]), step, digits, ""); - uiDefButF(block, UI_BTYPE_NUM, B_UVEDIT_VERTEX, IFACE_("Y:"), width, 0, width, UI_UNIT_Y, &uvedit_old_center[1], - UNPACK2(range_xy[1]), step, digits, ""); - UI_block_align_end(block); - } + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + Image *ima = sima->image; + BMEditMesh *em; + float center[2]; + int imx, imy, step, digits; + float width = 8 * UI_UNIT_X; + + ED_space_image_get_size(sima, &imx, &imy); + + em = BKE_editmesh_from_object(obedit); + + if (uvedit_center(scene, obedit, em, ima, center)) { + float range_xy[2][2] = { + {-10.0f, 10.0f}, + {-10.0f, 10.0f}, + }; + + copy_v2_v2(uvedit_old_center, center); + + /* expand UI range by center */ + CLAMP_MAX(range_xy[0][0], uvedit_old_center[0]); + CLAMP_MIN(range_xy[0][1], uvedit_old_center[0]); + CLAMP_MAX(range_xy[1][0], uvedit_old_center[1]); + CLAMP_MIN(range_xy[1][1], uvedit_old_center[1]); + + if (!(sima->flag & SI_COORDFLOATS)) { + uvedit_old_center[0] *= imx; + uvedit_old_center[1] *= imy; + + mul_v2_fl(range_xy[0], imx); + mul_v2_fl(range_xy[1], imy); + } + + if (sima->flag & SI_COORDFLOATS) { + step = 1; + digits = 3; + } + else { + step = 100; + digits = 2; + } + + UI_block_align_begin(block); + uiDefButF(block, + UI_BTYPE_NUM, + B_UVEDIT_VERTEX, + IFACE_("X:"), + 0, + 0, + width, + UI_UNIT_Y, + &uvedit_old_center[0], + UNPACK2(range_xy[0]), + step, + digits, + ""); + uiDefButF(block, + UI_BTYPE_NUM, + B_UVEDIT_VERTEX, + IFACE_("Y:"), + width, + 0, + width, + UI_UNIT_Y, + &uvedit_old_center[1], + UNPACK2(range_xy[1]), + step, + digits, + ""); + UI_block_align_end(block); + } } static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) { - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - Image *ima = sima->image; - BMEditMesh *em; - float center[2], delta[2]; - int imx, imy; - - if (event != B_UVEDIT_VERTEX) - return; - - em = BKE_editmesh_from_object(obedit); - - ED_space_image_get_size(sima, &imx, &imy); - uvedit_center(scene, obedit, em, ima, center); - - if (sima->flag & SI_COORDFLOATS) { - delta[0] = uvedit_old_center[0] - center[0]; - delta[1] = uvedit_old_center[1] - center[1]; - } - else { - delta[0] = uvedit_old_center[0] / imx - center[0]; - delta[1] = uvedit_old_center[1] / imy - center[1]; - } - - uvedit_translate(scene, obedit, em, ima, delta); - - WM_event_add_notifier(C, NC_IMAGE, sima->image); - DEG_id_tag_update((ID *)obedit->data, ID_RECALC_GEOMETRY); + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + Image *ima = sima->image; + BMEditMesh *em; + float center[2], delta[2]; + int imx, imy; + + if (event != B_UVEDIT_VERTEX) + return; + + em = BKE_editmesh_from_object(obedit); + + ED_space_image_get_size(sima, &imx, &imy); + uvedit_center(scene, obedit, em, ima, center); + + if (sima->flag & SI_COORDFLOATS) { + delta[0] = uvedit_old_center[0] - center[0]; + delta[1] = uvedit_old_center[1] - center[1]; + } + else { + delta[0] = uvedit_old_center[0] / imx - center[0]; + delta[1] = uvedit_old_center[1] / imy - center[1]; + } + + uvedit_translate(scene, obedit, em, ima, delta); + + WM_event_add_notifier(C, NC_IMAGE, sima->image); + DEG_id_tag_update((ID *)obedit->data, ID_RECALC_GEOMETRY); } /* Panels */ static bool image_panel_uv_poll(const bContext *C, PanelType *UNUSED(pt)) { - SpaceImage *sima = CTX_wm_space_image(C); - if (sima->mode != SI_MODE_UV) { - return false; - } - Object *obedit = CTX_data_edit_object(C); - return ED_uvedit_test(obedit); + SpaceImage *sima = CTX_wm_space_image(C); + if (sima->mode != SI_MODE_UV) { + return false; + } + Object *obedit = CTX_data_edit_object(C); + return ED_uvedit_test(obedit); } static void image_panel_uv(const bContext *C, Panel *pa) { - uiBlock *block; + uiBlock *block; - block = uiLayoutAbsoluteBlock(pa->layout); - UI_block_func_handle_set(block, do_uvedit_vertex, NULL); + block = uiLayoutAbsoluteBlock(pa->layout); + UI_block_func_handle_set(block, do_uvedit_vertex, NULL); - uvedit_vertex_buttons(C, block); + uvedit_vertex_buttons(C, block); } void ED_uvedit_buttons_register(ARegionType *art) { - PanelType *pt; - - pt = MEM_callocN(sizeof(PanelType), "spacetype image panel uv"); - strcpy(pt->idname, "IMAGE_PT_uv"); - strcpy(pt->label, N_("UV Vertex")); /* XXX C panels unavailable through RNA bpy.types! */ - pt->draw = image_panel_uv; - pt->poll = image_panel_uv_poll; - BLI_addtail(&art->paneltypes, pt); + PanelType *pt; + + pt = MEM_callocN(sizeof(PanelType), "spacetype image panel uv"); + strcpy(pt->idname, "IMAGE_PT_uv"); + strcpy(pt->label, N_("UV Vertex")); /* XXX C panels unavailable through RNA bpy.types! */ + pt->draw = image_panel_uv; + pt->poll = image_panel_uv_poll; + BLI_addtail(&art->paneltypes, pt); } diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 8bc2be11934..5ff90097840 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -21,7 +21,6 @@ * \ingroup eduv */ - #include <float.h> #include <math.h> #include <stdlib.h> @@ -71,434 +70,442 @@ static int draw_uvs_face_check(const ToolSettings *ts) { - /* checks if we are selecting only faces */ - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode == SCE_SELECT_FACE) - return 2; - else if (ts->selectmode & SCE_SELECT_FACE) - return 1; - else - return 0; - } - else - return (ts->uv_selectmode == UV_SELECT_FACE); + /* checks if we are selecting only faces */ + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode == SCE_SELECT_FACE) + return 2; + else if (ts->selectmode & SCE_SELECT_FACE) + return 1; + else + return 0; + } + else + return (ts->uv_selectmode == UV_SELECT_FACE); } /* ------------------------- */ void ED_image_draw_cursor(ARegion *ar, const float cursor[2]) { - float zoom[2], x_fac, y_fac; + float zoom[2], x_fac, y_fac; - UI_view2d_scale_get_inverse(&ar->v2d, &zoom[0], &zoom[1]); + UI_view2d_scale_get_inverse(&ar->v2d, &zoom[0], &zoom[1]); - mul_v2_fl(zoom, 256.0f * UI_DPI_FAC); - x_fac = zoom[0]; - y_fac = zoom[1]; + mul_v2_fl(zoom, 256.0f * UI_DPI_FAC); + x_fac = zoom[0]; + y_fac = zoom[1]; - GPU_line_width(1.0f); + GPU_line_width(1.0f); - GPU_matrix_translate_2fv(cursor); + GPU_matrix_translate_2fv(cursor); - const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + const uint shdr_pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); - immUniform1i("colors_len", 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); + immUniform1i("colors_len", 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(GPU_PRIM_LINES, 8); + immBegin(GPU_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.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.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.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.0f, -0.05f * y_fac); + immVertex2f(shdr_pos, -0.05f * x_fac, 0.0f); - immEnd(); + 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); + 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(GPU_PRIM_LINES, 8); + immBegin(GPU_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.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.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.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); + immVertex2f(shdr_pos, 0.0f, 0.1f * y_fac); + immVertex2f(shdr_pos, 0.0f, 0.020f * y_fac); - immEnd(); + immEnd(); - immUnbindProgram(); + immUnbindProgram(); - GPU_matrix_translate_2f(-cursor[0], -cursor[1]); + GPU_matrix_translate_2f(-cursor[0], -cursor[1]); } -static void uvedit_get_batches( - Object *ob, SpaceImage *sima, const ToolSettings *ts, - GPUBatch **faces, GPUBatch **edges, GPUBatch **verts, GPUBatch **facedots) +static void uvedit_get_batches(Object *ob, + SpaceImage *sima, + const ToolSettings *ts, + GPUBatch **faces, + GPUBatch **edges, + GPUBatch **verts, + GPUBatch **facedots) { - int drawfaces = draw_uvs_face_check(ts); - const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0; - const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0; - - *edges = DRW_mesh_batch_cache_get_edituv_edges(ob->data); - *verts = DRW_mesh_batch_cache_get_edituv_verts(ob->data); - - if (drawfaces) { - *facedots = DRW_mesh_batch_cache_get_edituv_facedots(ob->data); - } - else { - *facedots = NULL; - } - - if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) { - *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_area(ob->data); - } - else if (draw_stretch) { - *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_angle(ob->data); - } - else if (draw_faces) { - *faces = DRW_mesh_batch_cache_get_edituv_faces(ob->data); - } - else { - *faces = NULL; - } - - DRW_mesh_batch_cache_create_requested(ob, ob->data, ts, false, false); + int drawfaces = draw_uvs_face_check(ts); + const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0; + const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0; + + *edges = DRW_mesh_batch_cache_get_edituv_edges(ob->data); + *verts = DRW_mesh_batch_cache_get_edituv_verts(ob->data); + + if (drawfaces) { + *facedots = DRW_mesh_batch_cache_get_edituv_facedots(ob->data); + } + else { + *facedots = NULL; + } + + if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) { + *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_area(ob->data); + } + else if (draw_stretch) { + *faces = DRW_mesh_batch_cache_get_edituv_faces_strech_angle(ob->data); + } + else if (draw_faces) { + *faces = DRW_mesh_batch_cache_get_edituv_faces(ob->data); + } + else { + *faces = NULL; + } + + DRW_mesh_batch_cache_create_requested(ob, ob->data, ts, false, false); } -static void draw_uvs_shadow(SpaceImage *UNUSED(sima), Scene *scene, Object *obedit, Depsgraph *depsgraph) +static void draw_uvs_shadow(SpaceImage *UNUSED(sima), + Scene *scene, + Object *obedit, + Depsgraph *depsgraph) { - Object *eval_ob = DEG_get_evaluated_object(depsgraph, obedit); - Mesh *me = eval_ob->data; - float col[4]; - UI_GetThemeColor4fv(TH_UV_SHADOW, col); - - GPUBatch *edges = DRW_mesh_batch_cache_get_uv_edges(me); - DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false); - - if (edges) { - GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UV_UNIFORM_COLOR); - GPU_batch_uniform_4fv(edges, "color", col); - GPU_batch_draw(edges); - } + Object *eval_ob = DEG_get_evaluated_object(depsgraph, obedit); + Mesh *me = eval_ob->data; + float col[4]; + UI_GetThemeColor4fv(TH_UV_SHADOW, col); + + GPUBatch *edges = DRW_mesh_batch_cache_get_uv_edges(me); + DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false); + + if (edges) { + GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UV_UNIFORM_COLOR); + GPU_batch_uniform_4fv(edges, "color", col); + GPU_batch_draw(edges); + } } static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph) { - Object *eval_ob = DEG_get_evaluated_object(depsgraph, ob); - Mesh *me = eval_ob->data; - ToolSettings *ts = scene->toolsettings; - float col[4]; - UI_GetThemeColor4fv(TH_UV_SHADOW, col); - - if (me->mloopuv == NULL) { - return; - } - - GPUBatch *geom = DRW_mesh_batch_cache_get_uv_edges(me); - DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false); - - GPU_batch_program_set_builtin(geom, GPU_SHADER_2D_UV_UNIFORM_COLOR); - GPU_batch_uniform_4fv(geom, "color", col); - - const bool do_material_masking = (ts->uv_flag & UV_SHOW_SAME_IMAGE); - if (do_material_masking && me->mloopuv) { - /* Render loops that have the active material. Minize draw calls. */ - MPoly *mpoly = me->mpoly; - uint draw_start = 0; - uint idx = 0; - bool prev_ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1)); - - GPU_matrix_bind(geom->interface); - - /* TODO(fclem): If drawcall count becomes a problem in the future - * we can use multi draw indirect drawcalls for this. - * (not implemented in GPU module at the time of writing). */ - for (int a = 0; a < me->totpoly; a++, mpoly++) { - bool ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1)); - if (ma_match != prev_ma_match) { - if (ma_match == false) { - GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false); - } - else { - draw_start = idx; - } - } - idx += mpoly->totloop + 1; - prev_ma_match = ma_match; - } - if (prev_ma_match == true) { - GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false); - } - - GPU_batch_program_use_end(geom); - } - else { - GPU_batch_draw(geom); - } + Object *eval_ob = DEG_get_evaluated_object(depsgraph, ob); + Mesh *me = eval_ob->data; + ToolSettings *ts = scene->toolsettings; + float col[4]; + UI_GetThemeColor4fv(TH_UV_SHADOW, col); + + if (me->mloopuv == NULL) { + return; + } + + GPUBatch *geom = DRW_mesh_batch_cache_get_uv_edges(me); + DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false); + + GPU_batch_program_set_builtin(geom, GPU_SHADER_2D_UV_UNIFORM_COLOR); + GPU_batch_uniform_4fv(geom, "color", col); + + const bool do_material_masking = (ts->uv_flag & UV_SHOW_SAME_IMAGE); + if (do_material_masking && me->mloopuv) { + /* Render loops that have the active material. Minize draw calls. */ + MPoly *mpoly = me->mpoly; + uint draw_start = 0; + uint idx = 0; + bool prev_ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1)); + + GPU_matrix_bind(geom->interface); + + /* TODO(fclem): If drawcall count becomes a problem in the future + * we can use multi draw indirect drawcalls for this. + * (not implemented in GPU module at the time of writing). */ + for (int a = 0; a < me->totpoly; a++, mpoly++) { + bool ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1)); + if (ma_match != prev_ma_match) { + if (ma_match == false) { + GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false); + } + else { + draw_start = idx; + } + } + idx += mpoly->totloop + 1; + prev_ma_match = ma_match; + } + if (prev_ma_match == true) { + GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false); + } + + GPU_batch_program_use_end(geom); + } + else { + GPU_batch_draw(geom); + } } /* draws uv's in the image space */ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *depsgraph) { - GPUBatch *faces, *edges, *verts, *facedots; - Object *eval_ob = DEG_get_evaluated_object(depsgraph, obedit); - const ToolSettings *ts = scene->toolsettings; - float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - - if (sima->flag & SI_DRAWSHADOW) { - bool is_cage_like_final_meshes = false; - Mesh *me = (Mesh *)eval_ob->data; - BMEditMesh *embm = me->edit_mesh; - is_cage_like_final_meshes = embm && - embm->mesh_eval_final && - embm->mesh_eval_final->runtime.is_original; - - /* 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) && is_cage_like_final_meshes)) { - draw_uvs_shadow(sima, scene, obedit, depsgraph); - } - } - - uvedit_get_batches( - eval_ob, sima, ts, - &faces, &edges, &verts, &facedots); - - - bool interpedges; - bool do_elem_order_fix = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); - bool do_selected_edges = ((sima->flag & SI_NO_DRAWEDGES) == 0); - bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0; - if (ts->uv_flag & UV_SYNC_SELECTION) { - interpedges = (ts->selectmode & SCE_SELECT_VERTEX) != 0; - } - else { - interpedges = (ts->uv_selectmode == UV_SELECT_VERTEX); - } - - GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - - if (faces) { - GPU_batch_program_set_builtin(faces, (draw_stretch) - ? (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA) - ? GPU_SHADER_2D_UV_FACES_STRETCH_AREA - : GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE - : GPU_SHADER_2D_UV_FACES); - - if (!draw_stretch) { - GPU_blend(true); - - UI_GetThemeColor4fv(TH_FACE, col1); - UI_GetThemeColor4fv(TH_FACE_SELECT, col2); - UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3); - col3[3] *= 0.2; /* Simulate dithering */ - GPU_batch_uniform_4fv(faces, "faceColor", col1); - GPU_batch_uniform_4fv(faces, "selectColor", col2); - GPU_batch_uniform_4fv(faces, "activeColor", col3); - } - else if (sima->dt_uvstretch == SI_UVDT_STRETCH_ANGLE) { - float asp[2]; - ED_space_image_get_uv_aspect(sima, &asp[0], &asp[1]); - GPU_batch_uniform_2fv(faces, "aspect", asp); - } - - GPU_batch_draw(faces); - - if (!draw_stretch) { - GPU_blend(false); - } - } - if (edges) { - if (sima->flag & SI_SMOOTH_UV) { - GPU_line_smooth(true); - GPU_blend(true); - } - switch (sima->dt_uv) { - case SI_UVDT_DASH: - { - float dash_colors[2][4] = {{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}}; - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - - GPU_line_width(1.0f); - GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); - GPU_batch_uniform_4fv_array(edges, "colors", 2, (float *)dash_colors); - GPU_batch_uniform_2f(edges, "viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); - GPU_batch_uniform_1i(edges, "colors_len", 2); /* "advanced" mode */ - GPU_batch_uniform_1f(edges, "dash_width", 4.0f); - GPU_batch_draw(edges); - break; - } - case SI_UVDT_BLACK: - case SI_UVDT_WHITE: - { - GPU_line_width(1.0f); - GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR); - if (sima->dt_uv == SI_UVDT_WHITE) { - GPU_batch_uniform_4f(edges, "color", 1.0f, 1.0f, 1.0f, 1.0f); - } - else { - GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f); - } - GPU_batch_draw(edges); - break; - } - case SI_UVDT_OUTLINE: - { - GPU_line_width(3.0f); - GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR); - GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f); - GPU_batch_draw(edges); - - UI_GetThemeColor4fv(TH_WIRE_EDIT, col1); - UI_GetThemeColor4fv(TH_EDGE_SELECT, col2); - - /* We could modify the vbo's data filling - * instead of modifying the provoking vert. */ - glProvokingVertex(GL_FIRST_VERTEX_CONVENTION); - - GPU_line_width(1.0f); - GPU_batch_program_set_builtin(edges, (interpedges) - ? GPU_SHADER_2D_UV_EDGES_SMOOTH - : GPU_SHADER_2D_UV_EDGES); - GPU_batch_uniform_4fv(edges, "edgeColor", col1); - GPU_batch_uniform_4fv(edges, "selectColor", do_selected_edges ? col2 : col1); - GPU_batch_draw(edges); - - if (do_elem_order_fix && do_selected_edges) { - /* We have problem in this mode when face order make some edges - * appear unselected because an adjacent face is not selected and - * render after the selected face. - * So, to avoid sorting edges by state we just render selected edges - * on top. A bit overkill but it's simple. */ - GPU_blend(true); - GPU_batch_uniform_4fv(edges, "edgeColor", transparent); - GPU_batch_uniform_4fv(edges, "selectColor", col2); - GPU_batch_draw(edges); - GPU_blend(false); - } - glProvokingVertex(GL_LAST_VERTEX_CONVENTION); - break; - } - } - if (sima->flag & SI_SMOOTH_UV) { - GPU_line_smooth(false); - GPU_blend(false); - } - } - if (verts || facedots) { - float pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE); - UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2); - if (verts) { - float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */ - UI_GetThemeColor4fv(TH_VERTEX, col1); - GPU_blend(true); - GPU_enable_program_point_size(); - - GPU_batch_program_set_builtin(verts, GPU_SHADER_2D_UV_VERTS); - GPU_batch_uniform_4f(verts, "vertColor", col1[0], col1[1], col1[2], 1.0f); - GPU_batch_uniform_4fv(verts, "selectColor", (do_elem_order_fix) ? transparent : col2); - GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col); - GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2); - GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f); - GPU_batch_draw(verts); - - if (do_elem_order_fix) { - /* We have problem in this mode when face order make some verts - * appear unselected because an adjacent face is not selected and - * render after the selected face. - * So, to avoid sorting verts by state we just render selected verts - * on top. A bit overkill but it's simple. */ - GPU_batch_uniform_4fv(verts, "vertColor", transparent); - GPU_batch_uniform_4fv(verts, "selectColor", col2); - GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col); - GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2); - GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f); - GPU_batch_draw(verts); - } - - GPU_blend(false); - GPU_disable_program_point_size(); - } - if (facedots) { - GPU_point_size(pointsize); - - UI_GetThemeColor4fv(TH_WIRE, col1); - GPU_batch_program_set_builtin(facedots, GPU_SHADER_2D_UV_FACEDOTS); - GPU_batch_uniform_4fv(facedots, "vertColor", col1); - GPU_batch_uniform_4fv(facedots, "selectColor", col2); - GPU_batch_draw(facedots); - } - } + GPUBatch *faces, *edges, *verts, *facedots; + Object *eval_ob = DEG_get_evaluated_object(depsgraph, obedit); + const ToolSettings *ts = scene->toolsettings; + float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + if (sima->flag & SI_DRAWSHADOW) { + bool is_cage_like_final_meshes = false; + Mesh *me = (Mesh *)eval_ob->data; + BMEditMesh *embm = me->edit_mesh; + is_cage_like_final_meshes = embm && embm->mesh_eval_final && + embm->mesh_eval_final->runtime.is_original; + + /* 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) && is_cage_like_final_meshes)) { + draw_uvs_shadow(sima, scene, obedit, depsgraph); + } + } + + uvedit_get_batches(eval_ob, sima, ts, &faces, &edges, &verts, &facedots); + + bool interpedges; + bool do_elem_order_fix = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); + bool do_selected_edges = ((sima->flag & SI_NO_DRAWEDGES) == 0); + bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0; + if (ts->uv_flag & UV_SYNC_SELECTION) { + interpedges = (ts->selectmode & SCE_SELECT_VERTEX) != 0; + } + else { + interpedges = (ts->uv_selectmode == UV_SELECT_VERTEX); + } + + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + + if (faces) { + GPU_batch_program_set_builtin(faces, + (draw_stretch) ? (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA) ? + GPU_SHADER_2D_UV_FACES_STRETCH_AREA : + GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE : + GPU_SHADER_2D_UV_FACES); + + if (!draw_stretch) { + GPU_blend(true); + + UI_GetThemeColor4fv(TH_FACE, col1); + UI_GetThemeColor4fv(TH_FACE_SELECT, col2); + UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3); + col3[3] *= 0.2; /* Simulate dithering */ + GPU_batch_uniform_4fv(faces, "faceColor", col1); + GPU_batch_uniform_4fv(faces, "selectColor", col2); + GPU_batch_uniform_4fv(faces, "activeColor", col3); + } + else if (sima->dt_uvstretch == SI_UVDT_STRETCH_ANGLE) { + float asp[2]; + ED_space_image_get_uv_aspect(sima, &asp[0], &asp[1]); + GPU_batch_uniform_2fv(faces, "aspect", asp); + } + + GPU_batch_draw(faces); + + if (!draw_stretch) { + GPU_blend(false); + } + } + if (edges) { + if (sima->flag & SI_SMOOTH_UV) { + GPU_line_smooth(true); + GPU_blend(true); + } + switch (sima->dt_uv) { + case SI_UVDT_DASH: { + float dash_colors[2][4] = {{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}}; + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + + GPU_line_width(1.0f); + GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + GPU_batch_uniform_4fv_array(edges, "colors", 2, (float *)dash_colors); + GPU_batch_uniform_2f( + edges, "viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + GPU_batch_uniform_1i(edges, "colors_len", 2); /* "advanced" mode */ + GPU_batch_uniform_1f(edges, "dash_width", 4.0f); + GPU_batch_draw(edges); + break; + } + case SI_UVDT_BLACK: + case SI_UVDT_WHITE: { + GPU_line_width(1.0f); + GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR); + if (sima->dt_uv == SI_UVDT_WHITE) { + GPU_batch_uniform_4f(edges, "color", 1.0f, 1.0f, 1.0f, 1.0f); + } + else { + GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f); + } + GPU_batch_draw(edges); + break; + } + case SI_UVDT_OUTLINE: { + GPU_line_width(3.0f); + GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR); + GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f); + GPU_batch_draw(edges); + + UI_GetThemeColor4fv(TH_WIRE_EDIT, col1); + UI_GetThemeColor4fv(TH_EDGE_SELECT, col2); + + /* We could modify the vbo's data filling + * instead of modifying the provoking vert. */ + glProvokingVertex(GL_FIRST_VERTEX_CONVENTION); + + GPU_line_width(1.0f); + GPU_batch_program_set_builtin( + edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES); + GPU_batch_uniform_4fv(edges, "edgeColor", col1); + GPU_batch_uniform_4fv(edges, "selectColor", do_selected_edges ? col2 : col1); + GPU_batch_draw(edges); + + if (do_elem_order_fix && do_selected_edges) { + /* We have problem in this mode when face order make some edges + * appear unselected because an adjacent face is not selected and + * render after the selected face. + * So, to avoid sorting edges by state we just render selected edges + * on top. A bit overkill but it's simple. */ + GPU_blend(true); + GPU_batch_uniform_4fv(edges, "edgeColor", transparent); + GPU_batch_uniform_4fv(edges, "selectColor", col2); + GPU_batch_draw(edges); + GPU_blend(false); + } + glProvokingVertex(GL_LAST_VERTEX_CONVENTION); + break; + } + } + if (sima->flag & SI_SMOOTH_UV) { + GPU_line_smooth(false); + GPU_blend(false); + } + } + if (verts || facedots) { + float pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE); + UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2); + if (verts) { + float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */ + UI_GetThemeColor4fv(TH_VERTEX, col1); + GPU_blend(true); + GPU_enable_program_point_size(); + + GPU_batch_program_set_builtin(verts, GPU_SHADER_2D_UV_VERTS); + GPU_batch_uniform_4f(verts, "vertColor", col1[0], col1[1], col1[2], 1.0f); + GPU_batch_uniform_4fv(verts, "selectColor", (do_elem_order_fix) ? transparent : col2); + GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col); + GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2); + GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f); + GPU_batch_draw(verts); + + if (do_elem_order_fix) { + /* We have problem in this mode when face order make some verts + * appear unselected because an adjacent face is not selected and + * render after the selected face. + * So, to avoid sorting verts by state we just render selected verts + * on top. A bit overkill but it's simple. */ + GPU_batch_uniform_4fv(verts, "vertColor", transparent); + GPU_batch_uniform_4fv(verts, "selectColor", col2); + GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col); + GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2); + GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f); + GPU_batch_draw(verts); + } + + GPU_blend(false); + GPU_disable_program_point_size(); + } + if (facedots) { + GPU_point_size(pointsize); + + UI_GetThemeColor4fv(TH_WIRE, col1); + GPU_batch_program_set_builtin(facedots, GPU_SHADER_2D_UV_FACEDOTS); + GPU_batch_uniform_4fv(facedots, "vertColor", col1); + GPU_batch_uniform_4fv(facedots, "selectColor", col2); + GPU_batch_draw(facedots); + } + } } static void draw_uv_shadows_get( - SpaceImage *sima, Object *ob, Object *obedit, - bool *show_shadow, bool *show_texpaint) + SpaceImage *sima, Object *ob, Object *obedit, bool *show_shadow, bool *show_texpaint) { - *show_shadow = *show_texpaint = false; + *show_shadow = *show_texpaint = false; - if (ED_space_image_show_render(sima) || (sima->flag & SI_NO_DRAW_TEXPAINT)) - return; + if (ED_space_image_show_render(sima) || (sima->flag & SI_NO_DRAW_TEXPAINT)) + return; - if ((sima->mode == SI_MODE_PAINT) && obedit && obedit->type == OB_MESH) { - struct BMEditMesh *em = BKE_editmesh_from_object(obedit); + if ((sima->mode == SI_MODE_PAINT) && obedit && obedit->type == OB_MESH) { + struct BMEditMesh *em = BKE_editmesh_from_object(obedit); - *show_shadow = EDBM_uv_check(em); - } + *show_shadow = EDBM_uv_check(em); + } - *show_texpaint = (ob && ob->type == OB_MESH && ob->mode == OB_MODE_TEXTURE_PAINT); + *show_texpaint = (ob && ob->type == OB_MESH && ob->mode == OB_MODE_TEXTURE_PAINT); } -void ED_uvedit_draw_main( - SpaceImage *sima, - ARegion *ar, Scene *scene, ViewLayer *view_layer, Object *obedit, Object *obact, Depsgraph *depsgraph) +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; - - show_uvedit = ED_space_image_show_uvedit(sima, obedit); - draw_uv_shadows_get(sima, obact, obedit, &show_uvshadow, &show_texpaint_uvshadow); - - if (show_uvedit || show_uvshadow || show_texpaint_uvshadow) { - if (show_uvshadow) { - draw_uvs_shadow(sima, scene, obedit, depsgraph); - } - 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, ((View3D *)NULL), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob_iter = objects[ob_index]; - draw_uvs(sima, scene, ob_iter, depsgraph); - } - MEM_freeN(objects); - } - else { - draw_uvs_texpaint(scene, obact, depsgraph); - } - - if (show_uvedit && !(toolsettings->use_uv_sculpt)) - ED_image_draw_cursor(ar, sima->cursor); - } + ToolSettings *toolsettings = scene->toolsettings; + bool show_uvedit, show_uvshadow, show_texpaint_uvshadow; + + show_uvedit = ED_space_image_show_uvedit(sima, obedit); + draw_uv_shadows_get(sima, obact, obedit, &show_uvshadow, &show_texpaint_uvshadow); + + if (show_uvedit || show_uvshadow || show_texpaint_uvshadow) { + if (show_uvshadow) { + draw_uvs_shadow(sima, scene, obedit, depsgraph); + } + 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, ((View3D *)NULL), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + draw_uvs(sima, scene, ob_iter, depsgraph); + } + MEM_freeN(objects); + } + else { + draw_uvs_texpaint(scene, obact, depsgraph); + } + + 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 5510549ba0e..3f544ad90d1 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -21,7 +21,6 @@ * \ingroup eduv */ - #ifndef __UVEDIT_INTERN_H__ #define __UVEDIT_INTERN_H__ @@ -35,50 +34,72 @@ struct SpaceImage; struct wmOperatorType; /* geometric utilities */ -void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len); -void uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_offset); +void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len); +void uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_offset); /* find nearest */ typedef struct UvNearestHit { - /** Only for `*_multi(..)` versions of functions. */ - struct Object *ob; - /** Always set if we have a hit. */ - struct BMFace *efa; - struct BMLoop *l; - struct MLoopUV *luv, *luv_next; - /** Index of loop within face. */ - int lindex; - /** Needs to be set before calling nearest functions. */ - float dist_sq; + /** Only for `*_multi(..)` versions of functions. */ + struct Object *ob; + /** Always set if we have a hit. */ + struct BMFace *efa; + struct BMLoop *l; + struct MLoopUV *luv, *luv_next; + /** Index of loop within face. */ + int lindex; + /** Needs to be set before calling nearest functions. */ + float dist_sq; } UvNearestHit; -#define UV_NEAREST_HIT_INIT { .dist_sq = FLT_MAX, } - -bool uv_find_nearest_vert( - struct Scene *scene, struct Image *ima, struct Object *obedit, - const float co[2], const float penalty_dist, struct UvNearestHit *hit_final); -bool uv_find_nearest_vert_multi( - struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len, - const float co[2], const float penalty_dist, struct UvNearestHit *hit_final); - -bool uv_find_nearest_edge( - struct Scene *scene, struct Image *ima, struct Object *obedit, - const float co[2], struct UvNearestHit *hit_final); -bool uv_find_nearest_edge_multi( - struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len, - const float co[2], struct UvNearestHit *hit_final); - -bool uv_find_nearest_face( - struct Scene *scene, struct Image *ima, struct Object *obedit, - const float co[2], struct UvNearestHit *hit_final); -bool uv_find_nearest_face_multi( - struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len, - const float co[2], struct UvNearestHit *hit_final); +#define UV_NEAREST_HIT_INIT \ + { \ + .dist_sq = FLT_MAX, \ + } + +bool uv_find_nearest_vert(struct Scene *scene, + struct Image *ima, + struct Object *obedit, + const float co[2], + const float penalty_dist, + struct UvNearestHit *hit_final); +bool uv_find_nearest_vert_multi(struct Scene *scene, + struct Image *ima, + struct Object **objects, + const uint objects_len, + const float co[2], + const float penalty_dist, + struct UvNearestHit *hit_final); + +bool uv_find_nearest_edge(struct Scene *scene, + struct Image *ima, + struct Object *obedit, + const float co[2], + struct UvNearestHit *hit_final); +bool uv_find_nearest_edge_multi(struct Scene *scene, + struct Image *ima, + struct Object **objects, + const uint objects_len, + const float co[2], + struct UvNearestHit *hit_final); + +bool uv_find_nearest_face(struct Scene *scene, + struct Image *ima, + struct Object *obedit, + const float co[2], + struct UvNearestHit *hit_final); +bool uv_find_nearest_face_multi(struct Scene *scene, + struct Image *ima, + struct Object **objects, + const uint objects_len, + const float co[2], + struct UvNearestHit *hit_final); /* utility tool functions */ -void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit); +void uvedit_live_unwrap_update(struct SpaceImage *sima, + struct Scene *scene, + struct Object *obedit); /* operators */ diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 1bcf60077ff..291dbdf6942 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -21,7 +21,6 @@ * \ingroup eduv */ - #include <stdlib.h> #include <string.h> #include <math.h> @@ -87,12 +86,24 @@ #include "uvedit_intern.h" 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 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); -static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSettings *ts, Object *obedit); +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); +static void uv_select_tag_update_for_object(Depsgraph *depsgraph, + const ToolSettings *ts, + Object *obedit); /* -------------------------------------------------------------------- */ /** \name State Testing @@ -100,42 +111,42 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSett bool ED_uvedit_test(Object *obedit) { - BMEditMesh *em; - int ret; + BMEditMesh *em; + int ret; - if (!obedit) - return 0; + if (!obedit) + return 0; - if (obedit->type != OB_MESH) - return 0; + if (obedit->type != OB_MESH) + return 0; - em = BKE_editmesh_from_object(obedit); - ret = EDBM_uv_check(em); + em = BKE_editmesh_from_object(obedit); + ret = EDBM_uv_check(em); - return ret; + return ret; } static bool ED_operator_uvedit_can_uv_sculpt(struct bContext *C) { - SpaceImage *sima = CTX_wm_space_image(C); - ToolSettings *toolsettings = CTX_data_tool_settings(C); - Object *obedit = CTX_data_edit_object(C); + SpaceImage *sima = CTX_wm_space_image(C); + ToolSettings *toolsettings = CTX_data_tool_settings(C); + Object *obedit = CTX_data_edit_object(C); - return ED_space_image_show_uvedit(sima, obedit) && !(toolsettings->use_uv_sculpt); + return ED_space_image_show_uvedit(sima, obedit) && !(toolsettings->use_uv_sculpt); } -static int UNUSED_FUNCTION(ED_operator_uvmap_mesh) (bContext *C) +static int UNUSED_FUNCTION(ED_operator_uvmap_mesh)(bContext *C) { - Object *ob = CTX_data_active_object(C); + Object *ob = CTX_data_active_object(C); - if (ob && ob->type == OB_MESH) { - Mesh *me = ob->data; + if (ob && ob->type == OB_MESH) { + Mesh *me = ob->data; - if (CustomData_get_layer(&me->fdata, CD_MTFACE) != NULL) - return 1; - } + if (CustomData_get_layer(&me->fdata, CD_MTFACE) != NULL) + return 1; + } - return 0; + return 0; } /** \} */ @@ -146,52 +157,62 @@ static int UNUSED_FUNCTION(ED_operator_uvmap_mesh) (bContext *C) static bool is_image_texture_node(bNode *node) { - return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT); -} - -bool ED_object_get_active_image( - Object *ob, int mat_nr, - Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree) -{ - Material *ma = give_current_material(ob, mat_nr); - bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL; - bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL; - - if (node && is_image_texture_node(node)) { - if (r_ima) *r_ima = (Image *)node->id; - if (r_iuser) { - if (node->type == SH_NODE_TEX_IMAGE) { - *r_iuser = &((NodeTexImage *)node->storage)->iuser; - } - else if (node->type == SH_NODE_TEX_ENVIRONMENT) { - *r_iuser = &((NodeTexEnvironment *)node->storage)->iuser; - } - else { - *r_iuser = NULL; - } - } - if (r_node) *r_node = node; - if (r_ntree) *r_ntree = ntree; - return true; - } - - if (r_ima) *r_ima = NULL; - if (r_iuser) *r_iuser = NULL; - if (r_node) *r_node = node; - if (r_ntree) *r_ntree = ntree; - - return false; + return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT); +} + +bool ED_object_get_active_image(Object *ob, + int mat_nr, + Image **r_ima, + ImageUser **r_iuser, + bNode **r_node, + bNodeTree **r_ntree) +{ + Material *ma = give_current_material(ob, mat_nr); + bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL; + bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL; + + if (node && is_image_texture_node(node)) { + if (r_ima) + *r_ima = (Image *)node->id; + if (r_iuser) { + if (node->type == SH_NODE_TEX_IMAGE) { + *r_iuser = &((NodeTexImage *)node->storage)->iuser; + } + else if (node->type == SH_NODE_TEX_ENVIRONMENT) { + *r_iuser = &((NodeTexEnvironment *)node->storage)->iuser; + } + else { + *r_iuser = NULL; + } + } + if (r_node) + *r_node = node; + if (r_ntree) + *r_ntree = ntree; + return true; + } + + if (r_ima) + *r_ima = NULL; + if (r_iuser) + *r_iuser = NULL; + if (r_node) + *r_node = node; + if (r_ntree) + *r_ntree = ntree; + + return false; } void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *ima) { - Material *ma = give_current_material(ob, mat_nr); - bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL; + Material *ma = give_current_material(ob, mat_nr); + bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL; - if (node && is_image_texture_node(node)) { - node->id = &ima->id; - ED_node_tag_update_nodetree(bmain, ma->nodetree, node); - } + if (node && is_image_texture_node(node)) { + node->id = &ima->id; + ED_node_tag_update_nodetree(bmain, ma->nodetree, node); + } } /** \} */ @@ -202,18 +223,18 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist) { - int width, height; + int width, height; - if (sima) { - ED_space_image_get_size(sima, &width, &height); - } - else { - width = IMG_SIZE_FALLBACK; - height = IMG_SIZE_FALLBACK; - } + if (sima) { + ED_space_image_get_size(sima, &width, &height); + } + else { + width = IMG_SIZE_FALLBACK; + height = IMG_SIZE_FALLBACK; + } - dist[0] = pixeldist / width; - dist[1] = pixeldist / height; + dist[0] = pixeldist / width; + dist[1] = pixeldist / height; } /** \} */ @@ -222,313 +243,316 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist /** \name Visibility and Selection Utilities * \{ */ -static void uvedit_vertex_select_tagged(BMEditMesh *em, Scene *scene, bool select, int cd_loop_uv_offset) +static void uvedit_vertex_select_tagged(BMEditMesh *em, + Scene *scene, + bool select, + int cd_loop_uv_offset) { - BMFace *efa; - BMLoop *l; - BMIter iter, liter; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } } bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa) { - if (ts->uv_flag & UV_SYNC_SELECTION) - return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0); - else - return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); + if (ts->uv_flag & UV_SYNC_SELECTION) + return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0); + else + return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); } bool uvedit_face_visible_nolocal(Scene *scene, BMFace *efa) { - return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa); + return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa); } bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *ima, BMFace *efa) { - 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_ex(ts, efa) : false; - } - else { - return uvedit_face_visible_nolocal_ex(ts, efa); - } + 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_ex(ts, efa) : false; + } + else { + return uvedit_face_visible_nolocal_ex(ts, efa); + } } bool uvedit_face_visible_test(Scene *scene, Object *obedit, Image *ima, BMFace *efa) { - return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa); + return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa); } -bool uvedit_face_select_test_ex( - const ToolSettings *ts, BMFace *efa, - const int cd_loop_uv_offset) +bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset) { - if (ts->uv_flag & UV_SYNC_SELECTION) { - return (BM_elem_flag_test(efa, BM_ELEM_SELECT)); - } - else { - BMLoop *l; - MLoopUV *luv; - BMIter liter; + if (ts->uv_flag & UV_SYNC_SELECTION) { + return (BM_elem_flag_test(efa, BM_ELEM_SELECT)); + } + else { + BMLoop *l; + MLoopUV *luv; + BMIter liter; - 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 false; - } + 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 false; + } - return true; - } + return true; + } } bool uvedit_face_select_test(Scene *scene, BMFace *efa, const int cd_loop_uv_offset) { - return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset); + return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset); } -bool uvedit_face_select_set( - struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select, - const bool do_history, const int cd_loop_uv_offset) +bool uvedit_face_select_set(struct Scene *scene, + struct BMEditMesh *em, + struct BMFace *efa, + const bool select, + const bool do_history, + const int cd_loop_uv_offset) { - if (select) { - return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset); - } - else { - return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); - } + if (select) { + return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset); + } + else { + return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); + } } bool uvedit_face_select_enable( - Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history, - const int cd_loop_uv_offset) -{ - ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - BM_face_select_set(em->bm, efa, true); - if (do_history) { - BM_select_history_store(em->bm, (BMElem *)efa); - } - } - else { - BMLoop *l; - MLoopUV *luv; - BMIter liter; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag |= MLOOPUV_VERTSEL; - } - - return true; - } - - return false; -} - -bool uvedit_face_select_disable( - Scene *scene, BMEditMesh *em, BMFace *efa, - const int cd_loop_uv_offset) -{ - ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - BM_face_select_set(em->bm, efa, false); - } - else { - BMLoop *l; - MLoopUV *luv; - BMIter liter; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag &= ~MLOOPUV_VERTSEL; - } - - return true; - } - - return false; -} - -bool uvedit_edge_select_test_ex( - const ToolSettings *ts, BMLoop *l, - const int cd_loop_uv_offset) -{ - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) { - return BM_elem_flag_test(l->f, BM_ELEM_SELECT); - } - else if (ts->selectmode == SCE_SELECT_EDGE) { - return BM_elem_flag_test(l->e, BM_ELEM_SELECT); - } - else { - return BM_elem_flag_test(l->v, BM_ELEM_SELECT) && - BM_elem_flag_test(l->next->v, BM_ELEM_SELECT); - } - } - else { - MLoopUV *luv1, *luv2; - - luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - - return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL); - } + Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history, const int cd_loop_uv_offset) +{ + ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + BM_face_select_set(em->bm, efa, true); + if (do_history) { + BM_select_history_store(em->bm, (BMElem *)efa); + } + } + else { + BMLoop *l; + MLoopUV *luv; + BMIter liter; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag |= MLOOPUV_VERTSEL; + } + + return true; + } + + return false; +} + +bool uvedit_face_select_disable(Scene *scene, + BMEditMesh *em, + BMFace *efa, + const int cd_loop_uv_offset) +{ + ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + BM_face_select_set(em->bm, efa, false); + } + else { + BMLoop *l; + MLoopUV *luv; + BMIter liter; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag &= ~MLOOPUV_VERTSEL; + } + + return true; + } + + return false; +} + +bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) +{ + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) { + return BM_elem_flag_test(l->f, BM_ELEM_SELECT); + } + else if (ts->selectmode == SCE_SELECT_EDGE) { + return BM_elem_flag_test(l->e, BM_ELEM_SELECT); + } + else { + return BM_elem_flag_test(l->v, BM_ELEM_SELECT) && + BM_elem_flag_test(l->next->v, BM_ELEM_SELECT); + } + } + else { + MLoopUV *luv1, *luv2; + + luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + + return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL); + } } bool uvedit_edge_select_test(Scene *scene, BMLoop *l, const int cd_loop_uv_offset) { - return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); + return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); } -void uvedit_edge_select_set( - BMEditMesh *em, Scene *scene, BMLoop *l, const bool select, - const bool do_history, const int cd_loop_uv_offset) +void uvedit_edge_select_set(BMEditMesh *em, + Scene *scene, + BMLoop *l, + const bool select, + const bool do_history, + const int cd_loop_uv_offset) { - if (select) { - uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset); - } - else { - uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset); - } + if (select) { + uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset); + } + else { + uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset); + } } void uvedit_edge_select_enable( - BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history, - const int cd_loop_uv_offset) - -{ - ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) - BM_face_select_set(em->bm, l->f, true); - else if (ts->selectmode & SCE_SELECT_EDGE) - BM_edge_select_set(em->bm, l->e, true); - else { - BM_vert_select_set(em->bm, l->e->v1, true); - BM_vert_select_set(em->bm, l->e->v2, true); - } - - if (do_history) { - BM_select_history_store(em->bm, (BMElem *)l->e); - } - } - else { - MLoopUV *luv1, *luv2; - - luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - - luv1->flag |= MLOOPUV_VERTSEL; - luv2->flag |= MLOOPUV_VERTSEL; - } -} - -void uvedit_edge_select_disable( - BMEditMesh *em, Scene *scene, BMLoop *l, - const int cd_loop_uv_offset) - -{ - ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) - BM_face_select_set(em->bm, l->f, false); - else if (ts->selectmode & SCE_SELECT_EDGE) - BM_edge_select_set(em->bm, l->e, false); - else { - BM_vert_select_set(em->bm, l->e->v1, false); - BM_vert_select_set(em->bm, l->e->v2, false); - } - } - else { - MLoopUV *luv1, *luv2; - - luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - - luv1->flag &= ~MLOOPUV_VERTSEL; - luv2->flag &= ~MLOOPUV_VERTSEL; - } -} - -bool uvedit_uv_select_test_ex( - const ToolSettings *ts, BMLoop *l, - const int cd_loop_uv_offset) -{ - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) - return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT); - else - return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT); - } - else { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - return (luv->flag & MLOOPUV_VERTSEL) != 0; - } + BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history, const int cd_loop_uv_offset) + +{ + ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) + BM_face_select_set(em->bm, l->f, true); + else if (ts->selectmode & SCE_SELECT_EDGE) + BM_edge_select_set(em->bm, l->e, true); + else { + BM_vert_select_set(em->bm, l->e->v1, true); + BM_vert_select_set(em->bm, l->e->v2, true); + } + + if (do_history) { + BM_select_history_store(em->bm, (BMElem *)l->e); + } + } + else { + MLoopUV *luv1, *luv2; + + luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + + luv1->flag |= MLOOPUV_VERTSEL; + luv2->flag |= MLOOPUV_VERTSEL; + } +} + +void uvedit_edge_select_disable(BMEditMesh *em, + Scene *scene, + BMLoop *l, + const int cd_loop_uv_offset) + +{ + ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) + BM_face_select_set(em->bm, l->f, false); + else if (ts->selectmode & SCE_SELECT_EDGE) + BM_edge_select_set(em->bm, l->e, false); + else { + BM_vert_select_set(em->bm, l->e->v1, false); + BM_vert_select_set(em->bm, l->e->v2, false); + } + } + else { + MLoopUV *luv1, *luv2; + + luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + + luv1->flag &= ~MLOOPUV_VERTSEL; + luv2->flag &= ~MLOOPUV_VERTSEL; + } +} + +bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) +{ + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) + return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT); + else + return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT); + } + else { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + return (luv->flag & MLOOPUV_VERTSEL) != 0; + } } bool uvedit_uv_select_test(Scene *scene, BMLoop *l, const int cd_loop_uv_offset) { - return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); + return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); } -void uvedit_uv_select_set( - BMEditMesh *em, Scene *scene, BMLoop *l, const bool select, - const bool do_history, const int cd_loop_uv_offset) +void uvedit_uv_select_set(BMEditMesh *em, + Scene *scene, + BMLoop *l, + const bool select, + const bool do_history, + const int cd_loop_uv_offset) { - if (select) { - uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset); - } - else { - uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset); - } + if (select) { + uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset); + } + else { + uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset); + } } void uvedit_uv_select_enable( - BMEditMesh *em, Scene *scene, BMLoop *l, - const bool do_history, const int cd_loop_uv_offset) + BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history, const int cd_loop_uv_offset) { - ToolSettings *ts = scene->toolsettings; + ToolSettings *ts = scene->toolsettings; - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) - BM_face_select_set(em->bm, l->f, true); - else - BM_vert_select_set(em->bm, l->v, true); + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) + BM_face_select_set(em->bm, l->f, true); + else + BM_vert_select_set(em->bm, l->v, true); - if (do_history) { - BM_select_history_remove(em->bm, (BMElem *)l->v); - } - } - else { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag |= MLOOPUV_VERTSEL; - } + if (do_history) { + BM_select_history_remove(em->bm, (BMElem *)l->v); + } + } + else { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag |= MLOOPUV_VERTSEL; + } } -void uvedit_uv_select_disable( - BMEditMesh *em, Scene *scene, BMLoop *l, - const int cd_loop_uv_offset) +void uvedit_uv_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l, const int cd_loop_uv_offset) { - ToolSettings *ts = scene->toolsettings; + ToolSettings *ts = scene->toolsettings; - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) - BM_face_select_set(em->bm, l->f, false); - else - BM_vert_select_set(em->bm, l->v, false); - } - else { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag &= ~MLOOPUV_VERTSEL; - } + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) + BM_face_select_set(em->bm, l->f, false); + else + BM_vert_select_set(em->bm, l->v, false); + } + else { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag &= ~MLOOPUV_VERTSEL; + } } /** \} */ @@ -539,11 +563,11 @@ void uvedit_uv_select_disable( void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit) { - if (sima && (sima->flag & SI_LIVE_UNWRAP)) { - ED_uvedit_live_unwrap_begin(scene, obedit); - ED_uvedit_live_unwrap_re_solve(); - ED_uvedit_live_unwrap_end(0); - } + if (sima && (sima->flag & SI_LIVE_UNWRAP)) { + ED_uvedit_live_unwrap_begin(scene, obedit); + ED_uvedit_live_unwrap_re_solve(); + ED_uvedit_live_unwrap_end(0); + } } /** \} */ @@ -554,149 +578,157 @@ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit) void uv_poly_center(BMFace *f, float r_cent[2], const int cd_loop_uv_offset) { - BMLoop *l; - MLoopUV *luv; - BMIter liter; + BMLoop *l; + MLoopUV *luv; + BMIter liter; - zero_v2(r_cent); + zero_v2(r_cent); - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - add_v2_v2(r_cent, luv->uv); - } + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + add_v2_v2(r_cent, luv->uv); + } - mul_v2_fl(r_cent, 1.0f / (float)f->len); + mul_v2_fl(r_cent, 1.0f / (float)f->len); } void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len) { - int i; - for (i = 0; i < len; i++) { - uv[i][0] = uv_orig[i][0] * aspx; - uv[i][1] = uv_orig[i][1] * aspy; - } + int i; + for (i = 0; i < len; i++) { + uv[i][0] = uv_orig[i][0] * aspx; + uv[i][1] = uv_orig[i][1] * aspy; + } } -bool ED_uvedit_minmax_multi( - Scene *scene, Image *ima, Object **objects_edit, uint objects_len, - 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]) { - bool changed = false; - INIT_MINMAX2(r_min, r_max); + bool changed = false; + INIT_MINMAX2(r_min, r_max); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects_edit[ob_index]; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects_edit[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + 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_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; + 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); + 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) { - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag |= MLOOPUV_VERTSEL; - } - } + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag |= MLOOPUV_VERTSEL; + } + } } -static bool ED_uvedit_median_multi(Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2]) +static bool ED_uvedit_median_multi( + Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2]) { - unsigned int sel = 0; - zero_v2(co); + unsigned int sel = 0; + zero_v2(co); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects_edit[ob_index]; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects_edit[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + 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_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++; - } - } - } - } + 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++; + } + } + } + } - mul_v2_fl(co, 1.0f / (float)sel); + mul_v2_fl(co, 1.0f / (float)sel); - return (sel != 0); + return (sel != 0); } -static bool UNUSED_FUNCTION(ED_uvedit_median)(Scene *scene, Image *ima, Object *obedit, float co[2]) +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); + 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 ED_uvedit_center_multi( + Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float cent[2], char mode) { - bool changed = false; + bool changed = false; - if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */ - float min[2], max[2]; - 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_multi(scene, ima, objects_edit, objects_len, cent)) { - changed = true; - } - } + if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */ + float min[2], max[2]; + 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_multi(scene, ima, objects_edit, objects_len, cent)) { + changed = true; + } + } - return changed; + 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); + return ED_uvedit_center_multi(scene, ima, &obedit, 1, cent, mode); } /** \} */ @@ -706,264 +738,278 @@ bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], c * \{ */ bool uv_find_nearest_edge( - Scene *scene, Image *ima, Object *obedit, const float co[2], - UvNearestHit *hit) -{ - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv, *luv_next; - int i; - bool found = false; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - - 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->efa = efa; - - hit->l = l; - hit->luv = luv; - hit->luv_next = luv_next; - hit->lindex = i; - - hit->dist_sq = dist_test_sq; - found = true; - } - } - } - 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; + Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit) +{ + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv, *luv_next; + int i; + bool found = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) + { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + + 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->efa = efa; + + hit->l = l; + hit->luv = luv; + hit->luv_next = luv_next; + hit->lindex = i; + + hit->dist_sq = dist_test_sq; + found = true; + } + } + } + return found; +} + +bool uv_find_nearest_edge_multi(Scene *scene, + Image *ima, + Object **objects, + const uint objects_len, + const float co[2], + UvNearestHit *hit_final) +{ + bool found = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) { + hit_final->ob = obedit; + found = true; + } + } + return found; } bool uv_find_nearest_face( - Scene *scene, Image *ima, Object *obedit, const float co[2], - UvNearestHit *hit_final) + 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); - - /* 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, obedit, co, &hit)) { - hit.dist_sq = dist_sq_init; - hit.l = NULL; - hit.luv = hit.luv_next = NULL; - - BMIter iter; - BMFace *efa; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - float cent[2]; - uv_poly_center(efa, cent, cd_loop_uv_offset); - - const float dist_test_sq = len_squared_v2v2(co, cent); - - if (dist_test_sq < hit.dist_sq) { - hit.efa = efa; - hit.dist_sq = dist_test_sq; - found = true; - } - } - } - if (found) { - *hit_final = hit; - } - 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) -{ - const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv; - const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv; - const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv; - - return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) && - (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f)); -} - -bool uv_find_nearest_vert( - Scene *scene, Image *ima, Object *obedit, - float const co[2], const float penalty_dist, UvNearestHit *hit_final) -{ - bool found = false; - - /* 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, 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); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } - - BMIter liter; - BMLoop *l; - int i; - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - float dist_test_sq; - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist; - dist_test_sq = SQUARE(dist_test_sq); - } - else { - dist_test_sq = len_squared_v2v2(co, luv->uv); - } - - if (dist_test_sq <= hit.dist_sq) { - if (dist_test_sq == hit.dist_sq) { - if (!uv_nearest_between(l, co, cd_loop_uv_offset)) { - continue; - } - } - - hit.dist_sq = dist_test_sq; - - hit.l = l; - hit.luv = luv; - hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - hit.efa = efa; - hit.lindex = i; - found = true; - } - } - } - } - - if (found) { - *hit_final = hit; - } - - 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; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + bool found = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* 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, obedit, co, &hit)) { + hit.dist_sq = dist_sq_init; + hit.l = NULL; + hit.luv = hit.luv_next = NULL; + + BMIter iter; + BMFace *efa; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + float cent[2]; + uv_poly_center(efa, cent, cd_loop_uv_offset); + + const float dist_test_sq = len_squared_v2v2(co, cent); + + if (dist_test_sq < hit.dist_sq) { + hit.efa = efa; + hit.dist_sq = dist_test_sq; + found = true; + } + } + } + if (found) { + *hit_final = hit; + } + 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) +{ + const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv; + const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv; + const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv; + + return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) && + (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f)); +} + +bool uv_find_nearest_vert(Scene *scene, + Image *ima, + Object *obedit, + float const co[2], + const float penalty_dist, + UvNearestHit *hit_final) +{ + bool found = false; + + /* 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, 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); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + + BMIter liter; + BMLoop *l; + int i; + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) + { + float dist_test_sq; + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist; + dist_test_sq = SQUARE(dist_test_sq); + } + else { + dist_test_sq = len_squared_v2v2(co, luv->uv); + } + + if (dist_test_sq <= hit.dist_sq) { + if (dist_test_sq == hit.dist_sq) { + if (!uv_nearest_between(l, co, cd_loop_uv_offset)) { + continue; + } + } + + hit.dist_sq = dist_test_sq; + + hit.l = l; + hit.luv = luv; + hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + hit.efa = efa; + hit.lindex = i; + found = true; + } + } + } + } + + if (found) { + *hit_final = hit; + } + + 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 *dist_sq, float r_uv[2]) -{ - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMIter iter; - BMFace *efa; - const float *uv_best = NULL; - float dist_best = *dist_sq; - 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; - } - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv; - const float dist_test = len_squared_v2v2(co, uv); - if (dist_best > dist_test) { - dist_best = dist_test; - uv_best = uv; - } - } while ((l_iter = l_iter->next) != l_first); - } - - if (uv_best != NULL) { - copy_v2_v2(r_uv, uv_best); - *dist_sq = dist_best; - return true; - } - else { - return false; - } -} - -bool ED_uvedit_nearest_uv_multi( - Scene *scene, Image *ima, Object **objects, const uint objects_len, const float co[2], - float *dist_sq, float r_uv[2]) -{ - bool found = false; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) { - found = true; - } - } - return found; + Scene *scene, Object *obedit, Image *ima, const float co[2], float *dist_sq, float r_uv[2]) +{ + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMIter iter; + BMFace *efa; + const float *uv_best = NULL; + float dist_best = *dist_sq; + 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; + } + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv; + const float dist_test = len_squared_v2v2(co, uv); + if (dist_best > dist_test) { + dist_best = dist_test; + uv_best = uv; + } + } while ((l_iter = l_iter->next) != l_first); + } + + if (uv_best != NULL) { + copy_v2_v2(r_uv, uv_best); + *dist_sq = dist_best; + return true; + } + else { + return false; + } +} + +bool ED_uvedit_nearest_uv_multi(Scene *scene, + Image *ima, + Object **objects, + const uint objects_len, + const float co[2], + float *dist_sq, + float r_uv[2]) +{ + bool found = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) { + found = true; + } + } + return found; } /** \} */ @@ -974,185 +1020,192 @@ bool ED_uvedit_nearest_uv_multi( static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first) { - UvMapVert *iterv; - int count = 0; + UvMapVert *iterv; + int count = 0; - for (iterv = first; iterv; iterv = iterv->next) { - if (iterv->separate && iterv != first) - break; + for (iterv = first; iterv; iterv = iterv->next) { + if (iterv->separate && iterv != first) + break; - count++; - } + count++; + } - if (count < 5) - first->flag = 1; + if (count < 5) + first->flag = 1; } static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l) { - UvMapVert *iterv, *first; - first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); - - for (iterv = first; iterv; iterv = iterv->next) { - if (iterv->separate) - first = iterv; - if (iterv->poly_index == BM_elem_index_get(efa)) - return first; - } - - return NULL; -} - -static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, UvMapVert *first2, int *totface) + UvMapVert *iterv, *first; + first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); + + for (iterv = first; iterv; iterv = iterv->next) { + if (iterv->separate) + first = iterv; + if (iterv->poly_index == BM_elem_index_get(efa)) + return first; + } + + return NULL; +} + +static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, + UvMapVert *first1, + UvMapVert *first2, + int *totface) { - UvMapVert *iterv1, *iterv2; - BMFace *efa; - int tot = 0; - - /* count number of faces this edge has */ - for (iterv1 = first1; iterv1; iterv1 = iterv1->next) { - if (iterv1->separate && iterv1 != first1) - break; - - for (iterv2 = first2; iterv2; iterv2 = iterv2->next) { - if (iterv2->separate && iterv2 != first2) - break; - - if (iterv1->poly_index == iterv2->poly_index) { - /* if face already tagged, don't do this edge */ - efa = BM_face_at_index(em->bm, iterv1->poly_index); - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) - return false; - - tot++; - break; - } - } - } - - if (*totface == 0) /* start edge */ - *totface = tot; - else if (tot != *totface) /* check for same number of faces as start edge */ - return false; - - /* tag the faces */ - for (iterv1 = first1; iterv1; iterv1 = iterv1->next) { - if (iterv1->separate && iterv1 != first1) - break; - - for (iterv2 = first2; iterv2; iterv2 = iterv2->next) { - if (iterv2->separate && iterv2 != first2) - break; - - if (iterv1->poly_index == iterv2->poly_index) { - efa = BM_face_at_index(em->bm, iterv1->poly_index); - BM_elem_flag_enable(efa, BM_ELEM_TAG); - break; - } - } - } - - return true; -} - -static int uv_select_edgeloop( - 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; - UvVertMap *vmap; - UvMapVert *iterv_curr; - UvMapVert *iterv_next; - int starttotf; - bool looking, select; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* setup */ - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - vmap = BM_uv_vert_map_create(em->bm, limit, false, false); - - BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); - - if (!extend) { - uv_select_all_perform(scene, ima, obedit, SEL_DESELECT); - } - - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - - /* set flags for first face and verts */ - iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); - iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); - uv_select_edgeloop_vertex_loop_flag(iterv_curr); - uv_select_edgeloop_vertex_loop_flag(iterv_next); - - starttotf = 0; - uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf); - - /* sorry, first edge isn't even ok */ - looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0); - - /* iterate */ - while (looking) { - looking = false; - - /* 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) { - 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))) - continue; - if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next))) - continue; - - /* check if vertex is tagged and has right valence */ - if (iterv_curr->flag || iterv_next->flag) { - if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) { - looking = true; - BM_elem_flag_enable(efa, BM_ELEM_TAG); - - uv_select_edgeloop_vertex_loop_flag(iterv_curr); - uv_select_edgeloop_vertex_loop_flag(iterv_next); - break; - } - } - } - } - } - } - - /* do the actual select/deselect */ - iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); - iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); - iterv_curr->flag = 1; - iterv_next->flag = 1; - - if (extend) { - select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset)); - } - else { - select = true; - } - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l); - - if (iterv_curr->flag) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } - - /* cleanup */ - BM_uv_vert_map_free(vmap); - - return (select) ? 1 : -1; + UvMapVert *iterv1, *iterv2; + BMFace *efa; + int tot = 0; + + /* count number of faces this edge has */ + for (iterv1 = first1; iterv1; iterv1 = iterv1->next) { + if (iterv1->separate && iterv1 != first1) + break; + + for (iterv2 = first2; iterv2; iterv2 = iterv2->next) { + if (iterv2->separate && iterv2 != first2) + break; + + if (iterv1->poly_index == iterv2->poly_index) { + /* if face already tagged, don't do this edge */ + efa = BM_face_at_index(em->bm, iterv1->poly_index); + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) + return false; + + tot++; + break; + } + } + } + + if (*totface == 0) /* start edge */ + *totface = tot; + else if (tot != *totface) /* check for same number of faces as start edge */ + return false; + + /* tag the faces */ + for (iterv1 = first1; iterv1; iterv1 = iterv1->next) { + if (iterv1->separate && iterv1 != first1) + break; + + for (iterv2 = first2; iterv2; iterv2 = iterv2->next) { + if (iterv2->separate && iterv2 != first2) + break; + + if (iterv1->poly_index == iterv2->poly_index) { + efa = BM_face_at_index(em->bm, iterv1->poly_index); + BM_elem_flag_enable(efa, BM_ELEM_TAG); + break; + } + } + } + + return true; +} + +static int uv_select_edgeloop(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; + UvVertMap *vmap; + UvMapVert *iterv_curr; + UvMapVert *iterv_next; + int starttotf; + bool looking, select; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* setup */ + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + vmap = BM_uv_vert_map_create(em->bm, limit, false, false); + + BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); + + if (!extend) { + uv_select_all_perform(scene, ima, obedit, SEL_DESELECT); + } + + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + + /* set flags for first face and verts */ + iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); + iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); + uv_select_edgeloop_vertex_loop_flag(iterv_curr); + uv_select_edgeloop_vertex_loop_flag(iterv_next); + + starttotf = 0; + uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf); + + /* sorry, first edge isn't even ok */ + looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0); + + /* iterate */ + while (looking) { + looking = false; + + /* 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) { + 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))) + continue; + if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next))) + continue; + + /* check if vertex is tagged and has right valence */ + if (iterv_curr->flag || iterv_next->flag) { + if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) { + looking = true; + BM_elem_flag_enable(efa, BM_ELEM_TAG); + + uv_select_edgeloop_vertex_loop_flag(iterv_curr); + uv_select_edgeloop_vertex_loop_flag(iterv_next); + break; + } + } + } + } + } + } + + /* do the actual select/deselect */ + iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); + iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); + iterv_curr->flag = 1; + iterv_next->flag = 1; + + if (extend) { + select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset)); + } + else { + select = true; + } + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l); + + if (iterv_curr->flag) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + + /* cleanup */ + BM_uv_vert_map_free(vmap); + + return (select) ? 1 : -1; } /** \} */ @@ -1161,203 +1214,212 @@ static int uv_select_edgeloop( /** \name Select Linked * \{ */ -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) -{ - /* loop over objects, or just use hit_final->ob */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - if (hit_final && ob_index != 0) { - break; - } - Object *obedit = hit_final ? hit_final->ob : objects[ob_index]; - - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - UvVertMap *vmap; - UvMapVert *vlist, *iterv, *startv; - int i, stacksize = 0, *stack; - unsigned int a; - char *flag; - - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */ - - /* 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); - - if (vmap == NULL) - return; - - stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack"); - flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag"); - - 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); - - 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; - } - } - } - - while (stacksize > 0) { - - stacksize--; - a = stack[stacksize]; - - efa = BM_face_at_index(em->bm, a); - - 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)); - - startv = vlist; - - for (iterv = vlist; iterv; iterv = iterv->next) { - if (iterv->separate) - startv = iterv; - if (iterv->poly_index == a) - break; - } - - for (iterv = startv; iterv; iterv = iterv->next) { - if ((startv != iterv) && (iterv->separate)) - break; - else if (!flag[iterv->poly_index]) { - flag[iterv->poly_index] = 1; - stack[stacksize] = iterv->poly_index; - 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; - } - } - 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) { - found_selected = true; - } - } - - if (found_selected) { - deselect = true; - break; - } - } - } - } +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) +{ + /* loop over objects, or just use hit_final->ob */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + if (hit_final && ob_index != 0) { + break; + } + Object *obedit = hit_final ? hit_final->ob : objects[ob_index]; + + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + UvVertMap *vmap; + UvMapVert *vlist, *iterv, *startv; + int i, stacksize = 0, *stack; + unsigned int a; + char *flag; + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */ + + /* 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); + + if (vmap == NULL) + return; + + stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack"); + flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag"); + + 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); + + 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; + } + } + } + + while (stacksize > 0) { + + stacksize--; + a = stack[stacksize]; + + efa = BM_face_at_index(em->bm, a); + + 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)); + + startv = vlist; + + for (iterv = vlist; iterv; iterv = iterv->next) { + if (iterv->separate) + startv = iterv; + if (iterv->poly_index == a) + break; + } + + for (iterv = startv; iterv; iterv = iterv->next) { + if ((startv != iterv) && (iterv->separate)) + break; + else if (!flag[iterv->poly_index]) { + flag[iterv->poly_index] = 1; + stack[stacksize] = iterv->poly_index; + 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; + } + } + 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) { + 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); \ - } \ - } (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); - } - continue; - } - - if (!deselect) { - SET_SELECTION(true); - } - else { - SET_SELECTION(false); - } - } + 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); \ + } \ + } \ + (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); + } + continue; + } + + 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, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve) +static float *uv_sel_co_from_eve( + Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve) { - BMIter liter; - BMLoop *l; + BMIter liter; + BMLoop *l; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) - continue; + BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { + if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) + continue; - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - return luv->uv; - } - } + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + return luv->uv; + } + } - return NULL; + return NULL; } /** \} */ @@ -1368,149 +1430,149 @@ static float *uv_sel_co_from_eve(Scene *scene, Object *obedit, Image *ima, BMEdi static int uv_select_more_less(bContext *C, const bool select) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); - SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Image *ima = CTX_data_edit_image(C); + SpaceImage *sima = CTX_wm_space_image(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - ToolSettings *ts = scene->toolsettings; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + ToolSettings *ts = scene->toolsettings; - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &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); + 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; + bool changed = false; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (select) { - EDBM_select_more(em, true); - } - else { - EDBM_select_less(em, true); - } + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (select) { + EDBM_select_more(em, true); + } + else { + EDBM_select_less(em, true); + } - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - continue; - } + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + continue; + } - if (ts->uv_selectmode == UV_SELECT_FACE) { + if (ts->uv_selectmode == UV_SELECT_FACE) { - /* clear tags */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + /* clear tags */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - /* mark loops to be selected */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + /* mark loops to be selected */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (uvedit_face_visible_test(scene, obedit, ima, efa)) { -#define IS_SEL 1 +#define IS_SEL 1 #define IS_UNSEL 2 - int sel_state = 0; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (luv->flag & MLOOPUV_VERTSEL) { - sel_state |= IS_SEL; - } - else { - sel_state |= IS_UNSEL; - } - - /* if we have a mixed selection, tag to grow it */ - if (sel_state == (IS_SEL | IS_UNSEL)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - changed = true; - break; - } - } + int sel_state = 0; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (luv->flag & MLOOPUV_VERTSEL) { + sel_state |= IS_SEL; + } + else { + sel_state |= IS_UNSEL; + } + + /* if we have a mixed selection, tag to grow it */ + if (sel_state == (IS_SEL | IS_UNSEL)) { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + changed = true; + break; + } + } #undef IS_SEL #undef IS_UNSEL - - } - } - } - else { - - /* clear tags */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - BM_elem_flag_disable(l, BM_ELEM_TAG); - } - } - - /* mark loops to be selected */ - 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) { - - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) { - BM_elem_flag_enable(l->next, BM_ELEM_TAG); - BM_elem_flag_enable(l->prev, BM_ELEM_TAG); - changed = true; - } - } - } - } - } - - if (changed) { - /* Select tagged loops. */ - uv_select_flush_from_tag_loop(sima, scene, obedit, select); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + } + } + } + else { + + /* clear tags */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + BM_elem_flag_disable(l, BM_ELEM_TAG); + } + } + + /* mark loops to be selected */ + 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) { + + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) { + BM_elem_flag_enable(l->next, BM_ELEM_TAG); + BM_elem_flag_enable(l->prev, BM_ELEM_TAG); + changed = true; + } + } + } + } + } + + if (changed) { + /* Select tagged loops. */ + uv_select_flush_from_tag_loop(sima, scene, obedit, select); + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op)) { - return uv_select_more_less(C, true); + return uv_select_more_less(C, true); } static void UV_OT_select_more(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select More"; - ot->description = "Select more UV vertices connected to initial selection"; - ot->idname = "UV_OT_select_more"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Select More"; + ot->description = "Select more UV vertices connected to initial selection"; + ot->idname = "UV_OT_select_more"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_select_more_exec; - ot->poll = ED_operator_uvedit_space_image; + /* api callbacks */ + ot->exec = uv_select_more_exec; + ot->poll = ED_operator_uvedit_space_image; } static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op)) { - return uv_select_more_less(C, false); + return uv_select_more_less(C, false); } static void UV_OT_select_less(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Less"; - ot->description = "Deselect UV vertices at the boundary of each selection region"; - ot->idname = "UV_OT_select_less"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Select Less"; + ot->description = "Deselect UV vertices at the boundary of each selection region"; + ot->idname = "UV_OT_select_less"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_select_less_exec; - ot->poll = ED_operator_uvedit_space_image; + /* api callbacks */ + ot->exec = uv_select_less_exec; + ot->poll = ED_operator_uvedit_space_image; } /** \} */ @@ -1520,297 +1582,308 @@ static void UV_OT_select_less(wmOperatorType *ot) * \{ */ typedef enum eUVWeldAlign { - UV_STRAIGHTEN, - UV_STRAIGHTEN_X, - UV_STRAIGHTEN_Y, - UV_ALIGN_AUTO, - UV_ALIGN_X, - UV_ALIGN_Y, - UV_WELD, + UV_STRAIGHTEN, + UV_STRAIGHTEN_X, + UV_STRAIGHTEN_Y, + UV_ALIGN_AUTO, + UV_ALIGN_X, + UV_ALIGN_Y, + UV_WELD, } eUVWeldAlign; static void uv_weld_align(bContext *C, eUVWeldAlign tool) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); - ToolSettings *ts = scene->toolsettings; - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - float cent[2], min[2], max[2]; - - INIT_MINMAX2(min, max); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len); - - if (tool == UV_ALIGN_AUTO) { - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - - 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)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - minmax_v2v2_v2(min, max, luv->uv); - } - } - } - } - tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X; - } - - ED_uvedit_center_multi(scene, ima, objects, objects_len, cent, 0); - - 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; - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if (ELEM(tool, UV_ALIGN_X, UV_WELD)) { - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - - 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)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->uv[0] = cent[0]; - changed = true; - } - - } - } - } - - if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) { - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - - 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)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->uv[1] = cent[1]; - changed = true; - } - - } - } - } - - if (ELEM(tool, UV_STRAIGHTEN, UV_STRAIGHTEN_X, UV_STRAIGHTEN_Y)) { - BMEdge *eed; - BMLoop *l; - BMVert *eve; - BMVert *eve_start; - BMIter iter, liter, eiter; - - /* clear tag */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - - /* 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) { - if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) - continue; - - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - BM_elem_flag_enable(eve, BM_ELEM_TAG); - break; - } - } - } - - /* flush vertex tags to edges */ - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set( - eed, BM_ELEM_TAG, - (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) && - BM_elem_flag_test(eed->v2, BM_ELEM_TAG))); - } - - /* find a vertex with only one tagged edge */ - eve_start = NULL; - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - int tot_eed_tag = 0; - BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(eed, BM_ELEM_TAG)) { - tot_eed_tag++; - } - } - - if (tot_eed_tag == 1) { - eve_start = eve; - break; - } - } - - if (eve_start) { - BMVert **eve_line = NULL; - BMVert *eve_next = NULL; - BLI_array_declare(eve_line); - int i; - - eve = eve_start; - - /* walk over edges, building an array of verts in a line */ - while (eve) { - BLI_array_append(eve_line, eve); - /* don't touch again */ - BM_elem_flag_disable(eve, BM_ELEM_TAG); - - eve_next = NULL; - - /* find next eve */ - BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(eed, BM_ELEM_TAG)) { - BMVert *eve_other = BM_edge_other_vert(eed, eve); - if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) { - /* this is a tagged vert we didn't walk over yet, step onto it */ - eve_next = eve_other; - break; - } - } - } - - eve = eve_next; - } - - /* now we have all verts, make into a line */ - 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, 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 UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */ - float a = 0.0f; - eUVWeldAlign tool_local = tool; - - if (tool_local == UV_STRAIGHTEN_X) { - if (uv_start[1] == uv_end[1]) - tool_local = UV_STRAIGHTEN; - else - a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]); - } - else if (tool_local == UV_STRAIGHTEN_Y) { - if (uv_start[0] == uv_end[0]) - tool_local = UV_STRAIGHTEN; - else - a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]); - } - - /* 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) { - if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) - continue; - - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis: - * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1 - * Maybe this should be a BLI func? Or is it already existing? - * Could use interp_v2_v2v2, but not sure it's worth it here...*/ - if (tool_local == UV_STRAIGHTEN_X) - luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0]; - else if (tool_local == UV_STRAIGHTEN_Y) - luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1]; - else - closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end); - changed = true; - } - } - } - } - else { - /* error - not a line, needs 3+ points */ - } - - if (eve_line) { - MEM_freeN(eve_line); - } - } - else { - /* error - cant find an endpoint */ - } - } - - if (changed) { - uvedit_live_unwrap_update(sima, scene, obedit); - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - } - - MEM_freeN(objects); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = CTX_data_edit_image(C); + ToolSettings *ts = scene->toolsettings; + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + float cent[2], min[2], max[2]; + + INIT_MINMAX2(min, max); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + if (tool == UV_ALIGN_AUTO) { + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BMIter iter, liter; + BMFace *efa; + BMLoop *l; + + 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)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + minmax_v2v2_v2(min, max, luv->uv); + } + } + } + } + tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X; + } + + ED_uvedit_center_multi(scene, ima, objects, objects_len, cent, 0); + + 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; + + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (ELEM(tool, UV_ALIGN_X, UV_WELD)) { + BMIter iter, liter; + BMFace *efa; + BMLoop *l; + + 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)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->uv[0] = cent[0]; + changed = true; + } + } + } + } + + if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) { + BMIter iter, liter; + BMFace *efa; + BMLoop *l; + + 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)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->uv[1] = cent[1]; + changed = true; + } + } + } + } + + if (ELEM(tool, UV_STRAIGHTEN, UV_STRAIGHTEN_X, UV_STRAIGHTEN_Y)) { + BMEdge *eed; + BMLoop *l; + BMVert *eve; + BMVert *eve_start; + BMIter iter, liter, eiter; + + /* clear tag */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + /* 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) { + if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) + continue; + + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + BM_elem_flag_enable(eve, BM_ELEM_TAG); + break; + } + } + } + + /* flush vertex tags to edges */ + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set( + eed, + BM_ELEM_TAG, + (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) && BM_elem_flag_test(eed->v2, BM_ELEM_TAG))); + } + + /* find a vertex with only one tagged edge */ + eve_start = NULL; + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + int tot_eed_tag = 0; + BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(eed, BM_ELEM_TAG)) { + tot_eed_tag++; + } + } + + if (tot_eed_tag == 1) { + eve_start = eve; + break; + } + } + + if (eve_start) { + BMVert **eve_line = NULL; + BMVert *eve_next = NULL; + BLI_array_declare(eve_line); + int i; + + eve = eve_start; + + /* walk over edges, building an array of verts in a line */ + while (eve) { + BLI_array_append(eve_line, eve); + /* don't touch again */ + BM_elem_flag_disable(eve, BM_ELEM_TAG); + + eve_next = NULL; + + /* find next eve */ + BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(eed, BM_ELEM_TAG)) { + BMVert *eve_other = BM_edge_other_vert(eed, eve); + if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) { + /* this is a tagged vert we didn't walk over yet, step onto it */ + eve_next = eve_other; + break; + } + } + } + + eve = eve_next; + } + + /* now we have all verts, make into a line */ + 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, 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 UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */ + float a = 0.0f; + eUVWeldAlign tool_local = tool; + + if (tool_local == UV_STRAIGHTEN_X) { + if (uv_start[1] == uv_end[1]) + tool_local = UV_STRAIGHTEN; + else + a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]); + } + else if (tool_local == UV_STRAIGHTEN_Y) { + if (uv_start[0] == uv_end[0]) + tool_local = UV_STRAIGHTEN; + else + a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]); + } + + /* 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) { + if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) + continue; + + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis: + * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1 + * Maybe this should be a BLI func? Or is it already existing? + * Could use interp_v2_v2v2, but not sure it's worth it here...*/ + if (tool_local == UV_STRAIGHTEN_X) + luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0]; + else if (tool_local == UV_STRAIGHTEN_Y) + luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1]; + else + closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end); + changed = true; + } + } + } + } + else { + /* error - not a line, needs 3+ points */ + } + + if (eve_line) { + MEM_freeN(eve_line); + } + } + else { + /* error - cant find an endpoint */ + } + } + + if (changed) { + uvedit_live_unwrap_update(sima, scene, obedit); + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + } + + MEM_freeN(objects); } static int uv_align_exec(bContext *C, wmOperator *op) { - uv_weld_align(C, RNA_enum_get(op->ptr, "axis")); + uv_weld_align(C, RNA_enum_get(op->ptr, "axis")); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void UV_OT_align(wmOperatorType *ot) { - static const EnumPropertyItem axis_items[] = { - {UV_STRAIGHTEN, "ALIGN_S", 0, "Straighten", - "Align UVs along the line defined by the endpoints"}, - {UV_STRAIGHTEN_X, "ALIGN_T", 0, "Straighten X", - "Align UVs along the line defined by the endpoints along the X axis"}, - {UV_STRAIGHTEN_Y, "ALIGN_U", 0, "Straighten Y", - "Align UVs along the line defined by the endpoints along the Y axis"}, - {UV_ALIGN_AUTO, "ALIGN_AUTO", 0, "Align Auto", - "Automatically choose the axis on which there is most alignment already"}, - {UV_ALIGN_X, "ALIGN_X", 0, "Align X", "Align UVs on X axis"}, - {UV_ALIGN_Y, "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Align"; - ot->description = "Align selected UV vertices to an axis"; - ot->idname = "UV_OT_align"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_align_exec; - ot->poll = ED_operator_uvedit; - - /* properties */ - RNA_def_enum(ot->srna, "axis", axis_items, UV_ALIGN_AUTO, "Axis", "Axis to align UV locations on"); + static const EnumPropertyItem axis_items[] = { + {UV_STRAIGHTEN, + "ALIGN_S", + 0, + "Straighten", + "Align UVs along the line defined by the endpoints"}, + {UV_STRAIGHTEN_X, + "ALIGN_T", + 0, + "Straighten X", + "Align UVs along the line defined by the endpoints along the X axis"}, + {UV_STRAIGHTEN_Y, + "ALIGN_U", + 0, + "Straighten Y", + "Align UVs along the line defined by the endpoints along the Y axis"}, + {UV_ALIGN_AUTO, + "ALIGN_AUTO", + 0, + "Align Auto", + "Automatically choose the axis on which there is most alignment already"}, + {UV_ALIGN_X, "ALIGN_X", 0, "Align X", "Align UVs on X axis"}, + {UV_ALIGN_Y, "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Align"; + ot->description = "Align selected UV vertices to an axis"; + ot->idname = "UV_OT_align"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_align_exec; + ot->poll = ED_operator_uvedit; + + /* properties */ + RNA_def_enum( + ot->srna, "axis", axis_items, UV_ALIGN_AUTO, "Axis", "Axis to align UV locations on"); } /** \} */ @@ -1821,282 +1894,293 @@ static void UV_OT_align(wmOperatorType *ot) static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); - ToolSettings *ts = scene->toolsettings; - - const float threshold = RNA_float_get(op->ptr, "threshold"); - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len); - - bool *changed = MEM_callocN(sizeof(bool) * objects_len, "uv_remove_doubles_selected.changed"); - - /* Maximum index of an objects[i]'s MLoopUVs in MLoopUV_arr. - * It helps find which MLoopUV in *MLoopUV_arr belongs to which object. */ - uint *ob_mloopuv_max_idx = MEM_callocN(sizeof(uint) * objects_len, - "uv_remove_doubles_selected.ob_mloopuv_max_idx"); - - /* Calculate max possible number of kdtree nodes. */ - int uv_maxlen = 0; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - uv_maxlen += em->bm->totloop; - } - - KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen); - - int *duplicates = NULL; - BLI_array_declare(duplicates); - - MLoopUV **mloopuv_arr = NULL; - BLI_array_declare(mloopuv_arr); - - int mloopuv_count = 0; /* Also used for *duplicates count. */ - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - 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) { - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv); - BLI_array_append(duplicates, -1); - BLI_array_append(mloopuv_arr, luv); - mloopuv_count++; - } - } - } - - ob_mloopuv_max_idx[ob_index] = mloopuv_count - 1; - } - - BLI_kdtree_2d_balance(tree); - int found_duplicates = BLI_kdtree_2d_calc_duplicates_fast(tree, threshold, false, duplicates); - - if (found_duplicates > 0) { - /* Calculate average uv for duplicates. */ - int *uv_duplicate_count = MEM_callocN(sizeof(int) * mloopuv_count, - "uv_remove_doubles_selected.uv_duplicate_count"); - for (int i = 0; i < mloopuv_count; i++) { - if (duplicates[i] == -1) { /* If doesn't reference another */ - uv_duplicate_count[i]++; /* self */ - continue; - } - - if (duplicates[i] != i) { - /* If not self then accumulate uv for averaging. - * Self uv is already present in accumulator */ - add_v2_v2(mloopuv_arr[duplicates[i]]->uv, mloopuv_arr[i]->uv); - } - uv_duplicate_count[duplicates[i]]++; - } - - for (int i = 0; i < mloopuv_count; i++) { - if (uv_duplicate_count[i] < 2) { - continue; - } - - mul_v2_fl(mloopuv_arr[i]->uv, 1.0f / (float)uv_duplicate_count[i]); - } - MEM_freeN(uv_duplicate_count); - - /* Update duplicated uvs. */ - uint ob_index = 0; - for (int i = 0; i < mloopuv_count; i++) { - /* Make sure we know which object owns the MLoopUV at this index. - * Remember that in some cases the object will have no loop uv, - * thus we need the while loop, and not simply an if check. */ - while (ob_mloopuv_max_idx[ob_index] < i) { - ob_index++; - } - - if (duplicates[i] == -1) { - continue; - } - - copy_v2_v2(mloopuv_arr[i]->uv, mloopuv_arr[duplicates[i]]->uv); - changed[ob_index] = true; - } - - for (ob_index = 0; ob_index < objects_len; ob_index++) { - if (changed[ob_index]) { - Object *obedit = objects[ob_index]; - uvedit_live_unwrap_update(sima, scene, obedit); - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - } - } - - BLI_kdtree_2d_free(tree); - BLI_array_free(mloopuv_arr); - BLI_array_free(duplicates); - MEM_freeN(changed); - MEM_freeN(objects); - MEM_freeN(ob_mloopuv_max_idx); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = CTX_data_edit_image(C); + ToolSettings *ts = scene->toolsettings; + + const float threshold = RNA_float_get(op->ptr, "threshold"); + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + bool *changed = MEM_callocN(sizeof(bool) * objects_len, "uv_remove_doubles_selected.changed"); + + /* Maximum index of an objects[i]'s MLoopUVs in MLoopUV_arr. + * It helps find which MLoopUV in *MLoopUV_arr belongs to which object. */ + uint *ob_mloopuv_max_idx = MEM_callocN(sizeof(uint) * objects_len, + "uv_remove_doubles_selected.ob_mloopuv_max_idx"); + + /* Calculate max possible number of kdtree nodes. */ + int uv_maxlen = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } + + uv_maxlen += em->bm->totloop; + } + + KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen); + + int *duplicates = NULL; + BLI_array_declare(duplicates); + + MLoopUV **mloopuv_arr = NULL; + BLI_array_declare(mloopuv_arr); + + int mloopuv_count = 0; /* Also used for *duplicates count. */ + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + BMIter iter, liter; + BMFace *efa; + BMLoop *l; + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } + + 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) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv); + BLI_array_append(duplicates, -1); + BLI_array_append(mloopuv_arr, luv); + mloopuv_count++; + } + } + } + + ob_mloopuv_max_idx[ob_index] = mloopuv_count - 1; + } + + BLI_kdtree_2d_balance(tree); + int found_duplicates = BLI_kdtree_2d_calc_duplicates_fast(tree, threshold, false, duplicates); + + if (found_duplicates > 0) { + /* Calculate average uv for duplicates. */ + int *uv_duplicate_count = MEM_callocN(sizeof(int) * mloopuv_count, + "uv_remove_doubles_selected.uv_duplicate_count"); + for (int i = 0; i < mloopuv_count; i++) { + if (duplicates[i] == -1) { /* If doesn't reference another */ + uv_duplicate_count[i]++; /* self */ + continue; + } + + if (duplicates[i] != i) { + /* If not self then accumulate uv for averaging. + * Self uv is already present in accumulator */ + add_v2_v2(mloopuv_arr[duplicates[i]]->uv, mloopuv_arr[i]->uv); + } + uv_duplicate_count[duplicates[i]]++; + } + + for (int i = 0; i < mloopuv_count; i++) { + if (uv_duplicate_count[i] < 2) { + continue; + } + + mul_v2_fl(mloopuv_arr[i]->uv, 1.0f / (float)uv_duplicate_count[i]); + } + MEM_freeN(uv_duplicate_count); + + /* Update duplicated uvs. */ + uint ob_index = 0; + for (int i = 0; i < mloopuv_count; i++) { + /* Make sure we know which object owns the MLoopUV at this index. + * Remember that in some cases the object will have no loop uv, + * thus we need the while loop, and not simply an if check. */ + while (ob_mloopuv_max_idx[ob_index] < i) { + ob_index++; + } + + if (duplicates[i] == -1) { + continue; + } + + copy_v2_v2(mloopuv_arr[i]->uv, mloopuv_arr[duplicates[i]]->uv); + changed[ob_index] = true; + } + + for (ob_index = 0; ob_index < objects_len; ob_index++) { + if (changed[ob_index]) { + Object *obedit = objects[ob_index]; + uvedit_live_unwrap_update(sima, scene, obedit); + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + } + } + + BLI_kdtree_2d_free(tree); + BLI_array_free(mloopuv_arr); + BLI_array_free(duplicates); + MEM_freeN(changed); + MEM_freeN(objects); + MEM_freeN(ob_mloopuv_max_idx); + + return OPERATOR_FINISHED; } static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); - ToolSettings *ts = scene->toolsettings; - - const float threshold = RNA_float_get(op->ptr, "threshold"); - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len); - - /* Calculate max possible number of kdtree nodes. */ - int uv_maxlen = 0; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - uv_maxlen += em->bm->totloop; - } - - KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen); - - MLoopUV **mloopuv_arr = NULL; - BLI_array_declare(mloopuv_arr); - - int mloopuv_count = 0; - - /* Add visible non-selected uvs to tree */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (synced_selection && (em->bm->totvertsel == em->bm->totvert)) { - continue; - } - - 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) { - if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv); - BLI_array_append(mloopuv_arr, luv); - mloopuv_count++; - } - } - } - } - - BLI_kdtree_2d_balance(tree); - - /* For each selected uv, find duplicate non selected uv. */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - bool changed = false; - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - 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) { - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - KDTreeNearest_2d nearest; - const int i = BLI_kdtree_2d_find_nearest(tree, luv->uv, &nearest); - - if (i != -1 && nearest.dist < threshold) { - copy_v2_v2(luv->uv, mloopuv_arr[i]->uv); - changed = true; - } - } - } - } - - if (changed) { - uvedit_live_unwrap_update(sima, scene, obedit); - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - } - - BLI_kdtree_2d_free(tree); - BLI_array_free(mloopuv_arr); - MEM_freeN(objects); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = CTX_data_edit_image(C); + ToolSettings *ts = scene->toolsettings; + + const float threshold = RNA_float_get(op->ptr, "threshold"); + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + /* Calculate max possible number of kdtree nodes. */ + int uv_maxlen = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + uv_maxlen += em->bm->totloop; + } + + KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen); + + MLoopUV **mloopuv_arr = NULL; + BLI_array_declare(mloopuv_arr); + + int mloopuv_count = 0; + + /* Add visible non-selected uvs to tree */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + BMIter iter, liter; + BMFace *efa; + BMLoop *l; + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (synced_selection && (em->bm->totvertsel == em->bm->totvert)) { + continue; + } + + 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) { + if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv); + BLI_array_append(mloopuv_arr, luv); + mloopuv_count++; + } + } + } + } + + BLI_kdtree_2d_balance(tree); + + /* For each selected uv, find duplicate non selected uv. */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + BMIter iter, liter; + BMFace *efa; + BMLoop *l; + bool changed = false; + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } + + 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) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + KDTreeNearest_2d nearest; + const int i = BLI_kdtree_2d_find_nearest(tree, luv->uv, &nearest); + + if (i != -1 && nearest.dist < threshold) { + copy_v2_v2(luv->uv, mloopuv_arr[i]->uv); + changed = true; + } + } + } + } + + if (changed) { + uvedit_live_unwrap_update(sima, scene, obedit); + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + } + + BLI_kdtree_2d_free(tree); + BLI_array_free(mloopuv_arr); + MEM_freeN(objects); + + return OPERATOR_FINISHED; } static int uv_remove_doubles_exec(bContext *C, wmOperator *op) { - if (RNA_boolean_get(op->ptr, "use_unselected")) { - return uv_remove_doubles_to_unselected(C, op); - } - else { - return uv_remove_doubles_to_selected(C, op); - } + if (RNA_boolean_get(op->ptr, "use_unselected")) { + return uv_remove_doubles_to_unselected(C, op); + } + else { + return uv_remove_doubles_to_selected(C, op); + } } static void UV_OT_remove_doubles(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove Doubles UV"; - ot->description = "Selected UV vertices that are within a radius of each other are welded together"; - ot->idname = "UV_OT_remove_doubles"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_remove_doubles_exec; - ot->poll = ED_operator_uvedit; - - RNA_def_float(ot->srna, "threshold", 0.02f, 0.0f, 10.0f, - "Merge Distance", "Maximum distance between welded vertices", 0.0f, 1.0f); - RNA_def_boolean(ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices"); + /* identifiers */ + ot->name = "Remove Doubles UV"; + ot->description = + "Selected UV vertices that are within a radius of each other are welded together"; + ot->idname = "UV_OT_remove_doubles"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_remove_doubles_exec; + ot->poll = ED_operator_uvedit; + + RNA_def_float(ot->srna, + "threshold", + 0.02f, + 0.0f, + 10.0f, + "Merge Distance", + "Maximum distance between welded vertices", + 0.0f, + 1.0f); + RNA_def_boolean( + ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices"); } /** \} */ @@ -2107,22 +2191,22 @@ static void UV_OT_remove_doubles(wmOperatorType *ot) static int uv_weld_exec(bContext *C, wmOperator *UNUSED(op)) { - uv_weld_align(C, UV_WELD); + uv_weld_align(C, UV_WELD); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void UV_OT_weld(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Weld"; - ot->description = "Weld selected UV vertices together"; - ot->idname = "UV_OT_weld"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Weld"; + ot->description = "Weld selected UV vertices together"; + ot->idname = "UV_OT_weld"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_weld_exec; - ot->poll = ED_operator_uvedit; + /* api callbacks */ + ot->exec = uv_weld_exec; + ot->poll = ED_operator_uvedit; } /** \} */ @@ -2133,153 +2217,158 @@ static void UV_OT_weld(wmOperatorType *ot) 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; + 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; - MLoopUV *luv; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if (action == SEL_TOGGLE) { - action = uv_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT; - } - - if (ts->uv_flag & UV_SYNC_SELECTION) { - switch (action) { - case SEL_TOGGLE: - EDBM_select_toggle_all(em); - break; - case SEL_SELECT: - EDBM_flag_enable_all(em, BM_ELEM_SELECT); - break; - case SEL_DESELECT: - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - break; - case SEL_INVERT: - EDBM_select_swap(em); - EDBM_selectmode_flush(em); - break; - } - } - else { - 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); - - switch (action) { - case SEL_SELECT: - luv->flag |= MLOOPUV_VERTSEL; - break; - case SEL_DESELECT: - luv->flag &= ~MLOOPUV_VERTSEL; - break; - case SEL_INVERT: - luv->flag ^= MLOOPUV_VERTSEL; - break; - } - } - } - } + ToolSettings *ts = scene->toolsettings; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (action == SEL_TOGGLE) { + action = uv_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT; + } + + if (ts->uv_flag & UV_SYNC_SELECTION) { + switch (action) { + case SEL_TOGGLE: + EDBM_select_toggle_all(em); + break; + case SEL_SELECT: + EDBM_flag_enable_all(em, BM_ELEM_SELECT); + break; + case SEL_DESELECT: + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + break; + case SEL_INVERT: + EDBM_select_swap(em); + EDBM_selectmode_flush(em); + break; + } + } + else { + 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); + + switch (action) { + case SEL_SELECT: + luv->flag |= MLOOPUV_VERTSEL; + break; + case SEL_DESELECT: + luv->flag &= ~MLOOPUV_VERTSEL; + break; + case SEL_INVERT: + luv->flag ^= MLOOPUV_VERTSEL; + break; + } + } + } + } } static void uv_select_all_perform_multi( - Scene *scene, Image *ima, Object **objects, const uint objects_len, int action) + 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; - } + 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); - } + 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) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - Image *ima = CTX_data_edit_image(C); - ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + Image *ima = CTX_data_edit_image(C); + ViewLayer *view_layer = CTX_data_view_layer(C); - int action = RNA_enum_get(op->ptr, "action"); + int action = RNA_enum_get(op->ptr, "action"); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); - uv_select_all_perform_multi(scene, ima, objects, objects_len, action); + 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]; - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } - MEM_freeN(objects); + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void UV_OT_select_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "(De)select All"; - ot->description = "Change selection of all UV vertices"; - ot->idname = "UV_OT_select_all"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "(De)select All"; + ot->description = "Change selection of all UV vertices"; + ot->idname = "UV_OT_select_all"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_select_all_exec; - ot->poll = ED_operator_uvedit; + /* api callbacks */ + ot->exec = uv_select_all_exec; + ot->poll = ED_operator_uvedit; - WM_operator_properties_select_all(ot); + WM_operator_properties_select_all(ot); } /** \} */ @@ -2288,352 +2377,370 @@ static void UV_OT_select_all(wmOperatorType *ot) /** \name Mouse Select Operator * \{ */ -static bool uv_sticky_select(float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen) +static bool uv_sticky_select( + float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen) { - int i; + int i; - /* this function test if some vertex needs to selected - * in addition to the existing ones due to sticky select */ - if (sticky == SI_STICKY_DISABLE) - return false; + /* this function test if some vertex needs to selected + * in addition to the existing ones due to sticky select */ + if (sticky == SI_STICKY_DISABLE) + return false; - for (i = 0; i < hitlen; i++) { - if (hitv[i] == v) { - if (sticky == SI_STICKY_LOC) { - if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) - return true; - } - else if (sticky == SI_STICKY_VERTEX) - return true; - } - } + for (i = 0; i < hitlen; i++) { + if (hitv[i] == v) { + if (sticky == SI_STICKY_LOC) { + if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) + return true; + } + else if (sticky == SI_STICKY_VERTEX) + return true; + } + } - return false; + return false; } static int uv_mouse_select_multi( - bContext *C, Object **objects, uint objects_len, - const float co[2], bool extend, bool loop) -{ - Depsgraph *depsgraph = CTX_data_depsgraph(C); - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - Image *ima = CTX_data_edit_image(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - UvNearestHit hit = UV_NEAREST_HIT_INIT; - int i, selectmode, sticky, sync, *hitv = NULL; - bool select = true; - /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ - int flush = 0; - int hitlen = 0; - float limit[2], **hituv = NULL; - - /* 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 - * shift-selecting can consider an adjacent point close enough to add to - * the selection rather than de-selecting the closest. */ - - float penalty_dist; - { - float penalty[2]; - uvedit_pixel_to_float(sima, limit, 0.05f); - uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f)); - penalty_dist = len_v2(penalty); - } - - /* retrieve operation mode */ - if (ts->uv_flag & UV_SYNC_SELECTION) { - sync = 1; - - if (ts->selectmode & SCE_SELECT_FACE) - selectmode = UV_SELECT_FACE; - else if (ts->selectmode & SCE_SELECT_EDGE) - selectmode = UV_SELECT_EDGE; - else - selectmode = UV_SELECT_VERTEX; - - sticky = SI_STICKY_DISABLE; - } - else { - sync = 0; - selectmode = ts->uv_selectmode; - sticky = (sima) ? sima->sticky : 1; - } - - /* find nearest element */ - if (loop) { - /* find edge */ - if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { - return OPERATOR_CANCELLED; - } - - hitlen = 0; - } - else if (selectmode == UV_SELECT_VERTEX) { - /* find vertex */ - if (!uv_find_nearest_vert_multi(scene, ima, objects, objects_len, co, penalty_dist, &hit)) { - return OPERATOR_CANCELLED; - } - - /* mark 1 vertex as being hit */ - hitv = BLI_array_alloca(hitv, hit.efa->len); - hituv = BLI_array_alloca(hituv, hit.efa->len); - copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); - - hitv[hit.lindex] = BM_elem_index_get(hit.l->v); - hituv[hit.lindex] = hit.luv->uv; - - hitlen = hit.efa->len; - } - else if (selectmode == UV_SELECT_EDGE) { - /* find edge */ - if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { - return OPERATOR_CANCELLED; - } - - /* mark 2 edge vertices as being hit */ - hitv = BLI_array_alloca(hitv, hit.efa->len); - hituv = BLI_array_alloca(hituv, hit.efa->len); - copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); - - hitv[hit.lindex] = BM_elem_index_get(hit.l->v); - hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v); - hituv[hit.lindex] = hit.luv->uv; - hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv; - - hitlen = hit.efa->len; - } - else if (selectmode == UV_SELECT_FACE) { - /* find face */ - 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); - - /* mark all face vertices as being hit */ - - hitv = BLI_array_alloca(hitv, hit.efa->len); - hituv = BLI_array_alloca(hituv, hit.efa->len); - BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - hituv[i] = luv->uv; - hitv[i] = BM_elem_index_get(l->v); - } - - hitlen = hit.efa->len; - } - else if (selectmode == UV_SELECT_ISLAND) { - if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { - return OPERATOR_CANCELLED; - } - - hitlen = 0; - } - else { - hitlen = 0; - 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) { - 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_multi(scene, ima, objects, objects_len, limit, &hit, false, false, extend, false); - } - else if (extend) { - if (selectmode == UV_SELECT_VERTEX) { - /* (de)select uv vertex */ - select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); - uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_EDGE) { - /* (de)select edge */ - select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset)); - uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_FACE) { - /* (de)select face */ - select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset)); - uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset); - flush = -1; - } - - /* de-selecting an edge may deselect a face too - validate */ - if (sync) { - if (select == false) { - BM_select_history_validate(em->bm); - } - } - - /* (de)select sticky uv nodes */ - if (sticky != SI_STICKY_DISABLE) { - - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - - 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 (uv_sticky_select(limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - - flush = select ? 1 : -1; - } - } - else { - /* deselect all */ - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); - - if (selectmode == UV_SELECT_VERTEX) { - /* select vertex */ - uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_EDGE) { - /* select edge */ - uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_FACE) { - /* select face */ - uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset); - } - - /* select sticky uvs */ - if (sticky != SI_STICKY_DISABLE) { - 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 (sticky == SI_STICKY_DISABLE) continue; - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (uv_sticky_select(limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) - uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); - - flush = 1; - } - } - } - } - - if (sync) { - /* flush for mesh selection */ - - /* before bmesh */ + bContext *C, Object **objects, uint objects_len, const float co[2], bool extend, bool loop) +{ + Depsgraph *depsgraph = CTX_data_depsgraph(C); + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + Image *ima = CTX_data_edit_image(C); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + UvNearestHit hit = UV_NEAREST_HIT_INIT; + int i, selectmode, sticky, sync, *hitv = NULL; + bool select = true; + /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ + int flush = 0; + int hitlen = 0; + float limit[2], **hituv = NULL; + + /* 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 + * shift-selecting can consider an adjacent point close enough to add to + * the selection rather than de-selecting the closest. */ + + float penalty_dist; + { + float penalty[2]; + uvedit_pixel_to_float(sima, limit, 0.05f); + uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f)); + penalty_dist = len_v2(penalty); + } + + /* retrieve operation mode */ + if (ts->uv_flag & UV_SYNC_SELECTION) { + sync = 1; + + if (ts->selectmode & SCE_SELECT_FACE) + selectmode = UV_SELECT_FACE; + else if (ts->selectmode & SCE_SELECT_EDGE) + selectmode = UV_SELECT_EDGE; + else + selectmode = UV_SELECT_VERTEX; + + sticky = SI_STICKY_DISABLE; + } + else { + sync = 0; + selectmode = ts->uv_selectmode; + sticky = (sima) ? sima->sticky : 1; + } + + /* find nearest element */ + if (loop) { + /* find edge */ + if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { + return OPERATOR_CANCELLED; + } + + hitlen = 0; + } + else if (selectmode == UV_SELECT_VERTEX) { + /* find vertex */ + if (!uv_find_nearest_vert_multi(scene, ima, objects, objects_len, co, penalty_dist, &hit)) { + return OPERATOR_CANCELLED; + } + + /* mark 1 vertex as being hit */ + hitv = BLI_array_alloca(hitv, hit.efa->len); + hituv = BLI_array_alloca(hituv, hit.efa->len); + copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); + + hitv[hit.lindex] = BM_elem_index_get(hit.l->v); + hituv[hit.lindex] = hit.luv->uv; + + hitlen = hit.efa->len; + } + else if (selectmode == UV_SELECT_EDGE) { + /* find edge */ + if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { + return OPERATOR_CANCELLED; + } + + /* mark 2 edge vertices as being hit */ + hitv = BLI_array_alloca(hitv, hit.efa->len); + hituv = BLI_array_alloca(hituv, hit.efa->len); + copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); + + hitv[hit.lindex] = BM_elem_index_get(hit.l->v); + hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v); + hituv[hit.lindex] = hit.luv->uv; + hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv; + + hitlen = hit.efa->len; + } + else if (selectmode == UV_SELECT_FACE) { + /* find face */ + 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); + + /* mark all face vertices as being hit */ + + hitv = BLI_array_alloca(hitv, hit.efa->len); + hituv = BLI_array_alloca(hituv, hit.efa->len); + BM_ITER_ELEM_INDEX(l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) + { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + hituv[i] = luv->uv; + hitv[i] = BM_elem_index_get(l->v); + } + + hitlen = hit.efa->len; + } + else if (selectmode == UV_SELECT_ISLAND) { + if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { + return OPERATOR_CANCELLED; + } + + hitlen = 0; + } + else { + hitlen = 0; + 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) { + 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_multi( + scene, ima, objects, objects_len, limit, &hit, false, false, extend, false); + } + else if (extend) { + if (selectmode == UV_SELECT_VERTEX) { + /* (de)select uv vertex */ + select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); + uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_EDGE) { + /* (de)select edge */ + select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset)); + uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_FACE) { + /* (de)select face */ + select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset)); + uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset); + flush = -1; + } + + /* de-selecting an edge may deselect a face too - validate */ + if (sync) { + if (select == false) { + BM_select_history_validate(em->bm); + } + } + + /* (de)select sticky uv nodes */ + if (sticky != SI_STICKY_DISABLE) { + + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + + 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 (uv_sticky_select( + limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + + flush = select ? 1 : -1; + } + } + else { + /* deselect all */ + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + + if (selectmode == UV_SELECT_VERTEX) { + /* select vertex */ + uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_EDGE) { + /* select edge */ + uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_FACE) { + /* select face */ + uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset); + } + + /* select sticky uvs */ + if (sticky != SI_STICKY_DISABLE) { + 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 (sticky == SI_STICKY_DISABLE) + continue; + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (uv_sticky_select( + limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) + uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); + + flush = 1; + } + } + } + } + + if (sync) { + /* flush for mesh selection */ + + /* before bmesh */ #if 0 - if (ts->selectmode != SCE_SELECT_FACE) { - if (flush == 1) EDBM_select_flush(em); - else if (flush == -1) EDBM_deselect_flush(em); - } + if (ts->selectmode != SCE_SELECT_FACE) { + if (flush == 1) EDBM_select_flush(em); + else if (flush == -1) EDBM_deselect_flush(em); + } #else - if (flush != 0) { - if (loop) { - /* push vertex -> edge selection */ - if (select) { - EDBM_select_flush(em); - } - else { - EDBM_deselect_flush(em); - } - } - else { - EDBM_selectmode_flush(em); - } - } + if (flush != 0) { + if (loop) { + /* push vertex -> edge selection */ + if (select) { + EDBM_select_flush(em); + } + else { + EDBM_deselect_flush(em); + } + } + else { + EDBM_selectmode_flush(em); + } + } #endif - } + } - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obiter = objects[ob_index]; - uv_select_tag_update_for_object(depsgraph, ts, obiter); - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obiter = objects[ob_index]; + uv_select_tag_update_for_object(depsgraph, ts, obiter); + } - return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; + 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, ((View3D *)NULL), &objects_len); - int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, loop); - MEM_freeN(objects); - return ret; + 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, ((View3D *)NULL), &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) { - float co[2]; - bool extend, loop; + float co[2]; + bool extend, loop; - RNA_float_get_array(op->ptr, "location", co); - extend = RNA_boolean_get(op->ptr, "extend"); - loop = false; + RNA_float_get_array(op->ptr, "location", co); + extend = RNA_boolean_get(op->ptr, "extend"); + loop = false; - return uv_mouse_select(C, co, extend, loop); + return uv_mouse_select(C, co, extend, loop); } static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - float co[2]; + ARegion *ar = CTX_wm_region(C); + float co[2]; - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); - RNA_float_set_array(op->ptr, "location", co); + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + RNA_float_set_array(op->ptr, "location", co); - return uv_select_exec(C, op); + return uv_select_exec(C, op); } static void UV_OT_select(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select"; - ot->description = "Select UV vertices"; - ot->idname = "UV_OT_select"; - ot->flag = OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_exec; - ot->invoke = uv_select_invoke; - ot->poll = ED_operator_uvedit; /* requires space image */ - - /* properties */ - RNA_def_boolean(ot->srna, "extend", 0, - "Extend", "Extend selection rather than clearing the existing selection"); - RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, - "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f); + /* identifiers */ + ot->name = "Select"; + ot->description = "Select UV vertices"; + ot->idname = "UV_OT_select"; + ot->flag = OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_exec; + ot->invoke = uv_select_invoke; + ot->poll = ED_operator_uvedit; /* requires space image */ + + /* properties */ + RNA_def_boolean(ot->srna, + "extend", + 0, + "Extend", + "Extend selection rather than clearing the existing selection"); + RNA_def_float_vector( + ot->srna, + "location", + 2, + NULL, + -FLT_MAX, + FLT_MAX, + "Location", + "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", + -100.0f, + 100.0f); } /** \} */ @@ -2644,45 +2751,57 @@ static void UV_OT_select(wmOperatorType *ot) static int uv_select_loop_exec(bContext *C, wmOperator *op) { - float co[2]; - bool extend, loop; + float co[2]; + bool extend, loop; - RNA_float_get_array(op->ptr, "location", co); - extend = RNA_boolean_get(op->ptr, "extend"); - loop = true; + RNA_float_get_array(op->ptr, "location", co); + extend = RNA_boolean_get(op->ptr, "extend"); + loop = true; - return uv_mouse_select(C, co, extend, loop); + return uv_mouse_select(C, co, extend, loop); } static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - float co[2]; + ARegion *ar = CTX_wm_region(C); + float co[2]; - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); - RNA_float_set_array(op->ptr, "location", co); + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + RNA_float_set_array(op->ptr, "location", co); - return uv_select_loop_exec(C, op); + return uv_select_loop_exec(C, op); } static void UV_OT_select_loop(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Loop Select"; - ot->description = "Select a loop of connected UV vertices"; - ot->idname = "UV_OT_select_loop"; - ot->flag = OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_loop_exec; - ot->invoke = uv_select_loop_invoke; - ot->poll = ED_operator_uvedit; /* requires space image */ - - /* properties */ - RNA_def_boolean(ot->srna, "extend", 0, - "Extend", "Extend selection rather than clearing the existing selection"); - RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, - "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f); + /* identifiers */ + ot->name = "Loop Select"; + ot->description = "Select a loop of connected UV vertices"; + ot->idname = "UV_OT_select_loop"; + ot->flag = OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_loop_exec; + ot->invoke = uv_select_loop_invoke; + ot->poll = ED_operator_uvedit; /* requires space image */ + + /* properties */ + RNA_def_boolean(ot->srna, + "extend", + 0, + "Extend", + "Extend selection rather than clearing the existing selection"); + RNA_def_float_vector( + ot->srna, + "location", + 2, + NULL, + -FLT_MAX, + FLT_MAX, + "Location", + "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", + -100.0f, + 100.0f); } /** \} */ @@ -2693,95 +2812,105 @@ static void UV_OT_select_loop(wmOperatorType *ot) static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, int pick) { - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); - float limit[2]; - bool extend = true; - bool deselect = false; - bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); - - UvNearestHit hit = UV_NEAREST_HIT_INIT; - - if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) { - BKE_report(op->reports, RPT_ERROR, "Select linked only works in face select mode when sync selection is enabled"); - return OPERATOR_CANCELLED; - } - - if (pick) { - extend = RNA_boolean_get(op->ptr, "extend"); - 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, ((View3D *)NULL), &objects_len); - - if (pick) { - float co[2]; - - if (event) { - /* invoke */ - ARegion *ar = CTX_wm_region(C); - - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); - RNA_float_set_array(op->ptr, "location", co); - } - else { - /* exec */ - RNA_float_get_array(op->ptr, "location", co); - } - - if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { - MEM_freeN(objects); - return OPERATOR_CANCELLED; - } - } - - if (!extend) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); - } - - uv_select_linked_multi( - scene, ima, objects, objects_len, limit, pick ? &hit : NULL, - extend, 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, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - - MEM_SAFE_FREE(objects_free); - - return OPERATOR_FINISHED; + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + Image *ima = CTX_data_edit_image(C); + float limit[2]; + bool extend = true; + bool deselect = false; + bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); + + UvNearestHit hit = UV_NEAREST_HIT_INIT; + + if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) { + BKE_report(op->reports, + RPT_ERROR, + "Select linked only works in face select mode when sync selection is enabled"); + return OPERATOR_CANCELLED; + } + + if (pick) { + extend = RNA_boolean_get(op->ptr, "extend"); + 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, ((View3D *)NULL), &objects_len); + + if (pick) { + float co[2]; + + if (event) { + /* invoke */ + ARegion *ar = CTX_wm_region(C); + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + RNA_float_set_array(op->ptr, "location", co); + } + else { + /* exec */ + RNA_float_get_array(op->ptr, "location", co); + } + + if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { + MEM_freeN(objects); + return OPERATOR_CANCELLED; + } + } + + if (!extend) { + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + } + + uv_select_linked_multi(scene, + ima, + objects, + objects_len, + limit, + pick ? &hit : NULL, + extend, + 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, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_SAFE_FREE(objects_free); + + return OPERATOR_FINISHED; } static int uv_select_linked_exec(bContext *C, wmOperator *op) { - return uv_select_linked_internal(C, op, NULL, 0); + return uv_select_linked_internal(C, op, NULL, 0); } static void UV_OT_select_linked(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Linked"; - ot->description = "Select all UV vertices linked to the active UV map"; - ot->idname = "UV_OT_select_linked"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Select Linked"; + ot->description = "Select all UV vertices linked to the active UV map"; + ot->idname = "UV_OT_select_linked"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_select_linked_exec; - ot->poll = ED_operator_uvedit; /* requires space image */ + /* api callbacks */ + ot->exec = uv_select_linked_exec; + ot->poll = ED_operator_uvedit; /* requires space image */ } /** \} */ @@ -2792,33 +2921,49 @@ static void UV_OT_select_linked(wmOperatorType *ot) static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - return uv_select_linked_internal(C, op, event, 1); + return uv_select_linked_internal(C, op, event, 1); } static int uv_select_linked_pick_exec(bContext *C, wmOperator *op) { - return uv_select_linked_internal(C, op, NULL, 1); + return uv_select_linked_internal(C, op, NULL, 1); } static void UV_OT_select_linked_pick(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Linked Pick"; - ot->description = "Select all UV vertices linked under the mouse"; - ot->idname = "UV_OT_select_linked_pick"; - ot->flag = OPTYPE_UNDO; - - /* api callbacks */ - ot->invoke = uv_select_linked_pick_invoke; - ot->exec = uv_select_linked_pick_exec; - ot->poll = ED_operator_uvedit; /* requires space image */ - - /* properties */ - RNA_def_boolean(ot->srna, "extend", 0, - "Extend", "Extend selection rather than clearing the existing selection"); - RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked UV vertices rather than selecting them"); - RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, - "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f); + /* identifiers */ + ot->name = "Select Linked Pick"; + ot->description = "Select all UV vertices linked under the mouse"; + ot->idname = "UV_OT_select_linked_pick"; + ot->flag = OPTYPE_UNDO; + + /* api callbacks */ + ot->invoke = uv_select_linked_pick_invoke; + ot->exec = uv_select_linked_pick_exec; + ot->poll = ED_operator_uvedit; /* requires space image */ + + /* properties */ + RNA_def_boolean(ot->srna, + "extend", + 0, + "Extend", + "Extend selection rather than clearing the existing selection"); + RNA_def_boolean(ot->srna, + "deselect", + 0, + "Deselect", + "Deselect linked UV vertices rather than selecting them"); + RNA_def_float_vector( + ot->srna, + "location", + 2, + NULL, + -FLT_MAX, + FLT_MAX, + "Location", + "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", + -100.0f, + 100.0f); } /** \} */ @@ -2835,124 +2980,126 @@ static void UV_OT_select_linked_pick(wmOperatorType *ot) */ static int uv_select_split_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - ToolSettings *ts = scene->toolsettings; - Image *ima = CTX_data_edit_image(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + ToolSettings *ts = scene->toolsettings; + Image *ima = CTX_data_edit_image(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; - if (ts->uv_flag & UV_SYNC_SELECTION) { - BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled"); - return OPERATOR_CANCELLED; - } + if (ts->uv_flag & UV_SYNC_SELECTION) { + BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled"); + return OPERATOR_CANCELLED; + } - bool changed_multi = false; + bool changed_multi = false; - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMesh *bm = BKE_editmesh_from_object(obedit)->bm; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMesh *bm = BKE_editmesh_from_object(obedit)->bm; - bool changed = false; + bool changed = false; - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - bool is_sel = false; - bool is_unsel = false; + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + bool is_sel = false; + bool is_unsel = false; - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } - /* are we all selected? */ - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + /* are we all selected? */ + 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) { - is_sel = true; - } - else { - is_unsel = true; - } + if (luv->flag & MLOOPUV_VERTSEL) { + is_sel = true; + } + else { + is_unsel = true; + } - /* we have mixed selection, bail out */ - if (is_sel && is_unsel) { - break; - } - } + /* we have mixed selection, bail out */ + if (is_sel && is_unsel) { + break; + } + } - if (is_sel && is_unsel) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag &= ~MLOOPUV_VERTSEL; - } + if (is_sel && is_unsel) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag &= ~MLOOPUV_VERTSEL; + } - changed = true; - } - } + changed = true; + } + } - if (changed) { - changed_multi = true; - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL); - } - } - MEM_freeN(objects); + if (changed) { + changed_multi = true; + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL); + } + } + MEM_freeN(objects); - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } - static void UV_OT_select_split(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Split"; - ot->description = "Select only entirely selected faces"; - ot->idname = "UV_OT_select_split"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Select Split"; + ot->description = "Select only entirely selected faces"; + ot->idname = "UV_OT_select_split"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_select_split_exec; - ot->poll = ED_operator_uvedit; /* requires space image */ + /* api callbacks */ + ot->exec = uv_select_split_exec; + ot->poll = ED_operator_uvedit; /* requires space image */ } static void uv_select_sync_flush(ToolSettings *ts, BMEditMesh *em, const short select) { - /* bmesh API handles flushing but not on de-select */ - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode != SCE_SELECT_FACE) { - if (select == false) { - EDBM_deselect_flush(em); - } - else { - EDBM_select_flush(em); - } - } - - if (select == false) { - BM_select_history_validate(em->bm); - } - } -} - -static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSettings *ts, Object *obedit) -{ - if (ts->uv_flag & UV_SYNC_SELECTION) { - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); - } - else { - Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); - BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT); - /* Only for region redraw. */ - WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); - } + /* bmesh API handles flushing but not on de-select */ + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode != SCE_SELECT_FACE) { + if (select == false) { + EDBM_deselect_flush(em); + } + else { + EDBM_select_flush(em); + } + } + + if (select == false) { + BM_select_history_validate(em->bm); + } + } +} + +static void uv_select_tag_update_for_object(Depsgraph *depsgraph, + const ToolSettings *ts, + Object *obedit) +{ + if (ts->uv_flag & UV_SYNC_SELECTION) { + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); + } + else { + Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); + BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT); + /* Only for region redraw. */ + WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); + } } /** \} */ @@ -2966,45 +3113,49 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSett /** * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face */ -static void uv_select_flush_from_tag_sticky_loc_internal( - Scene *scene, BMEditMesh *em, UvVertMap *vmap, - const unsigned int efa_index, BMLoop *l, - const bool select, const int cd_loop_uv_offset) +static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, + BMEditMesh *em, + UvVertMap *vmap, + const unsigned int efa_index, + BMLoop *l, + const bool select, + const int cd_loop_uv_offset) { - UvMapVert *start_vlist = NULL, *vlist_iter; - BMFace *efa_vlist; + UvMapVert *start_vlist = NULL, *vlist_iter; + BMFace *efa_vlist; - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); + vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); - while (vlist_iter) { - if (vlist_iter->separate) - start_vlist = vlist_iter; + while (vlist_iter) { + if (vlist_iter->separate) + start_vlist = vlist_iter; - if (efa_index == vlist_iter->poly_index) - break; + if (efa_index == vlist_iter->poly_index) + break; - vlist_iter = vlist_iter->next; - } + vlist_iter = vlist_iter->next; + } - vlist_iter = start_vlist; - while (vlist_iter) { + vlist_iter = start_vlist; + while (vlist_iter) { - if (vlist_iter != start_vlist && vlist_iter->separate) - break; + if (vlist_iter != start_vlist && vlist_iter->separate) + break; - if (efa_index != vlist_iter->poly_index) { - BMLoop *l_other; - efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index); - /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */ + if (efa_index != vlist_iter->poly_index) { + BMLoop *l_other; + efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index); + /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */ - l_other = BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index); + l_other = BM_iter_at_index( + em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index); - uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset); - } - vlist_iter = vlist_iter->next; - } + uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset); + } + vlist_iter = vlist_iter->next; + } } /** @@ -3015,83 +3166,82 @@ static void uv_select_flush_from_tag_sticky_loc_internal( * * \note! This function is very similar to #uv_select_flush_from_tag_loop, be sure to update both upon changing. */ -static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select) -{ - /* Selecting UV Faces with some modes requires us to change - * the selection in other faces (depending on the sticky mode). - * - * This only needs to be done when the Mesh is not used for - * selection (so for sticky modes, vertex or location based). */ - - ToolSettings *ts = scene->toolsettings; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - 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) { - /* Tag all verts as untouched, then touch the ones that have a face center - * in the loop and select all MLoopUV's that use a touched vert. */ - 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) { - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - BM_elem_flag_enable(l->v, BM_ELEM_TAG); - } - } - } - - /* now select tagged verts */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } - } - else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { - struct UvVertMap *vmap; - float limit[2]; - unsigned int efa_index; - - uvedit_pixel_to_float(sima, limit, 0.05); - - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - vmap = BM_uv_vert_map_create(em->bm, limit, false, false); - if (vmap == NULL) { - return; - } - - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - uv_select_flush_from_tag_sticky_loc_internal( - scene, em, vmap, efa_index, l, - select, cd_loop_uv_offset); - } - } - } - BM_uv_vert_map_free(vmap); - - } - else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset); - } - } - } +static void uv_select_flush_from_tag_face(SpaceImage *sima, + Scene *scene, + Object *obedit, + const bool select) +{ + /* Selecting UV Faces with some modes requires us to change + * the selection in other faces (depending on the sticky mode). + * + * This only needs to be done when the Mesh is not used for + * selection (so for sticky modes, vertex or location based). */ + + ToolSettings *ts = scene->toolsettings; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + 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) { + /* Tag all verts as untouched, then touch the ones that have a face center + * in the loop and select all MLoopUV's that use a touched vert. */ + 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) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } + } + } + + /* now select tagged verts */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + } + else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { + struct UvVertMap *vmap; + float limit[2]; + unsigned int efa_index; + + uvedit_pixel_to_float(sima, limit, 0.05); + + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + vmap = BM_uv_vert_map_create(em->bm, limit, false, false); + if (vmap == NULL) { + return; + } + + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + uv_select_flush_from_tag_sticky_loc_internal( + scene, em, vmap, efa_index, l, select, cd_loop_uv_offset); + } + } + } + BM_uv_vert_map_free(vmap); + } + else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset); + } + } + } } - - /** * Flush the selection from loop tags based on sticky and selection modes. * @@ -3100,83 +3250,83 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object * * \note! This function is very similar to #uv_select_flush_from_tag_loop, be sure to update both upon changing. */ -static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select) -{ - /* Selecting UV Loops with some modes requires us to change - * the selection in other faces (depending on the sticky mode). - * - * This only needs to be done when the Mesh is not used for - * selection (so for sticky modes, vertex or location based). */ - - ToolSettings *ts = scene->toolsettings; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - - 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) { - /* Tag all verts as untouched, then touch the ones that have a face center - * in the loop and select all MLoopUV's that use a touched vert. */ - 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) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l, BM_ELEM_TAG)) { - BM_elem_flag_enable(l->v, BM_ELEM_TAG); - } - } - } - - /* now select tagged verts */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } - } - else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { - struct UvVertMap *vmap; - float limit[2]; - unsigned int efa_index; - - uvedit_pixel_to_float(sima, limit, 0.05); - - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - vmap = BM_uv_vert_map_create(em->bm, limit, false, false); - if (vmap == NULL) { - return; - } - - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l, BM_ELEM_TAG)) { - uv_select_flush_from_tag_sticky_loc_internal( - scene, em, vmap, efa_index, l, - select, cd_loop_uv_offset); - } - } - } - BM_uv_vert_map_free(vmap); - - } - else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } - } +static void uv_select_flush_from_tag_loop(SpaceImage *sima, + Scene *scene, + Object *obedit, + const bool select) +{ + /* Selecting UV Loops with some modes requires us to change + * the selection in other faces (depending on the sticky mode). + * + * This only needs to be done when the Mesh is not used for + * selection (so for sticky modes, vertex or location based). */ + + ToolSettings *ts = scene->toolsettings; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + + 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) { + /* Tag all verts as untouched, then touch the ones that have a face center + * in the loop and select all MLoopUV's that use a touched vert. */ + 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) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l, BM_ELEM_TAG)) { + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } + } + } + + /* now select tagged verts */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + } + else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { + struct UvVertMap *vmap; + float limit[2]; + unsigned int efa_index; + + uvedit_pixel_to_float(sima, limit, 0.05); + + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + vmap = BM_uv_vert_map_create(em->bm, limit, false, false); + if (vmap == NULL) { + return; + } + + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { + /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l, BM_ELEM_TAG)) { + uv_select_flush_from_tag_sticky_loc_internal( + scene, em, vmap, efa_index, l, select, cd_loop_uv_offset); + } + } + } + BM_uv_vert_map_free(vmap); + } + else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l, BM_ELEM_TAG)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + } } /** \} */ @@ -3187,144 +3337,144 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object static int uv_box_select_exec(bContext *C, wmOperator *op) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); - ARegion *ar = CTX_wm_region(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - rctf rectf; - bool pinned; - const bool use_face_center = ( - (ts->uv_flag & UV_SYNC_SELECTION) ? - (ts->selectmode == SCE_SELECT_FACE) : - (ts->uv_selectmode == UV_SELECT_FACE)); - - /* get rectangle from operator */ - WM_operator_properties_border_to_rctf(op, &rectf); - UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf); - - const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - const bool select = (sel_op != SEL_OP_SUB); - - pinned = RNA_boolean_get(op->ptr, "pinned"); - - bool changed_multi = false; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len); - - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); - } - - /* don't indent to avoid diff noise! */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - bool changed = false; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* 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); - } - } - 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) { - 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)) { - - /* 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); - } - } - } - } - - if (sima->sticky == SI_STICKY_VERTEX) { - uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); - } - } - - if (changed) { - changed_multi = true; - - uv_select_sync_flush(ts, em, select); - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } - } - - MEM_freeN(objects); - - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + Image *ima = CTX_data_edit_image(C); + ARegion *ar = CTX_wm_region(C); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + rctf rectf; + bool pinned; + const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_FACE) : + (ts->uv_selectmode == UV_SELECT_FACE)); + + /* get rectangle from operator */ + WM_operator_properties_border_to_rctf(op, &rectf); + UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf); + + const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + const bool select = (sel_op != SEL_OP_SUB); + + pinned = RNA_boolean_get(op->ptr, "pinned"); + + bool changed_multi = false; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + } + + /* don't indent to avoid diff noise! */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + bool changed = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* 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); + } + } + 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) { + 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)) { + + /* 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); + } + } + } + } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } + } + + if (changed) { + changed_multi = true; + + uv_select_sync_flush(ts, em, select); + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + + MEM_freeN(objects); + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } static void UV_OT_select_box(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Box Select"; - ot->description = "Select UV vertices using box selection"; - ot->idname = "UV_OT_select_box"; + /* identifiers */ + ot->name = "Box Select"; + ot->description = "Select UV vertices using box selection"; + ot->idname = "UV_OT_select_box"; - /* api callbacks */ - ot->invoke = WM_gesture_box_invoke; - ot->exec = uv_box_select_exec; - ot->modal = WM_gesture_box_modal; - ot->poll = ED_operator_uvedit_space_image; /* requires space image */ - ot->cancel = WM_gesture_box_cancel; + /* api callbacks */ + ot->invoke = WM_gesture_box_invoke; + ot->exec = uv_box_select_exec; + ot->modal = WM_gesture_box_modal; + ot->poll = ED_operator_uvedit_space_image; /* requires space image */ + ot->cancel = WM_gesture_box_cancel; - /* flags */ - ot->flag = OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_UNDO; - /* properties */ - RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only"); + /* properties */ + RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only"); - WM_operator_properties_gesture_box(ot); - WM_operator_properties_select_operation_simple(ot); + WM_operator_properties_gesture_box(ot); + WM_operator_properties_select_operation_simple(ot); } /** \} */ @@ -3335,142 +3485,142 @@ static void UV_OT_select_box(wmOperatorType *ot) static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2]) { - /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ - float x, y; - x = (uv[0] - offset[0]) * ellipse[0]; - y = (uv[1] - offset[1]) * ellipse[1]; - return ((x * x + y * y) < 1.0f); + /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ + float x, y; + x = (uv[0] - offset[0]) * ellipse[0]; + y = (uv[1] - offset[1]) * ellipse[1]; + return ((x * x + y * y) < 1.0f); } static int uv_circle_select_exec(bContext *C, wmOperator *op) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - ToolSettings *ts = scene->toolsettings; - ARegion *ar = CTX_wm_region(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - int x, y, radius, width, height; - float zoomx, zoomy, offset[2], ellipse[2]; - - const bool use_face_center = ( - (ts->uv_flag & UV_SYNC_SELECTION) ? - (ts->selectmode == SCE_SELECT_FACE) : - (ts->uv_selectmode == UV_SELECT_FACE)); - - /* get operator properties */ - x = RNA_int_get(op->ptr, "x"); - y = RNA_int_get(op->ptr, "y"); - radius = RNA_int_get(op->ptr, "radius"); - - /* compute ellipse size and location, not a circle since we deal - * with non square image. ellipse is normalized, r = 1.0. */ - ED_space_image_get_size(sima, &width, &height); - ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy); - - ellipse[0] = width * zoomx / radius; - ellipse[1] = height * zoomy / radius; - - UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]); - - bool changed_multi = false; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len); - - const eSelectOp sel_op = ED_select_op_modal( - RNA_enum_get(op->ptr, "mode"), WM_gesture_is_modal_first(op->customdata)); - const bool select = (sel_op != SEL_OP_SUB); - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); - changed_multi = true; - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - bool changed = false; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* do selection */ - if (use_face_center) { - changed = false; - 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 (uv_inside_circle(cent, offset, ellipse)) { - 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); - } - } - else { - 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) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (uv_inside_circle(luv->uv, offset, ellipse)) { - changed = true; - 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 (changed) { - changed_multi = true; - - uv_select_sync_flush(ts, em, select); - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } - } - MEM_freeN(objects); - - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = CTX_data_edit_image(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + ToolSettings *ts = scene->toolsettings; + ARegion *ar = CTX_wm_region(C); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + int x, y, radius, width, height; + float zoomx, zoomy, offset[2], ellipse[2]; + + const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_FACE) : + (ts->uv_selectmode == UV_SELECT_FACE)); + + /* get operator properties */ + x = RNA_int_get(op->ptr, "x"); + y = RNA_int_get(op->ptr, "y"); + radius = RNA_int_get(op->ptr, "radius"); + + /* compute ellipse size and location, not a circle since we deal + * with non square image. ellipse is normalized, r = 1.0. */ + ED_space_image_get_size(sima, &width, &height); + ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy); + + ellipse[0] = width * zoomx / radius; + ellipse[1] = height * zoomy / radius; + + UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]); + + bool changed_multi = false; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"), + WM_gesture_is_modal_first(op->customdata)); + const bool select = (sel_op != SEL_OP_SUB); + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + changed_multi = true; + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + bool changed = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* do selection */ + if (use_face_center) { + changed = false; + 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 (uv_inside_circle(cent, offset, ellipse)) { + 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); + } + } + else { + 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) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (uv_inside_circle(luv->uv, offset, ellipse)) { + changed = true; + 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 (changed) { + changed_multi = true; + + uv_select_sync_flush(ts, em, select); + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + MEM_freeN(objects); + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } static void UV_OT_select_circle(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Circle Select"; - ot->description = "Select UV vertices using circle selection"; - ot->idname = "UV_OT_select_circle"; + /* identifiers */ + ot->name = "Circle Select"; + ot->description = "Select UV vertices using circle selection"; + ot->idname = "UV_OT_select_circle"; - /* api callbacks */ - ot->invoke = WM_gesture_circle_invoke; - ot->modal = WM_gesture_circle_modal; - ot->exec = uv_circle_select_exec; - ot->poll = ED_operator_uvedit_space_image; /* requires space image */ - ot->cancel = WM_gesture_circle_cancel; + /* api callbacks */ + ot->invoke = WM_gesture_circle_invoke; + ot->modal = WM_gesture_circle_modal; + ot->exec = uv_circle_select_exec; + ot->poll = ED_operator_uvedit_space_image; /* requires space image */ + ot->cancel = WM_gesture_circle_cancel; - /* flags */ - ot->flag = OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_UNDO; - /* properties */ - WM_operator_properties_gesture_circle(ot); - WM_operator_properties_select_operation_simple(ot); + /* properties */ + WM_operator_properties_gesture_circle(ot); + WM_operator_properties_select_operation_simple(ot); } /** \} */ @@ -3479,148 +3629,148 @@ static void UV_OT_select_circle(wmOperatorType *ot) /** \name Lasso Select Operator * \{ */ -static bool do_lasso_select_mesh_uv( - bContext *C, const int mcords[][2], short moves, - const eSelectOp sel_op) -{ - Depsgraph *depsgraph = CTX_data_depsgraph(C); - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); - ARegion *ar = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - 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 bool select = (sel_op != SEL_OP_SUB); - - BMIter iter, liter; - - BMFace *efa; - BMLoop *l; - int screen_uv[2]; - bool changed_multi = false; - rcti rect; - - BLI_lasso_boundbox(&rect, mcords, moves); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len); - - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); - } - - /* don't indent to avoid diff noise! */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - - bool changed = false; - - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if (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); - } - } - 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) { - 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 (changed) { - changed_multi = true; - - uv_select_sync_flush(ts, em, select); - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } - } - MEM_freeN(objects); - - return changed_multi; +static bool do_lasso_select_mesh_uv(bContext *C, + const int mcords[][2], + short moves, + const eSelectOp sel_op) +{ + Depsgraph *depsgraph = CTX_data_depsgraph(C); + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = CTX_data_edit_image(C); + ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + 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 bool select = (sel_op != SEL_OP_SUB); + + BMIter iter, liter; + + BMFace *efa; + BMLoop *l; + int screen_uv[2]; + bool changed_multi = false; + rcti rect; + + BLI_lasso_boundbox(&rect, mcords, moves); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + } + + /* don't indent to avoid diff noise! */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + + bool changed = false; + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (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); + } + } + 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) { + 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 (changed) { + changed_multi = true; + + uv_select_sync_flush(ts, em, select); + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + MEM_freeN(objects); + + return changed_multi; } static int uv_lasso_select_exec(bContext *C, wmOperator *op) { - int mcords_tot; - const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + int mcords_tot; + const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); - if (mcords) { - const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - bool changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, sel_op); - MEM_freeN((void *)mcords); + if (mcords) { + const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + bool changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, sel_op); + MEM_freeN((void *)mcords); - return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED; - } + return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + } - return OPERATOR_PASS_THROUGH; + return OPERATOR_PASS_THROUGH; } static void UV_OT_select_lasso(wmOperatorType *ot) { - ot->name = "Lasso Select UV"; - ot->description = "Select UVs using lasso selection"; - ot->idname = "UV_OT_select_lasso"; + ot->name = "Lasso Select UV"; + ot->description = "Select UVs using lasso selection"; + ot->idname = "UV_OT_select_lasso"; - ot->invoke = WM_gesture_lasso_invoke; - ot->modal = WM_gesture_lasso_modal; - ot->exec = uv_lasso_select_exec; - ot->poll = ED_operator_uvedit_space_image; - ot->cancel = WM_gesture_lasso_cancel; + ot->invoke = WM_gesture_lasso_invoke; + ot->modal = WM_gesture_lasso_modal; + ot->exec = uv_lasso_select_exec; + ot->poll = ED_operator_uvedit_space_image; + ot->cancel = WM_gesture_lasso_cancel; - /* flags */ - ot->flag = OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_UNDO; - /* properties */ - WM_operator_properties_gesture_lasso(ot); - WM_operator_properties_select_operation_simple(ot); + /* properties */ + WM_operator_properties_gesture_lasso(ot); + WM_operator_properties_select_operation_simple(ot); } /** \} */ @@ -3631,78 +3781,78 @@ static void UV_OT_select_lasso(wmOperatorType *ot) static void uv_snap_to_pixel(float uvco[2], float w, float h) { - uvco[0] = roundf(uvco[0] * w) / w; - uvco[1] = roundf(uvco[1] * h) / h; + uvco[0] = roundf(uvco[0] * w) / w; + uvco[1] = roundf(uvco[1] * h) / h; } static void uv_snap_cursor_to_pixels(SpaceImage *sima) { - int width = 0, height = 0; + int width = 0, height = 0; - ED_space_image_get_size(sima, &width, &height); - uv_snap_to_pixel(sima->cursor, width, height); + ED_space_image_get_size(sima, &width, &height); + uv_snap_to_pixel(sima->cursor, width, height); } static bool uv_snap_cursor_to_selection( - Scene *scene, Image *ima, Object **objects_edit, uint objects_len, SpaceImage *sima) + Scene *scene, Image *ima, Object **objects_edit, uint objects_len, SpaceImage *sima) { - return ED_uvedit_center_multi(scene, ima, objects_edit, objects_len, 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); + SpaceImage *sima = CTX_wm_space_image(C); - bool changed = false; + bool changed = false; - switch (RNA_enum_get(op->ptr, "target")) { - case 0: - uv_snap_cursor_to_pixels(sima); - changed = true; - break; - case 1: - { - Scene *scene = CTX_data_scene(C); - Image *ima = CTX_data_edit_image(C); - ViewLayer *view_layer = CTX_data_view_layer(C); + switch (RNA_enum_get(op->ptr, "target")) { + case 0: + uv_snap_cursor_to_pixels(sima); + changed = true; + break; + case 1: { + 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, ((View3D *)NULL), &objects_len); - changed = uv_snap_cursor_to_selection(scene, ima, objects, objects_len, sima); - MEM_freeN(objects); - break; - } - } + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + changed = uv_snap_cursor_to_selection(scene, ima, objects, objects_len, sima); + MEM_freeN(objects); + break; + } + } - if (!changed) - return OPERATOR_CANCELLED; + if (!changed) + return OPERATOR_CANCELLED; - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, sima); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, sima); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void UV_OT_snap_cursor(wmOperatorType *ot) { - static const EnumPropertyItem target_items[] = { - {0, "PIXELS", 0, "Pixels", ""}, - {1, "SELECTED", 0, "Selected", ""}, - {0, NULL, 0, NULL, NULL}, - }; + static const EnumPropertyItem target_items[] = { + {0, "PIXELS", 0, "Pixels", ""}, + {1, "SELECTED", 0, "Selected", ""}, + {0, NULL, 0, NULL, NULL}, + }; - /* identifiers */ - ot->name = "Snap Cursor"; - ot->description = "Snap cursor to target type"; - ot->idname = "UV_OT_snap_cursor"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Snap Cursor"; + ot->description = "Snap cursor to target type"; + ot->idname = "UV_OT_snap_cursor"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_snap_cursor_exec; - ot->poll = ED_operator_uvedit_space_image; /* requires space image */ + /* api callbacks */ + ot->exec = uv_snap_cursor_exec; + ot->poll = ED_operator_uvedit_space_image; /* requires space image */ - /* properties */ - RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to"); + /* properties */ + RNA_def_enum( + ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to"); } /** \} */ @@ -3713,230 +3863,232 @@ static void UV_OT_snap_cursor(wmOperatorType *ot) static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, const float cursor[2]) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - bool changed = false; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + bool changed = false; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) - continue; + 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); - copy_v2_v2(luv->uv, cursor); - changed = true; - } - } - } + 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); + copy_v2_v2(luv->uv, cursor); + changed = true; + } + } + } - return changed; + return changed; } static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const float offset[2]) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - bool changed = false; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + bool changed = false; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) - continue; + 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); - add_v2_v2(luv->uv, offset); - changed = true; - } - } - } + 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); + add_v2_v2(luv->uv, offset); + changed = true; + } + } + } - return changed; + return changed; } static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMFace *f; - BMLoop *l, *lsub; - BMIter iter, liter, lsubiter; - MLoopUV *luv; - bool changed = false; - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - /* 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) { - 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)); - } - } - else { - BM_elem_flag_disable(f, BM_ELEM_TAG); - } - } - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_TAG)) { /* face: visible */ - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l, BM_ELEM_TAG)) { /* loop: selected*/ - float uv[2] = {0.0f, 0.0f}; - int uv_tot = 0; - - BM_ITER_ELEM (lsub, &lsubiter, l->v, BM_LOOPS_OF_VERT) { - if (BM_elem_flag_test(lsub->f, BM_ELEM_TAG) && /* face: visible */ - !BM_elem_flag_test(lsub, BM_ELEM_TAG)) /* loop: unselected */ - { - luv = BM_ELEM_CD_GET_VOID_P(lsub, cd_loop_uv_offset); - add_v2_v2(uv, luv->uv); - uv_tot++; - } - } - - if (uv_tot) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - mul_v2_v2fl(luv->uv, uv, 1.0f / (float)uv_tot); - changed = true; - } - } - } - } - } - - return changed; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMLoop *l, *lsub; + BMIter iter, liter, lsubiter; + MLoopUV *luv; + bool changed = false; + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + /* 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) { + 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)); + } + } + else { + BM_elem_flag_disable(f, BM_ELEM_TAG); + } + } + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG)) { /* face: visible */ + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l, BM_ELEM_TAG)) { /* loop: selected*/ + float uv[2] = {0.0f, 0.0f}; + int uv_tot = 0; + + BM_ITER_ELEM (lsub, &lsubiter, l->v, BM_LOOPS_OF_VERT) { + if (BM_elem_flag_test(lsub->f, BM_ELEM_TAG) && /* face: visible */ + !BM_elem_flag_test(lsub, BM_ELEM_TAG)) /* loop: unselected */ + { + luv = BM_ELEM_CD_GET_VOID_P(lsub, cd_loop_uv_offset); + add_v2_v2(uv, luv->uv); + uv_tot++; + } + } + + if (uv_tot) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + mul_v2_v2fl(luv->uv, uv, 1.0f / (float)uv_tot); + changed = true; + } + } + } + } + } + + return changed; } static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - Image *ima = sima->image; - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - int width = 0, height = 0; - float w, h; - bool changed = false; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + Image *ima = sima->image; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + 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_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - ED_space_image_get_size(sima, &width, &height); - w = (float)width; - h = (float)height; + 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) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) - continue; + 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); - uv_snap_to_pixel(luv->uv, w, h); - } - } + 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); + uv_snap_to_pixel(luv->uv, w, h); + } + } - changed = true; - } + changed = true; + } - return changed; + return changed; } static int uv_snap_selection_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); - ToolSettings *ts = scene->toolsettings; - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - const int target = RNA_enum_get(op->ptr, "target"); - float offset[2] = {0}; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len); - - if (target == 2) { - float center[2]; - if (!ED_uvedit_center_multi(scene, ima, objects, objects_len, center, sima->around)) { - MEM_freeN(objects); - return OPERATOR_CANCELLED; - } - sub_v2_v2v2(offset, sima->cursor, center); - } - - bool changed_multi = 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 (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - bool changed = false; - switch (target) { - case 0: - changed = uv_snap_uvs_to_pixels(sima, scene, obedit); - break; - case 1: - changed = uv_snap_uvs_to_cursor(scene, ima, obedit, sima->cursor); - break; - case 2: - changed = uv_snap_uvs_offset(scene, ima, obedit, offset); - break; - case 3: - changed = uv_snap_uvs_to_adjacent_unselected(scene, ima, obedit); - break; - } - - if (changed) { - changed_multi = true; - uvedit_live_unwrap_update(sima, scene, obedit); - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - } - MEM_freeN(objects); - - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = CTX_data_edit_image(C); + ToolSettings *ts = scene->toolsettings; + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + const int target = RNA_enum_get(op->ptr, "target"); + float offset[2] = {0}; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + if (target == 2) { + float center[2]; + if (!ED_uvedit_center_multi(scene, ima, objects, objects_len, center, sima->around)) { + MEM_freeN(objects); + return OPERATOR_CANCELLED; + } + sub_v2_v2v2(offset, sima->cursor, center); + } + + bool changed_multi = 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 (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } + + bool changed = false; + switch (target) { + case 0: + changed = uv_snap_uvs_to_pixels(sima, scene, obedit); + break; + case 1: + changed = uv_snap_uvs_to_cursor(scene, ima, obedit, sima->cursor); + break; + case 2: + changed = uv_snap_uvs_offset(scene, ima, obedit, offset); + break; + case 3: + changed = uv_snap_uvs_to_adjacent_unselected(scene, ima, obedit); + break; + } + + if (changed) { + changed_multi = true; + uvedit_live_unwrap_update(sima, scene, obedit); + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + } + MEM_freeN(objects); + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } static void UV_OT_snap_selected(wmOperatorType *ot) { - static const EnumPropertyItem target_items[] = { - {0, "PIXELS", 0, "Pixels", ""}, - {1, "CURSOR", 0, "Cursor", ""}, - {2, "CURSOR_OFFSET", 0, "Cursor (Offset)", ""}, - {3, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""}, - {0, NULL, 0, NULL, NULL}, - }; + static const EnumPropertyItem target_items[] = { + {0, "PIXELS", 0, "Pixels", ""}, + {1, "CURSOR", 0, "Cursor", ""}, + {2, "CURSOR_OFFSET", 0, "Cursor (Offset)", ""}, + {3, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""}, + {0, NULL, 0, NULL, NULL}, + }; - /* identifiers */ - ot->name = "Snap Selection"; - ot->description = "Snap selected UV vertices to target type"; - ot->idname = "UV_OT_snap_selected"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Snap Selection"; + ot->description = "Snap selected UV vertices to target type"; + ot->idname = "UV_OT_snap_selected"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_snap_selection_exec; - ot->poll = ED_operator_uvedit_space_image; + /* api callbacks */ + ot->exec = uv_snap_selection_exec; + ot->poll = ED_operator_uvedit_space_image; - /* properties */ - RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to"); + /* properties */ + RNA_def_enum( + ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to"); } /** \} */ @@ -3947,75 +4099,78 @@ static void UV_OT_snap_selected(wmOperatorType *ot) static int uv_pin_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - ToolSettings *ts = scene->toolsettings; - const bool clear = RNA_boolean_get(op->ptr, "clear"); - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &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; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - 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)) { - changed = true; - if (clear) { - luv->flag &= ~MLOOPUV_PINNED; - } - else { - luv->flag |= MLOOPUV_PINNED; - } - } - } - } - - if (changed) { - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE); - } - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Image *ima = CTX_data_edit_image(C); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + ToolSettings *ts = scene->toolsettings; + const bool clear = RNA_boolean_get(op->ptr, "clear"); + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &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; + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } + + 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)) { + changed = true; + if (clear) { + luv->flag &= ~MLOOPUV_PINNED; + } + else { + luv->flag |= MLOOPUV_PINNED; + } + } + } + } + + if (changed) { + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE); + } + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } static void UV_OT_pin(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Pin"; - ot->description = "Set/clear selected UV vertices as anchored between multiple unwrap operations"; - ot->idname = "UV_OT_pin"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Pin"; + ot->description = + "Set/clear selected UV vertices as anchored between multiple unwrap operations"; + ot->idname = "UV_OT_pin"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_pin_exec; - ot->poll = ED_operator_uvedit; + /* api callbacks */ + ot->exec = uv_pin_exec; + ot->poll = ED_operator_uvedit; - /* properties */ - RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it"); + /* properties */ + RNA_def_boolean( + ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it"); } /** \} */ @@ -4026,61 +4181,62 @@ static void UV_OT_pin(wmOperatorType *ot) static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + Image *ima = CTX_data_edit_image(C); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &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); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - bool changed = false; + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + bool changed = false; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { - continue; - } + 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); + 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_PINNED) { - uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); - changed = true; - } - } - } + if (luv->flag & MLOOPUV_PINNED) { + uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); + changed = true; + } + } + } - if (changed) { - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } - } - MEM_freeN(objects); + if (changed) { + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void UV_OT_select_pinned(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Selected Pinned"; - ot->description = "Select all pinned UV vertices"; - ot->idname = "UV_OT_select_pinned"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Selected Pinned"; + ot->description = "Select all pinned UV vertices"; + ot->idname = "UV_OT_select_pinned"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_select_pinned_exec; - ot->poll = ED_operator_uvedit; + /* api callbacks */ + ot->exec = uv_select_pinned_exec; + ot->poll = ED_operator_uvedit; } /** \} */ @@ -4091,137 +4247,138 @@ static void UV_OT_select_pinned(wmOperatorType *ot) /* check if we are selected or unselected based on 'bool_test' arg, * needed for select swap support */ -#define UV_SEL_TEST(luv, bool_test) ((((luv)->flag & MLOOPUV_VERTSEL) == MLOOPUV_VERTSEL) == bool_test) +#define UV_SEL_TEST(luv, bool_test) \ + ((((luv)->flag & MLOOPUV_VERTSEL) == MLOOPUV_VERTSEL) == bool_test) /* is every UV vert selected or unselected depending on bool_test */ -static bool bm_face_is_all_uv_sel( - BMFace *f, bool select_test, - const int cd_loop_uv_offset) +static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, const int cd_loop_uv_offset) { - BMLoop *l_iter; - BMLoop *l_first; + BMLoop *l_iter; + BMLoop *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); - if (!UV_SEL_TEST(luv, select_test)) { - return false; - } - } while ((l_iter = l_iter->next) != l_first); + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); + if (!UV_SEL_TEST(luv, select_test)) { + return false; + } + } while ((l_iter = l_iter->next) != l_first); - return true; + return true; } static int uv_hide_exec(bContext *C, wmOperator *op) { - SpaceImage *sima = CTX_wm_space_image(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); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - 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); - - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (EDBM_mesh_hide(em, swap)) { - EDBM_update_generic(em, true, false); - } - return OPERATOR_FINISHED; - } - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - int hide = 0; - - 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 (UV_SEL_TEST(luv, !swap)) { - hide = 1; - break; - } - } - - if (hide) { - /* note, a special case for edges could be used, - * for now edges act like verts and get flushed */ - if (use_face_center) { - if (em->selectmode == SCE_SELECT_FACE) { - /* check that every UV is selected */ - if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) { - BM_face_select_set(em->bm, efa, false); - } - uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); - } - else { - if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (UV_SEL_TEST(luv, !swap)) { - BM_vert_select_set(em->bm, l->v, false); - } - } - } - if (!swap) uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); - } - } - else if (em->selectmode == SCE_SELECT_FACE) { - /* check if a UV is de-selected */ - if (bm_face_is_all_uv_sel(efa, false, cd_loop_uv_offset) != !swap) { - BM_face_select_set(em->bm, efa, false); - uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); - } - } - else { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (UV_SEL_TEST(luv, !swap)) { - BM_vert_select_set(em->bm, l->v, false); - if (!swap) luv->flag &= ~MLOOPUV_VERTSEL; - } - } - } - } - } - - /* flush vertex selection changes */ - if (em->selectmode != SCE_SELECT_FACE) - EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX | SCE_SELECT_EDGE); - - BM_select_history_validate(em->bm); - - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - - return OPERATOR_FINISHED; + SpaceImage *sima = CTX_wm_space_image(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); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + 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); + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (EDBM_mesh_hide(em, swap)) { + EDBM_update_generic(em, true, false); + } + return OPERATOR_FINISHED; + } + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + int hide = 0; + + 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 (UV_SEL_TEST(luv, !swap)) { + hide = 1; + break; + } + } + + if (hide) { + /* note, a special case for edges could be used, + * for now edges act like verts and get flushed */ + if (use_face_center) { + if (em->selectmode == SCE_SELECT_FACE) { + /* check that every UV is selected */ + if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) { + BM_face_select_set(em->bm, efa, false); + } + uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); + } + else { + if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (UV_SEL_TEST(luv, !swap)) { + BM_vert_select_set(em->bm, l->v, false); + } + } + } + if (!swap) + uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); + } + } + else if (em->selectmode == SCE_SELECT_FACE) { + /* check if a UV is de-selected */ + if (bm_face_is_all_uv_sel(efa, false, cd_loop_uv_offset) != !swap) { + BM_face_select_set(em->bm, efa, false); + uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); + } + } + else { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (UV_SEL_TEST(luv, !swap)) { + BM_vert_select_set(em->bm, l->v, false); + if (!swap) + luv->flag &= ~MLOOPUV_VERTSEL; + } + } + } + } + } + + /* flush vertex selection changes */ + if (em->selectmode != SCE_SELECT_FACE) + EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX | SCE_SELECT_EDGE); + + BM_select_history_validate(em->bm); + + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; } #undef UV_SEL_TEST static void UV_OT_hide(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Hide Selected"; - ot->description = "Hide (un)selected UV vertices"; - ot->idname = "UV_OT_hide"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Hide Selected"; + ot->description = "Hide (un)selected UV vertices"; + ot->idname = "UV_OT_hide"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_hide_exec; - ot->poll = ED_operator_uvedit; + /* api callbacks */ + ot->exec = uv_hide_exec; + ot->poll = ED_operator_uvedit; - /* props */ - RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected"); + /* props */ + RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected"); } /** \} */ @@ -4232,136 +4389,136 @@ static void UV_OT_hide(wmOperatorType *ot) static int uv_reveal_exec(bContext *C, wmOperator *op) { - SpaceImage *sima = CTX_wm_space_image(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); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE); - const int stickymode = sima ? (sima->sticky != SI_STICKY_DISABLE) : 1; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - const bool select = RNA_boolean_get(op->ptr, "select"); - - /* note on tagging, selecting faces needs to be delayed so it doesn't select the verts and - * confuse our checks on selected verts. */ - - /* call the mesh function if we are in mesh sync sel */ - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (EDBM_mesh_reveal(em, select)) { - EDBM_update_generic(em, true, false); - } - return OPERATOR_FINISHED; - } - if (use_face_center) { - if (em->selectmode == SCE_SELECT_FACE) { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_elem_flag_disable(efa, BM_ELEM_TAG); - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL); - } - /* BM_face_select_set(em->bm, efa, true); */ - BM_elem_flag_enable(efa, BM_ELEM_TAG); - } - } - } - else { - /* enable adjacent faces to have disconnected UV selections if sticky is disabled */ - if (!stickymode) { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_elem_flag_disable(efa, BM_ELEM_TAG); - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - int totsel = 0; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT); - } - - if (!totsel) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL); - } - /* BM_face_select_set(em->bm, efa, true); */ - BM_elem_flag_enable(efa, BM_ELEM_TAG); - } - } - } - } - else { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_elem_flag_disable(efa, BM_ELEM_TAG); - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL); - } - } - /* BM_face_select_set(em->bm, efa, true); */ - BM_elem_flag_enable(efa, BM_ELEM_TAG); - } - } - } - } - } - else if (em->selectmode == SCE_SELECT_FACE) { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_elem_flag_disable(efa, BM_ELEM_TAG); - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL); - } - /* BM_face_select_set(em->bm, efa, true); */ - BM_elem_flag_enable(efa, BM_ELEM_TAG); - } - } - } - else { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_elem_flag_disable(efa, BM_ELEM_TAG); - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL); - } - } - /* BM_face_select_set(em->bm, efa, true); */ - BM_elem_flag_enable(efa, BM_ELEM_TAG); - } - } - } - - /* 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, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - - return OPERATOR_FINISHED; + SpaceImage *sima = CTX_wm_space_image(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); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE); + const int stickymode = sima ? (sima->sticky != SI_STICKY_DISABLE) : 1; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + const bool select = RNA_boolean_get(op->ptr, "select"); + + /* note on tagging, selecting faces needs to be delayed so it doesn't select the verts and + * confuse our checks on selected verts. */ + + /* call the mesh function if we are in mesh sync sel */ + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (EDBM_mesh_reveal(em, select)) { + EDBM_update_generic(em, true, false); + } + return OPERATOR_FINISHED; + } + if (use_face_center) { + if (em->selectmode == SCE_SELECT_FACE) { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_elem_flag_disable(efa, BM_ELEM_TAG); + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL); + } + /* BM_face_select_set(em->bm, efa, true); */ + BM_elem_flag_enable(efa, BM_ELEM_TAG); + } + } + } + else { + /* enable adjacent faces to have disconnected UV selections if sticky is disabled */ + if (!stickymode) { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_elem_flag_disable(efa, BM_ELEM_TAG); + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + int totsel = 0; + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT); + } + + if (!totsel) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL); + } + /* BM_face_select_set(em->bm, efa, true); */ + BM_elem_flag_enable(efa, BM_ELEM_TAG); + } + } + } + } + else { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_elem_flag_disable(efa, BM_ELEM_TAG); + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL); + } + } + /* BM_face_select_set(em->bm, efa, true); */ + BM_elem_flag_enable(efa, BM_ELEM_TAG); + } + } + } + } + } + else if (em->selectmode == SCE_SELECT_FACE) { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_elem_flag_disable(efa, BM_ELEM_TAG); + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL); + } + /* BM_face_select_set(em->bm, efa, true); */ + BM_elem_flag_enable(efa, BM_ELEM_TAG); + } + } + } + else { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_elem_flag_disable(efa, BM_ELEM_TAG); + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL); + } + } + /* BM_face_select_set(em->bm, efa, true); */ + BM_elem_flag_enable(efa, BM_ELEM_TAG); + } + } + } + + /* 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, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; } static void UV_OT_reveal(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Reveal Hidden"; - ot->description = "Reveal all hidden UV vertices"; - ot->idname = "UV_OT_reveal"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Reveal Hidden"; + ot->description = "Reveal all hidden UV vertices"; + ot->idname = "UV_OT_reveal"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_reveal_exec; - ot->poll = ED_operator_uvedit; + /* api callbacks */ + ot->exec = uv_reveal_exec; + ot->poll = ED_operator_uvedit; - RNA_def_boolean(ot->srna, "select", true, "Select", ""); + RNA_def_boolean(ot->srna, "select", true, "Select", ""); } /** \} */ @@ -4372,60 +4529,67 @@ static void UV_OT_reveal(wmOperatorType *ot) static bool uv_set_2d_cursor_poll(bContext *C) { - return ED_operator_uvedit_space_image(C) || - ED_space_image_maskedit_poll(C) || - ED_space_image_paint_curve(C); + return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) || + ED_space_image_paint_curve(C); } static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op) { - SpaceImage *sima = CTX_wm_space_image(C); + SpaceImage *sima = CTX_wm_space_image(C); - if (!sima) - return OPERATOR_CANCELLED; + if (!sima) + return OPERATOR_CANCELLED; - RNA_float_get_array(op->ptr, "location", sima->cursor); + RNA_float_get_array(op->ptr, "location", sima->cursor); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int uv_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - float location[2]; + ARegion *ar = CTX_wm_region(C); + float location[2]; - if (ar->regiontype == RGN_TYPE_WINDOW) { - if (event->mval[1] <= 16) { - SpaceImage *sima = CTX_wm_space_image(C); - if (sima && ED_space_image_show_cache(sima)) { - return OPERATOR_PASS_THROUGH; - } - } - } + if (ar->regiontype == RGN_TYPE_WINDOW) { + if (event->mval[1] <= 16) { + SpaceImage *sima = CTX_wm_space_image(C); + if (sima && ED_space_image_show_cache(sima)) { + return OPERATOR_PASS_THROUGH; + } + } + } - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]); - RNA_float_set_array(op->ptr, "location", location); + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]); + RNA_float_set_array(op->ptr, "location", location); - return uv_set_2d_cursor_exec(C, op); + return uv_set_2d_cursor_exec(C, op); } static void UV_OT_cursor_set(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set 2D Cursor"; - ot->description = "Set 2D cursor location"; - ot->idname = "UV_OT_cursor_set"; - - /* api callbacks */ - ot->exec = uv_set_2d_cursor_exec; - ot->invoke = uv_set_2d_cursor_invoke; - ot->poll = uv_set_2d_cursor_poll; - - /* properties */ - RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", - "Cursor location in normalized (0.0-1.0) coordinates", -10.0f, 10.0f); + /* identifiers */ + ot->name = "Set 2D Cursor"; + ot->description = "Set 2D cursor location"; + ot->idname = "UV_OT_cursor_set"; + + /* api callbacks */ + ot->exec = uv_set_2d_cursor_exec; + ot->invoke = uv_set_2d_cursor_invoke; + ot->poll = uv_set_2d_cursor_poll; + + /* properties */ + RNA_def_float_vector(ot->srna, + "location", + 2, + NULL, + -FLT_MAX, + FLT_MAX, + "Location", + "Cursor location in normalized (0.0-1.0) coordinates", + -10.0f, + 10.0f); } /** \} */ @@ -4436,136 +4600,136 @@ static void UV_OT_cursor_set(wmOperatorType *ot) static int uv_seams_from_islands_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - int ret = OPERATOR_CANCELLED; - const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT}; - const bool mark_seams = RNA_boolean_get(op->ptr, "mark_seams"); - const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - Mesh *me = (Mesh *)ob->data; - BMEditMesh *em = me->edit_mesh; - BMesh *bm = em->bm; - - UvVertMap *vmap; - BMEdge *editedge; - BMIter iter; - - if (!EDBM_uv_check(em)) { - continue; - } - ret = OPERATOR_FINISHED; - - /* This code sets editvert->tmp.l to the index. This will be useful later on. */ - BM_mesh_elem_table_ensure(bm, BM_FACE); - vmap = BM_uv_vert_map_create(bm, limit, false, false); - - BM_ITER_MESH (editedge, &iter, bm, BM_EDGES_OF_MESH) { - /* flags to determine if we uv is separated from first editface match */ - char separated1 = 0, separated2; - /* set to denote edge must be flagged as seam */ - char faces_separated = 0; - /* flag to keep track if uv1 is disconnected from first editface match */ - char v1coincident = 1; - /* For use with v1coincident. v1coincident will change only if we've had commonFaces */ - int commonFaces = 0; - - BMFace *efa1, *efa2; - - UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter; - /* mv2cache stores the first of the list of coincident uv's for later comparison - * mv2sep holds the last separator and is copied to mv2cache - * when a hit is first found */ - UvMapVert *mv2cache = NULL, *mv2sep = NULL; - - mvinit1 = vmap->vert[BM_elem_index_get(editedge->v1)]; - if (mark_seams) - BM_elem_flag_disable(editedge, BM_ELEM_SEAM); - - for (mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) { - if (mv1->separate && commonFaces) - v1coincident = 0; - - separated2 = 0; - efa1 = BM_face_at_index(bm, mv1->poly_index); - mvinit2 = vmap->vert[BM_elem_index_get(editedge->v2)]; - - for (mv2 = mvinit2; mv2; mv2 = mv2->next) { - if (mv2->separate) - mv2sep = mv2; - - efa2 = BM_face_at_index(bm, mv2->poly_index); - if (efa1 == efa2) { - /* if v1 is not coincident no point in comparing */ - if (v1coincident) { - /* have we found previously anything? */ - if (mv2cache) { - /* flag seam unless proved to be coincident with previous hit */ - separated2 = 1; - for (mviter = mv2cache; mviter; mviter = mviter->next) { - if (mviter->separate && mviter != mv2cache) - break; - /* coincident with previous hit, do not flag seam */ - if (mviter == mv2) - separated2 = 0; - } - } - /* First hit case, store the hit in the cache */ - else { - mv2cache = mv2sep; - commonFaces = 1; - } - } - else - separated1 = 1; - - if (separated1 || separated2) { - faces_separated = 1; - break; - } - } - } - } - - if (faces_separated) { - if (mark_seams) - BM_elem_flag_enable(editedge, BM_ELEM_SEAM); - if (mark_sharp) - BM_elem_flag_disable(editedge, BM_ELEM_SMOOTH); - } - } - - BM_uv_vert_map_free(vmap); - - DEG_id_tag_update(&me->id, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); - } - MEM_freeN(objects); - - return ret; + ViewLayer *view_layer = CTX_data_view_layer(C); + int ret = OPERATOR_CANCELLED; + const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT}; + const bool mark_seams = RNA_boolean_get(op->ptr, "mark_seams"); + const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + Mesh *me = (Mesh *)ob->data; + BMEditMesh *em = me->edit_mesh; + BMesh *bm = em->bm; + + UvVertMap *vmap; + BMEdge *editedge; + BMIter iter; + + if (!EDBM_uv_check(em)) { + continue; + } + ret = OPERATOR_FINISHED; + + /* This code sets editvert->tmp.l to the index. This will be useful later on. */ + BM_mesh_elem_table_ensure(bm, BM_FACE); + vmap = BM_uv_vert_map_create(bm, limit, false, false); + + BM_ITER_MESH (editedge, &iter, bm, BM_EDGES_OF_MESH) { + /* flags to determine if we uv is separated from first editface match */ + char separated1 = 0, separated2; + /* set to denote edge must be flagged as seam */ + char faces_separated = 0; + /* flag to keep track if uv1 is disconnected from first editface match */ + char v1coincident = 1; + /* For use with v1coincident. v1coincident will change only if we've had commonFaces */ + int commonFaces = 0; + + BMFace *efa1, *efa2; + + UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter; + /* mv2cache stores the first of the list of coincident uv's for later comparison + * mv2sep holds the last separator and is copied to mv2cache + * when a hit is first found */ + UvMapVert *mv2cache = NULL, *mv2sep = NULL; + + mvinit1 = vmap->vert[BM_elem_index_get(editedge->v1)]; + if (mark_seams) + BM_elem_flag_disable(editedge, BM_ELEM_SEAM); + + for (mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) { + if (mv1->separate && commonFaces) + v1coincident = 0; + + separated2 = 0; + efa1 = BM_face_at_index(bm, mv1->poly_index); + mvinit2 = vmap->vert[BM_elem_index_get(editedge->v2)]; + + for (mv2 = mvinit2; mv2; mv2 = mv2->next) { + if (mv2->separate) + mv2sep = mv2; + + efa2 = BM_face_at_index(bm, mv2->poly_index); + if (efa1 == efa2) { + /* if v1 is not coincident no point in comparing */ + if (v1coincident) { + /* have we found previously anything? */ + if (mv2cache) { + /* flag seam unless proved to be coincident with previous hit */ + separated2 = 1; + for (mviter = mv2cache; mviter; mviter = mviter->next) { + if (mviter->separate && mviter != mv2cache) + break; + /* coincident with previous hit, do not flag seam */ + if (mviter == mv2) + separated2 = 0; + } + } + /* First hit case, store the hit in the cache */ + else { + mv2cache = mv2sep; + commonFaces = 1; + } + } + else + separated1 = 1; + + if (separated1 || separated2) { + faces_separated = 1; + break; + } + } + } + } + + if (faces_separated) { + if (mark_seams) + BM_elem_flag_enable(editedge, BM_ELEM_SEAM); + if (mark_sharp) + BM_elem_flag_disable(editedge, BM_ELEM_SMOOTH); + } + } + + BM_uv_vert_map_free(vmap); + + DEG_id_tag_update(&me->id, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + } + MEM_freeN(objects); + + return ret; } - static void UV_OT_seams_from_islands(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Seams From Islands"; - ot->description = "Set mesh seams according to island setup in the UV editor"; - ot->idname = "UV_OT_seams_from_islands"; + /* identifiers */ + ot->name = "Seams From Islands"; + ot->description = "Set mesh seams according to island setup in the UV editor"; + ot->idname = "UV_OT_seams_from_islands"; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_seams_from_islands_exec; - ot->poll = ED_operator_uvedit; + /* api callbacks */ + ot->exec = uv_seams_from_islands_exec; + ot->poll = ED_operator_uvedit; - RNA_def_boolean(ot->srna, "mark_seams", 1, "Mark Seams", "Mark boundary edges as seams"); - RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp"); + RNA_def_boolean(ot->srna, "mark_seams", 1, "Mark Seams", "Mark boundary edges as seams"); + RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp"); } /** \} */ @@ -4576,95 +4740,106 @@ static void UV_OT_seams_from_islands(wmOperatorType *ot) static int uv_mark_seam_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - ToolSettings *ts = scene->toolsettings; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + ToolSettings *ts = scene->toolsettings; - BMFace *efa; - BMLoop *loop; - BMIter iter, liter; + BMFace *efa; + BMLoop *loop; + BMIter iter, liter; - const bool flag_set = !RNA_boolean_get(op->ptr, "clear"); - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + const bool flag_set = !RNA_boolean_get(op->ptr, "clear"); + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); - bool changed = false; + bool changed = false; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - Mesh *me = (Mesh *)ob->data; - BMEditMesh *em = me->edit_mesh; - BMesh *bm = em->bm; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + Mesh *me = (Mesh *)ob->data; + BMEditMesh *em = me->edit_mesh; + BMesh *bm = em->bm; - if (synced_selection && (bm->totedgesel == 0)) { - continue; - } + if (synced_selection && (bm->totedgesel == 0)) { + continue; + } - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) { - if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) { - BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set); - changed = true; - } - } - } + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) { + if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) { + BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set); + changed = true; + } + } + } - if (changed) { - DEG_id_tag_update(&me->id, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); - } - } + if (changed) { + DEG_id_tag_update(&me->id, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + } + } - if (changed) { - ED_uvedit_live_unwrap(scene, objects, objects_len); - } + if (changed) { + ED_uvedit_live_unwrap(scene, objects, objects_len); + } - MEM_freeN(objects); + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int uv_mark_seam_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - uiPopupMenu *pup; - uiLayout *layout; + uiPopupMenu *pup; + uiLayout *layout; - if (RNA_struct_property_is_set(op->ptr, "clear")) { - return uv_mark_seam_exec(C, op); - } + if (RNA_struct_property_is_set(op->ptr, "clear")) { + return uv_mark_seam_exec(C, op); + } - pup = UI_popup_menu_begin(C, IFACE_("Edges"), ICON_NONE); - layout = UI_popup_menu_layout(pup); + pup = UI_popup_menu_begin(C, IFACE_("Edges"), ICON_NONE); + layout = UI_popup_menu_layout(pup); - uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); - uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Mark Seam"), ICON_NONE, op->type->idname, "clear", false); - uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Seam"), ICON_NONE, op->type->idname, "clear", true); + uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); + uiItemBooleanO(layout, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Mark Seam"), + ICON_NONE, + op->type->idname, + "clear", + false); + uiItemBooleanO(layout, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Seam"), + ICON_NONE, + op->type->idname, + "clear", + true); - UI_popup_menu_end(C, pup); + UI_popup_menu_end(C, pup); - return OPERATOR_INTERFACE; + return OPERATOR_INTERFACE; } static void UV_OT_mark_seam(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Mark Seam"; - ot->description = "Mark selected UV edges as seams"; - ot->idname = "UV_OT_mark_seam"; + /* identifiers */ + ot->name = "Mark Seam"; + ot->description = "Mark selected UV edges as seams"; + ot->idname = "UV_OT_mark_seam"; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = uv_mark_seam_exec; - ot->invoke = uv_mark_seam_invoke; - ot->poll = ED_operator_uvedit; + /* api callbacks */ + ot->exec = uv_mark_seam_exec; + ot->invoke = uv_mark_seam_invoke; + ot->poll = ED_operator_uvedit; - RNA_def_boolean(ot->srna, "clear", false, "Clear Seams", "Clear instead of marking seams"); + RNA_def_boolean(ot->srna, "clear", false, "Clear Seams", "Clear instead of marking seams"); } /** \} */ @@ -4675,54 +4850,54 @@ static void UV_OT_mark_seam(wmOperatorType *ot) void ED_operatortypes_uvedit(void) { - WM_operatortype_append(UV_OT_select_all); - WM_operatortype_append(UV_OT_select); - WM_operatortype_append(UV_OT_select_loop); - WM_operatortype_append(UV_OT_select_linked); - WM_operatortype_append(UV_OT_select_linked_pick); - WM_operatortype_append(UV_OT_select_split); - WM_operatortype_append(UV_OT_select_pinned); - WM_operatortype_append(UV_OT_select_box); - WM_operatortype_append(UV_OT_select_lasso); - WM_operatortype_append(UV_OT_select_circle); - WM_operatortype_append(UV_OT_select_more); - WM_operatortype_append(UV_OT_select_less); + WM_operatortype_append(UV_OT_select_all); + WM_operatortype_append(UV_OT_select); + WM_operatortype_append(UV_OT_select_loop); + WM_operatortype_append(UV_OT_select_linked); + WM_operatortype_append(UV_OT_select_linked_pick); + WM_operatortype_append(UV_OT_select_split); + WM_operatortype_append(UV_OT_select_pinned); + WM_operatortype_append(UV_OT_select_box); + WM_operatortype_append(UV_OT_select_lasso); + WM_operatortype_append(UV_OT_select_circle); + WM_operatortype_append(UV_OT_select_more); + WM_operatortype_append(UV_OT_select_less); - WM_operatortype_append(UV_OT_snap_cursor); - WM_operatortype_append(UV_OT_snap_selected); + WM_operatortype_append(UV_OT_snap_cursor); + WM_operatortype_append(UV_OT_snap_selected); - WM_operatortype_append(UV_OT_align); + WM_operatortype_append(UV_OT_align); - WM_operatortype_append(UV_OT_stitch); + WM_operatortype_append(UV_OT_stitch); - WM_operatortype_append(UV_OT_seams_from_islands); - WM_operatortype_append(UV_OT_mark_seam); - WM_operatortype_append(UV_OT_weld); - WM_operatortype_append(UV_OT_remove_doubles); - WM_operatortype_append(UV_OT_pin); + WM_operatortype_append(UV_OT_seams_from_islands); + WM_operatortype_append(UV_OT_mark_seam); + WM_operatortype_append(UV_OT_weld); + WM_operatortype_append(UV_OT_remove_doubles); + WM_operatortype_append(UV_OT_pin); - WM_operatortype_append(UV_OT_average_islands_scale); - WM_operatortype_append(UV_OT_cube_project); - WM_operatortype_append(UV_OT_cylinder_project); - WM_operatortype_append(UV_OT_project_from_view); - WM_operatortype_append(UV_OT_minimize_stretch); - WM_operatortype_append(UV_OT_pack_islands); - WM_operatortype_append(UV_OT_reset); - WM_operatortype_append(UV_OT_sphere_project); - WM_operatortype_append(UV_OT_unwrap); + WM_operatortype_append(UV_OT_average_islands_scale); + WM_operatortype_append(UV_OT_cube_project); + WM_operatortype_append(UV_OT_cylinder_project); + WM_operatortype_append(UV_OT_project_from_view); + WM_operatortype_append(UV_OT_minimize_stretch); + WM_operatortype_append(UV_OT_pack_islands); + WM_operatortype_append(UV_OT_reset); + WM_operatortype_append(UV_OT_sphere_project); + WM_operatortype_append(UV_OT_unwrap); - WM_operatortype_append(UV_OT_reveal); - WM_operatortype_append(UV_OT_hide); + WM_operatortype_append(UV_OT_reveal); + WM_operatortype_append(UV_OT_hide); - WM_operatortype_append(UV_OT_cursor_set); + WM_operatortype_append(UV_OT_cursor_set); } void ED_keymap_uvedit(wmKeyConfig *keyconf) { - wmKeyMap *keymap; + wmKeyMap *keymap; - keymap = WM_keymap_ensure(keyconf, "UV Editor", 0, 0); - keymap->poll = ED_operator_uvedit_can_uv_sculpt; + keymap = WM_keymap_ensure(keyconf, "UV Editor", 0, 0); + keymap->poll = ED_operator_uvedit_can_uv_sculpt; } /** \} */ diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index 1a4e040472e..69183d02ab9 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -37,7 +37,7 @@ #include <stdio.h> #include <string.h> -#include "BLI_sys_types.h" /* for intptr_t support */ +#include "BLI_sys_types.h" /* for intptr_t support */ #include "eigen_capi.h" @@ -50,22 +50,25 @@ # define param_test_equals_int(condition) #else # define param_assert(condition) \ - if (!(condition)) \ - { /*printf("Assertion %s:%d\n", __FILE__, __LINE__); abort();*/ } (void)0 + if (!(condition)) { /*printf("Assertion %s:%d\n", __FILE__, __LINE__); abort();*/ \ + } \ + (void)0 # define param_warning(message) \ - { /*printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);*/ } (void)0 + {/*printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);*/}(void)0 # if 0 # define param_test_equals_ptr(str, a, b) \ - if (a != b) \ - { /*printf("Equals %s => %p != %p\n", str, a, b);*/ } (void)0 + if (a != b) { /*printf("Equals %s => %p != %p\n", str, a, b);*/ \ + } \ + (void)0 # define param_test_equals_int(str, a, b) \ - if (a != b) \ - { /*printf("Equals %s => %d != %d\n", str, a, b);*/ } (void)0 + if (a != b) { /*printf("Equals %s => %d != %d\n", str, a, b);*/ \ + } \ + (void)0 # endif #endif typedef enum PBool { - P_TRUE = 1, - P_FALSE = 0, + P_TRUE = 1, + P_FALSE = 0, } PBool; /* Special Purpose Hash */ @@ -73,18 +76,16 @@ typedef enum PBool { typedef intptr_t PHashKey; typedef struct PHashLink { - struct PHashLink *next; - PHashKey key; + struct PHashLink *next; + PHashKey key; } PHashLink; typedef struct PHash { - PHashLink **list; - PHashLink **buckets; - int size, cursize, cursize_id; + PHashLink **list; + PHashLink **buckets; + int size, cursize, cursize_id; } PHash; - - struct PChart; struct PEdge; struct PFace; @@ -94,142 +95,142 @@ struct PVert; /* Simplices */ typedef struct PVert { - struct PVert *nextlink; + struct PVert *nextlink; - union PVertUnion { - PHashKey key; /* construct */ - int id; /* abf/lscm matrix index */ - float distortion; /* area smoothing */ - HeapNode *heaplink; /* edge collapsing */ - } u; + union PVertUnion { + PHashKey key; /* construct */ + int id; /* abf/lscm matrix index */ + float distortion; /* area smoothing */ + HeapNode *heaplink; /* edge collapsing */ + } u; - struct PEdge *edge; - float co[3]; - float uv[2]; - unsigned char flag; + struct PEdge *edge; + float co[3]; + float uv[2]; + unsigned char flag; } PVert; typedef struct PEdge { - struct PEdge *nextlink; - - union PEdgeUnion { - PHashKey key; /* construct */ - int id; /* abf matrix index */ - HeapNode *heaplink; /* fill holes */ - struct PEdge *nextcollapse; /* simplification */ - } u; - - struct PVert *vert; - struct PEdge *pair; - struct PEdge *next; - struct PFace *face; - float *orig_uv, old_uv[2]; - unsigned short flag; + struct PEdge *nextlink; + + union PEdgeUnion { + PHashKey key; /* construct */ + int id; /* abf matrix index */ + HeapNode *heaplink; /* fill holes */ + struct PEdge *nextcollapse; /* simplification */ + } u; + + struct PVert *vert; + struct PEdge *pair; + struct PEdge *next; + struct PFace *face; + float *orig_uv, old_uv[2]; + unsigned short flag; } PEdge; typedef struct PFace { - struct PFace *nextlink; + struct PFace *nextlink; - union PFaceUnion { - PHashKey key; /* construct */ - int chart; /* construct splitting*/ - float area3d; /* stretch */ - int id; /* abf matrix index */ - } u; + union PFaceUnion { + PHashKey key; /* construct */ + int chart; /* construct splitting*/ + float area3d; /* stretch */ + int id; /* abf matrix index */ + } u; - struct PEdge *edge; - unsigned char flag; + struct PEdge *edge; + unsigned char flag; } PFace; enum PVertFlag { - PVERT_PIN = 1, - PVERT_SELECT = 2, - PVERT_INTERIOR = 4, - PVERT_COLLAPSE = 8, - PVERT_SPLIT = 16, + PVERT_PIN = 1, + PVERT_SELECT = 2, + PVERT_INTERIOR = 4, + PVERT_COLLAPSE = 8, + PVERT_SPLIT = 16, }; enum PEdgeFlag { - PEDGE_SEAM = 1, - PEDGE_VERTEX_SPLIT = 2, - PEDGE_PIN = 4, - PEDGE_SELECT = 8, - PEDGE_DONE = 16, - PEDGE_FILLED = 32, - PEDGE_COLLAPSE = 64, - PEDGE_COLLAPSE_EDGE = 128, - PEDGE_COLLAPSE_PAIR = 256, + PEDGE_SEAM = 1, + PEDGE_VERTEX_SPLIT = 2, + PEDGE_PIN = 4, + PEDGE_SELECT = 8, + PEDGE_DONE = 16, + PEDGE_FILLED = 32, + PEDGE_COLLAPSE = 64, + PEDGE_COLLAPSE_EDGE = 128, + PEDGE_COLLAPSE_PAIR = 256, }; /* for flipping faces */ #define PEDGE_VERTEX_FLAGS (PEDGE_PIN) enum PFaceFlag { - PFACE_CONNECTED = 1, - PFACE_FILLED = 2, - PFACE_COLLAPSE = 4, + PFACE_CONNECTED = 1, + PFACE_FILLED = 2, + PFACE_COLLAPSE = 4, }; /* Chart */ typedef struct PChart { - PVert *verts; - PEdge *edges; - PFace *faces; - int nverts, nedges, nfaces; - - PVert *collapsed_verts; - PEdge *collapsed_edges; - PFace *collapsed_faces; - - union PChartUnion { - struct PChartLscm { - LinearSolver *context; - float *abf_alpha; - PVert *pin1, *pin2; - } lscm; - struct PChartPack { - float rescale, area; - float size[2] /* , trans[2] */; - } pack; - } u; - - unsigned char flag; - struct PHandle *handle; + PVert *verts; + PEdge *edges; + PFace *faces; + int nverts, nedges, nfaces; + + PVert *collapsed_verts; + PEdge *collapsed_edges; + PFace *collapsed_faces; + + union PChartUnion { + struct PChartLscm { + LinearSolver *context; + float *abf_alpha; + PVert *pin1, *pin2; + } lscm; + struct PChartPack { + float rescale, area; + float size[2] /* , trans[2] */; + } pack; + } u; + + unsigned char flag; + struct PHandle *handle; } PChart; enum PChartFlag { - PCHART_HAS_PINS = 1, + PCHART_HAS_PINS = 1, }; enum PHandleState { - PHANDLE_STATE_ALLOCATED, - PHANDLE_STATE_CONSTRUCTED, - PHANDLE_STATE_LSCM, - PHANDLE_STATE_STRETCH, + PHANDLE_STATE_ALLOCATED, + PHANDLE_STATE_CONSTRUCTED, + PHANDLE_STATE_LSCM, + PHANDLE_STATE_STRETCH, }; typedef struct PHandle { - enum PHandleState state; - MemArena *arena; - MemArena *polyfill_arena; - Heap *polyfill_heap; + enum PHandleState state; + MemArena *arena; + MemArena *polyfill_arena; + Heap *polyfill_heap; - PChart *construction_chart; - PHash *hash_verts; - PHash *hash_edges; - PHash *hash_faces; + PChart *construction_chart; + PHash *hash_verts; + PHash *hash_edges; + PHash *hash_faces; - PChart **charts; - int ncharts; + PChart **charts; + int ncharts; - float aspx, aspy; + float aspx, aspy; - RNG *rng; - float blend; - char do_aspect; + RNG *rng; + float blend; + char do_aspect; } PHandle; /* PHash @@ -239,315 +240,319 @@ typedef struct PHandle { */ static int PHashSizes[] = { - 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, - 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169, - 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459, + 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, + 1031, 2053, 4099, 8209, 16411, 32771, 65537, 131101, 262147, 524309, + 1048583, 2097169, 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459, }; -#define PHASH_hash(ph, item) (((uintptr_t) (item)) % ((unsigned int) (ph)->cursize)) -#define PHASH_edge(v1, v2) (((v1) < (v2)) ? ((v1) * 39) ^ ((v2) * 31) : ((v1) * 31) ^ ((v2) * 39)) +#define PHASH_hash(ph, item) (((uintptr_t)(item)) % ((unsigned int)(ph)->cursize)) +#define PHASH_edge(v1, v2) (((v1) < (v2)) ? ((v1)*39) ^ ((v2)*31) : ((v1)*31) ^ ((v2)*39)) static PHash *phash_new(PHashLink **list, int sizehint) { - PHash *ph = (PHash *)MEM_callocN(sizeof(PHash), "PHash"); - ph->size = 0; - ph->cursize_id = 0; - ph->list = list; + PHash *ph = (PHash *)MEM_callocN(sizeof(PHash), "PHash"); + ph->size = 0; + ph->cursize_id = 0; + ph->list = list; - while (PHashSizes[ph->cursize_id] < sizehint) - ph->cursize_id++; + while (PHashSizes[ph->cursize_id] < sizehint) + ph->cursize_id++; - ph->cursize = PHashSizes[ph->cursize_id]; - ph->buckets = (PHashLink **)MEM_callocN(ph->cursize * sizeof(*ph->buckets), "PHashBuckets"); + ph->cursize = PHashSizes[ph->cursize_id]; + ph->buckets = (PHashLink **)MEM_callocN(ph->cursize * sizeof(*ph->buckets), "PHashBuckets"); - return ph; + return ph; } static void phash_delete(PHash *ph) { - MEM_freeN(ph->buckets); - MEM_freeN(ph); + MEM_freeN(ph->buckets); + MEM_freeN(ph); } static int phash_size(PHash *ph) { - return ph->size; + return ph->size; } static void phash_insert(PHash *ph, PHashLink *link) { - int size = ph->cursize; - uintptr_t hash = PHASH_hash(ph, link->key); - PHashLink *lookup = ph->buckets[hash]; + int size = ph->cursize; + uintptr_t hash = PHASH_hash(ph, link->key); + PHashLink *lookup = ph->buckets[hash]; - if (lookup == NULL) { - /* insert in front of the list */ - ph->buckets[hash] = link; - link->next = *(ph->list); - *(ph->list) = link; - } - else { - /* insert after existing element */ - link->next = lookup->next; - lookup->next = link; - } + if (lookup == NULL) { + /* insert in front of the list */ + ph->buckets[hash] = link; + link->next = *(ph->list); + *(ph->list) = link; + } + else { + /* insert after existing element */ + link->next = lookup->next; + lookup->next = link; + } - ph->size++; + ph->size++; - if (ph->size > (size * 3)) { - PHashLink *next = NULL, *first = *(ph->list); + if (ph->size > (size * 3)) { + PHashLink *next = NULL, *first = *(ph->list); - ph->cursize = PHashSizes[++ph->cursize_id]; - MEM_freeN(ph->buckets); - ph->buckets = (PHashLink **)MEM_callocN(ph->cursize * sizeof(*ph->buckets), "PHashBuckets"); - ph->size = 0; - *(ph->list) = NULL; + ph->cursize = PHashSizes[++ph->cursize_id]; + MEM_freeN(ph->buckets); + ph->buckets = (PHashLink **)MEM_callocN(ph->cursize * sizeof(*ph->buckets), "PHashBuckets"); + ph->size = 0; + *(ph->list) = NULL; - for (link = first; link; link = next) { - next = link->next; - phash_insert(ph, link); - } - } + for (link = first; link; link = next) { + next = link->next; + phash_insert(ph, link); + } + } } static PHashLink *phash_lookup(PHash *ph, PHashKey key) { - PHashLink *link; - uintptr_t hash = PHASH_hash(ph, key); + PHashLink *link; + uintptr_t hash = PHASH_hash(ph, key); - for (link = ph->buckets[hash]; link; link = link->next) - if (link->key == key) - return link; - else if (PHASH_hash(ph, link->key) != hash) - return NULL; + for (link = ph->buckets[hash]; link; link = link->next) + if (link->key == key) + return link; + else if (PHASH_hash(ph, link->key) != hash) + return NULL; - return link; + return link; } static PHashLink *phash_next(PHash *ph, PHashKey key, PHashLink *link) { - uintptr_t hash = PHASH_hash(ph, key); + uintptr_t hash = PHASH_hash(ph, key); - for (link = link->next; link; link = link->next) - if (link->key == key) - return link; - else if (PHASH_hash(ph, link->key) != hash) - return NULL; + for (link = link->next; link; link = link->next) + if (link->key == key) + return link; + else if (PHASH_hash(ph, link->key) != hash) + return NULL; - return link; + return link; } /* Geometry */ static float p_vec_angle_cos(float *v1, float *v2, float *v3) { - float d1[3], d2[3]; + float d1[3], d2[3]; - d1[0] = v1[0] - v2[0]; - d1[1] = v1[1] - v2[1]; - d1[2] = v1[2] - v2[2]; + d1[0] = v1[0] - v2[0]; + d1[1] = v1[1] - v2[1]; + d1[2] = v1[2] - v2[2]; - d2[0] = v3[0] - v2[0]; - d2[1] = v3[1] - v2[1]; - d2[2] = v3[2] - v2[2]; + d2[0] = v3[0] - v2[0]; + d2[1] = v3[1] - v2[1]; + d2[2] = v3[2] - v2[2]; - normalize_v3(d1); - normalize_v3(d2); + normalize_v3(d1); + normalize_v3(d2); - return d1[0] * d2[0] + d1[1] * d2[1] + d1[2] * d2[2]; + return d1[0] * d2[0] + d1[1] * d2[1] + d1[2] * d2[2]; } static float p_vec_angle(float *v1, float *v2, float *v3) { - float dot = p_vec_angle_cos(v1, v2, v3); + float dot = p_vec_angle_cos(v1, v2, v3); - if (dot <= -1.0f) - return (float)M_PI; - else if (dot >= 1.0f) - return 0.0f; - else - return acosf(dot); + if (dot <= -1.0f) + return (float)M_PI; + else if (dot >= 1.0f) + return 0.0f; + else + return acosf(dot); } static float p_vec2_angle(float *v1, float *v2, float *v3) { - float u1[3], u2[3], u3[3]; + float u1[3], u2[3], u3[3]; - u1[0] = v1[0]; u1[1] = v1[1]; u1[2] = 0.0f; - u2[0] = v2[0]; u2[1] = v2[1]; u2[2] = 0.0f; - u3[0] = v3[0]; u3[1] = v3[1]; u3[2] = 0.0f; + u1[0] = v1[0]; + u1[1] = v1[1]; + u1[2] = 0.0f; + u2[0] = v2[0]; + u2[1] = v2[1]; + u2[2] = 0.0f; + u3[0] = v3[0]; + u3[1] = v3[1]; + u3[2] = 0.0f; - return p_vec_angle(u1, u2, u3); + return p_vec_angle(u1, u2, u3); } static void p_triangle_angles(float *v1, float *v2, float *v3, float *a1, float *a2, float *a3) { - *a1 = p_vec_angle(v3, v1, v2); - *a2 = p_vec_angle(v1, v2, v3); - *a3 = (float)M_PI - *a2 - *a1; + *a1 = p_vec_angle(v3, v1, v2); + *a2 = p_vec_angle(v1, v2, v3); + *a3 = (float)M_PI - *a2 - *a1; } static void p_face_angles(PFace *f, float *a1, float *a2, float *a3) { - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; - p_triangle_angles(v1->co, v2->co, v3->co, a1, a2, a3); + p_triangle_angles(v1->co, v2->co, v3->co, a1, a2, a3); } static float p_face_area(PFace *f) { - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; - return area_tri_v3(v1->co, v2->co, v3->co); + return area_tri_v3(v1->co, v2->co, v3->co); } static float p_area_signed(float *v1, float *v2, float *v3) { - return 0.5f * (((v2[0] - v1[0]) * (v3[1] - v1[1])) - - ((v3[0] - v1[0]) * (v2[1] - v1[1]))); + return 0.5f * (((v2[0] - v1[0]) * (v3[1] - v1[1])) - ((v3[0] - v1[0]) * (v2[1] - v1[1]))); } static float p_face_uv_area_signed(PFace *f) { - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; - return 0.5f * (((v2->uv[0] - v1->uv[0]) * (v3->uv[1] - v1->uv[1])) - - ((v3->uv[0] - v1->uv[0]) * (v2->uv[1] - v1->uv[1]))); + return 0.5f * (((v2->uv[0] - v1->uv[0]) * (v3->uv[1] - v1->uv[1])) - + ((v3->uv[0] - v1->uv[0]) * (v2->uv[1] - v1->uv[1]))); } static float p_edge_length(PEdge *e) { - PVert *v1 = e->vert, *v2 = e->next->vert; - float d[3]; + PVert *v1 = e->vert, *v2 = e->next->vert; + float d[3]; - d[0] = v2->co[0] - v1->co[0]; - d[1] = v2->co[1] - v1->co[1]; - d[2] = v2->co[2] - v1->co[2]; + d[0] = v2->co[0] - v1->co[0]; + d[1] = v2->co[1] - v1->co[1]; + d[2] = v2->co[2] - v1->co[2]; - return sqrtf(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); + return sqrtf(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); } static float p_edge_uv_length(PEdge *e) { - PVert *v1 = e->vert, *v2 = e->next->vert; - float d[3]; + PVert *v1 = e->vert, *v2 = e->next->vert; + float d[3]; - d[0] = v2->uv[0] - v1->uv[0]; - d[1] = v2->uv[1] - v1->uv[1]; + d[0] = v2->uv[0] - v1->uv[0]; + d[1] = v2->uv[1] - v1->uv[1]; - return sqrtf(d[0] * d[0] + d[1] * d[1]); + return sqrtf(d[0] * d[0] + d[1] * d[1]); } static void p_chart_uv_bbox(PChart *chart, float minv[2], float maxv[2]) { - PVert *v; + PVert *v; - INIT_MINMAX2(minv, maxv); + INIT_MINMAX2(minv, maxv); - for (v = chart->verts; v; v = v->nextlink) { - minmax_v2v2_v2(minv, maxv, v->uv); - } + for (v = chart->verts; v; v = v->nextlink) { + minmax_v2v2_v2(minv, maxv, v->uv); + } } static void p_chart_uv_scale(PChart *chart, float scale) { - PVert *v; + PVert *v; - for (v = chart->verts; v; v = v->nextlink) { - v->uv[0] *= scale; - v->uv[1] *= scale; - } + for (v = chart->verts; v; v = v->nextlink) { + v->uv[0] *= scale; + v->uv[1] *= scale; + } } static void p_chart_uv_scale_xy(PChart *chart, float x, float y) { - PVert *v; + PVert *v; - for (v = chart->verts; v; v = v->nextlink) { - v->uv[0] *= x; - v->uv[1] *= y; - } + for (v = chart->verts; v; v = v->nextlink) { + v->uv[0] *= x; + v->uv[1] *= y; + } } static void p_chart_uv_translate(PChart *chart, float trans[2]) { - PVert *v; + PVert *v; - for (v = chart->verts; v; v = v->nextlink) { - v->uv[0] += trans[0]; - v->uv[1] += trans[1]; - } + for (v = chart->verts; v; v = v->nextlink) { + v->uv[0] += trans[0]; + v->uv[1] += trans[1]; + } } static void p_chart_uv_transform(PChart *chart, float mat[2][2]) { - PVert *v; + PVert *v; - for (v = chart->verts; v; v = v->nextlink) { - mul_m2v2(mat, v->uv); - } + for (v = chart->verts; v; v = v->nextlink) { + mul_m2v2(mat, v->uv); + } } static void p_chart_uv_to_array(PChart *chart, float (*points)[2]) { - PVert *v; - unsigned int i = 0; + PVert *v; + unsigned int i = 0; - for (v = chart->verts; v; v = v->nextlink) { - copy_v2_v2(points[i++], v->uv); - } + for (v = chart->verts; v; v = v->nextlink) { + copy_v2_v2(points[i++], v->uv); + } } static void UNUSED_FUNCTION(p_chart_uv_from_array)(PChart *chart, float (*points)[2]) { - PVert *v; - unsigned int i = 0; + PVert *v; + unsigned int i = 0; - for (v = chart->verts; v; v = v->nextlink) { - copy_v2_v2(v->uv, points[i++]); - } + for (v = chart->verts; v; v = v->nextlink) { + copy_v2_v2(v->uv, points[i++]); + } } - static PBool p_intersect_line_2d_dir(float *v1, float *dir1, float *v2, float *dir2, float *isect) { - float lmbda, div; + float lmbda, div; - div = dir2[0] * dir1[1] - dir2[1] * dir1[0]; + div = dir2[0] * dir1[1] - dir2[1] * dir1[0]; - if (div == 0.0f) - return P_FALSE; + if (div == 0.0f) + return P_FALSE; - lmbda = ((v1[1] - v2[1]) * dir1[0] - (v1[0] - v2[0]) * dir1[1]) / div; - isect[0] = v1[0] + lmbda * dir2[0]; - isect[1] = v1[1] + lmbda * dir2[1]; + lmbda = ((v1[1] - v2[1]) * dir1[0] - (v1[0] - v2[0]) * dir1[1]) / div; + isect[0] = v1[0] + lmbda * dir2[0]; + isect[1] = v1[1] + lmbda * dir2[1]; - return P_TRUE; + return P_TRUE; } #if 0 static PBool p_intersect_line_2d(float *v1, float *v2, float *v3, float *v4, float *isect) { - float dir1[2], dir2[2]; + float dir1[2], dir2[2]; - dir1[0] = v4[0] - v3[0]; - dir1[1] = v4[1] - v3[1]; + dir1[0] = v4[0] - v3[0]; + dir1[1] = v4[1] - v3[1]; - dir2[0] = v2[0] - v1[0]; - dir2[1] = v2[1] - v1[1]; + dir2[0] = v2[0] - v1[0]; + dir2[1] = v2[1] - v1[1]; - if (!p_intersect_line_2d_dir(v1, dir1, v2, dir2, isect)) { - /* parallel - should never happen in theory for polygon kernel, but - * let's give a point nearby in case things go wrong */ - isect[0] = (v1[0] + v2[0]) * 0.5f; - isect[1] = (v1[1] + v2[1]) * 0.5f; - return P_FALSE; - } + if (!p_intersect_line_2d_dir(v1, dir1, v2, dir2, isect)) { + /* parallel - should never happen in theory for polygon kernel, but + * let's give a point nearby in case things go wrong */ + isect[0] = (v1[0] + v2[0]) * 0.5f; + isect[1] = (v1[1] + v2[1]) * 0.5f; + return P_FALSE; + } - return P_TRUE; + return P_TRUE; } #endif @@ -555,75 +560,75 @@ static PBool p_intersect_line_2d(float *v1, float *v2, float *v3, float *v4, flo static PEdge *p_wheel_edge_next(PEdge *e) { - return e->next->next->pair; + return e->next->next->pair; } static PEdge *p_wheel_edge_prev(PEdge *e) { - return (e->pair) ? e->pair->next : NULL; + return (e->pair) ? e->pair->next : NULL; } static PEdge *p_boundary_edge_next(PEdge *e) { - return e->next->vert->edge; + return e->next->vert->edge; } static PEdge *p_boundary_edge_prev(PEdge *e) { - PEdge *we = e, *last; + PEdge *we = e, *last; - do { - last = we; - we = p_wheel_edge_next(we); - } while (we && (we != e)); + do { + last = we; + we = p_wheel_edge_next(we); + } while (we && (we != e)); - return last->next->next; + return last->next->next; } static PBool p_vert_interior(PVert *v) { - return (v->edge->pair != NULL); + return (v->edge->pair != NULL); } static void p_face_flip(PFace *f) { - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; - int f1 = e1->flag, f2 = e2->flag, f3 = e3->flag; - float *orig_uv1 = e1->orig_uv, *orig_uv2 = e2->orig_uv, *orig_uv3 = e3->orig_uv; + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; + int f1 = e1->flag, f2 = e2->flag, f3 = e3->flag; + float *orig_uv1 = e1->orig_uv, *orig_uv2 = e2->orig_uv, *orig_uv3 = e3->orig_uv; - e1->vert = v2; - e1->next = e3; - e1->orig_uv = orig_uv2; - e1->flag = (f1 & ~PEDGE_VERTEX_FLAGS) | (f2 & PEDGE_VERTEX_FLAGS); + e1->vert = v2; + e1->next = e3; + e1->orig_uv = orig_uv2; + e1->flag = (f1 & ~PEDGE_VERTEX_FLAGS) | (f2 & PEDGE_VERTEX_FLAGS); - e2->vert = v3; - e2->next = e1; - e2->orig_uv = orig_uv3; - e2->flag = (f2 & ~PEDGE_VERTEX_FLAGS) | (f3 & PEDGE_VERTEX_FLAGS); + e2->vert = v3; + e2->next = e1; + e2->orig_uv = orig_uv3; + e2->flag = (f2 & ~PEDGE_VERTEX_FLAGS) | (f3 & PEDGE_VERTEX_FLAGS); - e3->vert = v1; - e3->next = e2; - e3->orig_uv = orig_uv1; - e3->flag = (f3 & ~PEDGE_VERTEX_FLAGS) | (f1 & PEDGE_VERTEX_FLAGS); + e3->vert = v1; + e3->next = e2; + e3->orig_uv = orig_uv1; + e3->flag = (f3 & ~PEDGE_VERTEX_FLAGS) | (f1 & PEDGE_VERTEX_FLAGS); } #if 0 static void p_chart_topological_sanity_check(PChart *chart) { - PVert *v; - PEdge *e; + PVert *v; + PEdge *e; - for (v = chart->verts; v; v = v->nextlink) - param_test_equals_ptr("v->edge->vert", v, v->edge->vert); + for (v = chart->verts; v; v = v->nextlink) + param_test_equals_ptr("v->edge->vert", v, v->edge->vert); - for (e = chart->edges; e; e = e->nextlink) { - if (e->pair) { - param_test_equals_ptr("e->pair->pair", e, e->pair->pair); - param_test_equals_ptr("pair->vert", e->vert, e->pair->next->vert); - param_test_equals_ptr("pair->next->vert", e->next->vert, e->pair->vert); - } - } + for (e = chart->edges; e; e = e->nextlink) { + if (e->pair) { + param_test_equals_ptr("e->pair->pair", e, e->pair->pair); + param_test_equals_ptr("pair->vert", e->vert, e->pair->next->vert); + param_test_equals_ptr("pair->next->vert", e->next->vert, e->pair->vert); + } + } } #endif @@ -631,737 +636,748 @@ static void p_chart_topological_sanity_check(PChart *chart) static void p_vert_load_pin_select_uvs(PHandle *handle, PVert *v) { - PEdge *e; - int nedges = 0, npins = 0; - float pinuv[2]; - - v->uv[0] = v->uv[1] = 0.0f; - pinuv[0] = pinuv[1] = 0.0f; - e = v->edge; - do { - if (e->orig_uv) { - if (e->flag & PEDGE_SELECT) - v->flag |= PVERT_SELECT; - - if (e->flag & PEDGE_PIN) { - pinuv[0] += e->orig_uv[0] * handle->aspx; - pinuv[1] += e->orig_uv[1] * handle->aspy; - npins++; - } - else { - v->uv[0] += e->orig_uv[0] * handle->aspx; - v->uv[1] += e->orig_uv[1] * handle->aspy; - } - - nedges++; - } - - e = p_wheel_edge_next(e); - } while (e && e != (v->edge)); - - if (npins > 0) { - v->uv[0] = pinuv[0] / npins; - v->uv[1] = pinuv[1] / npins; - v->flag |= PVERT_PIN; - } - else if (nedges > 0) { - v->uv[0] /= nedges; - v->uv[1] /= nedges; - } + PEdge *e; + int nedges = 0, npins = 0; + float pinuv[2]; + + v->uv[0] = v->uv[1] = 0.0f; + pinuv[0] = pinuv[1] = 0.0f; + e = v->edge; + do { + if (e->orig_uv) { + if (e->flag & PEDGE_SELECT) + v->flag |= PVERT_SELECT; + + if (e->flag & PEDGE_PIN) { + pinuv[0] += e->orig_uv[0] * handle->aspx; + pinuv[1] += e->orig_uv[1] * handle->aspy; + npins++; + } + else { + v->uv[0] += e->orig_uv[0] * handle->aspx; + v->uv[1] += e->orig_uv[1] * handle->aspy; + } + + nedges++; + } + + e = p_wheel_edge_next(e); + } while (e && e != (v->edge)); + + if (npins > 0) { + v->uv[0] = pinuv[0] / npins; + v->uv[1] = pinuv[1] / npins; + v->flag |= PVERT_PIN; + } + else if (nedges > 0) { + v->uv[0] /= nedges; + v->uv[1] /= nedges; + } } static void p_flush_uvs(PHandle *handle, PChart *chart) { - PEdge *e; + PEdge *e; - for (e = chart->edges; e; e = e->nextlink) { - if (e->orig_uv) { - e->orig_uv[0] = e->vert->uv[0] / handle->aspx; - e->orig_uv[1] = e->vert->uv[1] / handle->aspy; - } - } + for (e = chart->edges; e; e = e->nextlink) { + if (e->orig_uv) { + e->orig_uv[0] = e->vert->uv[0] / handle->aspx; + e->orig_uv[1] = e->vert->uv[1] / handle->aspy; + } + } } static void p_flush_uvs_blend(PHandle *handle, PChart *chart, float blend) { - PEdge *e; - float invblend = 1.0f - blend; + PEdge *e; + float invblend = 1.0f - blend; - for (e = chart->edges; e; e = e->nextlink) { - if (e->orig_uv) { - e->orig_uv[0] = blend * e->old_uv[0] + invblend * e->vert->uv[0] / handle->aspx; - e->orig_uv[1] = blend * e->old_uv[1] + invblend * e->vert->uv[1] / handle->aspy; - } - } + for (e = chart->edges; e; e = e->nextlink) { + if (e->orig_uv) { + e->orig_uv[0] = blend * e->old_uv[0] + invblend * e->vert->uv[0] / handle->aspx; + e->orig_uv[1] = blend * e->old_uv[1] + invblend * e->vert->uv[1] / handle->aspy; + } + } } static void p_face_backup_uvs(PFace *f) { - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - if (e1->orig_uv) { - e1->old_uv[0] = e1->orig_uv[0]; - e1->old_uv[1] = e1->orig_uv[1]; - } - if (e2->orig_uv) { - e2->old_uv[0] = e2->orig_uv[0]; - e2->old_uv[1] = e2->orig_uv[1]; - } - if (e3->orig_uv) { - e3->old_uv[0] = e3->orig_uv[0]; - e3->old_uv[1] = e3->orig_uv[1]; - } + if (e1->orig_uv) { + e1->old_uv[0] = e1->orig_uv[0]; + e1->old_uv[1] = e1->orig_uv[1]; + } + if (e2->orig_uv) { + e2->old_uv[0] = e2->orig_uv[0]; + e2->old_uv[1] = e2->orig_uv[1]; + } + if (e3->orig_uv) { + e3->old_uv[0] = e3->orig_uv[0]; + e3->old_uv[1] = e3->orig_uv[1]; + } } static void p_face_restore_uvs(PFace *f) { - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - if (e1->orig_uv) { - e1->orig_uv[0] = e1->old_uv[0]; - e1->orig_uv[1] = e1->old_uv[1]; - } - if (e2->orig_uv) { - e2->orig_uv[0] = e2->old_uv[0]; - e2->orig_uv[1] = e2->old_uv[1]; - } - if (e3->orig_uv) { - e3->orig_uv[0] = e3->old_uv[0]; - e3->orig_uv[1] = e3->old_uv[1]; - } + if (e1->orig_uv) { + e1->orig_uv[0] = e1->old_uv[0]; + e1->orig_uv[1] = e1->old_uv[1]; + } + if (e2->orig_uv) { + e2->orig_uv[0] = e2->old_uv[0]; + e2->orig_uv[1] = e2->old_uv[1]; + } + if (e3->orig_uv) { + e3->orig_uv[0] = e3->old_uv[0]; + e3->orig_uv[1] = e3->old_uv[1]; + } } /* Construction (use only during construction, relies on u.key being set */ static PVert *p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge *e) { - PVert *v = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*v)); - copy_v3_v3(v->co, co); + PVert *v = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*v)); + copy_v3_v3(v->co, co); - /* Sanity check, a single nan/inf point causes the entire result to be invalid. - * Note that values within the calculation may _become_ non-finite, - * so the rest of the code still needs to take this possibility into account. */ - for (int i = 0; i < 3; i++) { - if (UNLIKELY(!isfinite(v->co[i]))) { - v->co[i] = 0.0f; - } - } + /* Sanity check, a single nan/inf point causes the entire result to be invalid. + * Note that values within the calculation may _become_ non-finite, + * so the rest of the code still needs to take this possibility into account. */ + for (int i = 0; i < 3; i++) { + if (UNLIKELY(!isfinite(v->co[i]))) { + v->co[i] = 0.0f; + } + } - v->u.key = key; - v->edge = e; - v->flag = 0; + v->u.key = key; + v->edge = e; + v->flag = 0; - phash_insert(handle->hash_verts, (PHashLink *)v); + phash_insert(handle->hash_verts, (PHashLink *)v); - return v; + return v; } static PVert *p_vert_lookup(PHandle *handle, PHashKey key, const float co[3], PEdge *e) { - PVert *v = (PVert *)phash_lookup(handle->hash_verts, key); + PVert *v = (PVert *)phash_lookup(handle->hash_verts, key); - if (v) - return v; - else - return p_vert_add(handle, key, co, e); + if (v) + return v; + else + return p_vert_add(handle, key, co, e); } static PVert *p_vert_copy(PChart *chart, PVert *v) { - PVert *nv = (PVert *)BLI_memarena_alloc(chart->handle->arena, sizeof(*nv)); + PVert *nv = (PVert *)BLI_memarena_alloc(chart->handle->arena, sizeof(*nv)); - copy_v3_v3(nv->co, v->co); - nv->uv[0] = v->uv[0]; - nv->uv[1] = v->uv[1]; - nv->u.key = v->u.key; - nv->edge = v->edge; - nv->flag = v->flag; + copy_v3_v3(nv->co, v->co); + nv->uv[0] = v->uv[0]; + nv->uv[1] = v->uv[1]; + nv->u.key = v->u.key; + nv->edge = v->edge; + nv->flag = v->flag; - return nv; + return nv; } static PEdge *p_edge_lookup(PHandle *handle, PHashKey *vkeys) { - PHashKey key = PHASH_edge(vkeys[0], vkeys[1]); - PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key); + PHashKey key = PHASH_edge(vkeys[0], vkeys[1]); + PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key); - while (e) { - if ((e->vert->u.key == vkeys[0]) && (e->next->vert->u.key == vkeys[1])) - return e; - else if ((e->vert->u.key == vkeys[1]) && (e->next->vert->u.key == vkeys[0])) - return e; + while (e) { + if ((e->vert->u.key == vkeys[0]) && (e->next->vert->u.key == vkeys[1])) + return e; + else if ((e->vert->u.key == vkeys[1]) && (e->next->vert->u.key == vkeys[0])) + return e; - e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e); - } + e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e); + } - return NULL; + return NULL; } static int p_face_exists(ParamHandle *phandle, ParamKey *pvkeys, int i1, int i2, int i3) { - PHandle *handle = (PHandle *)phandle; - PHashKey *vkeys = (PHashKey *)pvkeys; - PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]); - PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key); + PHandle *handle = (PHandle *)phandle; + PHashKey *vkeys = (PHashKey *)pvkeys; + PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]); + PEdge *e = (PEdge *)phash_lookup(handle->hash_edges, key); - while (e) { - if ((e->vert->u.key == vkeys[i1]) && (e->next->vert->u.key == vkeys[i2])) { - if (e->next->next->vert->u.key == vkeys[i3]) - return P_TRUE; - } - else if ((e->vert->u.key == vkeys[i2]) && (e->next->vert->u.key == vkeys[i1])) { - if (e->next->next->vert->u.key == vkeys[i3]) - return P_TRUE; - } + while (e) { + if ((e->vert->u.key == vkeys[i1]) && (e->next->vert->u.key == vkeys[i2])) { + if (e->next->next->vert->u.key == vkeys[i3]) + return P_TRUE; + } + else if ((e->vert->u.key == vkeys[i2]) && (e->next->vert->u.key == vkeys[i1])) { + if (e->next->next->vert->u.key == vkeys[i3]) + return P_TRUE; + } - e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e); - } + e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e); + } - return P_FALSE; + return P_FALSE; } static PChart *p_chart_new(PHandle *handle) { - PChart *chart = (PChart *)MEM_callocN(sizeof(*chart), "PChart"); - chart->handle = handle; + PChart *chart = (PChart *)MEM_callocN(sizeof(*chart), "PChart"); + chart->handle = handle; - return chart; + return chart; } static void p_chart_delete(PChart *chart) { - /* the actual links are free by memarena */ - MEM_freeN(chart); + /* the actual links are free by memarena */ + MEM_freeN(chart); } static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep) { - float *uv1, *uv2, *uvp1, *uvp2; - float limit[2]; + float *uv1, *uv2, *uvp1, *uvp2; + float limit[2]; - limit[0] = 0.00001; - limit[1] = 0.00001; + limit[0] = 0.00001; + limit[1] = 0.00001; - uv1 = e->orig_uv; - uv2 = e->next->orig_uv; + uv1 = e->orig_uv; + uv2 = e->next->orig_uv; - if (e->vert->u.key == ep->vert->u.key) { - uvp1 = ep->orig_uv; - uvp2 = ep->next->orig_uv; - } - else { - uvp1 = ep->next->orig_uv; - uvp2 = ep->orig_uv; - } + if (e->vert->u.key == ep->vert->u.key) { + uvp1 = ep->orig_uv; + uvp2 = ep->next->orig_uv; + } + else { + uvp1 = ep->next->orig_uv; + uvp2 = ep->orig_uv; + } - if ((fabsf(uv1[0] - uvp1[0]) > limit[0]) || (fabsf(uv1[1] - uvp1[1]) > limit[1])) { - e->flag |= PEDGE_SEAM; - ep->flag |= PEDGE_SEAM; - return P_TRUE; - } - if ((fabsf(uv2[0] - uvp2[0]) > limit[0]) || (fabsf(uv2[1] - uvp2[1]) > limit[1])) { - e->flag |= PEDGE_SEAM; - ep->flag |= PEDGE_SEAM; - return P_TRUE; - } + if ((fabsf(uv1[0] - uvp1[0]) > limit[0]) || (fabsf(uv1[1] - uvp1[1]) > limit[1])) { + e->flag |= PEDGE_SEAM; + ep->flag |= PEDGE_SEAM; + return P_TRUE; + } + if ((fabsf(uv2[0] - uvp2[0]) > limit[0]) || (fabsf(uv2[1] - uvp2[1]) > limit[1])) { + e->flag |= PEDGE_SEAM; + ep->flag |= PEDGE_SEAM; + return P_TRUE; + } - return P_FALSE; + return P_FALSE; } static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PEdge **pair, PBool impl) { - PHashKey key; - PEdge *pe; - PVert *v1, *v2; - PHashKey key1 = e->vert->u.key; - PHashKey key2 = e->next->vert->u.key; + PHashKey key; + PEdge *pe; + PVert *v1, *v2; + PHashKey key1 = e->vert->u.key; + PHashKey key2 = e->next->vert->u.key; - if (e->flag & PEDGE_SEAM) - return P_FALSE; + if (e->flag & PEDGE_SEAM) + return P_FALSE; - key = PHASH_edge(key1, key2); - pe = (PEdge *)phash_lookup(handle->hash_edges, key); - *pair = NULL; + key = PHASH_edge(key1, key2); + pe = (PEdge *)phash_lookup(handle->hash_edges, key); + *pair = NULL; - while (pe) { - if (pe != e) { - v1 = pe->vert; - v2 = pe->next->vert; + while (pe) { + if (pe != e) { + v1 = pe->vert; + v2 = pe->next->vert; - if (((v1->u.key == key1) && (v2->u.key == key2)) || - ((v1->u.key == key2) && (v2->u.key == key1))) - { + if (((v1->u.key == key1) && (v2->u.key == key2)) || + ((v1->u.key == key2) && (v2->u.key == key1))) { - /* don't connect seams and t-junctions */ - if ((pe->flag & PEDGE_SEAM) || *pair || - (impl && p_edge_implicit_seam(e, pe))) - { - *pair = NULL; - return P_FALSE; - } + /* don't connect seams and t-junctions */ + if ((pe->flag & PEDGE_SEAM) || *pair || (impl && p_edge_implicit_seam(e, pe))) { + *pair = NULL; + return P_FALSE; + } - *pair = pe; - } - } + *pair = pe; + } + } - pe = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)pe); - } + pe = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)pe); + } - if (*pair && (e->vert == (*pair)->vert)) { - if ((*pair)->next->pair || (*pair)->next->next->pair) { - /* non unfoldable, maybe mobius ring or klein bottle */ - *pair = NULL; - return P_FALSE; - } - } + if (*pair && (e->vert == (*pair)->vert)) { + if ((*pair)->next->pair || (*pair)->next->next->pair) { + /* non unfoldable, maybe mobius ring or klein bottle */ + *pair = NULL; + return P_FALSE; + } + } - return (*pair != NULL); + return (*pair != NULL); } static PBool p_edge_connect_pair(PHandle *handle, PEdge *e, PEdge ***stack, PBool impl) { - PEdge *pair = NULL; + PEdge *pair = NULL; - if (!e->pair && p_edge_has_pair(handle, e, &pair, impl)) { - if (e->vert == pair->vert) - p_face_flip(pair->face); + if (!e->pair && p_edge_has_pair(handle, e, &pair, impl)) { + if (e->vert == pair->vert) + p_face_flip(pair->face); - e->pair = pair; - pair->pair = e; + e->pair = pair; + pair->pair = e; - if (!(pair->face->flag & PFACE_CONNECTED)) { - **stack = pair; - (*stack)++; - } - } + if (!(pair->face->flag & PFACE_CONNECTED)) { + **stack = pair; + (*stack)++; + } + } - return (e->pair != NULL); + return (e->pair != NULL); } static int p_connect_pairs(PHandle *handle, PBool impl) { - PEdge **stackbase = MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces), "Pstackbase"); - PEdge **stack = stackbase; - PFace *f, *first; - PEdge *e, *e1, *e2; - PChart *chart = handle->construction_chart; - int ncharts = 0; + PEdge **stackbase = MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces), + "Pstackbase"); + PEdge **stack = stackbase; + PFace *f, *first; + PEdge *e, *e1, *e2; + PChart *chart = handle->construction_chart; + int ncharts = 0; - /* connect pairs, count edges, set vertex-edge pointer to a pairless edge */ - for (first = chart->faces; first; first = first->nextlink) { - if (first->flag & PFACE_CONNECTED) - continue; + /* connect pairs, count edges, set vertex-edge pointer to a pairless edge */ + for (first = chart->faces; first; first = first->nextlink) { + if (first->flag & PFACE_CONNECTED) + continue; - *stack = first->edge; - stack++; + *stack = first->edge; + stack++; - while (stack != stackbase) { - stack--; - e = *stack; - e1 = e->next; - e2 = e1->next; + while (stack != stackbase) { + stack--; + e = *stack; + e1 = e->next; + e2 = e1->next; - f = e->face; - f->flag |= PFACE_CONNECTED; + f = e->face; + f->flag |= PFACE_CONNECTED; - /* assign verts to charts so we can sort them later */ - f->u.chart = ncharts; + /* assign verts to charts so we can sort them later */ + f->u.chart = ncharts; - if (!p_edge_connect_pair(handle, e, &stack, impl)) - e->vert->edge = e; - if (!p_edge_connect_pair(handle, e1, &stack, impl)) - e1->vert->edge = e1; - if (!p_edge_connect_pair(handle, e2, &stack, impl)) - e2->vert->edge = e2; - } + if (!p_edge_connect_pair(handle, e, &stack, impl)) + e->vert->edge = e; + if (!p_edge_connect_pair(handle, e1, &stack, impl)) + e1->vert->edge = e1; + if (!p_edge_connect_pair(handle, e2, &stack, impl)) + e2->vert->edge = e2; + } - ncharts++; - } + ncharts++; + } - MEM_freeN(stackbase); + MEM_freeN(stackbase); - return ncharts; + return ncharts; } static void p_split_vert(PChart *chart, PEdge *e) { - PEdge *we, *lastwe = NULL; - PVert *v = e->vert; - PBool copy = P_TRUE; + PEdge *we, *lastwe = NULL; + PVert *v = e->vert; + PBool copy = P_TRUE; - if (e->flag & PEDGE_PIN) { - chart->flag |= PCHART_HAS_PINS; - } + if (e->flag & PEDGE_PIN) { + chart->flag |= PCHART_HAS_PINS; + } - if (e->flag & PEDGE_VERTEX_SPLIT) - return; + if (e->flag & PEDGE_VERTEX_SPLIT) + return; - /* rewind to start */ - lastwe = e; - for (we = p_wheel_edge_prev(e); we && (we != e); we = p_wheel_edge_prev(we)) - lastwe = we; + /* rewind to start */ + lastwe = e; + for (we = p_wheel_edge_prev(e); we && (we != e); we = p_wheel_edge_prev(we)) + lastwe = we; - /* go over all edges in wheel */ - for (we = lastwe; we; we = p_wheel_edge_next(we)) { - if (we->flag & PEDGE_VERTEX_SPLIT) - break; + /* go over all edges in wheel */ + for (we = lastwe; we; we = p_wheel_edge_next(we)) { + if (we->flag & PEDGE_VERTEX_SPLIT) + break; - we->flag |= PEDGE_VERTEX_SPLIT; + we->flag |= PEDGE_VERTEX_SPLIT; - if (we == v->edge) { - /* found it, no need to copy */ - copy = P_FALSE; - v->nextlink = chart->verts; - chart->verts = v; - chart->nverts++; - } - } + if (we == v->edge) { + /* found it, no need to copy */ + copy = P_FALSE; + v->nextlink = chart->verts; + chart->verts = v; + chart->nverts++; + } + } - if (copy) { - /* not found, copying */ - v->flag |= PVERT_SPLIT; - v = p_vert_copy(chart, v); - v->flag |= PVERT_SPLIT; + if (copy) { + /* not found, copying */ + v->flag |= PVERT_SPLIT; + v = p_vert_copy(chart, v); + v->flag |= PVERT_SPLIT; - v->nextlink = chart->verts; - chart->verts = v; - chart->nverts++; + v->nextlink = chart->verts; + chart->verts = v; + chart->nverts++; - v->edge = lastwe; + v->edge = lastwe; - we = lastwe; - do { - we->vert = v; - we = p_wheel_edge_next(we); - } while (we && (we != lastwe)); - } + we = lastwe; + do { + we->vert = v; + we = p_wheel_edge_next(we); + } while (we && (we != lastwe)); + } } static PChart **p_split_charts(PHandle *handle, PChart *chart, int ncharts) { - PChart **charts = MEM_mallocN(sizeof(*charts) * ncharts, "PCharts"), *nchart; - PFace *f, *nextf; - int i; + PChart **charts = MEM_mallocN(sizeof(*charts) * ncharts, "PCharts"), *nchart; + PFace *f, *nextf; + int i; - for (i = 0; i < ncharts; i++) - charts[i] = p_chart_new(handle); + for (i = 0; i < ncharts; i++) + charts[i] = p_chart_new(handle); - f = chart->faces; - while (f) { - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - nextf = f->nextlink; + f = chart->faces; + while (f) { + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + nextf = f->nextlink; - nchart = charts[f->u.chart]; + nchart = charts[f->u.chart]; - f->nextlink = nchart->faces; - nchart->faces = f; - e1->nextlink = nchart->edges; - nchart->edges = e1; - e2->nextlink = nchart->edges; - nchart->edges = e2; - e3->nextlink = nchart->edges; - nchart->edges = e3; + f->nextlink = nchart->faces; + nchart->faces = f; + e1->nextlink = nchart->edges; + nchart->edges = e1; + e2->nextlink = nchart->edges; + nchart->edges = e2; + e3->nextlink = nchart->edges; + nchart->edges = e3; - nchart->nfaces++; - nchart->nedges += 3; + nchart->nfaces++; + nchart->nedges += 3; - p_split_vert(nchart, e1); - p_split_vert(nchart, e2); - p_split_vert(nchart, e3); + p_split_vert(nchart, e1); + p_split_vert(nchart, e2); + p_split_vert(nchart, e3); - f = nextf; - } + f = nextf; + } - return charts; + return charts; } static PFace *p_face_add(PHandle *handle) { - PFace *f; - PEdge *e1, *e2, *e3; + PFace *f; + PEdge *e1, *e2, *e3; - /* allocate */ - f = (PFace *)BLI_memarena_alloc(handle->arena, sizeof(*f)); - f->flag = 0; /* init ! */ + /* allocate */ + f = (PFace *)BLI_memarena_alloc(handle->arena, sizeof(*f)); + f->flag = 0; /* init ! */ - e1 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e1)); - e2 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e2)); - e3 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e3)); + e1 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e1)); + e2 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e2)); + e3 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e3)); - /* set up edges */ - f->edge = e1; - e1->face = e2->face = e3->face = f; + /* set up edges */ + f->edge = e1; + e1->face = e2->face = e3->face = f; - e1->next = e2; - e2->next = e3; - e3->next = e1; + e1->next = e2; + e2->next = e3; + e3->next = e1; - e1->pair = NULL; - e2->pair = NULL; - e3->pair = NULL; + e1->pair = NULL; + e2->pair = NULL; + e3->pair = NULL; - e1->flag = 0; - e2->flag = 0; - e3->flag = 0; + e1->flag = 0; + e2->flag = 0; + e3->flag = 0; - return f; + return f; } -static PFace *p_face_add_construct(PHandle *handle, ParamKey key, ParamKey *vkeys, - float *co[4], float *uv[4], int i1, int i2, int i3, - ParamBool *pin, ParamBool *select) +static PFace *p_face_add_construct(PHandle *handle, + ParamKey key, + ParamKey *vkeys, + float *co[4], + float *uv[4], + int i1, + int i2, + int i3, + ParamBool *pin, + ParamBool *select) { - PFace *f = p_face_add(handle); - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + PFace *f = p_face_add(handle); + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - e1->vert = p_vert_lookup(handle, vkeys[i1], co[i1], e1); - e2->vert = p_vert_lookup(handle, vkeys[i2], co[i2], e2); - e3->vert = p_vert_lookup(handle, vkeys[i3], co[i3], e3); + e1->vert = p_vert_lookup(handle, vkeys[i1], co[i1], e1); + e2->vert = p_vert_lookup(handle, vkeys[i2], co[i2], e2); + e3->vert = p_vert_lookup(handle, vkeys[i3], co[i3], e3); - e1->orig_uv = uv[i1]; - e2->orig_uv = uv[i2]; - e3->orig_uv = uv[i3]; + e1->orig_uv = uv[i1]; + e2->orig_uv = uv[i2]; + e3->orig_uv = uv[i3]; - if (pin) { - if (pin[i1]) e1->flag |= PEDGE_PIN; - if (pin[i2]) e2->flag |= PEDGE_PIN; - if (pin[i3]) e3->flag |= PEDGE_PIN; - } + if (pin) { + if (pin[i1]) + e1->flag |= PEDGE_PIN; + if (pin[i2]) + e2->flag |= PEDGE_PIN; + if (pin[i3]) + e3->flag |= PEDGE_PIN; + } - if (select) { - if (select[i1]) e1->flag |= PEDGE_SELECT; - if (select[i2]) e2->flag |= PEDGE_SELECT; - if (select[i3]) e3->flag |= PEDGE_SELECT; - } + if (select) { + if (select[i1]) + e1->flag |= PEDGE_SELECT; + if (select[i2]) + e2->flag |= PEDGE_SELECT; + if (select[i3]) + e3->flag |= PEDGE_SELECT; + } - /* insert into hash */ - f->u.key = key; - phash_insert(handle->hash_faces, (PHashLink *)f); + /* insert into hash */ + f->u.key = key; + phash_insert(handle->hash_faces, (PHashLink *)f); - e1->u.key = PHASH_edge(vkeys[i1], vkeys[i2]); - e2->u.key = PHASH_edge(vkeys[i2], vkeys[i3]); - e3->u.key = PHASH_edge(vkeys[i3], vkeys[i1]); + e1->u.key = PHASH_edge(vkeys[i1], vkeys[i2]); + e2->u.key = PHASH_edge(vkeys[i2], vkeys[i3]); + e3->u.key = PHASH_edge(vkeys[i3], vkeys[i1]); - phash_insert(handle->hash_edges, (PHashLink *)e1); - phash_insert(handle->hash_edges, (PHashLink *)e2); - phash_insert(handle->hash_edges, (PHashLink *)e3); + phash_insert(handle->hash_edges, (PHashLink *)e1); + phash_insert(handle->hash_edges, (PHashLink *)e2); + phash_insert(handle->hash_edges, (PHashLink *)e3); - return f; + return f; } static PFace *p_face_add_fill(PChart *chart, PVert *v1, PVert *v2, PVert *v3) { - PFace *f = p_face_add(chart->handle); - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + PFace *f = p_face_add(chart->handle); + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - e1->vert = v1; - e2->vert = v2; - e3->vert = v3; + e1->vert = v1; + e2->vert = v2; + e3->vert = v3; - e1->orig_uv = e2->orig_uv = e3->orig_uv = NULL; + e1->orig_uv = e2->orig_uv = e3->orig_uv = NULL; - f->nextlink = chart->faces; - chart->faces = f; - e1->nextlink = chart->edges; - chart->edges = e1; - e2->nextlink = chart->edges; - chart->edges = e2; - e3->nextlink = chart->edges; - chart->edges = e3; + f->nextlink = chart->faces; + chart->faces = f; + e1->nextlink = chart->edges; + chart->edges = e1; + e2->nextlink = chart->edges; + chart->edges = e2; + e3->nextlink = chart->edges; + chart->edges = e3; - chart->nfaces++; - chart->nedges += 3; + chart->nfaces++; + chart->nedges += 3; - return f; + return f; } static PBool p_quad_split_direction(PHandle *handle, float **co, PHashKey *vkeys) { - /* slight bias to prefer one edge over the other in case they are equal, so - * that in symmetric models we choose the same split direction instead of - * depending on floating point errors to decide */ - float bias = 1.0f + 1e-6f; - float fac = len_v3v3(co[0], co[2]) * bias - len_v3v3(co[1], co[3]); - PBool dir = (fac <= 0.0f); - - /* the face exists check is there because of a special case: when - * two quads share three vertices, they can each be split into two - * triangles, resulting in two identical triangles. for example in - * suzanne's nose. */ - if (dir) { - if (p_face_exists(handle, vkeys, 0, 1, 2) || p_face_exists(handle, vkeys, 0, 2, 3)) - return !dir; - } - else { - if (p_face_exists(handle, vkeys, 0, 1, 3) || p_face_exists(handle, vkeys, 1, 2, 3)) - return !dir; - } - - return dir; + /* slight bias to prefer one edge over the other in case they are equal, so + * that in symmetric models we choose the same split direction instead of + * depending on floating point errors to decide */ + float bias = 1.0f + 1e-6f; + float fac = len_v3v3(co[0], co[2]) * bias - len_v3v3(co[1], co[3]); + PBool dir = (fac <= 0.0f); + + /* the face exists check is there because of a special case: when + * two quads share three vertices, they can each be split into two + * triangles, resulting in two identical triangles. for example in + * suzanne's nose. */ + if (dir) { + if (p_face_exists(handle, vkeys, 0, 1, 2) || p_face_exists(handle, vkeys, 0, 2, 3)) + return !dir; + } + else { + if (p_face_exists(handle, vkeys, 0, 1, 3) || p_face_exists(handle, vkeys, 1, 2, 3)) + return !dir; + } + + return dir; } /* Construction: boundary filling */ static void p_chart_boundaries(PChart *chart, int *nboundaries, PEdge **outer) { - PEdge *e, *be; - float len, maxlen = -1.0; + PEdge *e, *be; + float len, maxlen = -1.0; - if (nboundaries) - *nboundaries = 0; - if (outer) - *outer = NULL; + if (nboundaries) + *nboundaries = 0; + if (outer) + *outer = NULL; - for (e = chart->edges; e; e = e->nextlink) { - if (e->pair || (e->flag & PEDGE_DONE)) - continue; + for (e = chart->edges; e; e = e->nextlink) { + if (e->pair || (e->flag & PEDGE_DONE)) + continue; - if (nboundaries) - (*nboundaries)++; + if (nboundaries) + (*nboundaries)++; - len = 0.0f; + len = 0.0f; - be = e; - do { - be->flag |= PEDGE_DONE; - len += p_edge_length(be); - be = be->next->vert->edge; - } while (be != e); + be = e; + do { + be->flag |= PEDGE_DONE; + len += p_edge_length(be); + be = be->next->vert->edge; + } while (be != e); - if (outer && (len > maxlen)) { - *outer = e; - maxlen = len; - } - } + if (outer && (len > maxlen)) { + *outer = e; + maxlen = len; + } + } - for (e = chart->edges; e; e = e->nextlink) - e->flag &= ~PEDGE_DONE; + for (e = chart->edges; e; e = e->nextlink) + e->flag &= ~PEDGE_DONE; } static float p_edge_boundary_angle(PEdge *e) { - PEdge *we; - PVert *v, *v1, *v2; - float angle; - int n = 0; + PEdge *we; + PVert *v, *v1, *v2; + float angle; + int n = 0; - v = e->vert; + v = e->vert; - /* concave angle check -- could be better */ - angle = M_PI; + /* concave angle check -- could be better */ + angle = M_PI; - we = v->edge; - do { - v1 = we->next->vert; - v2 = we->next->next->vert; - angle -= p_vec_angle(v1->co, v->co, v2->co); + we = v->edge; + do { + v1 = we->next->vert; + v2 = we->next->next->vert; + angle -= p_vec_angle(v1->co, v->co, v2->co); - we = we->next->next->pair; - n++; - } while (we && (we != v->edge)); + we = we->next->next->pair; + n++; + } while (we && (we != v->edge)); - return angle; + return angle; } static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges) { - PEdge *e, *e1, *e2; + PEdge *e, *e1, *e2; - PFace *f; - struct Heap *heap = BLI_heap_new(); - float angle; + PFace *f; + struct Heap *heap = BLI_heap_new(); + float angle; - e = be; - do { - angle = p_edge_boundary_angle(e); - e->u.heaplink = BLI_heap_insert(heap, angle, e); + e = be; + do { + angle = p_edge_boundary_angle(e); + e->u.heaplink = BLI_heap_insert(heap, angle, e); - e = p_boundary_edge_next(e); - } while (e != be); + e = p_boundary_edge_next(e); + } while (e != be); - if (nedges == 2) { - /* no real boundary, but an isolated seam */ - e = be->next->vert->edge; - e->pair = be; - be->pair = e; + if (nedges == 2) { + /* no real boundary, but an isolated seam */ + e = be->next->vert->edge; + e->pair = be; + be->pair = e; - BLI_heap_remove(heap, e->u.heaplink); - BLI_heap_remove(heap, be->u.heaplink); - } - else { - while (nedges > 2) { - PEdge *ne, *ne1, *ne2; + BLI_heap_remove(heap, e->u.heaplink); + BLI_heap_remove(heap, be->u.heaplink); + } + else { + while (nedges > 2) { + PEdge *ne, *ne1, *ne2; - e = (PEdge *)BLI_heap_pop_min(heap); + e = (PEdge *)BLI_heap_pop_min(heap); - e1 = p_boundary_edge_prev(e); - e2 = p_boundary_edge_next(e); + e1 = p_boundary_edge_prev(e); + e2 = p_boundary_edge_next(e); - BLI_heap_remove(heap, e1->u.heaplink); - BLI_heap_remove(heap, e2->u.heaplink); - e->u.heaplink = e1->u.heaplink = e2->u.heaplink = NULL; + BLI_heap_remove(heap, e1->u.heaplink); + BLI_heap_remove(heap, e2->u.heaplink); + e->u.heaplink = e1->u.heaplink = e2->u.heaplink = NULL; - e->flag |= PEDGE_FILLED; - e1->flag |= PEDGE_FILLED; + e->flag |= PEDGE_FILLED; + e1->flag |= PEDGE_FILLED; - f = p_face_add_fill(chart, e->vert, e1->vert, e2->vert); - f->flag |= PFACE_FILLED; + f = p_face_add_fill(chart, e->vert, e1->vert, e2->vert); + f->flag |= PFACE_FILLED; - ne = f->edge->next->next; - ne1 = f->edge; - ne2 = f->edge->next; + ne = f->edge->next->next; + ne1 = f->edge; + ne2 = f->edge->next; - ne->flag = ne1->flag = ne2->flag = PEDGE_FILLED; + ne->flag = ne1->flag = ne2->flag = PEDGE_FILLED; - e->pair = ne; - ne->pair = e; - e1->pair = ne1; - ne1->pair = e1; + e->pair = ne; + ne->pair = e; + e1->pair = ne1; + ne1->pair = e1; - ne->vert = e2->vert; - ne1->vert = e->vert; - ne2->vert = e1->vert; + ne->vert = e2->vert; + ne1->vert = e->vert; + ne2->vert = e1->vert; - if (nedges == 3) { - e2->pair = ne2; - ne2->pair = e2; - } - else { - ne2->vert->edge = ne2; + if (nedges == 3) { + e2->pair = ne2; + ne2->pair = e2; + } + else { + ne2->vert->edge = ne2; - ne2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(ne2), ne2); - e2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(e2), e2); - } + ne2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(ne2), ne2); + e2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(e2), e2); + } - nedges--; - } - } + nedges--; + } + } - BLI_heap_free(heap, NULL); + BLI_heap_free(heap, NULL); } static void p_chart_fill_boundaries(PChart *chart, PEdge *outer) { - PEdge *e, *be; /* *enext - as yet unused */ - int nedges; + PEdge *e, *be; /* *enext - as yet unused */ + int nedges; - for (e = chart->edges; e; e = e->nextlink) { - /* enext = e->nextlink; - as yet unused */ + for (e = chart->edges; e; e = e->nextlink) { + /* enext = e->nextlink; - as yet unused */ - if (e->pair || (e->flag & PEDGE_FILLED)) - continue; + if (e->pair || (e->flag & PEDGE_FILLED)) + continue; - nedges = 0; - be = e; - do { - be->flag |= PEDGE_FILLED; - be = be->next->vert->edge; - nedges++; - } while (be != e); + nedges = 0; + be = e; + do { + be->flag |= PEDGE_FILLED; + be = be->next->vert->edge; + nedges++; + } while (be != e); - if (e != outer) - p_chart_fill_boundary(chart, e, nedges); - } + if (e != outer) + p_chart_fill_boundary(chart, e, nedges); + } } #if 0 @@ -1369,116 +1385,116 @@ static void p_chart_fill_boundaries(PChart *chart, PEdge *outer) static int p_polygon_point_in(float *cp1, float *cp2, float *p) { - if ((cp1[0] == p[0]) && (cp1[1] == p[1])) - return 2; - else if ((cp2[0] == p[0]) && (cp2[1] == p[1])) - return 3; - else - return (p_area_signed(cp1, cp2, p) >= 0.0f); + if ((cp1[0] == p[0]) && (cp1[1] == p[1])) + return 2; + else if ((cp2[0] == p[0]) && (cp2[1] == p[1])) + return 3; + else + return (p_area_signed(cp1, cp2, p) >= 0.0f); } static void p_polygon_kernel_clip(float (*oldpoints)[2], int noldpoints, float (*newpoints)[2], int *nnewpoints, float *cp1, float *cp2) { - float *p2, *p1, isect[2]; - int i, p2in, p1in; - - p1 = oldpoints[noldpoints - 1]; - p1in = p_polygon_point_in(cp1, cp2, p1); - *nnewpoints = 0; - - for (i = 0; i < noldpoints; i++) { - p2 = oldpoints[i]; - p2in = p_polygon_point_in(cp1, cp2, p2); - - if ((p2in >= 2) || (p1in && p2in)) { - newpoints[*nnewpoints][0] = p2[0]; - newpoints[*nnewpoints][1] = p2[1]; - (*nnewpoints)++; - } - else if (p1in && !p2in) { - if (p1in != 3) { - p_intersect_line_2d(p1, p2, cp1, cp2, isect); - newpoints[*nnewpoints][0] = isect[0]; - newpoints[*nnewpoints][1] = isect[1]; - (*nnewpoints)++; - } - } - else if (!p1in && p2in) { - p_intersect_line_2d(p1, p2, cp1, cp2, isect); - newpoints[*nnewpoints][0] = isect[0]; - newpoints[*nnewpoints][1] = isect[1]; - (*nnewpoints)++; - - newpoints[*nnewpoints][0] = p2[0]; - newpoints[*nnewpoints][1] = p2[1]; - (*nnewpoints)++; - } - - p1in = p2in; - p1 = p2; - } + float *p2, *p1, isect[2]; + int i, p2in, p1in; + + p1 = oldpoints[noldpoints - 1]; + p1in = p_polygon_point_in(cp1, cp2, p1); + *nnewpoints = 0; + + for (i = 0; i < noldpoints; i++) { + p2 = oldpoints[i]; + p2in = p_polygon_point_in(cp1, cp2, p2); + + if ((p2in >= 2) || (p1in && p2in)) { + newpoints[*nnewpoints][0] = p2[0]; + newpoints[*nnewpoints][1] = p2[1]; + (*nnewpoints)++; + } + else if (p1in && !p2in) { + if (p1in != 3) { + p_intersect_line_2d(p1, p2, cp1, cp2, isect); + newpoints[*nnewpoints][0] = isect[0]; + newpoints[*nnewpoints][1] = isect[1]; + (*nnewpoints)++; + } + } + else if (!p1in && p2in) { + p_intersect_line_2d(p1, p2, cp1, cp2, isect); + newpoints[*nnewpoints][0] = isect[0]; + newpoints[*nnewpoints][1] = isect[1]; + (*nnewpoints)++; + + newpoints[*nnewpoints][0] = p2[0]; + newpoints[*nnewpoints][1] = p2[1]; + (*nnewpoints)++; + } + + p1in = p2in; + p1 = p2; + } } static void p_polygon_kernel_center(float (*points)[2], int npoints, float *center) { - int i, size, nnewpoints = npoints; - float (*oldpoints)[2], (*newpoints)[2], *p1, *p2; - - size = npoints * 3; - oldpoints = MEM_mallocN(sizeof(float) * 2 * size, "PPolygonOldPoints"); - newpoints = MEM_mallocN(sizeof(float) * 2 * size, "PPolygonNewPoints"); - - memcpy(oldpoints, points, sizeof(float) * 2 * npoints); - - for (i = 0; i < npoints; i++) { - p1 = points[i]; - p2 = points[(i + 1) % npoints]; - p_polygon_kernel_clip(oldpoints, nnewpoints, newpoints, &nnewpoints, p1, p2); - - if (nnewpoints == 0) { - /* degenerate case, use center of original polygon */ - memcpy(oldpoints, points, sizeof(float) * 2 * npoints); - nnewpoints = npoints; - break; - } - else if (nnewpoints == 1) { - /* degenerate case, use remaining point */ - center[0] = newpoints[0][0]; - center[1] = newpoints[0][1]; - - MEM_freeN(oldpoints); - MEM_freeN(newpoints); - - return; - } - - if (nnewpoints * 2 > size) { - size *= 2; - MEM_freeN(oldpoints); - oldpoints = MEM_mallocN(sizeof(float) * 2 * size, "oldpoints"); - memcpy(oldpoints, newpoints, sizeof(float) * 2 * nnewpoints); - MEM_freeN(newpoints); - newpoints = MEM_mallocN(sizeof(float) * 2 * size, "newpoints"); - } - else { - float (*sw_points)[2] = oldpoints; - oldpoints = newpoints; - newpoints = sw_points; - } - } - - center[0] = center[1] = 0.0f; - - for (i = 0; i < nnewpoints; i++) { - center[0] += oldpoints[i][0]; - center[1] += oldpoints[i][1]; - } - - center[0] /= nnewpoints; - center[1] /= nnewpoints; - - MEM_freeN(oldpoints); - MEM_freeN(newpoints); + int i, size, nnewpoints = npoints; + float (*oldpoints)[2], (*newpoints)[2], *p1, *p2; + + size = npoints * 3; + oldpoints = MEM_mallocN(sizeof(float) * 2 * size, "PPolygonOldPoints"); + newpoints = MEM_mallocN(sizeof(float) * 2 * size, "PPolygonNewPoints"); + + memcpy(oldpoints, points, sizeof(float) * 2 * npoints); + + for (i = 0; i < npoints; i++) { + p1 = points[i]; + p2 = points[(i + 1) % npoints]; + p_polygon_kernel_clip(oldpoints, nnewpoints, newpoints, &nnewpoints, p1, p2); + + if (nnewpoints == 0) { + /* degenerate case, use center of original polygon */ + memcpy(oldpoints, points, sizeof(float) * 2 * npoints); + nnewpoints = npoints; + break; + } + else if (nnewpoints == 1) { + /* degenerate case, use remaining point */ + center[0] = newpoints[0][0]; + center[1] = newpoints[0][1]; + + MEM_freeN(oldpoints); + MEM_freeN(newpoints); + + return; + } + + if (nnewpoints * 2 > size) { + size *= 2; + MEM_freeN(oldpoints); + oldpoints = MEM_mallocN(sizeof(float) * 2 * size, "oldpoints"); + memcpy(oldpoints, newpoints, sizeof(float) * 2 * nnewpoints); + MEM_freeN(newpoints); + newpoints = MEM_mallocN(sizeof(float) * 2 * size, "newpoints"); + } + else { + float (*sw_points)[2] = oldpoints; + oldpoints = newpoints; + newpoints = sw_points; + } + } + + center[0] = center[1] = 0.0f; + + for (i = 0; i < nnewpoints; i++) { + center[0] += oldpoints[i][0]; + center[1] += oldpoints[i][1]; + } + + center[0] /= nnewpoints; + center[1] /= nnewpoints; + + MEM_freeN(oldpoints); + MEM_freeN(newpoints); } #endif @@ -1490,809 +1506,809 @@ int NCOLLAPSEX = 0; static float p_vert_cotan(float *v1, float *v2, float *v3) { - float a[3], b[3], c[3], clen; + float a[3], b[3], c[3], clen; - sub_v3_v3v3(a, v2, v1); - sub_v3_v3v3(b, v3, v1); - cross_v3_v3v3(c, a, b); + sub_v3_v3v3(a, v2, v1); + sub_v3_v3v3(b, v3, v1); + cross_v3_v3v3(c, a, b); - clen = len_v3(c); + clen = len_v3(c); - if (clen == 0.0f) - return 0.0f; + if (clen == 0.0f) + return 0.0f; - return dot_v3v3(a, b) / clen; + return dot_v3v3(a, b) / clen; } static PBool p_vert_flipped_wheel_triangle(PVert *v) { - PEdge *e = v->edge; + PEdge *e = v->edge; - do { - if (p_face_uv_area_signed(e->face) < 0.0f) - return P_TRUE; + do { + if (p_face_uv_area_signed(e->face) < 0.0f) + return P_TRUE; - e = p_wheel_edge_next(e); - } while (e && (e != v->edge)); + e = p_wheel_edge_next(e); + } while (e && (e != v->edge)); - return P_FALSE; + return P_FALSE; } static PBool p_vert_map_harmonic_weights(PVert *v) { - float weightsum, positionsum[2], olduv[2]; + float weightsum, positionsum[2], olduv[2]; - weightsum = 0.0f; - positionsum[0] = positionsum[1] = 0.0f; + weightsum = 0.0f; + positionsum[0] = positionsum[1] = 0.0f; - if (p_vert_interior(v)) { - PEdge *e = v->edge; + if (p_vert_interior(v)) { + PEdge *e = v->edge; - do { - float t1, t2, weight; - PVert *v1, *v2; + do { + float t1, t2, weight; + PVert *v1, *v2; - v1 = e->next->vert; - v2 = e->next->next->vert; - t1 = p_vert_cotan(v2->co, e->vert->co, v1->co); + v1 = e->next->vert; + v2 = e->next->next->vert; + t1 = p_vert_cotan(v2->co, e->vert->co, v1->co); - v1 = e->pair->next->vert; - v2 = e->pair->next->next->vert; - t2 = p_vert_cotan(v2->co, e->pair->vert->co, v1->co); + v1 = e->pair->next->vert; + v2 = e->pair->next->next->vert; + t2 = p_vert_cotan(v2->co, e->pair->vert->co, v1->co); - weight = 0.5f * (t1 + t2); - weightsum += weight; - positionsum[0] += weight * e->pair->vert->uv[0]; - positionsum[1] += weight * e->pair->vert->uv[1]; + weight = 0.5f * (t1 + t2); + weightsum += weight; + positionsum[0] += weight * e->pair->vert->uv[0]; + positionsum[1] += weight * e->pair->vert->uv[1]; - e = p_wheel_edge_next(e); - } while (e && (e != v->edge)); - } - else { - PEdge *e = v->edge; + e = p_wheel_edge_next(e); + } while (e && (e != v->edge)); + } + else { + PEdge *e = v->edge; - do { - float t1, t2; - PVert *v1, *v2; + do { + float t1, t2; + PVert *v1, *v2; - v2 = e->next->vert; - v1 = e->next->next->vert; + v2 = e->next->vert; + v1 = e->next->next->vert; - t1 = p_vert_cotan(v1->co, v->co, v2->co); - t2 = p_vert_cotan(v2->co, v->co, v1->co); + t1 = p_vert_cotan(v1->co, v->co, v2->co); + t2 = p_vert_cotan(v2->co, v->co, v1->co); - weightsum += t1 + t2; - positionsum[0] += (v2->uv[1] - v1->uv[1]) + (t1 * v2->uv[0] + t2 * v1->uv[0]); - positionsum[1] += (v1->uv[0] - v2->uv[0]) + (t1 * v2->uv[1] + t2 * v1->uv[1]); + weightsum += t1 + t2; + positionsum[0] += (v2->uv[1] - v1->uv[1]) + (t1 * v2->uv[0] + t2 * v1->uv[0]); + positionsum[1] += (v1->uv[0] - v2->uv[0]) + (t1 * v2->uv[1] + t2 * v1->uv[1]); - e = p_wheel_edge_next(e); - } while (e && (e != v->edge)); - } + e = p_wheel_edge_next(e); + } while (e && (e != v->edge)); + } - if (weightsum != 0.0f) { - weightsum = 1.0f / weightsum; - positionsum[0] *= weightsum; - positionsum[1] *= weightsum; - } + if (weightsum != 0.0f) { + weightsum = 1.0f / weightsum; + positionsum[0] *= weightsum; + positionsum[1] *= weightsum; + } - olduv[0] = v->uv[0]; - olduv[1] = v->uv[1]; - v->uv[0] = positionsum[0]; - v->uv[1] = positionsum[1]; + olduv[0] = v->uv[0]; + olduv[1] = v->uv[1]; + v->uv[0] = positionsum[0]; + v->uv[1] = positionsum[1]; - if (p_vert_flipped_wheel_triangle(v)) { - v->uv[0] = olduv[0]; - v->uv[1] = olduv[1]; + if (p_vert_flipped_wheel_triangle(v)) { + v->uv[0] = olduv[0]; + v->uv[1] = olduv[1]; - return P_FALSE; - } + return P_FALSE; + } - return P_TRUE; + return P_TRUE; } static void p_vert_harmonic_insert(PVert *v) { - PEdge *e; + PEdge *e; - if (!p_vert_map_harmonic_weights(v)) { - /* do polygon kernel center insertion: this is quite slow, but should - * only be needed for 0.01 % of verts or so, when insert with harmonic - * weights fails */ + if (!p_vert_map_harmonic_weights(v)) { + /* do polygon kernel center insertion: this is quite slow, but should + * only be needed for 0.01 % of verts or so, when insert with harmonic + * weights fails */ - int npoints = 0, i; - float (*points)[2]; + int npoints = 0, i; + float (*points)[2]; - e = v->edge; - do { - npoints++; - e = p_wheel_edge_next(e); - } while (e && (e != v->edge)); + e = v->edge; + do { + npoints++; + e = p_wheel_edge_next(e); + } while (e && (e != v->edge)); - if (e == NULL) - npoints++; + if (e == NULL) + npoints++; - points = MEM_mallocN(sizeof(float) * 2 * npoints, "PHarmonicPoints"); + points = MEM_mallocN(sizeof(float) * 2 * npoints, "PHarmonicPoints"); - e = v->edge; - i = 0; - do { - PEdge *nexte = p_wheel_edge_next(e); + e = v->edge; + i = 0; + do { + PEdge *nexte = p_wheel_edge_next(e); - points[i][0] = e->next->vert->uv[0]; - points[i][1] = e->next->vert->uv[1]; + points[i][0] = e->next->vert->uv[0]; + points[i][1] = e->next->vert->uv[1]; - if (nexte == NULL) { - i++; - points[i][0] = e->next->next->vert->uv[0]; - points[i][1] = e->next->next->vert->uv[1]; - break; - } + if (nexte == NULL) { + i++; + points[i][0] = e->next->next->vert->uv[0]; + points[i][1] = e->next->next->vert->uv[1]; + break; + } - e = nexte; - i++; - } while (e != v->edge); + e = nexte; + i++; + } while (e != v->edge); - p_polygon_kernel_center(points, npoints, v->uv); + p_polygon_kernel_center(points, npoints, v->uv); - MEM_freeN(points); - } + MEM_freeN(points); + } - e = v->edge; - do { - if (!(e->next->vert->flag & PVERT_PIN)) - p_vert_map_harmonic_weights(e->next->vert); - e = p_wheel_edge_next(e); - } while (e && (e != v->edge)); + e = v->edge; + do { + if (!(e->next->vert->flag & PVERT_PIN)) + p_vert_map_harmonic_weights(e->next->vert); + e = p_wheel_edge_next(e); + } while (e && (e != v->edge)); - p_vert_map_harmonic_weights(v); + p_vert_map_harmonic_weights(v); } static void p_vert_fix_edge_pointer(PVert *v) { - PEdge *start = v->edge; + PEdge *start = v->edge; - /* set v->edge pointer to the edge with no pair, if there is one */ - while (v->edge->pair) { - v->edge = p_wheel_edge_prev(v->edge); + /* set v->edge pointer to the edge with no pair, if there is one */ + while (v->edge->pair) { + v->edge = p_wheel_edge_prev(v->edge); - if (v->edge == start) - break; - } + if (v->edge == start) + break; + } } static void p_collapsing_verts(PEdge *edge, PEdge *pair, PVert **newv, PVert **keepv) { - /* the two vertices that are involved in the collapse */ - if (edge) { - *newv = edge->vert; - *keepv = edge->next->vert; - } - else { - *newv = pair->next->vert; - *keepv = pair->vert; - } + /* the two vertices that are involved in the collapse */ + if (edge) { + *newv = edge->vert; + *keepv = edge->next->vert; + } + else { + *newv = pair->next->vert; + *keepv = pair->vert; + } } static void p_collapse_edge(PEdge *edge, PEdge *pair) { - PVert *oldv, *keepv; - PEdge *e; + PVert *oldv, *keepv; + PEdge *e; - p_collapsing_verts(edge, pair, &oldv, &keepv); + p_collapsing_verts(edge, pair, &oldv, &keepv); - /* change e->vert pointers from old vertex to the target vertex */ - e = oldv->edge; - do { - if ((e != edge) && !(pair && pair->next == e)) - e->vert = keepv; + /* change e->vert pointers from old vertex to the target vertex */ + e = oldv->edge; + do { + if ((e != edge) && !(pair && pair->next == e)) + e->vert = keepv; - e = p_wheel_edge_next(e); - } while (e && (e != oldv->edge)); + e = p_wheel_edge_next(e); + } while (e && (e != oldv->edge)); - /* set keepv->edge pointer */ - if ((edge && (keepv->edge == edge->next)) || (keepv->edge == pair)) { - if (edge && edge->next->pair) - keepv->edge = edge->next->pair->next; - else if (pair && pair->next->next->pair) - keepv->edge = pair->next->next->pair; - else if (edge && edge->next->next->pair) - keepv->edge = edge->next->next->pair; - else - keepv->edge = pair->next->pair->next; - } + /* set keepv->edge pointer */ + if ((edge && (keepv->edge == edge->next)) || (keepv->edge == pair)) { + if (edge && edge->next->pair) + keepv->edge = edge->next->pair->next; + else if (pair && pair->next->next->pair) + keepv->edge = pair->next->next->pair; + else if (edge && edge->next->next->pair) + keepv->edge = edge->next->next->pair; + else + keepv->edge = pair->next->pair->next; + } - /* update pairs and v->edge pointers */ - if (edge) { - PEdge *e1 = edge->next, *e2 = e1->next; + /* update pairs and v->edge pointers */ + if (edge) { + PEdge *e1 = edge->next, *e2 = e1->next; - if (e1->pair) - e1->pair->pair = e2->pair; + if (e1->pair) + e1->pair->pair = e2->pair; - if (e2->pair) { - e2->pair->pair = e1->pair; - e2->vert->edge = p_wheel_edge_prev(e2); - } - else - e2->vert->edge = p_wheel_edge_next(e2); + if (e2->pair) { + e2->pair->pair = e1->pair; + e2->vert->edge = p_wheel_edge_prev(e2); + } + else + e2->vert->edge = p_wheel_edge_next(e2); - p_vert_fix_edge_pointer(e2->vert); - } + p_vert_fix_edge_pointer(e2->vert); + } - if (pair) { - PEdge *e1 = pair->next, *e2 = e1->next; + if (pair) { + PEdge *e1 = pair->next, *e2 = e1->next; - if (e1->pair) - e1->pair->pair = e2->pair; + if (e1->pair) + e1->pair->pair = e2->pair; - if (e2->pair) { - e2->pair->pair = e1->pair; - e2->vert->edge = p_wheel_edge_prev(e2); - } - else - e2->vert->edge = p_wheel_edge_next(e2); + if (e2->pair) { + e2->pair->pair = e1->pair; + e2->vert->edge = p_wheel_edge_prev(e2); + } + else + e2->vert->edge = p_wheel_edge_next(e2); - p_vert_fix_edge_pointer(e2->vert); - } + p_vert_fix_edge_pointer(e2->vert); + } - p_vert_fix_edge_pointer(keepv); + p_vert_fix_edge_pointer(keepv); - /* mark for move to collapsed list later */ - oldv->flag |= PVERT_COLLAPSE; + /* mark for move to collapsed list later */ + oldv->flag |= PVERT_COLLAPSE; - if (edge) { - PFace *f = edge->face; - PEdge *e1 = edge->next, *e2 = e1->next; + if (edge) { + PFace *f = edge->face; + PEdge *e1 = edge->next, *e2 = e1->next; - f->flag |= PFACE_COLLAPSE; - edge->flag |= PEDGE_COLLAPSE; - e1->flag |= PEDGE_COLLAPSE; - e2->flag |= PEDGE_COLLAPSE; - } + f->flag |= PFACE_COLLAPSE; + edge->flag |= PEDGE_COLLAPSE; + e1->flag |= PEDGE_COLLAPSE; + e2->flag |= PEDGE_COLLAPSE; + } - if (pair) { - PFace *f = pair->face; - PEdge *e1 = pair->next, *e2 = e1->next; + if (pair) { + PFace *f = pair->face; + PEdge *e1 = pair->next, *e2 = e1->next; - f->flag |= PFACE_COLLAPSE; - pair->flag |= PEDGE_COLLAPSE; - e1->flag |= PEDGE_COLLAPSE; - e2->flag |= PEDGE_COLLAPSE; - } + f->flag |= PFACE_COLLAPSE; + pair->flag |= PEDGE_COLLAPSE; + e1->flag |= PEDGE_COLLAPSE; + e2->flag |= PEDGE_COLLAPSE; + } } static void p_split_vertex(PEdge *edge, PEdge *pair) { - PVert *newv, *keepv; - PEdge *e; + PVert *newv, *keepv; + PEdge *e; - p_collapsing_verts(edge, pair, &newv, &keepv); + p_collapsing_verts(edge, pair, &newv, &keepv); - /* update edge pairs */ - if (edge) { - PEdge *e1 = edge->next, *e2 = e1->next; + /* update edge pairs */ + if (edge) { + PEdge *e1 = edge->next, *e2 = e1->next; - if (e1->pair) - e1->pair->pair = e1; - if (e2->pair) - e2->pair->pair = e2; + if (e1->pair) + e1->pair->pair = e1; + if (e2->pair) + e2->pair->pair = e2; - e2->vert->edge = e2; - p_vert_fix_edge_pointer(e2->vert); - keepv->edge = e1; - } + e2->vert->edge = e2; + p_vert_fix_edge_pointer(e2->vert); + keepv->edge = e1; + } - if (pair) { - PEdge *e1 = pair->next, *e2 = e1->next; + if (pair) { + PEdge *e1 = pair->next, *e2 = e1->next; - if (e1->pair) - e1->pair->pair = e1; - if (e2->pair) - e2->pair->pair = e2; + if (e1->pair) + e1->pair->pair = e1; + if (e2->pair) + e2->pair->pair = e2; - e2->vert->edge = e2; - p_vert_fix_edge_pointer(e2->vert); - keepv->edge = pair; - } + e2->vert->edge = e2; + p_vert_fix_edge_pointer(e2->vert); + keepv->edge = pair; + } - p_vert_fix_edge_pointer(keepv); + p_vert_fix_edge_pointer(keepv); - /* set e->vert pointers to restored vertex */ - e = newv->edge; - do { - e->vert = newv; - e = p_wheel_edge_next(e); - } while (e && (e != newv->edge)); + /* set e->vert pointers to restored vertex */ + e = newv->edge; + do { + e->vert = newv; + e = p_wheel_edge_next(e); + } while (e && (e != newv->edge)); } static PBool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair) { - PVert *oldv, *keepv; + PVert *oldv, *keepv; - p_collapsing_verts(edge, pair, &oldv, &keepv); + p_collapsing_verts(edge, pair, &oldv, &keepv); - /* boundary edges */ - if (!edge || !pair) { - /* avoid collapsing chart into an edge */ - if (edge && !edge->next->pair && !edge->next->next->pair) - return P_FALSE; - else if (pair && !pair->next->pair && !pair->next->next->pair) - return P_FALSE; - } - /* avoid merging two boundaries (oldv and keepv are on the 'other side' of - * the chart) */ - else if (!p_vert_interior(oldv) && !p_vert_interior(keepv)) - return P_FALSE; + /* boundary edges */ + if (!edge || !pair) { + /* avoid collapsing chart into an edge */ + if (edge && !edge->next->pair && !edge->next->next->pair) + return P_FALSE; + else if (pair && !pair->next->pair && !pair->next->next->pair) + return P_FALSE; + } + /* avoid merging two boundaries (oldv and keepv are on the 'other side' of + * the chart) */ + else if (!p_vert_interior(oldv) && !p_vert_interior(keepv)) + return P_FALSE; - return P_TRUE; + return P_TRUE; } static PBool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float *vnew) { - float nold[3], nnew[3], sub1[3], sub2[3]; + float nold[3], nnew[3], sub1[3], sub2[3]; - sub_v3_v3v3(sub1, vold, v1); - sub_v3_v3v3(sub2, vold, v2); - cross_v3_v3v3(nold, sub1, sub2); + sub_v3_v3v3(sub1, vold, v1); + sub_v3_v3v3(sub2, vold, v2); + cross_v3_v3v3(nold, sub1, sub2); - sub_v3_v3v3(sub1, vnew, v1); - sub_v3_v3v3(sub2, vnew, v2); - cross_v3_v3v3(nnew, sub1, sub2); + sub_v3_v3v3(sub1, vnew, v1); + sub_v3_v3v3(sub2, vnew, v2); + cross_v3_v3v3(nnew, sub1, sub2); - return (dot_v3v3(nold, nnew) <= 0.0f); + return (dot_v3v3(nold, nnew) <= 0.0f); } static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair) { - PVert *oldv, *keepv; - PEdge *e; - float angulardefect, angle; + PVert *oldv, *keepv; + PEdge *e; + float angulardefect, angle; - p_collapsing_verts(edge, pair, &oldv, &keepv); + p_collapsing_verts(edge, pair, &oldv, &keepv); - angulardefect = 2 * M_PI; + angulardefect = 2 * M_PI; - e = oldv->edge; - do { - float a[3], b[3], minangle, maxangle; - PEdge *e1 = e->next, *e2 = e1->next; - PVert *v1 = e1->vert, *v2 = e2->vert; - int i; + e = oldv->edge; + do { + float a[3], b[3], minangle, maxangle; + PEdge *e1 = e->next, *e2 = e1->next; + PVert *v1 = e1->vert, *v2 = e2->vert; + int i; - angle = p_vec_angle(v1->co, oldv->co, v2->co); - angulardefect -= angle; + angle = p_vec_angle(v1->co, oldv->co, v2->co); + angulardefect -= angle; - /* skip collapsing faces */ - if (v1 == keepv || v2 == keepv) { - e = p_wheel_edge_next(e); - continue; - } + /* skip collapsing faces */ + if (v1 == keepv || v2 == keepv) { + e = p_wheel_edge_next(e); + continue; + } - if (p_collapse_normal_flipped(v1->co, v2->co, oldv->co, keepv->co)) - return P_FALSE; + if (p_collapse_normal_flipped(v1->co, v2->co, oldv->co, keepv->co)) + return P_FALSE; - a[0] = angle; - a[1] = p_vec_angle(v2->co, v1->co, oldv->co); - a[2] = M_PI - a[0] - a[1]; + a[0] = angle; + a[1] = p_vec_angle(v2->co, v1->co, oldv->co); + a[2] = M_PI - a[0] - a[1]; - b[0] = p_vec_angle(v1->co, keepv->co, v2->co); - b[1] = p_vec_angle(v2->co, v1->co, keepv->co); - b[2] = M_PI - b[0] - b[1]; + b[0] = p_vec_angle(v1->co, keepv->co, v2->co); + b[1] = p_vec_angle(v2->co, v1->co, keepv->co); + b[2] = M_PI - b[0] - b[1]; - /* abf criterion 1: avoid sharp and obtuse angles */ - minangle = 15.0f * M_PI / 180.0f; - maxangle = M_PI - minangle; + /* abf criterion 1: avoid sharp and obtuse angles */ + minangle = 15.0f * M_PI / 180.0f; + maxangle = M_PI - minangle; - for (i = 0; i < 3; i++) { - if ((b[i] < a[i]) && (b[i] < minangle)) - return P_FALSE; - else if ((b[i] > a[i]) && (b[i] > maxangle)) - return P_FALSE; - } + for (i = 0; i < 3; i++) { + if ((b[i] < a[i]) && (b[i] < minangle)) + return P_FALSE; + else if ((b[i] > a[i]) && (b[i] > maxangle)) + return P_FALSE; + } - e = p_wheel_edge_next(e); - } while (e && (e != oldv->edge)); + e = p_wheel_edge_next(e); + } while (e && (e != oldv->edge)); - if (p_vert_interior(oldv)) { - /* hlscm criterion: angular defect smaller than threshold */ - if (fabsf(angulardefect) > (float)(M_PI * 30.0 / 180.0)) - return P_FALSE; - } - else { - PVert *v1 = p_boundary_edge_next(oldv->edge)->vert; - PVert *v2 = p_boundary_edge_prev(oldv->edge)->vert; + if (p_vert_interior(oldv)) { + /* hlscm criterion: angular defect smaller than threshold */ + if (fabsf(angulardefect) > (float)(M_PI * 30.0 / 180.0)) + return P_FALSE; + } + else { + PVert *v1 = p_boundary_edge_next(oldv->edge)->vert; + PVert *v2 = p_boundary_edge_prev(oldv->edge)->vert; - /* abf++ criterion 2: avoid collapsing verts inwards */ - if (p_vert_interior(keepv)) - return P_FALSE; + /* abf++ criterion 2: avoid collapsing verts inwards */ + if (p_vert_interior(keepv)) + return P_FALSE; - /* don't collapse significant boundary changes */ - angle = p_vec_angle(v1->co, oldv->co, v2->co); - if (angle < (M_PI * 160.0 / 180.0)) - return P_FALSE; - } + /* don't collapse significant boundary changes */ + angle = p_vec_angle(v1->co, oldv->co, v2->co); + if (angle < (M_PI * 160.0 / 180.0)) + return P_FALSE; + } - return P_TRUE; + return P_TRUE; } static PBool p_collapse_allowed(PEdge *edge, PEdge *pair) { - PVert *oldv, *keepv; + PVert *oldv, *keepv; - p_collapsing_verts(edge, pair, &oldv, &keepv); + p_collapsing_verts(edge, pair, &oldv, &keepv); - if (oldv->flag & PVERT_PIN) - return P_FALSE; + if (oldv->flag & PVERT_PIN) + return P_FALSE; - return (p_collapse_allowed_topologic(edge, pair) && - p_collapse_allowed_geometric(edge, pair)); + return (p_collapse_allowed_topologic(edge, pair) && + p_collapse_allowed_geometric(edge, pair)); } static float p_collapse_cost(PEdge *edge, PEdge *pair) { - /* based on volume and boundary optimization from: - * "Fast and Memory Efficient Polygonal Simplification" P. Lindstrom, G. Turk */ + /* based on volume and boundary optimization from: + * "Fast and Memory Efficient Polygonal Simplification" P. Lindstrom, G. Turk */ - PVert *oldv, *keepv; - PEdge *e; - PFace *oldf1, *oldf2; - float volumecost = 0.0f, areacost = 0.0f, edgevec[3], cost, weight, elen; - float shapecost = 0.0f; - float shapeold = 0.0f, shapenew = 0.0f; - int nshapeold = 0, nshapenew = 0; + PVert *oldv, *keepv; + PEdge *e; + PFace *oldf1, *oldf2; + float volumecost = 0.0f, areacost = 0.0f, edgevec[3], cost, weight, elen; + float shapecost = 0.0f; + float shapeold = 0.0f, shapenew = 0.0f; + int nshapeold = 0, nshapenew = 0; - p_collapsing_verts(edge, pair, &oldv, &keepv); - oldf1 = (edge) ? edge->face : NULL; - oldf2 = (pair) ? pair->face : NULL; + p_collapsing_verts(edge, pair, &oldv, &keepv); + oldf1 = (edge) ? edge->face : NULL; + oldf2 = (pair) ? pair->face : NULL; - sub_v3_v3v3(edgevec, keepv->co, oldv->co); + sub_v3_v3v3(edgevec, keepv->co, oldv->co); - e = oldv->edge; - do { - float a1, a2, a3; - float *co1 = e->next->vert->co; - float *co2 = e->next->next->vert->co; + e = oldv->edge; + do { + float a1, a2, a3; + float *co1 = e->next->vert->co; + float *co2 = e->next->next->vert->co; - if ((e->face != oldf1) && (e->face != oldf2)) { - float tetrav2[3], tetrav3[3], c[3]; + if ((e->face != oldf1) && (e->face != oldf2)) { + float tetrav2[3], tetrav3[3], c[3]; - /* tetrahedron volume = (1/3!)*|a.(b x c)| */ - sub_v3_v3v3(tetrav2, co1, oldv->co); - sub_v3_v3v3(tetrav3, co2, oldv->co); - cross_v3_v3v3(c, tetrav2, tetrav3); + /* tetrahedron volume = (1/3!)*|a.(b x c)| */ + sub_v3_v3v3(tetrav2, co1, oldv->co); + sub_v3_v3v3(tetrav3, co2, oldv->co); + cross_v3_v3v3(c, tetrav2, tetrav3); - volumecost += fabsf(dot_v3v3(edgevec, c) / 6.0f); -#if 0 - shapecost += dot_v3v3(co1, keepv->co); + volumecost += fabsf(dot_v3v3(edgevec, c) / 6.0f); +# if 0 + shapecost += dot_v3v3(co1, keepv->co); - if (p_wheel_edge_next(e) == NULL) - shapecost += dot_v3v3(co2, keepv->co); -#endif + if (p_wheel_edge_next(e) == NULL) + shapecost += dot_v3v3(co2, keepv->co); +# endif - p_triangle_angles(oldv->co, co1, co2, &a1, &a2, &a3); - a1 = a1 - M_PI / 3.0; - a2 = a2 - M_PI / 3.0; - a3 = a3 - M_PI / 3.0; - shapeold = (a1 * a1 + a2 * a2 + a3 * a3) / ((M_PI / 2) * (M_PI / 2)); - - nshapeold++; - } - else { - p_triangle_angles(keepv->co, co1, co2, &a1, &a2, &a3); - a1 = a1 - M_PI / 3.0; - a2 = a2 - M_PI / 3.0; - a3 = a3 - M_PI / 3.0; - shapenew = (a1 * a1 + a2 * a2 + a3 * a3) / ((M_PI / 2) * (M_PI / 2)); - - nshapenew++; - } - - e = p_wheel_edge_next(e); - } while (e && (e != oldv->edge)); - - if (!p_vert_interior(oldv)) { - PVert *v1 = p_boundary_edge_prev(oldv->edge)->vert; - PVert *v2 = p_boundary_edge_next(oldv->edge)->vert; - - areacost = area_tri_v3(oldv->co, v1->co, v2->co); - } - - elen = len_v3(edgevec); - weight = 1.0f; /* 0.2f */ - cost = weight * volumecost * volumecost + elen * elen * areacost * areacost; -#if 0 - cost += shapecost; -#else - shapeold /= nshapeold; - shapenew /= nshapenew; - shapecost = (shapeold + 0.00001) / (shapenew + 0.00001); + p_triangle_angles(oldv->co, co1, co2, &a1, &a2, &a3); + a1 = a1 - M_PI / 3.0; + a2 = a2 - M_PI / 3.0; + a3 = a3 - M_PI / 3.0; + shapeold = (a1 * a1 + a2 * a2 + a3 * a3) / ((M_PI / 2) * (M_PI / 2)); + + nshapeold++; + } + else { + p_triangle_angles(keepv->co, co1, co2, &a1, &a2, &a3); + a1 = a1 - M_PI / 3.0; + a2 = a2 - M_PI / 3.0; + a3 = a3 - M_PI / 3.0; + shapenew = (a1 * a1 + a2 * a2 + a3 * a3) / ((M_PI / 2) * (M_PI / 2)); + + nshapenew++; + } + + e = p_wheel_edge_next(e); + } while (e && (e != oldv->edge)); + + if (!p_vert_interior(oldv)) { + PVert *v1 = p_boundary_edge_prev(oldv->edge)->vert; + PVert *v2 = p_boundary_edge_next(oldv->edge)->vert; + + areacost = area_tri_v3(oldv->co, v1->co, v2->co); + } + + elen = len_v3(edgevec); + weight = 1.0f; /* 0.2f */ + cost = weight * volumecost * volumecost + elen * elen * areacost * areacost; +# if 0 + cost += shapecost; +# else + shapeold /= nshapeold; + shapenew /= nshapenew; + shapecost = (shapeold + 0.00001) / (shapenew + 0.00001); - cost *= shapecost; -#endif + cost *= shapecost; +# endif - return cost; + return cost; } static void p_collapse_cost_vertex(PVert *vert, float *mincost, PEdge **mine) { - PEdge *e, *enext, *pair; + PEdge *e, *enext, *pair; - *mine = NULL; - *mincost = 0.0f; - e = vert->edge; - do { - if (p_collapse_allowed(e, e->pair)) { - float cost = p_collapse_cost(e, e->pair); + *mine = NULL; + *mincost = 0.0f; + e = vert->edge; + do { + if (p_collapse_allowed(e, e->pair)) { + float cost = p_collapse_cost(e, e->pair); - if ((*mine == NULL) || (cost < *mincost)) { - *mincost = cost; - *mine = e; - } - } + if ((*mine == NULL) || (cost < *mincost)) { + *mincost = cost; + *mine = e; + } + } - enext = p_wheel_edge_next(e); + enext = p_wheel_edge_next(e); - if (enext == NULL) { - /* the other boundary edge, where we only have the pair halfedge */ - pair = e->next->next; + if (enext == NULL) { + /* the other boundary edge, where we only have the pair halfedge */ + pair = e->next->next; - if (p_collapse_allowed(NULL, pair)) { - float cost = p_collapse_cost(NULL, pair); + if (p_collapse_allowed(NULL, pair)) { + float cost = p_collapse_cost(NULL, pair); - if ((*mine == NULL) || (cost < *mincost)) { - *mincost = cost; - *mine = pair; - } - } + if ((*mine == NULL) || (cost < *mincost)) { + *mincost = cost; + *mine = pair; + } + } - break; - } + break; + } - e = enext; - } while (e != vert->edge); + e = enext; + } while (e != vert->edge); } static void p_chart_post_collapse_flush(PChart *chart, PEdge *collapsed) { - /* move to collapsed_ */ - - PVert *v, *nextv = NULL, *verts = chart->verts; - PEdge *e, *nexte = NULL, *edges = chart->edges, *laste = NULL; - PFace *f, *nextf = NULL, *faces = chart->faces; - - chart->verts = chart->collapsed_verts = NULL; - chart->edges = chart->collapsed_edges = NULL; - chart->faces = chart->collapsed_faces = NULL; - - chart->nverts = chart->nedges = chart->nfaces = 0; - - for (v = verts; v; v = nextv) { - nextv = v->nextlink; - - if (v->flag & PVERT_COLLAPSE) { - v->nextlink = chart->collapsed_verts; - chart->collapsed_verts = v; - } - else { - v->nextlink = chart->verts; - chart->verts = v; - chart->nverts++; - } - } - - for (e = edges; e; e = nexte) { - nexte = e->nextlink; - - if (!collapsed || !(e->flag & PEDGE_COLLAPSE_EDGE)) { - if (e->flag & PEDGE_COLLAPSE) { - e->nextlink = chart->collapsed_edges; - chart->collapsed_edges = e; - } - else { - e->nextlink = chart->edges; - chart->edges = e; - chart->nedges++; - } - } - } - - /* these are added last so they can be popped of in the right order - * for splitting */ - for (e = collapsed; e; e = e->nextlink) { - e->nextlink = e->u.nextcollapse; - laste = e; - } - if (laste) { - laste->nextlink = chart->collapsed_edges; - chart->collapsed_edges = collapsed; - } - - for (f = faces; f; f = nextf) { - nextf = f->nextlink; - - if (f->flag & PFACE_COLLAPSE) { - f->nextlink = chart->collapsed_faces; - chart->collapsed_faces = f; - } - else { - f->nextlink = chart->faces; - chart->faces = f; - chart->nfaces++; - } - } + /* move to collapsed_ */ + + PVert *v, *nextv = NULL, *verts = chart->verts; + PEdge *e, *nexte = NULL, *edges = chart->edges, *laste = NULL; + PFace *f, *nextf = NULL, *faces = chart->faces; + + chart->verts = chart->collapsed_verts = NULL; + chart->edges = chart->collapsed_edges = NULL; + chart->faces = chart->collapsed_faces = NULL; + + chart->nverts = chart->nedges = chart->nfaces = 0; + + for (v = verts; v; v = nextv) { + nextv = v->nextlink; + + if (v->flag & PVERT_COLLAPSE) { + v->nextlink = chart->collapsed_verts; + chart->collapsed_verts = v; + } + else { + v->nextlink = chart->verts; + chart->verts = v; + chart->nverts++; + } + } + + for (e = edges; e; e = nexte) { + nexte = e->nextlink; + + if (!collapsed || !(e->flag & PEDGE_COLLAPSE_EDGE)) { + if (e->flag & PEDGE_COLLAPSE) { + e->nextlink = chart->collapsed_edges; + chart->collapsed_edges = e; + } + else { + e->nextlink = chart->edges; + chart->edges = e; + chart->nedges++; + } + } + } + + /* these are added last so they can be popped of in the right order + * for splitting */ + for (e = collapsed; e; e = e->nextlink) { + e->nextlink = e->u.nextcollapse; + laste = e; + } + if (laste) { + laste->nextlink = chart->collapsed_edges; + chart->collapsed_edges = collapsed; + } + + for (f = faces; f; f = nextf) { + nextf = f->nextlink; + + if (f->flag & PFACE_COLLAPSE) { + f->nextlink = chart->collapsed_faces; + chart->collapsed_faces = f; + } + else { + f->nextlink = chart->faces; + chart->faces = f; + chart->nfaces++; + } + } } static void p_chart_post_split_flush(PChart *chart) { - /* move from collapsed_ */ + /* move from collapsed_ */ - PVert *v, *nextv = NULL; - PEdge *e, *nexte = NULL; - PFace *f, *nextf = NULL; + PVert *v, *nextv = NULL; + PEdge *e, *nexte = NULL; + PFace *f, *nextf = NULL; - for (v = chart->collapsed_verts; v; v = nextv) { - nextv = v->nextlink; - v->nextlink = chart->verts; - chart->verts = v; - chart->nverts++; - } + for (v = chart->collapsed_verts; v; v = nextv) { + nextv = v->nextlink; + v->nextlink = chart->verts; + chart->verts = v; + chart->nverts++; + } - for (e = chart->collapsed_edges; e; e = nexte) { - nexte = e->nextlink; - e->nextlink = chart->edges; - chart->edges = e; - chart->nedges++; - } + for (e = chart->collapsed_edges; e; e = nexte) { + nexte = e->nextlink; + e->nextlink = chart->edges; + chart->edges = e; + chart->nedges++; + } - for (f = chart->collapsed_faces; f; f = nextf) { - nextf = f->nextlink; - f->nextlink = chart->faces; - chart->faces = f; - chart->nfaces++; - } + for (f = chart->collapsed_faces; f; f = nextf) { + nextf = f->nextlink; + f->nextlink = chart->faces; + chart->faces = f; + chart->nfaces++; + } - chart->collapsed_verts = NULL; - chart->collapsed_edges = NULL; - chart->collapsed_faces = NULL; + chart->collapsed_verts = NULL; + chart->collapsed_edges = NULL; + chart->collapsed_faces = NULL; } static void p_chart_simplify_compute(PChart *chart) { - /* Computes a list of edge collapses / vertex splits. The collapsed - * simplices go in the chart->collapsed_* lists, The original and - * collapsed may then be view as stacks, where the next collapse/split - * is at the top of the respective lists. */ + /* Computes a list of edge collapses / vertex splits. The collapsed + * simplices go in the chart->collapsed_* lists, The original and + * collapsed may then be view as stacks, where the next collapse/split + * is at the top of the respective lists. */ - Heap *heap = BLI_heap_new(); - PVert *v, **wheelverts; - PEdge *collapsededges = NULL, *e; - int nwheelverts, i, ncollapsed = 0; + Heap *heap = BLI_heap_new(); + PVert *v, **wheelverts; + PEdge *collapsededges = NULL, *e; + int nwheelverts, i, ncollapsed = 0; - wheelverts = MEM_mallocN(sizeof(PVert *) * chart->nverts, "PChartWheelVerts"); + wheelverts = MEM_mallocN(sizeof(PVert *) * chart->nverts, "PChartWheelVerts"); - /* insert all potential collapses into heap */ - for (v = chart->verts; v; v = v->nextlink) { - float cost; - PEdge *e = NULL; + /* insert all potential collapses into heap */ + for (v = chart->verts; v; v = v->nextlink) { + float cost; + PEdge *e = NULL; - p_collapse_cost_vertex(v, &cost, &e); + p_collapse_cost_vertex(v, &cost, &e); - if (e) - v->u.heaplink = BLI_heap_insert(heap, cost, e); - else - v->u.heaplink = NULL; - } + if (e) + v->u.heaplink = BLI_heap_insert(heap, cost, e); + else + v->u.heaplink = NULL; + } - for (e = chart->edges; e; e = e->nextlink) - e->u.nextcollapse = NULL; + for (e = chart->edges; e; e = e->nextlink) + e->u.nextcollapse = NULL; - /* pop edge collapse out of heap one by one */ - while (!BLI_heap_is_empty(heap)) { - if (ncollapsed == NCOLLAPSE) - break; + /* pop edge collapse out of heap one by one */ + while (!BLI_heap_is_empty(heap)) { + if (ncollapsed == NCOLLAPSE) + break; - HeapNode *link = BLI_heap_top(heap); - PEdge *edge = (PEdge *)BLI_heap_pop_min(heap), *pair = edge->pair; - PVert *oldv, *keepv; - PEdge *wheele, *nexte; + HeapNode *link = BLI_heap_top(heap); + PEdge *edge = (PEdge *)BLI_heap_pop_min(heap), *pair = edge->pair; + PVert *oldv, *keepv; + PEdge *wheele, *nexte; - /* remember the edges we collapsed */ - edge->u.nextcollapse = collapsededges; - collapsededges = edge; + /* remember the edges we collapsed */ + edge->u.nextcollapse = collapsededges; + collapsededges = edge; - if (edge->vert->u.heaplink != link) { - edge->flag |= (PEDGE_COLLAPSE_EDGE | PEDGE_COLLAPSE_PAIR); - edge->next->vert->u.heaplink = NULL; - SWAP(PEdge *, edge, pair); - } - else { - edge->flag |= PEDGE_COLLAPSE_EDGE; - edge->vert->u.heaplink = NULL; - } + if (edge->vert->u.heaplink != link) { + edge->flag |= (PEDGE_COLLAPSE_EDGE | PEDGE_COLLAPSE_PAIR); + edge->next->vert->u.heaplink = NULL; + SWAP(PEdge *, edge, pair); + } + else { + edge->flag |= PEDGE_COLLAPSE_EDGE; + edge->vert->u.heaplink = NULL; + } - p_collapsing_verts(edge, pair, &oldv, &keepv); + p_collapsing_verts(edge, pair, &oldv, &keepv); - /* gather all wheel verts and remember them before collapse */ - nwheelverts = 0; - wheele = oldv->edge; + /* gather all wheel verts and remember them before collapse */ + nwheelverts = 0; + wheele = oldv->edge; - do { - wheelverts[nwheelverts++] = wheele->next->vert; - nexte = p_wheel_edge_next(wheele); + do { + wheelverts[nwheelverts++] = wheele->next->vert; + nexte = p_wheel_edge_next(wheele); - if (nexte == NULL) - wheelverts[nwheelverts++] = wheele->next->next->vert; + if (nexte == NULL) + wheelverts[nwheelverts++] = wheele->next->next->vert; - wheele = nexte; - } while (wheele && (wheele != oldv->edge)); + wheele = nexte; + } while (wheele && (wheele != oldv->edge)); - /* collapse */ - p_collapse_edge(edge, pair); + /* collapse */ + p_collapse_edge(edge, pair); - for (i = 0; i < nwheelverts; i++) { - float cost; - PEdge *collapse = NULL; + for (i = 0; i < nwheelverts; i++) { + float cost; + PEdge *collapse = NULL; - v = wheelverts[i]; + v = wheelverts[i]; - if (v->u.heaplink) { - BLI_heap_remove(heap, v->u.heaplink); - v->u.heaplink = NULL; - } + if (v->u.heaplink) { + BLI_heap_remove(heap, v->u.heaplink); + v->u.heaplink = NULL; + } - p_collapse_cost_vertex(v, &cost, &collapse); + p_collapse_cost_vertex(v, &cost, &collapse); - if (collapse) - v->u.heaplink = BLI_heap_insert(heap, cost, collapse); - } + if (collapse) + v->u.heaplink = BLI_heap_insert(heap, cost, collapse); + } - ncollapsed++; - } + ncollapsed++; + } - MEM_freeN(wheelverts); - BLI_heap_free(heap, NULL); + MEM_freeN(wheelverts); + BLI_heap_free(heap, NULL); - p_chart_post_collapse_flush(chart, collapsededges); + p_chart_post_collapse_flush(chart, collapsededges); } static void p_chart_complexify(PChart *chart) { - PEdge *e, *pair, *edge; - PVert *newv, *keepv; - int x = 0; + PEdge *e, *pair, *edge; + PVert *newv, *keepv; + int x = 0; - for (e = chart->collapsed_edges; e; e = e->nextlink) { - if (!(e->flag & PEDGE_COLLAPSE_EDGE)) - break; + for (e = chart->collapsed_edges; e; e = e->nextlink) { + if (!(e->flag & PEDGE_COLLAPSE_EDGE)) + break; - edge = e; - pair = e->pair; + edge = e; + pair = e->pair; - if (edge->flag & PEDGE_COLLAPSE_PAIR) { - SWAP(PEdge *, edge, pair); - } + if (edge->flag & PEDGE_COLLAPSE_PAIR) { + SWAP(PEdge *, edge, pair); + } - p_split_vertex(edge, pair); - p_collapsing_verts(edge, pair, &newv, &keepv); + p_split_vertex(edge, pair); + p_collapsing_verts(edge, pair, &newv, &keepv); - if (x >= NCOLLAPSEX) { - newv->uv[0] = keepv->uv[0]; - newv->uv[1] = keepv->uv[1]; - } - else { - p_vert_harmonic_insert(newv); - x++; - } - } + if (x >= NCOLLAPSEX) { + newv->uv[0] = keepv->uv[0]; + newv->uv[1] = keepv->uv[1]; + } + else { + p_vert_harmonic_insert(newv); + x++; + } + } - p_chart_post_split_flush(chart); + p_chart_post_split_flush(chart); } -#if 0 +# if 0 static void p_chart_simplify(PChart *chart) { - /* Not implemented, needs proper reordering in split_flush. */ + /* Not implemented, needs proper reordering in split_flush. */ } -#endif +# endif #endif /* ABF */ @@ -2300,925 +2316,937 @@ static void p_chart_simplify(PChart *chart) #define ABF_MAX_ITER 20 typedef struct PAbfSystem { - int ninterior, nfaces, nangles; - float *alpha, *beta, *sine, *cosine, *weight; - float *bAlpha, *bTriangle, *bInterior; - float *lambdaTriangle, *lambdaPlanar, *lambdaLength; - float (*J2dt)[3], *bstar, *dstar; - float minangle, maxangle; + int ninterior, nfaces, nangles; + float *alpha, *beta, *sine, *cosine, *weight; + float *bAlpha, *bTriangle, *bInterior; + float *lambdaTriangle, *lambdaPlanar, *lambdaLength; + float (*J2dt)[3], *bstar, *dstar; + float minangle, maxangle; } PAbfSystem; static void p_abf_setup_system(PAbfSystem *sys) { - int i; + int i; - sys->alpha = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFalpha"); - sys->beta = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFbeta"); - sys->sine = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFsine"); - sys->cosine = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFcosine"); - sys->weight = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFweight"); + sys->alpha = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFalpha"); + sys->beta = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFbeta"); + sys->sine = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFsine"); + sys->cosine = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFcosine"); + sys->weight = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFweight"); - sys->bAlpha = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFbalpha"); - sys->bTriangle = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFbtriangle"); - sys->bInterior = (float *)MEM_mallocN(sizeof(float) * 2 * sys->ninterior, "ABFbinterior"); + sys->bAlpha = (float *)MEM_mallocN(sizeof(float) * sys->nangles, "ABFbalpha"); + sys->bTriangle = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFbtriangle"); + sys->bInterior = (float *)MEM_mallocN(sizeof(float) * 2 * sys->ninterior, "ABFbinterior"); - sys->lambdaTriangle = (float *)MEM_callocN(sizeof(float) * sys->nfaces, "ABFlambdatri"); - sys->lambdaPlanar = (float *)MEM_callocN(sizeof(float) * sys->ninterior, "ABFlamdaplane"); - sys->lambdaLength = (float *)MEM_mallocN(sizeof(float) * sys->ninterior, "ABFlambdalen"); + sys->lambdaTriangle = (float *)MEM_callocN(sizeof(float) * sys->nfaces, "ABFlambdatri"); + sys->lambdaPlanar = (float *)MEM_callocN(sizeof(float) * sys->ninterior, "ABFlamdaplane"); + sys->lambdaLength = (float *)MEM_mallocN(sizeof(float) * sys->ninterior, "ABFlambdalen"); - sys->J2dt = MEM_mallocN(sizeof(float) * sys->nangles * 3, "ABFj2dt"); - sys->bstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFbstar"); - sys->dstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFdstar"); + sys->J2dt = MEM_mallocN(sizeof(float) * sys->nangles * 3, "ABFj2dt"); + sys->bstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFbstar"); + sys->dstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFdstar"); - for (i = 0; i < sys->ninterior; i++) - sys->lambdaLength[i] = 1.0; + for (i = 0; i < sys->ninterior; i++) + sys->lambdaLength[i] = 1.0; - sys->minangle = 1.0 * M_PI / 180.0; - sys->maxangle = (float)M_PI - sys->minangle; + sys->minangle = 1.0 * M_PI / 180.0; + sys->maxangle = (float)M_PI - sys->minangle; } static void p_abf_free_system(PAbfSystem *sys) { - MEM_freeN(sys->alpha); - MEM_freeN(sys->beta); - MEM_freeN(sys->sine); - MEM_freeN(sys->cosine); - MEM_freeN(sys->weight); - MEM_freeN(sys->bAlpha); - MEM_freeN(sys->bTriangle); - MEM_freeN(sys->bInterior); - MEM_freeN(sys->lambdaTriangle); - MEM_freeN(sys->lambdaPlanar); - MEM_freeN(sys->lambdaLength); - MEM_freeN(sys->J2dt); - MEM_freeN(sys->bstar); - MEM_freeN(sys->dstar); + MEM_freeN(sys->alpha); + MEM_freeN(sys->beta); + MEM_freeN(sys->sine); + MEM_freeN(sys->cosine); + MEM_freeN(sys->weight); + MEM_freeN(sys->bAlpha); + MEM_freeN(sys->bTriangle); + MEM_freeN(sys->bInterior); + MEM_freeN(sys->lambdaTriangle); + MEM_freeN(sys->lambdaPlanar); + MEM_freeN(sys->lambdaLength); + MEM_freeN(sys->J2dt); + MEM_freeN(sys->bstar); + MEM_freeN(sys->dstar); } static void p_abf_compute_sines(PAbfSystem *sys) { - int i; - float *sine = sys->sine, *cosine = sys->cosine, *alpha = sys->alpha; + int i; + float *sine = sys->sine, *cosine = sys->cosine, *alpha = sys->alpha; - for (i = 0; i < sys->nangles; i++, sine++, cosine++, alpha++) { - *sine = sinf(*alpha); - *cosine = cosf(*alpha); - } + for (i = 0; i < sys->nangles; i++, sine++, cosine++, alpha++) { + *sine = sinf(*alpha); + *cosine = cosf(*alpha); + } } static float p_abf_compute_sin_product(PAbfSystem *sys, PVert *v, int aid) { - PEdge *e, *e1, *e2; - float sin1, sin2; + PEdge *e, *e1, *e2; + float sin1, sin2; - sin1 = sin2 = 1.0; + sin1 = sin2 = 1.0; - e = v->edge; - do { - e1 = e->next; - e2 = e->next->next; + e = v->edge; + do { + e1 = e->next; + e2 = e->next->next; - if (aid == e1->u.id) { - /* we are computing a derivative for this angle, - * so we use cos and drop the other part */ - sin1 *= sys->cosine[e1->u.id]; - sin2 = 0.0; - } - else - sin1 *= sys->sine[e1->u.id]; + if (aid == e1->u.id) { + /* we are computing a derivative for this angle, + * so we use cos and drop the other part */ + sin1 *= sys->cosine[e1->u.id]; + sin2 = 0.0; + } + else + sin1 *= sys->sine[e1->u.id]; - if (aid == e2->u.id) { - /* see above */ - sin1 = 0.0; - sin2 *= sys->cosine[e2->u.id]; - } - else - sin2 *= sys->sine[e2->u.id]; + if (aid == e2->u.id) { + /* see above */ + sin1 = 0.0; + sin2 *= sys->cosine[e2->u.id]; + } + else + sin2 *= sys->sine[e2->u.id]; - e = e->next->next->pair; - } while (e && (e != v->edge)); + e = e->next->next->pair; + } while (e && (e != v->edge)); - return (sin1 - sin2); + return (sin1 - sin2); } static float p_abf_compute_grad_alpha(PAbfSystem *sys, PFace *f, PEdge *e) { - PVert *v = e->vert, *v1 = e->next->vert, *v2 = e->next->next->vert; - float deriv; + PVert *v = e->vert, *v1 = e->next->vert, *v2 = e->next->next->vert; + float deriv; - deriv = (sys->alpha[e->u.id] - sys->beta[e->u.id]) * sys->weight[e->u.id]; - deriv += sys->lambdaTriangle[f->u.id]; + deriv = (sys->alpha[e->u.id] - sys->beta[e->u.id]) * sys->weight[e->u.id]; + deriv += sys->lambdaTriangle[f->u.id]; - if (v->flag & PVERT_INTERIOR) { - deriv += sys->lambdaPlanar[v->u.id]; - } + if (v->flag & PVERT_INTERIOR) { + deriv += sys->lambdaPlanar[v->u.id]; + } - if (v1->flag & PVERT_INTERIOR) { - float product = p_abf_compute_sin_product(sys, v1, e->u.id); - deriv += sys->lambdaLength[v1->u.id] * product; - } + if (v1->flag & PVERT_INTERIOR) { + float product = p_abf_compute_sin_product(sys, v1, e->u.id); + deriv += sys->lambdaLength[v1->u.id] * product; + } - if (v2->flag & PVERT_INTERIOR) { - float product = p_abf_compute_sin_product(sys, v2, e->u.id); - deriv += sys->lambdaLength[v2->u.id] * product; - } + if (v2->flag & PVERT_INTERIOR) { + float product = p_abf_compute_sin_product(sys, v2, e->u.id); + deriv += sys->lambdaLength[v2->u.id] * product; + } - return deriv; + return deriv; } static float p_abf_compute_gradient(PAbfSystem *sys, PChart *chart) { - PFace *f; - PEdge *e; - PVert *v; - float norm = 0.0; + PFace *f; + PEdge *e; + PVert *v; + float norm = 0.0; - for (f = chart->faces; f; f = f->nextlink) { - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - float gtriangle, galpha1, galpha2, galpha3; + for (f = chart->faces; f; f = f->nextlink) { + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + float gtriangle, galpha1, galpha2, galpha3; - galpha1 = p_abf_compute_grad_alpha(sys, f, e1); - galpha2 = p_abf_compute_grad_alpha(sys, f, e2); - galpha3 = p_abf_compute_grad_alpha(sys, f, e3); + galpha1 = p_abf_compute_grad_alpha(sys, f, e1); + galpha2 = p_abf_compute_grad_alpha(sys, f, e2); + galpha3 = p_abf_compute_grad_alpha(sys, f, e3); - sys->bAlpha[e1->u.id] = -galpha1; - sys->bAlpha[e2->u.id] = -galpha2; - sys->bAlpha[e3->u.id] = -galpha3; + sys->bAlpha[e1->u.id] = -galpha1; + sys->bAlpha[e2->u.id] = -galpha2; + sys->bAlpha[e3->u.id] = -galpha3; - norm += galpha1 * galpha1 + galpha2 * galpha2 + galpha3 * galpha3; + norm += galpha1 * galpha1 + galpha2 * galpha2 + galpha3 * galpha3; - gtriangle = sys->alpha[e1->u.id] + sys->alpha[e2->u.id] + sys->alpha[e3->u.id] - (float)M_PI; - sys->bTriangle[f->u.id] = -gtriangle; - norm += gtriangle * gtriangle; - } + gtriangle = sys->alpha[e1->u.id] + sys->alpha[e2->u.id] + sys->alpha[e3->u.id] - (float)M_PI; + sys->bTriangle[f->u.id] = -gtriangle; + norm += gtriangle * gtriangle; + } - for (v = chart->verts; v; v = v->nextlink) { - if (v->flag & PVERT_INTERIOR) { - float gplanar = -2 * M_PI, glength; + for (v = chart->verts; v; v = v->nextlink) { + if (v->flag & PVERT_INTERIOR) { + float gplanar = -2 * M_PI, glength; - e = v->edge; - do { - gplanar += sys->alpha[e->u.id]; - e = e->next->next->pair; - } while (e && (e != v->edge)); + e = v->edge; + do { + gplanar += sys->alpha[e->u.id]; + e = e->next->next->pair; + } while (e && (e != v->edge)); - sys->bInterior[v->u.id] = -gplanar; - norm += gplanar * gplanar; + sys->bInterior[v->u.id] = -gplanar; + norm += gplanar * gplanar; - glength = p_abf_compute_sin_product(sys, v, -1); - sys->bInterior[sys->ninterior + v->u.id] = -glength; - norm += glength * glength; - } - } + glength = p_abf_compute_sin_product(sys, v, -1); + sys->bInterior[sys->ninterior + v->u.id] = -glength; + norm += glength * glength; + } + } - return norm; + return norm; } static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) { - PFace *f; - PEdge *e; - int i, j, ninterior = sys->ninterior, nvar = 2 * sys->ninterior; - PBool success; - LinearSolver *context; - - context = EIG_linear_solver_new(0, nvar, 1); - - for (i = 0; i < nvar; i++) - EIG_linear_solver_right_hand_side_add(context, 0, i, sys->bInterior[i]); - - for (f = chart->faces; f; f = f->nextlink) { - float wi1, wi2, wi3, b, si, beta[3], j2[3][3], W[3][3]; - float row1[6], row2[6], row3[6]; - int vid[6]; - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; - - wi1 = 1.0f / sys->weight[e1->u.id]; - wi2 = 1.0f / sys->weight[e2->u.id]; - wi3 = 1.0f / sys->weight[e3->u.id]; - - /* bstar1 = (J1*dInv*bAlpha - bTriangle) */ - b = sys->bAlpha[e1->u.id] * wi1; - b += sys->bAlpha[e2->u.id] * wi2; - b += sys->bAlpha[e3->u.id] * wi3; - b -= sys->bTriangle[f->u.id]; - - /* si = J1*d*J1t */ - si = 1.0f / (wi1 + wi2 + wi3); - - /* J1t*si*bstar1 - bAlpha */ - beta[0] = b * si - sys->bAlpha[e1->u.id]; - beta[1] = b * si - sys->bAlpha[e2->u.id]; - beta[2] = b * si - sys->bAlpha[e3->u.id]; - - /* use this later for computing other lambda's */ - sys->bstar[f->u.id] = b; - sys->dstar[f->u.id] = si; - - /* set matrix */ - W[0][0] = si - sys->weight[e1->u.id]; W[0][1] = si; W[0][2] = si; - W[1][0] = si; W[1][1] = si - sys->weight[e2->u.id]; W[1][2] = si; - W[2][0] = si; W[2][1] = si; W[2][2] = si - sys->weight[e3->u.id]; - - vid[0] = vid[1] = vid[2] = vid[3] = vid[4] = vid[5] = -1; - - if (v1->flag & PVERT_INTERIOR) { - vid[0] = v1->u.id; - vid[3] = ninterior + v1->u.id; - - sys->J2dt[e1->u.id][0] = j2[0][0] = 1.0f * wi1; - sys->J2dt[e2->u.id][0] = j2[1][0] = p_abf_compute_sin_product(sys, v1, e2->u.id) * wi2; - sys->J2dt[e3->u.id][0] = j2[2][0] = p_abf_compute_sin_product(sys, v1, e3->u.id) * wi3; - - EIG_linear_solver_right_hand_side_add(context, 0, v1->u.id, j2[0][0] * beta[0]); - EIG_linear_solver_right_hand_side_add(context, 0, ninterior + v1->u.id, j2[1][0] * beta[1] + j2[2][0] * beta[2]); - - row1[0] = j2[0][0] * W[0][0]; - row2[0] = j2[0][0] * W[1][0]; - row3[0] = j2[0][0] * W[2][0]; - - row1[3] = j2[1][0] * W[0][1] + j2[2][0] * W[0][2]; - row2[3] = j2[1][0] * W[1][1] + j2[2][0] * W[1][2]; - row3[3] = j2[1][0] * W[2][1] + j2[2][0] * W[2][2]; - } - - if (v2->flag & PVERT_INTERIOR) { - vid[1] = v2->u.id; - vid[4] = ninterior + v2->u.id; - - sys->J2dt[e1->u.id][1] = j2[0][1] = p_abf_compute_sin_product(sys, v2, e1->u.id) * wi1; - sys->J2dt[e2->u.id][1] = j2[1][1] = 1.0f * wi2; - sys->J2dt[e3->u.id][1] = j2[2][1] = p_abf_compute_sin_product(sys, v2, e3->u.id) * wi3; - - EIG_linear_solver_right_hand_side_add(context, 0, v2->u.id, j2[1][1] * beta[1]); - EIG_linear_solver_right_hand_side_add(context, 0, ninterior + v2->u.id, j2[0][1] * beta[0] + j2[2][1] * beta[2]); - - row1[1] = j2[1][1] * W[0][1]; - row2[1] = j2[1][1] * W[1][1]; - row3[1] = j2[1][1] * W[2][1]; - - row1[4] = j2[0][1] * W[0][0] + j2[2][1] * W[0][2]; - row2[4] = j2[0][1] * W[1][0] + j2[2][1] * W[1][2]; - row3[4] = j2[0][1] * W[2][0] + j2[2][1] * W[2][2]; - } - - if (v3->flag & PVERT_INTERIOR) { - vid[2] = v3->u.id; - vid[5] = ninterior + v3->u.id; - - sys->J2dt[e1->u.id][2] = j2[0][2] = p_abf_compute_sin_product(sys, v3, e1->u.id) * wi1; - sys->J2dt[e2->u.id][2] = j2[1][2] = p_abf_compute_sin_product(sys, v3, e2->u.id) * wi2; - sys->J2dt[e3->u.id][2] = j2[2][2] = 1.0f * wi3; - - EIG_linear_solver_right_hand_side_add(context, 0, v3->u.id, j2[2][2] * beta[2]); - EIG_linear_solver_right_hand_side_add(context, 0, ninterior + v3->u.id, j2[0][2] * beta[0] + j2[1][2] * beta[1]); - - row1[2] = j2[2][2] * W[0][2]; - row2[2] = j2[2][2] * W[1][2]; - row3[2] = j2[2][2] * W[2][2]; - - row1[5] = j2[0][2] * W[0][0] + j2[1][2] * W[0][1]; - row2[5] = j2[0][2] * W[1][0] + j2[1][2] * W[1][1]; - row3[5] = j2[0][2] * W[2][0] + j2[1][2] * W[2][1]; - } - - for (i = 0; i < 3; i++) { - int r = vid[i]; - - if (r == -1) - continue; - - for (j = 0; j < 6; j++) { - int c = vid[j]; - - if (c == -1) - continue; - - if (i == 0) - EIG_linear_solver_matrix_add(context, r, c, j2[0][i] * row1[j]); - else - EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[0][i] * row1[j]); - - if (i == 1) - EIG_linear_solver_matrix_add(context, r, c, j2[1][i] * row2[j]); - else - EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[1][i] * row2[j]); - - - if (i == 2) - EIG_linear_solver_matrix_add(context, r, c, j2[2][i] * row3[j]); - else - EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[2][i] * row3[j]); - } - } - } - - success = EIG_linear_solver_solve(context); - - if (success) { - for (f = chart->faces; f; f = f->nextlink) { - float dlambda1, pre[3], dalpha; - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; - - pre[0] = pre[1] = pre[2] = 0.0; - - if (v1->flag & PVERT_INTERIOR) { - float x = EIG_linear_solver_variable_get(context, 0, v1->u.id); - float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v1->u.id); - pre[0] += sys->J2dt[e1->u.id][0] * x; - pre[1] += sys->J2dt[e2->u.id][0] * x2; - pre[2] += sys->J2dt[e3->u.id][0] * x2; - } - - if (v2->flag & PVERT_INTERIOR) { - float x = EIG_linear_solver_variable_get(context, 0, v2->u.id); - float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v2->u.id); - pre[0] += sys->J2dt[e1->u.id][1] * x2; - pre[1] += sys->J2dt[e2->u.id][1] * x; - pre[2] += sys->J2dt[e3->u.id][1] * x2; - } - - if (v3->flag & PVERT_INTERIOR) { - float x = EIG_linear_solver_variable_get(context, 0, v3->u.id); - float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v3->u.id); - pre[0] += sys->J2dt[e1->u.id][2] * x2; - pre[1] += sys->J2dt[e2->u.id][2] * x2; - pre[2] += sys->J2dt[e3->u.id][2] * x; - } - - dlambda1 = pre[0] + pre[1] + pre[2]; - dlambda1 = sys->dstar[f->u.id] * (sys->bstar[f->u.id] - dlambda1); - - sys->lambdaTriangle[f->u.id] += dlambda1; - - dalpha = (sys->bAlpha[e1->u.id] - dlambda1); - sys->alpha[e1->u.id] += dalpha / sys->weight[e1->u.id] - pre[0]; - - dalpha = (sys->bAlpha[e2->u.id] - dlambda1); - sys->alpha[e2->u.id] += dalpha / sys->weight[e2->u.id] - pre[1]; - - dalpha = (sys->bAlpha[e3->u.id] - dlambda1); - sys->alpha[e3->u.id] += dalpha / sys->weight[e3->u.id] - pre[2]; - - /* clamp */ - e = f->edge; - do { - if (sys->alpha[e->u.id] > (float)M_PI) - sys->alpha[e->u.id] = (float)M_PI; - else if (sys->alpha[e->u.id] < 0.0f) - sys->alpha[e->u.id] = 0.0f; - } while (e != f->edge); - } - - for (i = 0; i < ninterior; i++) { - sys->lambdaPlanar[i] += (float)EIG_linear_solver_variable_get(context, 0, i); - sys->lambdaLength[i] += (float)EIG_linear_solver_variable_get(context, 0, ninterior + i); - } - } - - EIG_linear_solver_delete(context); - - return success; + PFace *f; + PEdge *e; + int i, j, ninterior = sys->ninterior, nvar = 2 * sys->ninterior; + PBool success; + LinearSolver *context; + + context = EIG_linear_solver_new(0, nvar, 1); + + for (i = 0; i < nvar; i++) + EIG_linear_solver_right_hand_side_add(context, 0, i, sys->bInterior[i]); + + for (f = chart->faces; f; f = f->nextlink) { + float wi1, wi2, wi3, b, si, beta[3], j2[3][3], W[3][3]; + float row1[6], row2[6], row3[6]; + int vid[6]; + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; + + wi1 = 1.0f / sys->weight[e1->u.id]; + wi2 = 1.0f / sys->weight[e2->u.id]; + wi3 = 1.0f / sys->weight[e3->u.id]; + + /* bstar1 = (J1*dInv*bAlpha - bTriangle) */ + b = sys->bAlpha[e1->u.id] * wi1; + b += sys->bAlpha[e2->u.id] * wi2; + b += sys->bAlpha[e3->u.id] * wi3; + b -= sys->bTriangle[f->u.id]; + + /* si = J1*d*J1t */ + si = 1.0f / (wi1 + wi2 + wi3); + + /* J1t*si*bstar1 - bAlpha */ + beta[0] = b * si - sys->bAlpha[e1->u.id]; + beta[1] = b * si - sys->bAlpha[e2->u.id]; + beta[2] = b * si - sys->bAlpha[e3->u.id]; + + /* use this later for computing other lambda's */ + sys->bstar[f->u.id] = b; + sys->dstar[f->u.id] = si; + + /* set matrix */ + W[0][0] = si - sys->weight[e1->u.id]; + W[0][1] = si; + W[0][2] = si; + W[1][0] = si; + W[1][1] = si - sys->weight[e2->u.id]; + W[1][2] = si; + W[2][0] = si; + W[2][1] = si; + W[2][2] = si - sys->weight[e3->u.id]; + + vid[0] = vid[1] = vid[2] = vid[3] = vid[4] = vid[5] = -1; + + if (v1->flag & PVERT_INTERIOR) { + vid[0] = v1->u.id; + vid[3] = ninterior + v1->u.id; + + sys->J2dt[e1->u.id][0] = j2[0][0] = 1.0f * wi1; + sys->J2dt[e2->u.id][0] = j2[1][0] = p_abf_compute_sin_product(sys, v1, e2->u.id) * wi2; + sys->J2dt[e3->u.id][0] = j2[2][0] = p_abf_compute_sin_product(sys, v1, e3->u.id) * wi3; + + EIG_linear_solver_right_hand_side_add(context, 0, v1->u.id, j2[0][0] * beta[0]); + EIG_linear_solver_right_hand_side_add( + context, 0, ninterior + v1->u.id, j2[1][0] * beta[1] + j2[2][0] * beta[2]); + + row1[0] = j2[0][0] * W[0][0]; + row2[0] = j2[0][0] * W[1][0]; + row3[0] = j2[0][0] * W[2][0]; + + row1[3] = j2[1][0] * W[0][1] + j2[2][0] * W[0][2]; + row2[3] = j2[1][0] * W[1][1] + j2[2][0] * W[1][2]; + row3[3] = j2[1][0] * W[2][1] + j2[2][0] * W[2][2]; + } + + if (v2->flag & PVERT_INTERIOR) { + vid[1] = v2->u.id; + vid[4] = ninterior + v2->u.id; + + sys->J2dt[e1->u.id][1] = j2[0][1] = p_abf_compute_sin_product(sys, v2, e1->u.id) * wi1; + sys->J2dt[e2->u.id][1] = j2[1][1] = 1.0f * wi2; + sys->J2dt[e3->u.id][1] = j2[2][1] = p_abf_compute_sin_product(sys, v2, e3->u.id) * wi3; + + EIG_linear_solver_right_hand_side_add(context, 0, v2->u.id, j2[1][1] * beta[1]); + EIG_linear_solver_right_hand_side_add( + context, 0, ninterior + v2->u.id, j2[0][1] * beta[0] + j2[2][1] * beta[2]); + + row1[1] = j2[1][1] * W[0][1]; + row2[1] = j2[1][1] * W[1][1]; + row3[1] = j2[1][1] * W[2][1]; + + row1[4] = j2[0][1] * W[0][0] + j2[2][1] * W[0][2]; + row2[4] = j2[0][1] * W[1][0] + j2[2][1] * W[1][2]; + row3[4] = j2[0][1] * W[2][0] + j2[2][1] * W[2][2]; + } + + if (v3->flag & PVERT_INTERIOR) { + vid[2] = v3->u.id; + vid[5] = ninterior + v3->u.id; + + sys->J2dt[e1->u.id][2] = j2[0][2] = p_abf_compute_sin_product(sys, v3, e1->u.id) * wi1; + sys->J2dt[e2->u.id][2] = j2[1][2] = p_abf_compute_sin_product(sys, v3, e2->u.id) * wi2; + sys->J2dt[e3->u.id][2] = j2[2][2] = 1.0f * wi3; + + EIG_linear_solver_right_hand_side_add(context, 0, v3->u.id, j2[2][2] * beta[2]); + EIG_linear_solver_right_hand_side_add( + context, 0, ninterior + v3->u.id, j2[0][2] * beta[0] + j2[1][2] * beta[1]); + + row1[2] = j2[2][2] * W[0][2]; + row2[2] = j2[2][2] * W[1][2]; + row3[2] = j2[2][2] * W[2][2]; + + row1[5] = j2[0][2] * W[0][0] + j2[1][2] * W[0][1]; + row2[5] = j2[0][2] * W[1][0] + j2[1][2] * W[1][1]; + row3[5] = j2[0][2] * W[2][0] + j2[1][2] * W[2][1]; + } + + for (i = 0; i < 3; i++) { + int r = vid[i]; + + if (r == -1) + continue; + + for (j = 0; j < 6; j++) { + int c = vid[j]; + + if (c == -1) + continue; + + if (i == 0) + EIG_linear_solver_matrix_add(context, r, c, j2[0][i] * row1[j]); + else + EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[0][i] * row1[j]); + + if (i == 1) + EIG_linear_solver_matrix_add(context, r, c, j2[1][i] * row2[j]); + else + EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[1][i] * row2[j]); + + if (i == 2) + EIG_linear_solver_matrix_add(context, r, c, j2[2][i] * row3[j]); + else + EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[2][i] * row3[j]); + } + } + } + + success = EIG_linear_solver_solve(context); + + if (success) { + for (f = chart->faces; f; f = f->nextlink) { + float dlambda1, pre[3], dalpha; + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; + + pre[0] = pre[1] = pre[2] = 0.0; + + if (v1->flag & PVERT_INTERIOR) { + float x = EIG_linear_solver_variable_get(context, 0, v1->u.id); + float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v1->u.id); + pre[0] += sys->J2dt[e1->u.id][0] * x; + pre[1] += sys->J2dt[e2->u.id][0] * x2; + pre[2] += sys->J2dt[e3->u.id][0] * x2; + } + + if (v2->flag & PVERT_INTERIOR) { + float x = EIG_linear_solver_variable_get(context, 0, v2->u.id); + float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v2->u.id); + pre[0] += sys->J2dt[e1->u.id][1] * x2; + pre[1] += sys->J2dt[e2->u.id][1] * x; + pre[2] += sys->J2dt[e3->u.id][1] * x2; + } + + if (v3->flag & PVERT_INTERIOR) { + float x = EIG_linear_solver_variable_get(context, 0, v3->u.id); + float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v3->u.id); + pre[0] += sys->J2dt[e1->u.id][2] * x2; + pre[1] += sys->J2dt[e2->u.id][2] * x2; + pre[2] += sys->J2dt[e3->u.id][2] * x; + } + + dlambda1 = pre[0] + pre[1] + pre[2]; + dlambda1 = sys->dstar[f->u.id] * (sys->bstar[f->u.id] - dlambda1); + + sys->lambdaTriangle[f->u.id] += dlambda1; + + dalpha = (sys->bAlpha[e1->u.id] - dlambda1); + sys->alpha[e1->u.id] += dalpha / sys->weight[e1->u.id] - pre[0]; + + dalpha = (sys->bAlpha[e2->u.id] - dlambda1); + sys->alpha[e2->u.id] += dalpha / sys->weight[e2->u.id] - pre[1]; + + dalpha = (sys->bAlpha[e3->u.id] - dlambda1); + sys->alpha[e3->u.id] += dalpha / sys->weight[e3->u.id] - pre[2]; + + /* clamp */ + e = f->edge; + do { + if (sys->alpha[e->u.id] > (float)M_PI) + sys->alpha[e->u.id] = (float)M_PI; + else if (sys->alpha[e->u.id] < 0.0f) + sys->alpha[e->u.id] = 0.0f; + } while (e != f->edge); + } + + for (i = 0; i < ninterior; i++) { + sys->lambdaPlanar[i] += (float)EIG_linear_solver_variable_get(context, 0, i); + sys->lambdaLength[i] += (float)EIG_linear_solver_variable_get(context, 0, ninterior + i); + } + } + + EIG_linear_solver_delete(context); + + return success; } static PBool p_chart_abf_solve(PChart *chart) { - PVert *v; - PFace *f; - PEdge *e, *e1, *e2, *e3; - PAbfSystem sys; - int i; - float /* lastnorm, */ /* UNUSED */ limit = (chart->nfaces > 100) ? 1.0f : 0.001f; - - /* setup id's */ - sys.ninterior = sys.nfaces = sys.nangles = 0; - - for (v = chart->verts; v; v = v->nextlink) { - if (p_vert_interior(v)) { - v->flag |= PVERT_INTERIOR; - v->u.id = sys.ninterior++; - } - else - v->flag &= ~PVERT_INTERIOR; - } - - for (f = chart->faces; f; f = f->nextlink) { - e1 = f->edge; e2 = e1->next; e3 = e2->next; - f->u.id = sys.nfaces++; - - /* angle id's are conveniently stored in half edges */ - e1->u.id = sys.nangles++; - e2->u.id = sys.nangles++; - e3->u.id = sys.nangles++; - } - - p_abf_setup_system(&sys); - - /* compute initial angles */ - for (f = chart->faces; f; f = f->nextlink) { - float a1, a2, a3; - - e1 = f->edge; e2 = e1->next; e3 = e2->next; - p_face_angles(f, &a1, &a2, &a3); - - if (a1 < sys.minangle) - a1 = sys.minangle; - else if (a1 > sys.maxangle) - a1 = sys.maxangle; - if (a2 < sys.minangle) - a2 = sys.minangle; - else if (a2 > sys.maxangle) - a2 = sys.maxangle; - if (a3 < sys.minangle) - a3 = sys.minangle; - else if (a3 > sys.maxangle) - a3 = sys.maxangle; - - sys.alpha[e1->u.id] = sys.beta[e1->u.id] = a1; - sys.alpha[e2->u.id] = sys.beta[e2->u.id] = a2; - sys.alpha[e3->u.id] = sys.beta[e3->u.id] = a3; - - sys.weight[e1->u.id] = 2.0f / (a1 * a1); - sys.weight[e2->u.id] = 2.0f / (a2 * a2); - sys.weight[e3->u.id] = 2.0f / (a3 * a3); - } - - for (v = chart->verts; v; v = v->nextlink) { - if (v->flag & PVERT_INTERIOR) { - float anglesum = 0.0, scale; - - e = v->edge; - do { - anglesum += sys.beta[e->u.id]; - e = e->next->next->pair; - } while (e && (e != v->edge)); - - scale = (anglesum == 0.0f) ? 0.0f : 2.0f * (float)M_PI / anglesum; - - e = v->edge; - do { - sys.beta[e->u.id] = sys.alpha[e->u.id] = sys.beta[e->u.id] * scale; - e = e->next->next->pair; - } while (e && (e != v->edge)); - } - } - - if (sys.ninterior > 0) { - p_abf_compute_sines(&sys); - - /* iteration */ - /* lastnorm = 1e10; */ /* UNUSED */ - - for (i = 0; i < ABF_MAX_ITER; i++) { - float norm = p_abf_compute_gradient(&sys, chart); - - /* lastnorm = norm; */ /* UNUSED */ - - if (norm < limit) - break; - - if (!p_abf_matrix_invert(&sys, chart)) { - param_warning("ABF failed to invert matrix"); - p_abf_free_system(&sys); - return P_FALSE; - } - - p_abf_compute_sines(&sys); - } - - if (i == ABF_MAX_ITER) { - param_warning("ABF maximum iterations reached"); - p_abf_free_system(&sys); - return P_FALSE; - } - } - - chart->u.lscm.abf_alpha = MEM_dupallocN(sys.alpha); - p_abf_free_system(&sys); - - return P_TRUE; + PVert *v; + PFace *f; + PEdge *e, *e1, *e2, *e3; + PAbfSystem sys; + int i; + float /* lastnorm, */ /* UNUSED */ limit = (chart->nfaces > 100) ? 1.0f : 0.001f; + + /* setup id's */ + sys.ninterior = sys.nfaces = sys.nangles = 0; + + for (v = chart->verts; v; v = v->nextlink) { + if (p_vert_interior(v)) { + v->flag |= PVERT_INTERIOR; + v->u.id = sys.ninterior++; + } + else + v->flag &= ~PVERT_INTERIOR; + } + + for (f = chart->faces; f; f = f->nextlink) { + e1 = f->edge; + e2 = e1->next; + e3 = e2->next; + f->u.id = sys.nfaces++; + + /* angle id's are conveniently stored in half edges */ + e1->u.id = sys.nangles++; + e2->u.id = sys.nangles++; + e3->u.id = sys.nangles++; + } + + p_abf_setup_system(&sys); + + /* compute initial angles */ + for (f = chart->faces; f; f = f->nextlink) { + float a1, a2, a3; + + e1 = f->edge; + e2 = e1->next; + e3 = e2->next; + p_face_angles(f, &a1, &a2, &a3); + + if (a1 < sys.minangle) + a1 = sys.minangle; + else if (a1 > sys.maxangle) + a1 = sys.maxangle; + if (a2 < sys.minangle) + a2 = sys.minangle; + else if (a2 > sys.maxangle) + a2 = sys.maxangle; + if (a3 < sys.minangle) + a3 = sys.minangle; + else if (a3 > sys.maxangle) + a3 = sys.maxangle; + + sys.alpha[e1->u.id] = sys.beta[e1->u.id] = a1; + sys.alpha[e2->u.id] = sys.beta[e2->u.id] = a2; + sys.alpha[e3->u.id] = sys.beta[e3->u.id] = a3; + + sys.weight[e1->u.id] = 2.0f / (a1 * a1); + sys.weight[e2->u.id] = 2.0f / (a2 * a2); + sys.weight[e3->u.id] = 2.0f / (a3 * a3); + } + + for (v = chart->verts; v; v = v->nextlink) { + if (v->flag & PVERT_INTERIOR) { + float anglesum = 0.0, scale; + + e = v->edge; + do { + anglesum += sys.beta[e->u.id]; + e = e->next->next->pair; + } while (e && (e != v->edge)); + + scale = (anglesum == 0.0f) ? 0.0f : 2.0f * (float)M_PI / anglesum; + + e = v->edge; + do { + sys.beta[e->u.id] = sys.alpha[e->u.id] = sys.beta[e->u.id] * scale; + e = e->next->next->pair; + } while (e && (e != v->edge)); + } + } + + if (sys.ninterior > 0) { + p_abf_compute_sines(&sys); + + /* iteration */ + /* lastnorm = 1e10; */ /* UNUSED */ + + for (i = 0; i < ABF_MAX_ITER; i++) { + float norm = p_abf_compute_gradient(&sys, chart); + + /* lastnorm = norm; */ /* UNUSED */ + + if (norm < limit) + break; + + if (!p_abf_matrix_invert(&sys, chart)) { + param_warning("ABF failed to invert matrix"); + p_abf_free_system(&sys); + return P_FALSE; + } + + p_abf_compute_sines(&sys); + } + + if (i == ABF_MAX_ITER) { + param_warning("ABF maximum iterations reached"); + p_abf_free_system(&sys); + return P_FALSE; + } + } + + chart->u.lscm.abf_alpha = MEM_dupallocN(sys.alpha); + p_abf_free_system(&sys); + + return P_TRUE; } /* Least Squares Conformal Maps */ static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2) { - if (!*pin1 || !*pin2 || *pin1 == *pin2) { - /* degenerate case */ - PFace *f = chart->faces; - *pin1 = f->edge->vert; - *pin2 = f->edge->next->vert; - - (*pin1)->uv[0] = 0.0f; - (*pin1)->uv[1] = 0.5f; - (*pin2)->uv[0] = 1.0f; - (*pin2)->uv[1] = 0.5f; - } - else { - int diru, dirv, dirx, diry; - float sub[3]; - - sub_v3_v3v3(sub, (*pin1)->co, (*pin2)->co); - sub[0] = fabsf(sub[0]); - sub[1] = fabsf(sub[1]); - sub[2] = fabsf(sub[2]); - - if ((sub[0] > sub[1]) && (sub[0] > sub[2])) { - dirx = 0; - diry = (sub[1] > sub[2]) ? 1 : 2; - } - else if ((sub[1] > sub[0]) && (sub[1] > sub[2])) { - dirx = 1; - diry = (sub[0] > sub[2]) ? 0 : 2; - } - else { - dirx = 2; - diry = (sub[0] > sub[1]) ? 0 : 1; - } - - if (dirx == 2) { - diru = 1; - dirv = 0; - } - else { - diru = 0; - dirv = 1; - } - - (*pin1)->uv[diru] = (*pin1)->co[dirx]; - (*pin1)->uv[dirv] = (*pin1)->co[diry]; - (*pin2)->uv[diru] = (*pin2)->co[dirx]; - (*pin2)->uv[dirv] = (*pin2)->co[diry]; - } + if (!*pin1 || !*pin2 || *pin1 == *pin2) { + /* degenerate case */ + PFace *f = chart->faces; + *pin1 = f->edge->vert; + *pin2 = f->edge->next->vert; + + (*pin1)->uv[0] = 0.0f; + (*pin1)->uv[1] = 0.5f; + (*pin2)->uv[0] = 1.0f; + (*pin2)->uv[1] = 0.5f; + } + else { + int diru, dirv, dirx, diry; + float sub[3]; + + sub_v3_v3v3(sub, (*pin1)->co, (*pin2)->co); + sub[0] = fabsf(sub[0]); + sub[1] = fabsf(sub[1]); + sub[2] = fabsf(sub[2]); + + if ((sub[0] > sub[1]) && (sub[0] > sub[2])) { + dirx = 0; + diry = (sub[1] > sub[2]) ? 1 : 2; + } + else if ((sub[1] > sub[0]) && (sub[1] > sub[2])) { + dirx = 1; + diry = (sub[0] > sub[2]) ? 0 : 2; + } + else { + dirx = 2; + diry = (sub[0] > sub[1]) ? 0 : 1; + } + + if (dirx == 2) { + diru = 1; + dirv = 0; + } + else { + diru = 0; + dirv = 1; + } + + (*pin1)->uv[diru] = (*pin1)->co[dirx]; + (*pin1)->uv[dirv] = (*pin1)->co[diry]; + (*pin2)->uv[diru] = (*pin2)->co[dirx]; + (*pin2)->uv[dirv] = (*pin2)->co[diry]; + } } static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2) { - PEdge *be, *lastbe = NULL, *maxe1 = NULL, *maxe2 = NULL, *be1, *be2; - PEdge *cure = NULL, *firste1 = NULL, *firste2 = NULL, *nextbe; - float maxlen = 0.0f, curlen = 0.0f, totlen = 0.0f, firstlen = 0.0f; - float len1, len2; - - /* find longest series of verts split in the chart itself, these are - * marked during construction */ - be = outer; - lastbe = p_boundary_edge_prev(be); - do { - float len = p_edge_length(be); - totlen += len; - - nextbe = p_boundary_edge_next(be); - - if ((be->vert->flag & PVERT_SPLIT) || - (lastbe->vert->flag & nextbe->vert->flag & PVERT_SPLIT)) - { - if (!cure) { - if (be == outer) - firste1 = be; - cure = be; - } - else - curlen += p_edge_length(lastbe); - } - else if (cure) { - if (curlen > maxlen) { - maxlen = curlen; - maxe1 = cure; - maxe2 = lastbe; - } - - if (firste1 == cure) { - firstlen = curlen; - firste2 = lastbe; - } - - curlen = 0.0f; - cure = NULL; - } - - lastbe = be; - be = nextbe; - } while (be != outer); - - /* make sure we also count a series of splits over the starting point */ - if (cure && (cure != outer)) { - firstlen += curlen + p_edge_length(be); - - if (firstlen > maxlen) { - maxlen = firstlen; - maxe1 = cure; - maxe2 = firste2; - } - } - - if (!maxe1 || !maxe2 || (maxlen < 0.5f * totlen)) - return P_FALSE; - - /* find pin1 in the split vertices */ - be1 = maxe1; - be2 = maxe2; - len1 = 0.0f; - len2 = 0.0f; - - do { - if (len1 < len2) { - len1 += p_edge_length(be1); - be1 = p_boundary_edge_next(be1); - } - else { - be2 = p_boundary_edge_prev(be2); - len2 += p_edge_length(be2); - } - } while (be1 != be2); - - *pin1 = be1->vert; - - /* find pin2 outside the split vertices */ - be1 = maxe1; - be2 = maxe2; - len1 = 0.0f; - len2 = 0.0f; - - do { - if (len1 < len2) { - be1 = p_boundary_edge_prev(be1); - len1 += p_edge_length(be1); - } - else { - len2 += p_edge_length(be2); - be2 = p_boundary_edge_next(be2); - } - } while (be1 != be2); - - *pin2 = be1->vert; - - p_chart_pin_positions(chart, pin1, pin2); - - return !equals_v3v3((*pin1)->co, (*pin2)->co); + PEdge *be, *lastbe = NULL, *maxe1 = NULL, *maxe2 = NULL, *be1, *be2; + PEdge *cure = NULL, *firste1 = NULL, *firste2 = NULL, *nextbe; + float maxlen = 0.0f, curlen = 0.0f, totlen = 0.0f, firstlen = 0.0f; + float len1, len2; + + /* find longest series of verts split in the chart itself, these are + * marked during construction */ + be = outer; + lastbe = p_boundary_edge_prev(be); + do { + float len = p_edge_length(be); + totlen += len; + + nextbe = p_boundary_edge_next(be); + + if ((be->vert->flag & PVERT_SPLIT) || + (lastbe->vert->flag & nextbe->vert->flag & PVERT_SPLIT)) { + if (!cure) { + if (be == outer) + firste1 = be; + cure = be; + } + else + curlen += p_edge_length(lastbe); + } + else if (cure) { + if (curlen > maxlen) { + maxlen = curlen; + maxe1 = cure; + maxe2 = lastbe; + } + + if (firste1 == cure) { + firstlen = curlen; + firste2 = lastbe; + } + + curlen = 0.0f; + cure = NULL; + } + + lastbe = be; + be = nextbe; + } while (be != outer); + + /* make sure we also count a series of splits over the starting point */ + if (cure && (cure != outer)) { + firstlen += curlen + p_edge_length(be); + + if (firstlen > maxlen) { + maxlen = firstlen; + maxe1 = cure; + maxe2 = firste2; + } + } + + if (!maxe1 || !maxe2 || (maxlen < 0.5f * totlen)) + return P_FALSE; + + /* find pin1 in the split vertices */ + be1 = maxe1; + be2 = maxe2; + len1 = 0.0f; + len2 = 0.0f; + + do { + if (len1 < len2) { + len1 += p_edge_length(be1); + be1 = p_boundary_edge_next(be1); + } + else { + be2 = p_boundary_edge_prev(be2); + len2 += p_edge_length(be2); + } + } while (be1 != be2); + + *pin1 = be1->vert; + + /* find pin2 outside the split vertices */ + be1 = maxe1; + be2 = maxe2; + len1 = 0.0f; + len2 = 0.0f; + + do { + if (len1 < len2) { + be1 = p_boundary_edge_prev(be1); + len1 += p_edge_length(be1); + } + else { + len2 += p_edge_length(be2); + be2 = p_boundary_edge_next(be2); + } + } while (be1 != be2); + + *pin2 = be1->vert; + + p_chart_pin_positions(chart, pin1, pin2); + + return !equals_v3v3((*pin1)->co, (*pin2)->co); } static void p_chart_extrema_verts(PChart *chart, PVert **pin1, PVert **pin2) { - float minv[3], maxv[3], dirlen; - PVert *v, *minvert[3], *maxvert[3]; - int i, dir; + float minv[3], maxv[3], dirlen; + PVert *v, *minvert[3], *maxvert[3]; + int i, dir; - /* find minimum and maximum verts over x/y/z axes */ - minv[0] = minv[1] = minv[2] = 1e20; - maxv[0] = maxv[1] = maxv[2] = -1e20; + /* find minimum and maximum verts over x/y/z axes */ + minv[0] = minv[1] = minv[2] = 1e20; + maxv[0] = maxv[1] = maxv[2] = -1e20; - minvert[0] = minvert[1] = minvert[2] = NULL; - maxvert[0] = maxvert[1] = maxvert[2] = NULL; + minvert[0] = minvert[1] = minvert[2] = NULL; + maxvert[0] = maxvert[1] = maxvert[2] = NULL; - for (v = chart->verts; v; v = v->nextlink) { - for (i = 0; i < 3; i++) { - if (v->co[i] < minv[i]) { - minv[i] = v->co[i]; - minvert[i] = v; - } - if (v->co[i] > maxv[i]) { - maxv[i] = v->co[i]; - maxvert[i] = v; - } - } - } + for (v = chart->verts; v; v = v->nextlink) { + for (i = 0; i < 3; i++) { + if (v->co[i] < minv[i]) { + minv[i] = v->co[i]; + minvert[i] = v; + } + if (v->co[i] > maxv[i]) { + maxv[i] = v->co[i]; + maxvert[i] = v; + } + } + } - /* find axes with longest distance */ - dir = 0; - dirlen = -1.0; + /* find axes with longest distance */ + dir = 0; + dirlen = -1.0; - for (i = 0; i < 3; i++) { - if (maxv[i] - minv[i] > dirlen) { - dir = i; - dirlen = maxv[i] - minv[i]; - } - } + for (i = 0; i < 3; i++) { + if (maxv[i] - minv[i] > dirlen) { + dir = i; + dirlen = maxv[i] - minv[i]; + } + } - *pin1 = minvert[dir]; - *pin2 = maxvert[dir]; + *pin1 = minvert[dir]; + *pin2 = maxvert[dir]; - p_chart_pin_positions(chart, pin1, pin2); + p_chart_pin_positions(chart, pin1, pin2); } static void p_chart_lscm_load_solution(PChart *chart) { - LinearSolver *context = chart->u.lscm.context; - PVert *v; + LinearSolver *context = chart->u.lscm.context; + PVert *v; - for (v = chart->verts; v; v = v->nextlink) { - v->uv[0] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id); - v->uv[1] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id + 1); - } + for (v = chart->verts; v; v = v->nextlink) { + v->uv[0] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id); + v->uv[1] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id + 1); + } } static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) { - PVert *v, *pin1, *pin2; - PBool select = P_FALSE, deselect = P_FALSE; - int npins = 0, id = 0; - - /* give vertices matrix indices and count pins */ - for (v = chart->verts; v; v = v->nextlink) { - if (v->flag & PVERT_PIN) { - npins++; - if (v->flag & PVERT_SELECT) - select = P_TRUE; - } - - if (!(v->flag & PVERT_SELECT)) - deselect = P_TRUE; - } - - if ((live && (!select || !deselect)) || (npins == 1)) { - chart->u.lscm.context = NULL; - } - else { + PVert *v, *pin1, *pin2; + PBool select = P_FALSE, deselect = P_FALSE; + int npins = 0, id = 0; + + /* give vertices matrix indices and count pins */ + for (v = chart->verts; v; v = v->nextlink) { + if (v->flag & PVERT_PIN) { + npins++; + if (v->flag & PVERT_SELECT) + select = P_TRUE; + } + + if (!(v->flag & PVERT_SELECT)) + deselect = P_TRUE; + } + + if ((live && (!select || !deselect)) || (npins == 1)) { + chart->u.lscm.context = NULL; + } + else { #if 0 - p_chart_simplify_compute(chart); - p_chart_topological_sanity_check(chart); + p_chart_simplify_compute(chart); + p_chart_topological_sanity_check(chart); #endif - if (abf) { - if (!p_chart_abf_solve(chart)) - param_warning("ABF solving failed: falling back to LSCM.\n"); - } + if (abf) { + if (!p_chart_abf_solve(chart)) + param_warning("ABF solving failed: falling back to LSCM.\n"); + } - if (npins <= 1) { - /* not enough pins, lets find some ourself */ - PEdge *outer; + if (npins <= 1) { + /* not enough pins, lets find some ourself */ + PEdge *outer; - p_chart_boundaries(chart, NULL, &outer); + p_chart_boundaries(chart, NULL, &outer); - /* outer can be NULL with non-finite coords. */ - if (!(outer && p_chart_symmetry_pins(chart, outer, &pin1, &pin2))) { - p_chart_extrema_verts(chart, &pin1, &pin2); - } + /* outer can be NULL with non-finite coords. */ + if (!(outer && p_chart_symmetry_pins(chart, outer, &pin1, &pin2))) { + p_chart_extrema_verts(chart, &pin1, &pin2); + } - chart->u.lscm.pin1 = pin1; - chart->u.lscm.pin2 = pin2; - } + chart->u.lscm.pin1 = pin1; + chart->u.lscm.pin2 = pin2; + } - for (v = chart->verts; v; v = v->nextlink) - v->u.id = id++; + for (v = chart->verts; v; v = v->nextlink) + v->u.id = id++; - chart->u.lscm.context = EIG_linear_least_squares_solver_new(2 * chart->nfaces, 2 * chart->nverts, 1); - } + chart->u.lscm.context = EIG_linear_least_squares_solver_new( + 2 * chart->nfaces, 2 * chart->nverts, 1); + } } static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart) { - LinearSolver *context = chart->u.lscm.context; - PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2; - PFace *f; - float *alpha = chart->u.lscm.abf_alpha; - float area_pinned_up, area_pinned_down; - bool flip_faces; - int row; + LinearSolver *context = chart->u.lscm.context; + PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2; + PFace *f; + float *alpha = chart->u.lscm.abf_alpha; + float area_pinned_up, area_pinned_down; + bool flip_faces; + int row; #if 0 - /* TODO: make loading pins work for simplify/complexify. */ + /* TODO: make loading pins work for simplify/complexify. */ #endif - for (v = chart->verts; v; v = v->nextlink) - if (v->flag & PVERT_PIN) - p_vert_load_pin_select_uvs(handle, v); /* reload for live */ - - if (chart->u.lscm.pin1) { - EIG_linear_solver_variable_lock(context, 2 * pin1->u.id); - EIG_linear_solver_variable_lock(context, 2 * pin1->u.id + 1); - EIG_linear_solver_variable_lock(context, 2 * pin2->u.id); - EIG_linear_solver_variable_lock(context, 2 * pin2->u.id + 1); - - EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id, pin1->uv[0]); - EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id + 1, pin1->uv[1]); - EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id, pin2->uv[0]); - EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id + 1, pin2->uv[1]); - } - else { - /* set and lock the pins */ - for (v = chart->verts; v; v = v->nextlink) { - if (v->flag & PVERT_PIN) { - EIG_linear_solver_variable_lock(context, 2 * v->u.id); - EIG_linear_solver_variable_lock(context, 2 * v->u.id + 1); - - EIG_linear_solver_variable_set(context, 0, 2 * v->u.id, v->uv[0]); - EIG_linear_solver_variable_set(context, 0, 2 * v->u.id + 1, v->uv[1]); - } - } - } - - /* detect up direction based on pinned vertices */ - area_pinned_up = 0.0f; - area_pinned_down = 0.0f; - - for (f = chart->faces; f; f = f->nextlink) { - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; - - if ((v1->flag & PVERT_PIN) && (v2->flag & PVERT_PIN) && (v3->flag & PVERT_PIN)) { - float area = p_face_uv_area_signed(f); - - if (area > 0.0f) - area_pinned_up += area; - else - area_pinned_down -= area; - } - } - - flip_faces = (area_pinned_down > area_pinned_up); - - /* construct matrix */ - - row = 0; - for (f = chart->faces; f; f = f->nextlink) { - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; - float a1, a2, a3, ratio, cosine, sine; - float sina1, sina2, sina3, sinmax; - - if (alpha) { - /* use abf angles if passed on */ - a1 = *(alpha++); - a2 = *(alpha++); - a3 = *(alpha++); - } - else - p_face_angles(f, &a1, &a2, &a3); - - if (flip_faces) { - SWAP(float, a2, a3); - SWAP(PEdge *, e2, e3); - SWAP(PVert *, v2, v3); - } - - sina1 = sinf(a1); - sina2 = sinf(a2); - sina3 = sinf(a3); - - sinmax = max_fff(sina1, sina2, sina3); - - /* shift vertices to find most stable order */ - if (sina3 != sinmax) { - SHIFT3(PVert *, v1, v2, v3); - SHIFT3(float, a1, a2, a3); - SHIFT3(float, sina1, sina2, sina3); - - if (sina2 == sinmax) { - SHIFT3(PVert *, v1, v2, v3); - SHIFT3(float, a1, a2, a3); - SHIFT3(float, sina1, sina2, sina3); - } - } - - /* angle based lscm formulation */ - ratio = (sina3 == 0.0f) ? 1.0f : sina2 / sina3; - cosine = cosf(a1) * ratio; - sine = sina1 * ratio; - - EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, cosine - 1.0f); - EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, -sine); - EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -cosine); - EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, sine); - EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id, 1.0); - row++; - - EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, sine); - EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, cosine - 1.0f); - EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -sine); - EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, -cosine); - EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id + 1, 1.0); - row++; - } - - if (EIG_linear_solver_solve(context)) { - p_chart_lscm_load_solution(chart); - return P_TRUE; - } - else { - for (v = chart->verts; v; v = v->nextlink) { - v->uv[0] = 0.0f; - v->uv[1] = 0.0f; - } - } - - return P_FALSE; + for (v = chart->verts; v; v = v->nextlink) + if (v->flag & PVERT_PIN) + p_vert_load_pin_select_uvs(handle, v); /* reload for live */ + + if (chart->u.lscm.pin1) { + EIG_linear_solver_variable_lock(context, 2 * pin1->u.id); + EIG_linear_solver_variable_lock(context, 2 * pin1->u.id + 1); + EIG_linear_solver_variable_lock(context, 2 * pin2->u.id); + EIG_linear_solver_variable_lock(context, 2 * pin2->u.id + 1); + + EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id, pin1->uv[0]); + EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id + 1, pin1->uv[1]); + EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id, pin2->uv[0]); + EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id + 1, pin2->uv[1]); + } + else { + /* set and lock the pins */ + for (v = chart->verts; v; v = v->nextlink) { + if (v->flag & PVERT_PIN) { + EIG_linear_solver_variable_lock(context, 2 * v->u.id); + EIG_linear_solver_variable_lock(context, 2 * v->u.id + 1); + + EIG_linear_solver_variable_set(context, 0, 2 * v->u.id, v->uv[0]); + EIG_linear_solver_variable_set(context, 0, 2 * v->u.id + 1, v->uv[1]); + } + } + } + + /* detect up direction based on pinned vertices */ + area_pinned_up = 0.0f; + area_pinned_down = 0.0f; + + for (f = chart->faces; f; f = f->nextlink) { + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; + + if ((v1->flag & PVERT_PIN) && (v2->flag & PVERT_PIN) && (v3->flag & PVERT_PIN)) { + float area = p_face_uv_area_signed(f); + + if (area > 0.0f) + area_pinned_up += area; + else + area_pinned_down -= area; + } + } + + flip_faces = (area_pinned_down > area_pinned_up); + + /* construct matrix */ + + row = 0; + for (f = chart->faces; f; f = f->nextlink) { + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; + float a1, a2, a3, ratio, cosine, sine; + float sina1, sina2, sina3, sinmax; + + if (alpha) { + /* use abf angles if passed on */ + a1 = *(alpha++); + a2 = *(alpha++); + a3 = *(alpha++); + } + else + p_face_angles(f, &a1, &a2, &a3); + + if (flip_faces) { + SWAP(float, a2, a3); + SWAP(PEdge *, e2, e3); + SWAP(PVert *, v2, v3); + } + + sina1 = sinf(a1); + sina2 = sinf(a2); + sina3 = sinf(a3); + + sinmax = max_fff(sina1, sina2, sina3); + + /* shift vertices to find most stable order */ + if (sina3 != sinmax) { + SHIFT3(PVert *, v1, v2, v3); + SHIFT3(float, a1, a2, a3); + SHIFT3(float, sina1, sina2, sina3); + + if (sina2 == sinmax) { + SHIFT3(PVert *, v1, v2, v3); + SHIFT3(float, a1, a2, a3); + SHIFT3(float, sina1, sina2, sina3); + } + } + + /* angle based lscm formulation */ + ratio = (sina3 == 0.0f) ? 1.0f : sina2 / sina3; + cosine = cosf(a1) * ratio; + sine = sina1 * ratio; + + EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, cosine - 1.0f); + EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, -sine); + EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -cosine); + EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, sine); + EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id, 1.0); + row++; + + EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, sine); + EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, cosine - 1.0f); + EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -sine); + EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, -cosine); + EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id + 1, 1.0); + row++; + } + + if (EIG_linear_solver_solve(context)) { + p_chart_lscm_load_solution(chart); + return P_TRUE; + } + else { + for (v = chart->verts; v; v = v->nextlink) { + v->uv[0] = 0.0f; + v->uv[1] = 0.0f; + } + } + + return P_FALSE; } static void p_chart_lscm_end(PChart *chart) { - if (chart->u.lscm.context) - EIG_linear_solver_delete(chart->u.lscm.context); + if (chart->u.lscm.context) + EIG_linear_solver_delete(chart->u.lscm.context); - if (chart->u.lscm.abf_alpha) { - MEM_freeN(chart->u.lscm.abf_alpha); - chart->u.lscm.abf_alpha = NULL; - } + if (chart->u.lscm.abf_alpha) { + MEM_freeN(chart->u.lscm.abf_alpha); + chart->u.lscm.abf_alpha = NULL; + } - chart->u.lscm.context = NULL; - chart->u.lscm.pin1 = NULL; - chart->u.lscm.pin2 = NULL; + chart->u.lscm.context = NULL; + chart->u.lscm.pin1 = NULL; + chart->u.lscm.pin2 = NULL; } /* Stretch */ @@ -3227,386 +3255,386 @@ static void p_chart_lscm_end(PChart *chart) static void p_stretch_pin_boundary(PChart *chart) { - PVert *v; + PVert *v; - for (v = chart->verts; v; v = v->nextlink) - if (v->edge->pair == NULL) - v->flag |= PVERT_PIN; - else - v->flag &= ~PVERT_PIN; + for (v = chart->verts; v; v = v->nextlink) + if (v->edge->pair == NULL) + v->flag |= PVERT_PIN; + else + v->flag &= ~PVERT_PIN; } static float p_face_stretch(PFace *f) { - float T, w, tmp[3]; - float Ps[3], Pt[3]; - float a, c, area; - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; + float T, w, tmp[3]; + float Ps[3], Pt[3]; + float a, c, area; + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert; - area = p_face_uv_area_signed(f); + area = p_face_uv_area_signed(f); - if (area <= 0.0f) /* flipped face -> infinite stretch */ - return 1e10f; + if (area <= 0.0f) /* flipped face -> infinite stretch */ + return 1e10f; - w = 1.0f / (2.0f * area); + w = 1.0f / (2.0f * area); - /* compute derivatives */ - copy_v3_v3(Ps, v1->co); - mul_v3_fl(Ps, (v2->uv[1] - v3->uv[1])); + /* compute derivatives */ + copy_v3_v3(Ps, v1->co); + mul_v3_fl(Ps, (v2->uv[1] - v3->uv[1])); - copy_v3_v3(tmp, v2->co); - mul_v3_fl(tmp, (v3->uv[1] - v1->uv[1])); - add_v3_v3(Ps, tmp); + copy_v3_v3(tmp, v2->co); + mul_v3_fl(tmp, (v3->uv[1] - v1->uv[1])); + add_v3_v3(Ps, tmp); - copy_v3_v3(tmp, v3->co); - mul_v3_fl(tmp, (v1->uv[1] - v2->uv[1])); - add_v3_v3(Ps, tmp); + copy_v3_v3(tmp, v3->co); + mul_v3_fl(tmp, (v1->uv[1] - v2->uv[1])); + add_v3_v3(Ps, tmp); - mul_v3_fl(Ps, w); + mul_v3_fl(Ps, w); - copy_v3_v3(Pt, v1->co); - mul_v3_fl(Pt, (v3->uv[0] - v2->uv[0])); + copy_v3_v3(Pt, v1->co); + mul_v3_fl(Pt, (v3->uv[0] - v2->uv[0])); - copy_v3_v3(tmp, v2->co); - mul_v3_fl(tmp, (v1->uv[0] - v3->uv[0])); - add_v3_v3(Pt, tmp); + copy_v3_v3(tmp, v2->co); + mul_v3_fl(tmp, (v1->uv[0] - v3->uv[0])); + add_v3_v3(Pt, tmp); - copy_v3_v3(tmp, v3->co); - mul_v3_fl(tmp, (v2->uv[0] - v1->uv[0])); - add_v3_v3(Pt, tmp); + copy_v3_v3(tmp, v3->co); + mul_v3_fl(tmp, (v2->uv[0] - v1->uv[0])); + add_v3_v3(Pt, tmp); - mul_v3_fl(Pt, w); + mul_v3_fl(Pt, w); - /* Sander Tensor */ - a = dot_v3v3(Ps, Ps); - c = dot_v3v3(Pt, Pt); + /* Sander Tensor */ + a = dot_v3v3(Ps, Ps); + c = dot_v3v3(Pt, Pt); - T = sqrtf(0.5f * (a + c)); - if (f->flag & PFACE_FILLED) - T *= 0.2f; + T = sqrtf(0.5f * (a + c)); + if (f->flag & PFACE_FILLED) + T *= 0.2f; - return T; + return T; } static float p_stretch_compute_vertex(PVert *v) { - PEdge *e = v->edge; - float sum = 0.0f; + PEdge *e = v->edge; + float sum = 0.0f; - do { - sum += p_face_stretch(e->face); - e = p_wheel_edge_next(e); - } while (e && e != (v->edge)); + do { + sum += p_face_stretch(e->face); + e = p_wheel_edge_next(e); + } while (e && e != (v->edge)); - return sum; + return sum; } static void p_chart_stretch_minimize(PChart *chart, RNG *rng) { - PVert *v; - PEdge *e; - int j, nedges; - float orig_stretch, low, stretch_low, high, stretch_high, mid, stretch; - float orig_uv[2], dir[2], random_angle, trusted_radius; - - for (v = chart->verts; v; v = v->nextlink) { - if ((v->flag & PVERT_PIN) || !(v->flag & PVERT_SELECT)) - continue; - - orig_stretch = p_stretch_compute_vertex(v); - orig_uv[0] = v->uv[0]; - orig_uv[1] = v->uv[1]; - - /* move vertex in a random direction */ - trusted_radius = 0.0f; - nedges = 0; - e = v->edge; - - do { - trusted_radius += p_edge_uv_length(e); - nedges++; - - e = p_wheel_edge_next(e); - } while (e && e != (v->edge)); - - trusted_radius /= 2 * nedges; - - random_angle = BLI_rng_get_float(rng) * 2.0f * (float)M_PI; - dir[0] = trusted_radius * cosf(random_angle); - dir[1] = trusted_radius * sinf(random_angle); - - /* calculate old and new stretch */ - low = 0; - stretch_low = orig_stretch; - - add_v2_v2v2(v->uv, orig_uv, dir); - high = 1; - stretch = stretch_high = p_stretch_compute_vertex(v); - - /* binary search for lowest stretch position */ - for (j = 0; j < P_STRETCH_ITER; j++) { - mid = 0.5f * (low + high); - v->uv[0] = orig_uv[0] + mid * dir[0]; - v->uv[1] = orig_uv[1] + mid * dir[1]; - stretch = p_stretch_compute_vertex(v); - - if (stretch_low < stretch_high) { - high = mid; - stretch_high = stretch; - } - else { - low = mid; - stretch_low = stretch; - } - } - - /* no luck, stretch has increased, reset to old values */ - if (stretch >= orig_stretch) - copy_v2_v2(v->uv, orig_uv); - } + PVert *v; + PEdge *e; + int j, nedges; + float orig_stretch, low, stretch_low, high, stretch_high, mid, stretch; + float orig_uv[2], dir[2], random_angle, trusted_radius; + + for (v = chart->verts; v; v = v->nextlink) { + if ((v->flag & PVERT_PIN) || !(v->flag & PVERT_SELECT)) + continue; + + orig_stretch = p_stretch_compute_vertex(v); + orig_uv[0] = v->uv[0]; + orig_uv[1] = v->uv[1]; + + /* move vertex in a random direction */ + trusted_radius = 0.0f; + nedges = 0; + e = v->edge; + + do { + trusted_radius += p_edge_uv_length(e); + nedges++; + + e = p_wheel_edge_next(e); + } while (e && e != (v->edge)); + + trusted_radius /= 2 * nedges; + + random_angle = BLI_rng_get_float(rng) * 2.0f * (float)M_PI; + dir[0] = trusted_radius * cosf(random_angle); + dir[1] = trusted_radius * sinf(random_angle); + + /* calculate old and new stretch */ + low = 0; + stretch_low = orig_stretch; + + add_v2_v2v2(v->uv, orig_uv, dir); + high = 1; + stretch = stretch_high = p_stretch_compute_vertex(v); + + /* binary search for lowest stretch position */ + for (j = 0; j < P_STRETCH_ITER; j++) { + mid = 0.5f * (low + high); + v->uv[0] = orig_uv[0] + mid * dir[0]; + v->uv[1] = orig_uv[1] + mid * dir[1]; + stretch = p_stretch_compute_vertex(v); + + if (stretch_low < stretch_high) { + high = mid; + stretch_high = stretch; + } + else { + low = mid; + stretch_low = stretch; + } + } + + /* no luck, stretch has increased, reset to old values */ + if (stretch >= orig_stretch) + copy_v2_v2(v->uv, orig_uv); + } } /* Minimum area enclosing rectangle for packing */ static int p_compare_geometric_uv(const void *a, const void *b) { - const PVert *v1 = *(const PVert * const *)a; - const PVert *v2 = *(const PVert * const *)b; + const PVert *v1 = *(const PVert *const *)a; + const PVert *v2 = *(const PVert *const *)b; - if (v1->uv[0] < v2->uv[0]) - return -1; - else if (v1->uv[0] == v2->uv[0]) { - if (v1->uv[1] < v2->uv[1]) - return -1; - else if (v1->uv[1] == v2->uv[1]) - return 0; - else - return 1; - } - else - return 1; + if (v1->uv[0] < v2->uv[0]) + return -1; + else if (v1->uv[0] == v2->uv[0]) { + if (v1->uv[1] < v2->uv[1]) + return -1; + else if (v1->uv[1] == v2->uv[1]) + return 0; + else + return 1; + } + else + return 1; } static PBool p_chart_convex_hull(PChart *chart, PVert ***verts, int *nverts, int *right) { - /* Graham algorithm, taken from: - * http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117225 */ + /* Graham algorithm, taken from: + * http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117225 */ - PEdge *be, *e; - int npoints = 0, i, ulen, llen; - PVert **U, **L, **points, **p; + PEdge *be, *e; + int npoints = 0, i, ulen, llen; + PVert **U, **L, **points, **p; - p_chart_boundaries(chart, NULL, &be); + p_chart_boundaries(chart, NULL, &be); - if (!be) - return P_FALSE; + if (!be) + return P_FALSE; - e = be; - do { - npoints++; - e = p_boundary_edge_next(e); - } while (e != be); + e = be; + do { + npoints++; + e = p_boundary_edge_next(e); + } while (e != be); - p = points = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints * 2, "PCHullpoints"); - U = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints, "PCHullU"); - L = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints, "PCHullL"); + p = points = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints * 2, "PCHullpoints"); + U = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints, "PCHullU"); + L = (PVert **)MEM_mallocN(sizeof(PVert *) * npoints, "PCHullL"); - e = be; - do { - *p = e->vert; - p++; - e = p_boundary_edge_next(e); - } while (e != be); + e = be; + do { + *p = e->vert; + p++; + e = p_boundary_edge_next(e); + } while (e != be); - qsort(points, npoints, sizeof(PVert *), p_compare_geometric_uv); + qsort(points, npoints, sizeof(PVert *), p_compare_geometric_uv); - ulen = llen = 0; - for (p = points, i = 0; i < npoints; i++, p++) { - while ((ulen > 1) && (p_area_signed(U[ulen - 2]->uv, (*p)->uv, U[ulen - 1]->uv) <= 0)) - ulen--; - while ((llen > 1) && (p_area_signed(L[llen - 2]->uv, (*p)->uv, L[llen - 1]->uv) >= 0)) - llen--; + ulen = llen = 0; + for (p = points, i = 0; i < npoints; i++, p++) { + while ((ulen > 1) && (p_area_signed(U[ulen - 2]->uv, (*p)->uv, U[ulen - 1]->uv) <= 0)) + ulen--; + while ((llen > 1) && (p_area_signed(L[llen - 2]->uv, (*p)->uv, L[llen - 1]->uv) >= 0)) + llen--; - U[ulen] = *p; - ulen++; - L[llen] = *p; - llen++; - } + U[ulen] = *p; + ulen++; + L[llen] = *p; + llen++; + } - npoints = 0; - for (p = points, i = 0; i < ulen; i++, p++, npoints++) - *p = U[i]; + npoints = 0; + for (p = points, i = 0; i < ulen; i++, p++, npoints++) + *p = U[i]; - /* the first and last point in L are left out, since they are also in U */ - for (i = llen - 2; i > 0; i--, p++, npoints++) - *p = L[i]; + /* the first and last point in L are left out, since they are also in U */ + for (i = llen - 2; i > 0; i--, p++, npoints++) + *p = L[i]; - *verts = points; - *nverts = npoints; - *right = ulen - 1; + *verts = points; + *nverts = npoints; + *right = ulen - 1; - MEM_freeN(U); - MEM_freeN(L); + MEM_freeN(U); + MEM_freeN(L); - return P_TRUE; + return P_TRUE; } static float p_rectangle_area(float *p1, float *dir, float *p2, float *p3, float *p4) { - /* given 4 points on the rectangle edges and the direction of on edge, - * compute the area of the rectangle */ + /* given 4 points on the rectangle edges and the direction of on edge, + * compute the area of the rectangle */ - float orthodir[2], corner1[2], corner2[2], corner3[2]; + float orthodir[2], corner1[2], corner2[2], corner3[2]; - orthodir[0] = dir[1]; - orthodir[1] = -dir[0]; + orthodir[0] = dir[1]; + orthodir[1] = -dir[0]; - if (!p_intersect_line_2d_dir(p1, dir, p2, orthodir, corner1)) - return 1e10; + if (!p_intersect_line_2d_dir(p1, dir, p2, orthodir, corner1)) + return 1e10; - if (!p_intersect_line_2d_dir(p1, dir, p4, orthodir, corner2)) - return 1e10; + if (!p_intersect_line_2d_dir(p1, dir, p4, orthodir, corner2)) + return 1e10; - if (!p_intersect_line_2d_dir(p3, dir, p4, orthodir, corner3)) - return 1e10; + if (!p_intersect_line_2d_dir(p3, dir, p4, orthodir, corner3)) + return 1e10; - return len_v2v2(corner1, corner2) * len_v2v2(corner2, corner3); + return len_v2v2(corner1, corner2) * len_v2v2(corner2, corner3); } static float p_chart_minimum_area_angle(PChart *chart) { - /* minimum area enclosing rectangle with rotating calipers, info: - * http://cgm.cs.mcgill.ca/~orm/maer.html */ - - float rotated, minarea, minangle, area, len; - float *angles, miny, maxy, v[2], a[4], mina; - int npoints, right, i_min, i_max, i, idx[4], nextidx; - PVert **points, *p1, *p2, *p3, *p4, *p1n; - - /* compute convex hull */ - if (!p_chart_convex_hull(chart, &points, &npoints, &right)) - return 0.0; - - /* find left/top/right/bottom points, and compute angle for each point */ - angles = MEM_mallocN(sizeof(float) * npoints, "PMinAreaAngles"); - - i_min = i_max = 0; - miny = 1e10; - maxy = -1e10; + /* minimum area enclosing rectangle with rotating calipers, info: + * http://cgm.cs.mcgill.ca/~orm/maer.html */ + + float rotated, minarea, minangle, area, len; + float *angles, miny, maxy, v[2], a[4], mina; + int npoints, right, i_min, i_max, i, idx[4], nextidx; + PVert **points, *p1, *p2, *p3, *p4, *p1n; + + /* compute convex hull */ + if (!p_chart_convex_hull(chart, &points, &npoints, &right)) + return 0.0; + + /* find left/top/right/bottom points, and compute angle for each point */ + angles = MEM_mallocN(sizeof(float) * npoints, "PMinAreaAngles"); + + i_min = i_max = 0; + miny = 1e10; + maxy = -1e10; - for (i = 0; i < npoints; i++) { - p1 = (i == 0) ? points[npoints - 1] : points[i - 1]; - p2 = points[i]; - p3 = (i == npoints - 1) ? points[0] : points[i + 1]; + for (i = 0; i < npoints; i++) { + p1 = (i == 0) ? points[npoints - 1] : points[i - 1]; + p2 = points[i]; + p3 = (i == npoints - 1) ? points[0] : points[i + 1]; - angles[i] = (float)M_PI - p_vec2_angle(p1->uv, p2->uv, p3->uv); + angles[i] = (float)M_PI - p_vec2_angle(p1->uv, p2->uv, p3->uv); - if (points[i]->uv[1] < miny) { - miny = points[i]->uv[1]; - i_min = i; - } - if (points[i]->uv[1] > maxy) { - maxy = points[i]->uv[1]; - i_max = i; - } - } + if (points[i]->uv[1] < miny) { + miny = points[i]->uv[1]; + i_min = i; + } + if (points[i]->uv[1] > maxy) { + maxy = points[i]->uv[1]; + i_max = i; + } + } - /* left, top, right, bottom */ - idx[0] = 0; - idx[1] = i_max; - idx[2] = right; - idx[3] = i_min; + /* left, top, right, bottom */ + idx[0] = 0; + idx[1] = i_max; + idx[2] = right; + idx[3] = i_min; - v[0] = points[idx[0]]->uv[0]; - v[1] = points[idx[0]]->uv[1] + 1.0f; - a[0] = p_vec2_angle(points[(idx[0] + 1) % npoints]->uv, points[idx[0]]->uv, v); + v[0] = points[idx[0]]->uv[0]; + v[1] = points[idx[0]]->uv[1] + 1.0f; + a[0] = p_vec2_angle(points[(idx[0] + 1) % npoints]->uv, points[idx[0]]->uv, v); - v[0] = points[idx[1]]->uv[0] + 1.0f; - v[1] = points[idx[1]]->uv[1]; - a[1] = p_vec2_angle(points[(idx[1] + 1) % npoints]->uv, points[idx[1]]->uv, v); + v[0] = points[idx[1]]->uv[0] + 1.0f; + v[1] = points[idx[1]]->uv[1]; + a[1] = p_vec2_angle(points[(idx[1] + 1) % npoints]->uv, points[idx[1]]->uv, v); - v[0] = points[idx[2]]->uv[0]; - v[1] = points[idx[2]]->uv[1] - 1.0f; - a[2] = p_vec2_angle(points[(idx[2] + 1) % npoints]->uv, points[idx[2]]->uv, v); + v[0] = points[idx[2]]->uv[0]; + v[1] = points[idx[2]]->uv[1] - 1.0f; + a[2] = p_vec2_angle(points[(idx[2] + 1) % npoints]->uv, points[idx[2]]->uv, v); - v[0] = points[idx[3]]->uv[0] - 1.0f; - v[1] = points[idx[3]]->uv[1]; - a[3] = p_vec2_angle(points[(idx[3] + 1) % npoints]->uv, points[idx[3]]->uv, v); + v[0] = points[idx[3]]->uv[0] - 1.0f; + v[1] = points[idx[3]]->uv[1]; + a[3] = p_vec2_angle(points[(idx[3] + 1) % npoints]->uv, points[idx[3]]->uv, v); - /* 4 rotating calipers */ + /* 4 rotating calipers */ - rotated = 0.0; - minarea = 1e10; - minangle = 0.0; + rotated = 0.0; + minarea = 1e10; + minangle = 0.0; - while (rotated <= (float)(M_PI / 2.0)) { /* INVESTIGATE: how far to rotate? */ - /* rotate with the smallest angle */ - i_min = 0; - mina = 1e10; + while (rotated <= (float)(M_PI / 2.0)) { /* INVESTIGATE: how far to rotate? */ + /* rotate with the smallest angle */ + i_min = 0; + mina = 1e10; - for (i = 0; i < 4; i++) - if (a[i] < mina) { - mina = a[i]; - i_min = i; - } + for (i = 0; i < 4; i++) + if (a[i] < mina) { + mina = a[i]; + i_min = i; + } - rotated += mina; - nextidx = (idx[i_min] + 1) % npoints; + rotated += mina; + nextidx = (idx[i_min] + 1) % npoints; - a[i_min] = angles[nextidx]; - a[(i_min + 1) % 4] = a[(i_min + 1) % 4] - mina; - a[(i_min + 2) % 4] = a[(i_min + 2) % 4] - mina; - a[(i_min + 3) % 4] = a[(i_min + 3) % 4] - mina; + a[i_min] = angles[nextidx]; + a[(i_min + 1) % 4] = a[(i_min + 1) % 4] - mina; + a[(i_min + 2) % 4] = a[(i_min + 2) % 4] - mina; + a[(i_min + 3) % 4] = a[(i_min + 3) % 4] - mina; - /* compute area */ - p1 = points[idx[i_min]]; - p1n = points[nextidx]; - p2 = points[idx[(i_min + 1) % 4]]; - p3 = points[idx[(i_min + 2) % 4]]; - p4 = points[idx[(i_min + 3) % 4]]; + /* compute area */ + p1 = points[idx[i_min]]; + p1n = points[nextidx]; + p2 = points[idx[(i_min + 1) % 4]]; + p3 = points[idx[(i_min + 2) % 4]]; + p4 = points[idx[(i_min + 3) % 4]]; - len = len_v2v2(p1->uv, p1n->uv); + len = len_v2v2(p1->uv, p1n->uv); - if (len > 0.0f) { - len = 1.0f / len; - v[0] = (p1n->uv[0] - p1->uv[0]) * len; - v[1] = (p1n->uv[1] - p1->uv[1]) * len; + if (len > 0.0f) { + len = 1.0f / len; + v[0] = (p1n->uv[0] - p1->uv[0]) * len; + v[1] = (p1n->uv[1] - p1->uv[1]) * len; - area = p_rectangle_area(p1->uv, v, p2->uv, p3->uv, p4->uv); + area = p_rectangle_area(p1->uv, v, p2->uv, p3->uv, p4->uv); - /* remember smallest area */ - if (area < minarea) { - minarea = area; - minangle = rotated; - } - } + /* remember smallest area */ + if (area < minarea) { + minarea = area; + minangle = rotated; + } + } - idx[i_min] = nextidx; - } + idx[i_min] = nextidx; + } - /* try keeping rotation as small as possible */ - if (minangle > (float)(M_PI / 4)) - minangle -= (float)(M_PI / 2.0); + /* try keeping rotation as small as possible */ + if (minangle > (float)(M_PI / 4)) + minangle -= (float)(M_PI / 2.0); - MEM_freeN(angles); - MEM_freeN(points); - - return minangle; + MEM_freeN(angles); + MEM_freeN(points); + + return minangle; } static void p_chart_rotate_minimum_area(PChart *chart) { - float angle = p_chart_minimum_area_angle(chart); - float sine = sinf(angle); - float cosine = cosf(angle); - PVert *v; + float angle = p_chart_minimum_area_angle(chart); + float sine = sinf(angle); + float cosine = cosf(angle); + PVert *v; - for (v = chart->verts; v; v = v->nextlink) { - float oldu = v->uv[0], oldv = v->uv[1]; - v->uv[0] = cosine * oldu - sine * oldv; - v->uv[1] = sine * oldu + cosine * oldv; - } + for (v = chart->verts; v; v = v->nextlink) { + float oldu = v->uv[0], oldv = v->uv[1]; + v->uv[0] = cosine * oldu - sine * oldv; + v->uv[1] = sine * oldu + cosine * oldv; + } } /* Area Smoothing */ @@ -3614,1083 +3642,1110 @@ static void p_chart_rotate_minimum_area(PChart *chart) /* 2d bsp tree for inverse mapping - that's a bit silly */ typedef struct SmoothTriangle { - float co1[2], co2[2], co3[2]; - float oco1[2], oco2[2], oco3[2]; + float co1[2], co2[2], co3[2]; + float oco1[2], oco2[2], oco3[2]; } SmoothTriangle; typedef struct SmoothNode { - struct SmoothNode *c1, *c2; - SmoothTriangle **tri; - float split; - int axis, ntri; + struct SmoothNode *c1, *c2; + SmoothTriangle **tri; + float split; + int axis, ntri; } SmoothNode; -static void p_barycentric_2d(const float v1[2], const float v2[2], const float v3[2], const float p[2], float b[3]) +static void p_barycentric_2d( + const float v1[2], const float v2[2], const float v3[2], const float p[2], float b[3]) { - float a[2], c[2], h[2], div; + float a[2], c[2], h[2], div; - a[0] = v2[0] - v1[0]; - a[1] = v2[1] - v1[1]; - c[0] = v3[0] - v1[0]; - c[1] = v3[1] - v1[1]; + a[0] = v2[0] - v1[0]; + a[1] = v2[1] - v1[1]; + c[0] = v3[0] - v1[0]; + c[1] = v3[1] - v1[1]; - div = a[0] * c[1] - a[1] * c[0]; + div = a[0] * c[1] - a[1] * c[0]; - if (div == 0.0f) { - b[0] = 1.0f / 3.0f; - b[1] = 1.0f / 3.0f; - b[2] = 1.0f / 3.0f; - } - else { - h[0] = p[0] - v1[0]; - h[1] = p[1] - v1[1]; + if (div == 0.0f) { + b[0] = 1.0f / 3.0f; + b[1] = 1.0f / 3.0f; + b[2] = 1.0f / 3.0f; + } + else { + h[0] = p[0] - v1[0]; + h[1] = p[1] - v1[1]; - div = 1.0f / div; + div = 1.0f / div; - b[1] = (h[0] * c[1] - h[1] * c[0]) * div; - b[2] = (a[0] * h[1] - a[1] * h[0]) * div; - b[0] = 1.0f - b[1] - b[2]; - } + b[1] = (h[0] * c[1] - h[1] * c[0]) * div; + b[2] = (a[0] * h[1] - a[1] * h[0]) * div; + b[0] = 1.0f - b[1] - b[2]; + } } static PBool p_triangle_inside(SmoothTriangle *t, float co[2]) { - float b[3]; + float b[3]; - p_barycentric_2d(t->co1, t->co2, t->co3, co, b); + p_barycentric_2d(t->co1, t->co2, t->co3, co, b); - if ((b[0] >= 0.0f) && (b[1] >= 0.0f) && (b[2] >= 0.0f)) { - co[0] = t->oco1[0] * b[0] + t->oco2[0] * b[1] + t->oco3[0] * b[2]; - co[1] = t->oco1[1] * b[0] + t->oco2[1] * b[1] + t->oco3[1] * b[2]; - return P_TRUE; - } + if ((b[0] >= 0.0f) && (b[1] >= 0.0f) && (b[2] >= 0.0f)) { + co[0] = t->oco1[0] * b[0] + t->oco2[0] * b[1] + t->oco3[0] * b[2]; + co[1] = t->oco1[1] * b[0] + t->oco2[1] * b[1] + t->oco3[1] * b[2]; + return P_TRUE; + } - return P_FALSE; + return P_FALSE; } -static SmoothNode *p_node_new(MemArena *arena, SmoothTriangle **tri, int ntri, float *bmin, float *bmax, int depth) +static SmoothNode *p_node_new( + MemArena *arena, SmoothTriangle **tri, int ntri, float *bmin, float *bmax, int depth) { - SmoothNode *node = BLI_memarena_alloc(arena, sizeof(*node)); - int axis, i, t1size = 0, t2size = 0; - float split, /* mi, */ /* UNUSED */ mx; - SmoothTriangle **t1, **t2, *t; + SmoothNode *node = BLI_memarena_alloc(arena, sizeof(*node)); + int axis, i, t1size = 0, t2size = 0; + float split, /* mi, */ /* UNUSED */ mx; + SmoothTriangle **t1, **t2, *t; - node->tri = tri; - node->ntri = ntri; + node->tri = tri; + node->ntri = ntri; - if (ntri <= 10 || depth >= 15) - return node; + if (ntri <= 10 || depth >= 15) + return node; - t1 = MEM_mallocN(sizeof(*t1) * ntri, "PNodeTri1"); - t2 = MEM_mallocN(sizeof(*t2) * ntri, "PNodeTri1"); + t1 = MEM_mallocN(sizeof(*t1) * ntri, "PNodeTri1"); + t2 = MEM_mallocN(sizeof(*t2) * ntri, "PNodeTri1"); - axis = (bmax[0] - bmin[0] > bmax[1] - bmin[1]) ? 0 : 1; - split = 0.5f * (bmin[axis] + bmax[axis]); + axis = (bmax[0] - bmin[0] > bmax[1] - bmin[1]) ? 0 : 1; + split = 0.5f * (bmin[axis] + bmax[axis]); - for (i = 0; i < ntri; i++) { - t = tri[i]; + for (i = 0; i < ntri; i++) { + t = tri[i]; - if ((t->co1[axis] <= split) || (t->co2[axis] <= split) || (t->co3[axis] <= split)) { - t1[t1size] = t; - t1size++; - } - if ((t->co1[axis] >= split) || (t->co2[axis] >= split) || (t->co3[axis] >= split)) { - t2[t2size] = t; - t2size++; - } - } + if ((t->co1[axis] <= split) || (t->co2[axis] <= split) || (t->co3[axis] <= split)) { + t1[t1size] = t; + t1size++; + } + if ((t->co1[axis] >= split) || (t->co2[axis] >= split) || (t->co3[axis] >= split)) { + t2[t2size] = t; + t2size++; + } + } - if ((t1size == t2size) && (t1size == ntri)) { - MEM_freeN(t1); - MEM_freeN(t2); - return node; - } + if ((t1size == t2size) && (t1size == ntri)) { + MEM_freeN(t1); + MEM_freeN(t2); + return node; + } - node->tri = NULL; - node->ntri = 0; - MEM_freeN(tri); + node->tri = NULL; + node->ntri = 0; + MEM_freeN(tri); - node->axis = axis; - node->split = split; + node->axis = axis; + node->split = split; - /* mi = bmin[axis]; */ /* UNUSED */ - mx = bmax[axis]; - bmax[axis] = split; - node->c1 = p_node_new(arena, t1, t1size, bmin, bmax, depth + 1); + /* mi = bmin[axis]; */ /* UNUSED */ + mx = bmax[axis]; + bmax[axis] = split; + node->c1 = p_node_new(arena, t1, t1size, bmin, bmax, depth + 1); - bmin[axis] = bmax[axis]; - bmax[axis] = mx; - node->c2 = p_node_new(arena, t2, t2size, bmin, bmax, depth + 1); + bmin[axis] = bmax[axis]; + bmax[axis] = mx; + node->c2 = p_node_new(arena, t2, t2size, bmin, bmax, depth + 1); - return node; + return node; } static void p_node_delete(SmoothNode *node) { - if (node->c1) - p_node_delete(node->c1); - if (node->c2) - p_node_delete(node->c2); - if (node->tri) - MEM_freeN(node->tri); + if (node->c1) + p_node_delete(node->c1); + if (node->c2) + p_node_delete(node->c2); + if (node->tri) + MEM_freeN(node->tri); } static PBool p_node_intersect(SmoothNode *node, float co[2]) { - int i; - - if (node->tri) { - for (i = 0; i < node->ntri; i++) - if (p_triangle_inside(node->tri[i], co)) - return P_TRUE; + int i; - return P_FALSE; - } - else { - if (co[node->axis] < node->split) - return p_node_intersect(node->c1, co); - else - return p_node_intersect(node->c2, co); - } + if (node->tri) { + for (i = 0; i < node->ntri; i++) + if (p_triangle_inside(node->tri[i], co)) + return P_TRUE; + return P_FALSE; + } + else { + if (co[node->axis] < node->split) + return p_node_intersect(node->c1, co); + else + return p_node_intersect(node->c2, co); + } } /* smoothing */ static int p_compare_float(const void *a_, const void *b_) { - const float a = *(const float *)a_; - const float b = *(const float *)b_; + const float a = *(const float *)a_; + const float b = *(const float *)b_; - if (a < b) - return -1; - else if (a == b) - return 0; - else - return 1; + if (a < b) + return -1; + else if (a == b) + return 0; + else + return 1; } static float p_smooth_median_edge_length(PChart *chart) { - PEdge *e; - float *lengths = MEM_mallocN(sizeof(chart->edges) * chart->nedges, "PMedianLength"); - float median; - int i; + PEdge *e; + float *lengths = MEM_mallocN(sizeof(chart->edges) * chart->nedges, "PMedianLength"); + float median; + int i; - /* ok, so i'm lazy */ - for (i = 0, e = chart->edges; e; e = e->nextlink, i++) - lengths[i] = p_edge_length(e); + /* ok, so i'm lazy */ + for (i = 0, e = chart->edges; e; e = e->nextlink, i++) + lengths[i] = p_edge_length(e); - qsort(lengths, i, sizeof(float), p_compare_float); + qsort(lengths, i, sizeof(float), p_compare_float); - median = lengths[i / 2]; - MEM_freeN(lengths); + median = lengths[i / 2]; + MEM_freeN(lengths); - return median; + return median; } static float p_smooth_distortion(PEdge *e, float avg2d, float avg3d) { - float len2d = p_edge_uv_length(e) * avg3d; - float len3d = p_edge_length(e) * avg2d; + float len2d = p_edge_uv_length(e) * avg3d; + float len3d = p_edge_length(e) * avg2d; - return (len3d == 0.0f) ? 0.0f : len2d / len3d; + return (len3d == 0.0f) ? 0.0f : len2d / len3d; } static void p_smooth(PChart *chart) { - PEdge *e; - PVert *v; - PFace *f; - int j, it2, maxiter2, it; - int nedges = chart->nedges, nwheel, gridx, gridy; - int edgesx, edgesy, nsize, esize, i, x, y, maxiter, totiter; - float minv[2], maxv[2], median, invmedian, avglen2d, avglen3d; - float center[2], dx, dy, *nodes, dlimit, d, *oldnodesx, *oldnodesy; - float *nodesx, *nodesy, *hedges, *vedges, climit, moved, padding; - SmoothTriangle *triangles, *t, *t2, **tri, **trip; - SmoothNode *root; - MemArena *arena; - - if (nedges == 0) - return; - - p_chart_uv_bbox(chart, minv, maxv); - median = p_smooth_median_edge_length(chart) * 0.10f; - - if (median == 0.0f) - return; - - invmedian = 1.0f / median; - - /* compute edge distortion */ - avglen2d = avglen3d = 0.0; - - for (e = chart->edges; e; e = e->nextlink) { - avglen2d += p_edge_uv_length(e); - avglen3d += p_edge_length(e); - } - - avglen2d /= nedges; - avglen3d /= nedges; - - for (v = chart->verts; v; v = v->nextlink) { - v->u.distortion = 0.0; - nwheel = 0; - - e = v->edge; - do { - v->u.distortion += p_smooth_distortion(e, avglen2d, avglen3d); - nwheel++; - - e = e->next->next->pair; - } while (e && (e != v->edge)); - - v->u.distortion /= nwheel; - } - - /* need to do excessive grid size checking still */ - center[0] = 0.5f * (minv[0] + maxv[0]); - center[1] = 0.5f * (minv[1] + maxv[1]); - - dx = 0.5f * (maxv[0] - minv[0]); - dy = 0.5f * (maxv[1] - minv[1]); - - padding = 0.15f; - dx += padding * dx + 2.0f * median; - dy += padding * dy + 2.0f * median; - - gridx = (int)(dx * invmedian); - gridy = (int)(dy * invmedian); - - minv[0] = center[0] - median * gridx; - minv[1] = center[1] - median * gridy; - maxv[0] = center[0] + median * gridx; - maxv[1] = center[1] + median * gridy; - - /* create grid */ - gridx = gridx * 2 + 1; - gridy = gridy * 2 + 1; - - if ((gridx <= 2) || (gridy <= 2)) - return; - - edgesx = gridx - 1; - edgesy = gridy - 1; - nsize = gridx * gridy; - esize = edgesx * edgesy; - - nodes = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodes"); - nodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesX"); - nodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesY"); - oldnodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesX"); - oldnodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesY"); - hedges = MEM_mallocN(sizeof(float) * esize, "PSmoothHEdges"); - vedges = MEM_mallocN(sizeof(float) * esize, "PSmoothVEdges"); - - if (!nodes || !nodesx || !nodesy || !oldnodesx || !oldnodesy || !hedges || !vedges) { - if (nodes) MEM_freeN(nodes); - if (nodesx) MEM_freeN(nodesx); - if (nodesy) MEM_freeN(nodesy); - if (oldnodesx) MEM_freeN(oldnodesx); - if (oldnodesy) MEM_freeN(oldnodesy); - if (hedges) MEM_freeN(hedges); - if (vedges) MEM_freeN(vedges); - - // printf("Not enough memory for area smoothing grid"); - return; - } - - for (x = 0; x < gridx; x++) { - for (y = 0; y < gridy; y++) { - i = x + y * gridx; - - nodesx[i] = minv[0] + median * x; - nodesy[i] = minv[1] + median * y; - - nodes[i] = 1.0f; - } - } - - /* embed in grid */ - for (f = chart->faces; f; f = f->nextlink) { - PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - float fmin[2], fmax[2]; - int bx1, by1, bx2, by2; - - INIT_MINMAX2(fmin, fmax); + PEdge *e; + PVert *v; + PFace *f; + int j, it2, maxiter2, it; + int nedges = chart->nedges, nwheel, gridx, gridy; + int edgesx, edgesy, nsize, esize, i, x, y, maxiter, totiter; + float minv[2], maxv[2], median, invmedian, avglen2d, avglen3d; + float center[2], dx, dy, *nodes, dlimit, d, *oldnodesx, *oldnodesy; + float *nodesx, *nodesy, *hedges, *vedges, climit, moved, padding; + SmoothTriangle *triangles, *t, *t2, **tri, **trip; + SmoothNode *root; + MemArena *arena; + + if (nedges == 0) + return; + + p_chart_uv_bbox(chart, minv, maxv); + median = p_smooth_median_edge_length(chart) * 0.10f; + + if (median == 0.0f) + return; + + invmedian = 1.0f / median; + + /* compute edge distortion */ + avglen2d = avglen3d = 0.0; + + for (e = chart->edges; e; e = e->nextlink) { + avglen2d += p_edge_uv_length(e); + avglen3d += p_edge_length(e); + } + + avglen2d /= nedges; + avglen3d /= nedges; + + for (v = chart->verts; v; v = v->nextlink) { + v->u.distortion = 0.0; + nwheel = 0; + + e = v->edge; + do { + v->u.distortion += p_smooth_distortion(e, avglen2d, avglen3d); + nwheel++; + + e = e->next->next->pair; + } while (e && (e != v->edge)); + + v->u.distortion /= nwheel; + } + + /* need to do excessive grid size checking still */ + center[0] = 0.5f * (minv[0] + maxv[0]); + center[1] = 0.5f * (minv[1] + maxv[1]); + + dx = 0.5f * (maxv[0] - minv[0]); + dy = 0.5f * (maxv[1] - minv[1]); + + padding = 0.15f; + dx += padding * dx + 2.0f * median; + dy += padding * dy + 2.0f * median; + + gridx = (int)(dx * invmedian); + gridy = (int)(dy * invmedian); + + minv[0] = center[0] - median * gridx; + minv[1] = center[1] - median * gridy; + maxv[0] = center[0] + median * gridx; + maxv[1] = center[1] + median * gridy; + + /* create grid */ + gridx = gridx * 2 + 1; + gridy = gridy * 2 + 1; + + if ((gridx <= 2) || (gridy <= 2)) + return; + + edgesx = gridx - 1; + edgesy = gridy - 1; + nsize = gridx * gridy; + esize = edgesx * edgesy; + + nodes = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodes"); + nodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesX"); + nodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesY"); + oldnodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesX"); + oldnodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesY"); + hedges = MEM_mallocN(sizeof(float) * esize, "PSmoothHEdges"); + vedges = MEM_mallocN(sizeof(float) * esize, "PSmoothVEdges"); + + if (!nodes || !nodesx || !nodesy || !oldnodesx || !oldnodesy || !hedges || !vedges) { + if (nodes) + MEM_freeN(nodes); + if (nodesx) + MEM_freeN(nodesx); + if (nodesy) + MEM_freeN(nodesy); + if (oldnodesx) + MEM_freeN(oldnodesx); + if (oldnodesy) + MEM_freeN(oldnodesy); + if (hedges) + MEM_freeN(hedges); + if (vedges) + MEM_freeN(vedges); + + // printf("Not enough memory for area smoothing grid"); + return; + } + + for (x = 0; x < gridx; x++) { + for (y = 0; y < gridy; y++) { + i = x + y * gridx; + + nodesx[i] = minv[0] + median * x; + nodesy[i] = minv[1] + median * y; + + nodes[i] = 1.0f; + } + } + + /* embed in grid */ + for (f = chart->faces; f; f = f->nextlink) { + PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; + float fmin[2], fmax[2]; + int bx1, by1, bx2, by2; + + INIT_MINMAX2(fmin, fmax); + + minmax_v2v2_v2(fmin, fmax, e1->vert->uv); + minmax_v2v2_v2(fmin, fmax, e2->vert->uv); + minmax_v2v2_v2(fmin, fmax, e3->vert->uv); + + bx1 = (int)((fmin[0] - minv[0]) * invmedian); + by1 = (int)((fmin[1] - minv[1]) * invmedian); + bx2 = (int)((fmax[0] - minv[0]) * invmedian + 2); + by2 = (int)((fmax[1] - minv[1]) * invmedian + 2); + + for (x = bx1; x < bx2; x++) { + for (y = by1; y < by2; y++) { + float p[2], b[3]; + + i = x + y * gridx; + + p[0] = nodesx[i]; + p[1] = nodesy[i]; + + p_barycentric_2d(e1->vert->uv, e2->vert->uv, e3->vert->uv, p, b); + + if ((b[0] > 0.0f) && (b[1] > 0.0f) && (b[2] > 0.0f)) { + nodes[i] = e1->vert->u.distortion * b[0]; + nodes[i] += e2->vert->u.distortion * b[1]; + nodes[i] += e3->vert->u.distortion * b[2]; + } + } + } + } + + /* smooth the grid */ + maxiter = 10; + totiter = 0; + climit = 0.00001f * nsize; + + for (it = 0; it < maxiter; it++) { + moved = 0.0f; + + for (x = 0; x < edgesx; x++) { + for (y = 0; y < edgesy; y++) { + i = x + y * gridx; + j = x + y * edgesx; + + hedges[j] = (nodes[i] + nodes[i + 1]) * 0.5f; + vedges[j] = (nodes[i] + nodes[i + gridx]) * 0.5f; + + /* we do *inverse* mapping */ + hedges[j] = 1.0f / hedges[j]; + vedges[j] = 1.0f / vedges[j]; + } + } + + maxiter2 = 50; + dlimit = 0.0001f; + + for (it2 = 0; it2 < maxiter2; it2++) { + d = 0.0f; + totiter += 1; + + memcpy(oldnodesx, nodesx, sizeof(float) * nsize); + memcpy(oldnodesy, nodesy, sizeof(float) * nsize); - minmax_v2v2_v2(fmin, fmax, e1->vert->uv); - minmax_v2v2_v2(fmin, fmax, e2->vert->uv); - minmax_v2v2_v2(fmin, fmax, e3->vert->uv); - - bx1 = (int)((fmin[0] - minv[0]) * invmedian); - by1 = (int)((fmin[1] - minv[1]) * invmedian); - bx2 = (int)((fmax[0] - minv[0]) * invmedian + 2); - by2 = (int)((fmax[1] - minv[1]) * invmedian + 2); - - for (x = bx1; x < bx2; x++) { - for (y = by1; y < by2; y++) { - float p[2], b[3]; - - i = x + y * gridx; - - p[0] = nodesx[i]; - p[1] = nodesy[i]; - - p_barycentric_2d(e1->vert->uv, e2->vert->uv, e3->vert->uv, p, b); - - if ((b[0] > 0.0f) && (b[1] > 0.0f) && (b[2] > 0.0f)) { - nodes[i] = e1->vert->u.distortion * b[0]; - nodes[i] += e2->vert->u.distortion * b[1]; - nodes[i] += e3->vert->u.distortion * b[2]; - } - } - } - } - - /* smooth the grid */ - maxiter = 10; - totiter = 0; - climit = 0.00001f * nsize; - - for (it = 0; it < maxiter; it++) { - moved = 0.0f; - - for (x = 0; x < edgesx; x++) { - for (y = 0; y < edgesy; y++) { - i = x + y * gridx; - j = x + y * edgesx; - - hedges[j] = (nodes[i] + nodes[i + 1]) * 0.5f; - vedges[j] = (nodes[i] + nodes[i + gridx]) * 0.5f; - - /* we do *inverse* mapping */ - hedges[j] = 1.0f / hedges[j]; - vedges[j] = 1.0f / vedges[j]; - } - } + for (x = 1; x < gridx - 1; x++) { + for (y = 1; y < gridy - 1; y++) { + float p[2], oldp[2], sum1, sum2, diff[2], length; - maxiter2 = 50; - dlimit = 0.0001f; + i = x + gridx * y; + j = x + edgesx * y; - for (it2 = 0; it2 < maxiter2; it2++) { - d = 0.0f; - totiter += 1; + oldp[0] = oldnodesx[i]; + oldp[1] = oldnodesy[i]; - memcpy(oldnodesx, nodesx, sizeof(float) * nsize); - memcpy(oldnodesy, nodesy, sizeof(float) * nsize); + sum1 = hedges[j - 1] * oldnodesx[i - 1]; + sum1 += hedges[j] * oldnodesx[i + 1]; + sum1 += vedges[j - edgesx] * oldnodesx[i - gridx]; + sum1 += vedges[j] * oldnodesx[i + gridx]; - for (x = 1; x < gridx - 1; x++) { - for (y = 1; y < gridy - 1; y++) { - float p[2], oldp[2], sum1, sum2, diff[2], length; + sum2 = hedges[j - 1]; + sum2 += hedges[j]; + sum2 += vedges[j - edgesx]; + sum2 += vedges[j]; - i = x + gridx * y; - j = x + edgesx * y; + nodesx[i] = sum1 / sum2; - oldp[0] = oldnodesx[i]; - oldp[1] = oldnodesy[i]; + sum1 = hedges[j - 1] * oldnodesy[i - 1]; + sum1 += hedges[j] * oldnodesy[i + 1]; + sum1 += vedges[j - edgesx] * oldnodesy[i - gridx]; + sum1 += vedges[j] * oldnodesy[i + gridx]; - sum1 = hedges[j - 1] * oldnodesx[i - 1]; - sum1 += hedges[j] * oldnodesx[i + 1]; - sum1 += vedges[j - edgesx] * oldnodesx[i - gridx]; - sum1 += vedges[j] * oldnodesx[i + gridx]; + nodesy[i] = sum1 / sum2; - sum2 = hedges[j - 1]; - sum2 += hedges[j]; - sum2 += vedges[j - edgesx]; - sum2 += vedges[j]; + p[0] = nodesx[i]; + p[1] = nodesy[i]; - nodesx[i] = sum1 / sum2; + diff[0] = p[0] - oldp[0]; + diff[1] = p[1] - oldp[1]; - sum1 = hedges[j - 1] * oldnodesy[i - 1]; - sum1 += hedges[j] * oldnodesy[i + 1]; - sum1 += vedges[j - edgesx] * oldnodesy[i - gridx]; - sum1 += vedges[j] * oldnodesy[i + gridx]; + length = len_v2(diff); + d = max_ff(d, length); + moved += length; + } + } - nodesy[i] = sum1 / sum2; + if (d < dlimit) + break; + } - p[0] = nodesx[i]; - p[1] = nodesy[i]; + if (moved < climit) + break; + } - diff[0] = p[0] - oldp[0]; - diff[1] = p[1] - oldp[1]; + MEM_freeN(oldnodesx); + MEM_freeN(oldnodesy); + MEM_freeN(hedges); + MEM_freeN(vedges); - length = len_v2(diff); - d = max_ff(d, length); - moved += length; - } - } + /* create bsp */ + t = triangles = MEM_mallocN(sizeof(SmoothTriangle) * esize * 2, "PSmoothTris"); + trip = tri = MEM_mallocN(sizeof(SmoothTriangle *) * esize * 2, "PSmoothTriP"); - if (d < dlimit) - break; - } + if (!triangles || !tri) { + MEM_freeN(nodes); + MEM_freeN(nodesx); + MEM_freeN(nodesy); - if (moved < climit) - break; - } + if (triangles) + MEM_freeN(triangles); + if (tri) + MEM_freeN(tri); - MEM_freeN(oldnodesx); - MEM_freeN(oldnodesy); - MEM_freeN(hedges); - MEM_freeN(vedges); + // printf("Not enough memory for area smoothing grid"); + return; + } - /* create bsp */ - t = triangles = MEM_mallocN(sizeof(SmoothTriangle) * esize * 2, "PSmoothTris"); - trip = tri = MEM_mallocN(sizeof(SmoothTriangle *) * esize * 2, "PSmoothTriP"); + for (x = 0; x < edgesx; x++) { + for (y = 0; y < edgesy; y++) { + i = x + y * gridx; - if (!triangles || !tri) { - MEM_freeN(nodes); - MEM_freeN(nodesx); - MEM_freeN(nodesy); + t->co1[0] = nodesx[i]; + t->co1[1] = nodesy[i]; - if (triangles) MEM_freeN(triangles); - if (tri) MEM_freeN(tri); + t->co2[0] = nodesx[i + 1]; + t->co2[1] = nodesy[i + 1]; - // printf("Not enough memory for area smoothing grid"); - return; - } + t->co3[0] = nodesx[i + gridx]; + t->co3[1] = nodesy[i + gridx]; - for (x = 0; x < edgesx; x++) { - for (y = 0; y < edgesy; y++) { - i = x + y * gridx; + t->oco1[0] = minv[0] + x * median; + t->oco1[1] = minv[1] + y * median; - t->co1[0] = nodesx[i]; - t->co1[1] = nodesy[i]; + t->oco2[0] = minv[0] + (x + 1) * median; + t->oco2[1] = minv[1] + y * median; - t->co2[0] = nodesx[i + 1]; - t->co2[1] = nodesy[i + 1]; + t->oco3[0] = minv[0] + x * median; + t->oco3[1] = minv[1] + (y + 1) * median; - t->co3[0] = nodesx[i + gridx]; - t->co3[1] = nodesy[i + gridx]; + t2 = t + 1; - t->oco1[0] = minv[0] + x * median; - t->oco1[1] = minv[1] + y * median; + t2->co1[0] = nodesx[i + gridx + 1]; + t2->co1[1] = nodesy[i + gridx + 1]; - t->oco2[0] = minv[0] + (x + 1) * median; - t->oco2[1] = minv[1] + y * median; + t2->oco1[0] = minv[0] + (x + 1) * median; + t2->oco1[1] = minv[1] + (y + 1) * median; - t->oco3[0] = minv[0] + x * median; - t->oco3[1] = minv[1] + (y + 1) * median; + t2->co2[0] = t->co2[0]; + t2->co2[1] = t->co2[1]; + t2->oco2[0] = t->oco2[0]; + t2->oco2[1] = t->oco2[1]; - t2 = t + 1; + t2->co3[0] = t->co3[0]; + t2->co3[1] = t->co3[1]; + t2->oco3[0] = t->oco3[0]; + t2->oco3[1] = t->oco3[1]; - t2->co1[0] = nodesx[i + gridx + 1]; - t2->co1[1] = nodesy[i + gridx + 1]; + *trip = t; + trip++; + t++; + *trip = t; + trip++; + t++; + } + } - t2->oco1[0] = minv[0] + (x + 1) * median; - t2->oco1[1] = minv[1] + (y + 1) * median; + MEM_freeN(nodes); + MEM_freeN(nodesx); + MEM_freeN(nodesy); - t2->co2[0] = t->co2[0]; t2->co2[1] = t->co2[1]; - t2->oco2[0] = t->oco2[0]; t2->oco2[1] = t->oco2[1]; + arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param smooth arena"); + root = p_node_new(arena, tri, esize * 2, minv, maxv, 0); - t2->co3[0] = t->co3[0]; t2->co3[1] = t->co3[1]; - t2->oco3[0] = t->oco3[0]; t2->oco3[1] = t->oco3[1]; + for (v = chart->verts; v; v = v->nextlink) + if (!p_node_intersect(root, v->uv)) + param_warning("area smoothing error: couldn't find mapping triangle\n"); - *trip = t; trip++; t++; - *trip = t; trip++; t++; - } - } + p_node_delete(root); + BLI_memarena_free(arena); - MEM_freeN(nodes); - MEM_freeN(nodesx); - MEM_freeN(nodesy); - - arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param smooth arena"); - root = p_node_new(arena, tri, esize * 2, minv, maxv, 0); - - for (v = chart->verts; v; v = v->nextlink) - if (!p_node_intersect(root, v->uv)) - param_warning("area smoothing error: couldn't find mapping triangle\n"); - - p_node_delete(root); - BLI_memarena_free(arena); - - MEM_freeN(triangles); + MEM_freeN(triangles); } /* Exported */ ParamHandle *param_construct_begin(void) { - PHandle *handle = MEM_callocN(sizeof(*handle), "PHandle"); - handle->construction_chart = p_chart_new(handle); - handle->state = PHANDLE_STATE_ALLOCATED; - handle->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param construct arena"); - handle->polyfill_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "param polyfill arena"); - handle->polyfill_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); - handle->aspx = 1.0f; - handle->aspy = 1.0f; - handle->do_aspect = false; + PHandle *handle = MEM_callocN(sizeof(*handle), "PHandle"); + handle->construction_chart = p_chart_new(handle); + handle->state = PHANDLE_STATE_ALLOCATED; + handle->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param construct arena"); + handle->polyfill_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "param polyfill arena"); + handle->polyfill_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); + handle->aspx = 1.0f; + handle->aspy = 1.0f; + handle->do_aspect = false; - handle->hash_verts = phash_new((PHashLink **)&handle->construction_chart->verts, 1); - handle->hash_edges = phash_new((PHashLink **)&handle->construction_chart->edges, 1); - handle->hash_faces = phash_new((PHashLink **)&handle->construction_chart->faces, 1); + handle->hash_verts = phash_new((PHashLink **)&handle->construction_chart->verts, 1); + handle->hash_edges = phash_new((PHashLink **)&handle->construction_chart->edges, 1); + handle->hash_faces = phash_new((PHashLink **)&handle->construction_chart->faces, 1); - return (ParamHandle *)handle; + return (ParamHandle *)handle; } void param_aspect_ratio(ParamHandle *handle, float aspx, float aspy) { - PHandle *phandle = (PHandle *)handle; + PHandle *phandle = (PHandle *)handle; - phandle->aspx = aspx; - phandle->aspy = aspy; - phandle->do_aspect = true; + phandle->aspx = aspx; + phandle->aspy = aspy; + phandle->do_aspect = true; } void param_delete(ParamHandle *handle) { - PHandle *phandle = (PHandle *)handle; - int i; - - param_assert((phandle->state == PHANDLE_STATE_ALLOCATED) || - (phandle->state == PHANDLE_STATE_CONSTRUCTED)); - - for (i = 0; i < phandle->ncharts; i++) - p_chart_delete(phandle->charts[i]); - - if (phandle->charts) - MEM_freeN(phandle->charts); - - if (phandle->construction_chart) { - p_chart_delete(phandle->construction_chart); - - phash_delete(phandle->hash_verts); - phash_delete(phandle->hash_edges); - phash_delete(phandle->hash_faces); - } - - BLI_memarena_free(phandle->arena); - BLI_memarena_free(phandle->polyfill_arena); - BLI_heap_free(phandle->polyfill_heap, NULL); - MEM_freeN(phandle); -} - -static void p_add_ngon(ParamHandle *handle, ParamKey key, int nverts, - ParamKey *vkeys, float **co, float **uv, - ParamBool *pin, ParamBool *select) -{ - /* Allocate memory for polyfill. */ - PHandle *phandle = (PHandle *)handle; - MemArena *arena = phandle->polyfill_arena; - Heap *heap = phandle->polyfill_heap; - unsigned int nfilltri = nverts - 2; - unsigned int (*tris)[3] = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri); - float (*projverts)[2] = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)nverts); - - /* Calc normal, flipped: to get a positive 2d cross product. */ - float normal[3]; - zero_v3(normal); - - const float *co_curr, *co_prev = co[nverts - 1]; - for (int j = 0; j < nverts; j++) { - co_curr = co[j]; - add_newell_cross_v3_v3v3(normal, co_prev, co_curr); - co_prev = co_curr; - } - if (UNLIKELY(normalize_v3(normal) == 0.0f)) { - normal[2] = 1.0f; - } - - /* Project verts to 2d. */ - float axis_mat[3][3]; - axis_dominant_v3_to_m3_negate(axis_mat, normal); - for (int j = 0; j < nverts; j++) { - mul_v2_m3v3(projverts[j], axis_mat, co[j]); - } - - BLI_polyfill_calc_arena(projverts, nverts, 1, tris, arena); - - /* Beautify helps avoid thin triangles that give numerical problems. */ - BLI_polyfill_beautify(projverts, nverts, tris, arena, heap); - - /* Add triangles. */ - for (int j = 0; j < nfilltri; j++) { - unsigned int *tri = tris[j]; - unsigned int v0 = tri[0]; - unsigned int v1 = tri[1]; - unsigned int v2 = tri[2]; - - ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]}; - float *tri_co[3] = {co[v0], co[v1], co[v2]}; - float *tri_uv[3] = {uv[v0], uv[v1], uv[v2]}; - ParamBool tri_pin[3] = {pin[v0], pin[v1], pin[v2]}; - ParamBool tri_select[3] = {select[v0], select[v1], select[v2]}; - - param_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select); - } - - BLI_memarena_clear(arena); -} - -void param_face_add(ParamHandle *handle, ParamKey key, int nverts, - ParamKey *vkeys, float *co[4], float *uv[4], - ParamBool *pin, ParamBool *select) -{ - PHandle *phandle = (PHandle *)handle; - - param_assert(phash_lookup(phandle->hash_faces, key) == NULL); - param_assert(phandle->state == PHANDLE_STATE_ALLOCATED); - param_assert((nverts == 3) || (nverts == 4)); - - if (nverts > 4) { - /* ngon */ - p_add_ngon(handle, key, nverts, vkeys, co, uv, pin, select); - } - else if (nverts == 4) { - /* quad */ - if (p_quad_split_direction(phandle, co, vkeys)) { - p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select); - p_face_add_construct(phandle, key, vkeys, co, uv, 0, 2, 3, pin, select); - } - else { - p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 3, pin, select); - p_face_add_construct(phandle, key, vkeys, co, uv, 1, 2, 3, pin, select); - } - } - else if (!p_face_exists(phandle, vkeys, 0, 1, 2)) { - /* triangle */ - p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select); - } + PHandle *phandle = (PHandle *)handle; + int i; + + param_assert((phandle->state == PHANDLE_STATE_ALLOCATED) || + (phandle->state == PHANDLE_STATE_CONSTRUCTED)); + + for (i = 0; i < phandle->ncharts; i++) + p_chart_delete(phandle->charts[i]); + + if (phandle->charts) + MEM_freeN(phandle->charts); + + if (phandle->construction_chart) { + p_chart_delete(phandle->construction_chart); + + phash_delete(phandle->hash_verts); + phash_delete(phandle->hash_edges); + phash_delete(phandle->hash_faces); + } + + BLI_memarena_free(phandle->arena); + BLI_memarena_free(phandle->polyfill_arena); + BLI_heap_free(phandle->polyfill_heap, NULL); + MEM_freeN(phandle); +} + +static void p_add_ngon(ParamHandle *handle, + ParamKey key, + int nverts, + ParamKey *vkeys, + float **co, + float **uv, + ParamBool *pin, + ParamBool *select) +{ + /* Allocate memory for polyfill. */ + PHandle *phandle = (PHandle *)handle; + MemArena *arena = phandle->polyfill_arena; + Heap *heap = phandle->polyfill_heap; + unsigned int nfilltri = nverts - 2; + unsigned int(*tris)[3] = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri); + float(*projverts)[2] = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)nverts); + + /* Calc normal, flipped: to get a positive 2d cross product. */ + float normal[3]; + zero_v3(normal); + + const float *co_curr, *co_prev = co[nverts - 1]; + for (int j = 0; j < nverts; j++) { + co_curr = co[j]; + add_newell_cross_v3_v3v3(normal, co_prev, co_curr); + co_prev = co_curr; + } + if (UNLIKELY(normalize_v3(normal) == 0.0f)) { + normal[2] = 1.0f; + } + + /* Project verts to 2d. */ + float axis_mat[3][3]; + axis_dominant_v3_to_m3_negate(axis_mat, normal); + for (int j = 0; j < nverts; j++) { + mul_v2_m3v3(projverts[j], axis_mat, co[j]); + } + + BLI_polyfill_calc_arena(projverts, nverts, 1, tris, arena); + + /* Beautify helps avoid thin triangles that give numerical problems. */ + BLI_polyfill_beautify(projverts, nverts, tris, arena, heap); + + /* Add triangles. */ + for (int j = 0; j < nfilltri; j++) { + unsigned int *tri = tris[j]; + unsigned int v0 = tri[0]; + unsigned int v1 = tri[1]; + unsigned int v2 = tri[2]; + + ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]}; + float *tri_co[3] = {co[v0], co[v1], co[v2]}; + float *tri_uv[3] = {uv[v0], uv[v1], uv[v2]}; + ParamBool tri_pin[3] = {pin[v0], pin[v1], pin[v2]}; + ParamBool tri_select[3] = {select[v0], select[v1], select[v2]}; + + param_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select); + } + + BLI_memarena_clear(arena); +} + +void param_face_add(ParamHandle *handle, + ParamKey key, + int nverts, + ParamKey *vkeys, + float *co[4], + float *uv[4], + ParamBool *pin, + ParamBool *select) +{ + PHandle *phandle = (PHandle *)handle; + + param_assert(phash_lookup(phandle->hash_faces, key) == NULL); + param_assert(phandle->state == PHANDLE_STATE_ALLOCATED); + param_assert((nverts == 3) || (nverts == 4)); + + if (nverts > 4) { + /* ngon */ + p_add_ngon(handle, key, nverts, vkeys, co, uv, pin, select); + } + else if (nverts == 4) { + /* quad */ + if (p_quad_split_direction(phandle, co, vkeys)) { + p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select); + p_face_add_construct(phandle, key, vkeys, co, uv, 0, 2, 3, pin, select); + } + else { + p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 3, pin, select); + p_face_add_construct(phandle, key, vkeys, co, uv, 1, 2, 3, pin, select); + } + } + else if (!p_face_exists(phandle, vkeys, 0, 1, 2)) { + /* triangle */ + p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select); + } } void param_edge_set_seam(ParamHandle *handle, ParamKey *vkeys) { - PHandle *phandle = (PHandle *)handle; - PEdge *e; + PHandle *phandle = (PHandle *)handle; + PEdge *e; - param_assert(phandle->state == PHANDLE_STATE_ALLOCATED); + param_assert(phandle->state == PHANDLE_STATE_ALLOCATED); - e = p_edge_lookup(phandle, vkeys); - if (e) - e->flag |= PEDGE_SEAM; + e = p_edge_lookup(phandle, vkeys); + if (e) + e->flag |= PEDGE_SEAM; } void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl) { - PHandle *phandle = (PHandle *)handle; - PChart *chart = phandle->construction_chart; - int i, j, nboundaries = 0; - PEdge *outer; + PHandle *phandle = (PHandle *)handle; + PChart *chart = phandle->construction_chart; + int i, j, nboundaries = 0; + PEdge *outer; - param_assert(phandle->state == PHANDLE_STATE_ALLOCATED); + param_assert(phandle->state == PHANDLE_STATE_ALLOCATED); - phandle->ncharts = p_connect_pairs(phandle, (PBool)impl); - phandle->charts = p_split_charts(phandle, chart, phandle->ncharts); + phandle->ncharts = p_connect_pairs(phandle, (PBool)impl); + phandle->charts = p_split_charts(phandle, chart, phandle->ncharts); - p_chart_delete(phandle->construction_chart); - phandle->construction_chart = NULL; + p_chart_delete(phandle->construction_chart); + phandle->construction_chart = NULL; - phash_delete(phandle->hash_verts); - phash_delete(phandle->hash_edges); - phash_delete(phandle->hash_faces); - phandle->hash_verts = phandle->hash_edges = phandle->hash_faces = NULL; + phash_delete(phandle->hash_verts); + phash_delete(phandle->hash_edges); + phash_delete(phandle->hash_faces); + phandle->hash_verts = phandle->hash_edges = phandle->hash_faces = NULL; - for (i = j = 0; i < phandle->ncharts; i++) { - PVert *v; - chart = phandle->charts[i]; + for (i = j = 0; i < phandle->ncharts; i++) { + PVert *v; + chart = phandle->charts[i]; - p_chart_boundaries(chart, &nboundaries, &outer); + p_chart_boundaries(chart, &nboundaries, &outer); - if (!impl && nboundaries == 0) { - p_chart_delete(chart); - continue; - } + if (!impl && nboundaries == 0) { + p_chart_delete(chart); + continue; + } - phandle->charts[j] = chart; - j++; + phandle->charts[j] = chart; + j++; - if (fill && (nboundaries > 1)) - p_chart_fill_boundaries(chart, outer); + if (fill && (nboundaries > 1)) + p_chart_fill_boundaries(chart, outer); - for (v = chart->verts; v; v = v->nextlink) - p_vert_load_pin_select_uvs(handle, v); - } + for (v = chart->verts; v; v = v->nextlink) + p_vert_load_pin_select_uvs(handle, v); + } - phandle->ncharts = j; + phandle->ncharts = j; - phandle->state = PHANDLE_STATE_CONSTRUCTED; + phandle->state = PHANDLE_STATE_CONSTRUCTED; } void param_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf) { - PHandle *phandle = (PHandle *)handle; - PFace *f; - int i; + PHandle *phandle = (PHandle *)handle; + PFace *f; + int i; - param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED); - phandle->state = PHANDLE_STATE_LSCM; + param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED); + phandle->state = PHANDLE_STATE_LSCM; - for (i = 0; i < phandle->ncharts; i++) { - for (f = phandle->charts[i]->faces; f; f = f->nextlink) - p_face_backup_uvs(f); - p_chart_lscm_begin(phandle->charts[i], (PBool)live, (PBool)abf); - } + for (i = 0; i < phandle->ncharts; i++) { + for (f = phandle->charts[i]->faces; f; f = f->nextlink) + p_face_backup_uvs(f); + p_chart_lscm_begin(phandle->charts[i], (PBool)live, (PBool)abf); + } } void param_lscm_solve(ParamHandle *handle) { - PHandle *phandle = (PHandle *)handle; - PChart *chart; - int i; - PBool result; + PHandle *phandle = (PHandle *)handle; + PChart *chart; + int i; + PBool result; - param_assert(phandle->state == PHANDLE_STATE_LSCM); + param_assert(phandle->state == PHANDLE_STATE_LSCM); - for (i = 0; i < phandle->ncharts; i++) { - chart = phandle->charts[i]; + for (i = 0; i < phandle->ncharts; i++) { + chart = phandle->charts[i]; - if (chart->u.lscm.context) { - result = p_chart_lscm_solve(phandle, chart); + if (chart->u.lscm.context) { + result = p_chart_lscm_solve(phandle, chart); - if (result && !(chart->flag & PCHART_HAS_PINS)) - p_chart_rotate_minimum_area(chart); + if (result && !(chart->flag & PCHART_HAS_PINS)) + p_chart_rotate_minimum_area(chart); - if (!result || (chart->u.lscm.pin1)) - p_chart_lscm_end(chart); - } - } + if (!result || (chart->u.lscm.pin1)) + p_chart_lscm_end(chart); + } + } } void param_lscm_end(ParamHandle *handle) { - PHandle *phandle = (PHandle *)handle; - int i; + PHandle *phandle = (PHandle *)handle; + int i; - param_assert(phandle->state == PHANDLE_STATE_LSCM); + param_assert(phandle->state == PHANDLE_STATE_LSCM); - for (i = 0; i < phandle->ncharts; i++) { - p_chart_lscm_end(phandle->charts[i]); + for (i = 0; i < phandle->ncharts; i++) { + p_chart_lscm_end(phandle->charts[i]); #if 0 - p_chart_complexify(phandle->charts[i]); + p_chart_complexify(phandle->charts[i]); #endif - } + } - phandle->state = PHANDLE_STATE_CONSTRUCTED; + phandle->state = PHANDLE_STATE_CONSTRUCTED; } void param_stretch_begin(ParamHandle *handle) { - PHandle *phandle = (PHandle *)handle; - PChart *chart; - PVert *v; - PFace *f; - int i; + PHandle *phandle = (PHandle *)handle; + PChart *chart; + PVert *v; + PFace *f; + int i; - param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED); - phandle->state = PHANDLE_STATE_STRETCH; + param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED); + phandle->state = PHANDLE_STATE_STRETCH; - phandle->rng = BLI_rng_new(31415926); - phandle->blend = 0.0f; + phandle->rng = BLI_rng_new(31415926); + phandle->blend = 0.0f; - for (i = 0; i < phandle->ncharts; i++) { - chart = phandle->charts[i]; + for (i = 0; i < phandle->ncharts; i++) { + chart = phandle->charts[i]; - for (v = chart->verts; v; v = v->nextlink) - v->flag &= ~PVERT_PIN; /* don't use user-defined pins */ + for (v = chart->verts; v; v = v->nextlink) + v->flag &= ~PVERT_PIN; /* don't use user-defined pins */ - p_stretch_pin_boundary(chart); + p_stretch_pin_boundary(chart); - for (f = chart->faces; f; f = f->nextlink) { - p_face_backup_uvs(f); - f->u.area3d = p_face_area(f); - } - } + for (f = chart->faces; f; f = f->nextlink) { + p_face_backup_uvs(f); + f->u.area3d = p_face_area(f); + } + } } void param_stretch_blend(ParamHandle *handle, float blend) { - PHandle *phandle = (PHandle *)handle; + PHandle *phandle = (PHandle *)handle; - param_assert(phandle->state == PHANDLE_STATE_STRETCH); - phandle->blend = blend; + param_assert(phandle->state == PHANDLE_STATE_STRETCH); + phandle->blend = blend; } void param_stretch_iter(ParamHandle *handle) { - PHandle *phandle = (PHandle *)handle; - PChart *chart; - int i; + PHandle *phandle = (PHandle *)handle; + PChart *chart; + int i; - param_assert(phandle->state == PHANDLE_STATE_STRETCH); + param_assert(phandle->state == PHANDLE_STATE_STRETCH); - for (i = 0; i < phandle->ncharts; i++) { - chart = phandle->charts[i]; - p_chart_stretch_minimize(chart, phandle->rng); - } + for (i = 0; i < phandle->ncharts; i++) { + chart = phandle->charts[i]; + p_chart_stretch_minimize(chart, phandle->rng); + } } void param_stretch_end(ParamHandle *handle) { - PHandle *phandle = (PHandle *)handle; + PHandle *phandle = (PHandle *)handle; - param_assert(phandle->state == PHANDLE_STATE_STRETCH); - phandle->state = PHANDLE_STATE_CONSTRUCTED; + param_assert(phandle->state == PHANDLE_STATE_STRETCH); + phandle->state = PHANDLE_STATE_CONSTRUCTED; - BLI_rng_free(phandle->rng); - phandle->rng = NULL; + BLI_rng_free(phandle->rng); + phandle->rng = NULL; } void param_smooth_area(ParamHandle *handle) { - PHandle *phandle = (PHandle *)handle; - int i; + PHandle *phandle = (PHandle *)handle; + int i; - param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED); + param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED); - for (i = 0; i < phandle->ncharts; i++) { - PChart *chart = phandle->charts[i]; - PVert *v; + for (i = 0; i < phandle->ncharts; i++) { + PChart *chart = phandle->charts[i]; + PVert *v; - for (v = chart->verts; v; v = v->nextlink) - v->flag &= ~PVERT_PIN; + for (v = chart->verts; v; v = v->nextlink) + v->flag &= ~PVERT_PIN; - p_smooth(chart); - } + p_smooth(chart); + } } /* don't pack, just rotate (used for better packing) */ static void param_pack_rotate(ParamHandle *handle, bool ignore_pinned) { - PChart *chart; - int i; + PChart *chart; + int i; - PHandle *phandle = (PHandle *)handle; + PHandle *phandle = (PHandle *)handle; - for (i = 0; i < phandle->ncharts; i++) { - float (*points)[2]; - float angle; + for (i = 0; i < phandle->ncharts; i++) { + float(*points)[2]; + float angle; - chart = phandle->charts[i]; + chart = phandle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { - continue; - } + if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + continue; + } - points = MEM_mallocN(sizeof(*points) * chart->nverts, __func__); + points = MEM_mallocN(sizeof(*points) * chart->nverts, __func__); - p_chart_uv_to_array(chart, points); + p_chart_uv_to_array(chart, points); - angle = BLI_convexhull_aabb_fit_points_2d(points, chart->nverts); + angle = BLI_convexhull_aabb_fit_points_2d(points, chart->nverts); - MEM_freeN(points); + MEM_freeN(points); - if (angle != 0.0f) { - float mat[2][2]; - angle_to_mat2(mat, angle); - p_chart_uv_transform(chart, mat); - } - } + if (angle != 0.0f) { + float mat[2][2]; + angle_to_mat2(mat, angle); + p_chart_uv_transform(chart, mat); + } + } } void param_pack(ParamHandle *handle, float margin, bool do_rotate, bool ignore_pinned) { - /* box packing variables */ - BoxPack *boxarray, *box; - float tot_width, tot_height, scale; - - PChart *chart; - int i, unpacked = 0; - float trans[2]; - double area = 0.0; + /* box packing variables */ + BoxPack *boxarray, *box; + float tot_width, tot_height, scale; - PHandle *phandle = (PHandle *)handle; + PChart *chart; + int i, unpacked = 0; + float trans[2]; + double area = 0.0; - if (phandle->ncharts == 0) - return; + PHandle *phandle = (PHandle *)handle; - /* this could be its own function */ - if (do_rotate) { - param_pack_rotate(handle, ignore_pinned); - } + if (phandle->ncharts == 0) + return; - if (phandle->aspx != phandle->aspy) - param_scale(handle, 1.0f / phandle->aspx, 1.0f / phandle->aspy); + /* this could be its own function */ + if (do_rotate) { + param_pack_rotate(handle, ignore_pinned); + } - /* we may not use all these boxes */ - boxarray = MEM_mallocN(phandle->ncharts * sizeof(BoxPack), "BoxPack box"); + if (phandle->aspx != phandle->aspy) + param_scale(handle, 1.0f / phandle->aspx, 1.0f / phandle->aspy); + /* we may not use all these boxes */ + boxarray = MEM_mallocN(phandle->ncharts * sizeof(BoxPack), "BoxPack box"); - for (i = 0; i < phandle->ncharts; i++) { - chart = phandle->charts[i]; + for (i = 0; i < phandle->ncharts; i++) { + chart = phandle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { - unpacked++; - continue; - } + if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + unpacked++; + continue; + } - box = boxarray + (i - unpacked); + box = boxarray + (i - unpacked); - p_chart_uv_bbox(chart, trans, chart->u.pack.size); + p_chart_uv_bbox(chart, trans, chart->u.pack.size); - trans[0] = -trans[0]; - trans[1] = -trans[1]; + trans[0] = -trans[0]; + trans[1] = -trans[1]; - p_chart_uv_translate(chart, trans); + p_chart_uv_translate(chart, trans); - box->w = chart->u.pack.size[0] + trans[0]; - box->h = chart->u.pack.size[1] + trans[1]; - box->index = i; /* warning this index skips PCHART_HAS_PINS boxes */ + box->w = chart->u.pack.size[0] + trans[0]; + box->h = chart->u.pack.size[1] + trans[1]; + box->index = i; /* warning this index skips PCHART_HAS_PINS boxes */ - if (margin > 0.0f) - area += (double)sqrtf(box->w * box->h); - } + if (margin > 0.0f) + area += (double)sqrtf(box->w * box->h); + } - if (margin > 0.0f) { - /* multiply the margin by the area to give predictable results not dependent on UV scale, - * ...Without using the area running pack multiple times also gives a bad feedback loop. - * multiply by 0.1 so the margin value from the UI can be from - * 0.0 to 1.0 but not give a massive margin */ - margin = (margin * (float)area) * 0.1f; - unpacked = 0; - for (i = 0; i < phandle->ncharts; i++) { - chart = phandle->charts[i]; + if (margin > 0.0f) { + /* multiply the margin by the area to give predictable results not dependent on UV scale, + * ...Without using the area running pack multiple times also gives a bad feedback loop. + * multiply by 0.1 so the margin value from the UI can be from + * 0.0 to 1.0 but not give a massive margin */ + margin = (margin * (float)area) * 0.1f; + unpacked = 0; + for (i = 0; i < phandle->ncharts; i++) { + chart = phandle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { - unpacked++; - continue; - } + if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + unpacked++; + continue; + } - box = boxarray + (i - unpacked); - trans[0] = margin; - trans[1] = margin; - p_chart_uv_translate(chart, trans); - box->w += margin * 2; - box->h += margin * 2; - } - } + box = boxarray + (i - unpacked); + trans[0] = margin; + trans[1] = margin; + p_chart_uv_translate(chart, trans); + box->w += margin * 2; + box->h += margin * 2; + } + } - BLI_box_pack_2d(boxarray, phandle->ncharts - unpacked, &tot_width, &tot_height); + BLI_box_pack_2d(boxarray, phandle->ncharts - unpacked, &tot_width, &tot_height); - if (tot_height > tot_width) - scale = 1.0f / tot_height; - else - scale = 1.0f / tot_width; + if (tot_height > tot_width) + scale = 1.0f / tot_height; + else + scale = 1.0f / tot_width; - for (i = 0; i < phandle->ncharts - unpacked; i++) { - box = boxarray + i; - trans[0] = box->x; - trans[1] = box->y; + for (i = 0; i < phandle->ncharts - unpacked; i++) { + box = boxarray + i; + trans[0] = box->x; + trans[1] = box->y; - chart = phandle->charts[box->index]; - p_chart_uv_translate(chart, trans); - p_chart_uv_scale(chart, scale); - } - MEM_freeN(boxarray); + chart = phandle->charts[box->index]; + p_chart_uv_translate(chart, trans); + p_chart_uv_scale(chart, scale); + } + MEM_freeN(boxarray); - if (phandle->aspx != phandle->aspy) - param_scale(handle, phandle->aspx, phandle->aspy); + if (phandle->aspx != phandle->aspy) + param_scale(handle, phandle->aspx, phandle->aspy); } void param_average(ParamHandle *handle, bool ignore_pinned) { - PChart *chart; - int i; - float tot_uvarea = 0.0f, tot_facearea = 0.0f; - float tot_fac, fac; - float minv[2], maxv[2], trans[2]; - PHandle *phandle = (PHandle *)handle; + PChart *chart; + int i; + float tot_uvarea = 0.0f, tot_facearea = 0.0f; + float tot_fac, fac; + float minv[2], maxv[2], trans[2]; + PHandle *phandle = (PHandle *)handle; - if (phandle->ncharts == 0) - return; + if (phandle->ncharts == 0) + return; - for (i = 0; i < phandle->ncharts; i++) { - PFace *f; - chart = phandle->charts[i]; + for (i = 0; i < phandle->ncharts; i++) { + PFace *f; + chart = phandle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { - continue; - } + if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + continue; + } - chart->u.pack.area = 0.0f; /* 3d area */ - chart->u.pack.rescale = 0.0f; /* UV area, abusing rescale for tmp storage, oh well :/ */ + chart->u.pack.area = 0.0f; /* 3d area */ + chart->u.pack.rescale = 0.0f; /* UV area, abusing rescale for tmp storage, oh well :/ */ - for (f = chart->faces; f; f = f->nextlink) { - chart->u.pack.area += p_face_area(f); - chart->u.pack.rescale += fabsf(p_face_uv_area_signed(f)); - } + for (f = chart->faces; f; f = f->nextlink) { + chart->u.pack.area += p_face_area(f); + chart->u.pack.rescale += fabsf(p_face_uv_area_signed(f)); + } - tot_facearea += chart->u.pack.area; - tot_uvarea += chart->u.pack.rescale; - } + tot_facearea += chart->u.pack.area; + tot_uvarea += chart->u.pack.rescale; + } - if (tot_facearea == tot_uvarea || tot_facearea == 0.0f || tot_uvarea == 0.0f) { - /* nothing to do */ - return; - } + if (tot_facearea == tot_uvarea || tot_facearea == 0.0f || tot_uvarea == 0.0f) { + /* nothing to do */ + return; + } - tot_fac = tot_facearea / tot_uvarea; + tot_fac = tot_facearea / tot_uvarea; - for (i = 0; i < phandle->ncharts; i++) { - chart = phandle->charts[i]; + for (i = 0; i < phandle->ncharts; i++) { + chart = phandle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { - continue; - } + if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + continue; + } - if (chart->u.pack.area != 0.0f && chart->u.pack.rescale != 0.0f) { - fac = chart->u.pack.area / chart->u.pack.rescale; + if (chart->u.pack.area != 0.0f && chart->u.pack.rescale != 0.0f) { + fac = chart->u.pack.area / chart->u.pack.rescale; - /* Get the island center */ - p_chart_uv_bbox(chart, minv, maxv); - trans[0] = (minv[0] + maxv[0]) / -2.0f; - trans[1] = (minv[1] + maxv[1]) / -2.0f; + /* Get the island center */ + p_chart_uv_bbox(chart, minv, maxv); + trans[0] = (minv[0] + maxv[0]) / -2.0f; + trans[1] = (minv[1] + maxv[1]) / -2.0f; - /* Move center to 0,0 */ - p_chart_uv_translate(chart, trans); - p_chart_uv_scale(chart, sqrtf(fac / tot_fac)); + /* Move center to 0,0 */ + p_chart_uv_translate(chart, trans); + p_chart_uv_scale(chart, sqrtf(fac / tot_fac)); - /* Move to original center */ - trans[0] = -trans[0]; - trans[1] = -trans[1]; - p_chart_uv_translate(chart, trans); - } - } + /* Move to original center */ + trans[0] = -trans[0]; + trans[1] = -trans[1]; + p_chart_uv_translate(chart, trans); + } + } } void param_scale(ParamHandle *handle, float x, float y) { - PHandle *phandle = (PHandle *)handle; - PChart *chart; - int i; + PHandle *phandle = (PHandle *)handle; + PChart *chart; + int i; - for (i = 0; i < phandle->ncharts; i++) { - chart = phandle->charts[i]; - p_chart_uv_scale_xy(chart, x, y); - } + for (i = 0; i < phandle->ncharts; i++) { + chart = phandle->charts[i]; + p_chart_uv_scale_xy(chart, x, y); + } } void param_flush(ParamHandle *handle) { - PHandle *phandle = (PHandle *)handle; - PChart *chart; - int i; + PHandle *phandle = (PHandle *)handle; + PChart *chart; + int i; - for (i = 0; i < phandle->ncharts; i++) { - chart = phandle->charts[i]; + for (i = 0; i < phandle->ncharts; i++) { + chart = phandle->charts[i]; - if ((phandle->state == PHANDLE_STATE_LSCM) && !chart->u.lscm.context) - continue; + if ((phandle->state == PHANDLE_STATE_LSCM) && !chart->u.lscm.context) + continue; - if (phandle->blend == 0.0f) - p_flush_uvs(phandle, chart); - else - p_flush_uvs_blend(phandle, chart, phandle->blend); - } + if (phandle->blend == 0.0f) + p_flush_uvs(phandle, chart); + else + p_flush_uvs_blend(phandle, chart, phandle->blend); + } } void param_flush_restore(ParamHandle *handle) { - PHandle *phandle = (PHandle *)handle; - PChart *chart; - PFace *f; - int i; + PHandle *phandle = (PHandle *)handle; + PChart *chart; + PFace *f; + int i; - for (i = 0; i < phandle->ncharts; i++) { - chart = phandle->charts[i]; + for (i = 0; i < phandle->ncharts; i++) { + chart = phandle->charts[i]; - for (f = chart->faces; f; f = f->nextlink) - p_face_restore_uvs(f); - } + for (f = chart->faces; f; f = f->nextlink) + p_face_restore_uvs(f); + } } diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.h b/source/blender/editors/uvedit/uvedit_parametrizer.h index 6724b568f57..2b80241e6e3 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.h +++ b/source/blender/editors/uvedit/uvedit_parametrizer.h @@ -25,13 +25,13 @@ extern "C" { #endif -#include "BLI_sys_types.h" // for intptr_t support +#include "BLI_sys_types.h" // for intptr_t support -typedef void ParamHandle; /* handle to a set of charts */ -typedef intptr_t ParamKey; /* (hash) key for identifying verts and faces */ +typedef void ParamHandle; /* handle to a set of charts */ +typedef intptr_t ParamKey; /* (hash) key for identifying verts and faces */ typedef enum ParamBool { - PARAM_TRUE = 1, - PARAM_FALSE = 0, + PARAM_TRUE = 1, + PARAM_FALSE = 0, } ParamBool; /* Chart construction: @@ -58,8 +58,7 @@ void param_face_add(ParamHandle *handle, ParamBool *pin, ParamBool *select); -void param_edge_set_seam(ParamHandle *handle, - ParamKey *vkeys); +void param_edge_set_seam(ParamHandle *handle, ParamKey *vkeys); void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl); void param_delete(ParamHandle *chart); @@ -107,7 +106,6 @@ void param_scale(ParamHandle *handle, float x, float y); void param_flush(ParamHandle *handle); void param_flush_restore(ParamHandle *handle); - #ifdef __cplusplus } #endif diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 91167e247f4..71a3fdf055e 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -21,7 +21,6 @@ * \ingroup eduv */ - #include <stdlib.h> #include <string.h> #include <math.h> @@ -73,26 +72,25 @@ /* object that stores display data for previewing before confirming stitching */ typedef struct StitchPreviewer { - /* here we'll store the preview triangle indices of the mesh */ - float *preview_polys; - /* uvs per polygon. */ - unsigned int *uvs_per_polygon; - /*number of preview polygons */ - unsigned int num_polys; - /* preview data. These will be either the previewed vertices or edges - * depending on stitch mode settings */ - float *preview_stitchable; - float *preview_unstitchable; - /* here we'll store the number of elements to be drawn */ - unsigned int num_stitchable; - unsigned int num_unstitchable; - unsigned int preview_uvs; - /* ...and here we'll store the static island triangles */ - float *static_tris; - unsigned int num_static_tris; + /* here we'll store the preview triangle indices of the mesh */ + float *preview_polys; + /* uvs per polygon. */ + unsigned int *uvs_per_polygon; + /*number of preview polygons */ + unsigned int num_polys; + /* preview data. These will be either the previewed vertices or edges + * depending on stitch mode settings */ + float *preview_stitchable; + float *preview_unstitchable; + /* here we'll store the number of elements to be drawn */ + unsigned int num_stitchable; + unsigned int num_unstitchable; + unsigned int preview_uvs; + /* ...and here we'll store the static island triangles */ + float *static_tris; + unsigned int num_static_tris; } StitchPreviewer; - struct IslandStitchData; /** @@ -101,115 +99,114 @@ struct IslandStitchData; * elements of the island except from the stitchable. */ typedef struct IslandStitchData { - /* rotation can be used only for edges, for vertices there is no such notion */ - float rotation; - float rotation_neg; - float translation[2]; - /* Used for rotation, the island will rotate around this point */ - float medianPoint[2]; - int numOfElements; - int num_rot_elements; - int num_rot_elements_neg; - /* flag to remember if island has been added for preview */ - char addedForPreview; - /* flag an island to be considered for determining static island */ - char stitchableCandidate; - /* if edge rotation is used, flag so that vertex rotation is not used */ - bool use_edge_rotation; + /* rotation can be used only for edges, for vertices there is no such notion */ + float rotation; + float rotation_neg; + float translation[2]; + /* Used for rotation, the island will rotate around this point */ + float medianPoint[2]; + int numOfElements; + int num_rot_elements; + int num_rot_elements_neg; + /* flag to remember if island has been added for preview */ + char addedForPreview; + /* flag an island to be considered for determining static island */ + char stitchableCandidate; + /* if edge rotation is used, flag so that vertex rotation is not used */ + bool use_edge_rotation; } IslandStitchData; /* just for averaging UVs */ typedef struct UVVertAverage { - float uv[2]; - unsigned short count; + float uv[2]; + unsigned short count; } UVVertAverage; typedef struct UvEdge { - /** index to uv buffer */ - unsigned int uv1; - unsigned int uv2; - /** general use flag - * (Used to check if edge is boundary here, and propagates to adjacency elements) */ - unsigned char flag; - /** element that guarantees element->face - * has the edge on element->tfindex and element->tfindex+1 is the second uv */ - UvElement *element; - /** next uv edge with the same exact vertices as this one. - * Calculated at startup to save time */ - struct UvEdge *next; - /** point to first of common edges. Needed for iteration */ - struct UvEdge *first; + /** index to uv buffer */ + unsigned int uv1; + unsigned int uv2; + /** general use flag + * (Used to check if edge is boundary here, and propagates to adjacency elements) */ + unsigned char flag; + /** element that guarantees element->face + * has the edge on element->tfindex and element->tfindex+1 is the second uv */ + UvElement *element; + /** next uv edge with the same exact vertices as this one. + * Calculated at startup to save time */ + struct UvEdge *next; + /** point to first of common edges. Needed for iteration */ + struct UvEdge *first; } UvEdge; - /* stitch state object */ typedef struct StitchState { - float aspect; - /* object for editmesh */ - Object *obedit; - /* editmesh, cached for use in modal handler */ - BMEditMesh *em; - - /* element map for getting info about uv connectivity */ - UvElementMap *element_map; - /* edge container */ - UvEdge *uvedges; - /* container of first of a group of coincident uvs, these will be operated upon */ - UvElement **uvs; - /* maps uvelements to their first coincident uv */ - int *map; - /* 2D normals per uv to calculate rotation for snapping */ - float *normals; - /* edge storage */ - UvEdge *edges; - /* hash for quick lookup of edges */ - GHash *edge_hash; - /* which islands to stop at (to make active) when pressing 'I' */ - bool *island_is_stitchable; - - /* count of separate uvs and edges */ - int total_separate_edges; - int total_separate_uvs; - /* hold selection related information */ - void **selection_stack; - int selection_size; - - /* store number of primitives per face so that we can allocate the active island buffer later */ - unsigned int *tris_per_island; - /* preview data */ - StitchPreviewer *stitch_preview; + float aspect; + /* object for editmesh */ + Object *obedit; + /* editmesh, cached for use in modal handler */ + BMEditMesh *em; + + /* element map for getting info about uv connectivity */ + UvElementMap *element_map; + /* edge container */ + UvEdge *uvedges; + /* container of first of a group of coincident uvs, these will be operated upon */ + UvElement **uvs; + /* maps uvelements to their first coincident uv */ + int *map; + /* 2D normals per uv to calculate rotation for snapping */ + float *normals; + /* edge storage */ + UvEdge *edges; + /* hash for quick lookup of edges */ + GHash *edge_hash; + /* which islands to stop at (to make active) when pressing 'I' */ + bool *island_is_stitchable; + + /* count of separate uvs and edges */ + int total_separate_edges; + int total_separate_uvs; + /* hold selection related information */ + void **selection_stack; + int selection_size; + + /* store number of primitives per face so that we can allocate the active island buffer later */ + unsigned int *tris_per_island; + /* preview data */ + StitchPreviewer *stitch_preview; } StitchState; /* Stitch state container. */ typedef struct StitchStateContainer { - /* clear seams of stitched edges after stitch */ - bool clear_seams; - /* use limit flag */ - bool use_limit; - /* limit to operator, same as original operator */ - float limit_dist; - /* snap uv islands together during stitching */ - bool snap_islands; - /* stitch at midpoints or at islands */ - bool midpoints; - /* vert or edge mode used for stitching */ - char mode; - /* handle for drawing */ - void *draw_handle; - /* island that stays in place */ - int static_island; - - /* Objects and states are aligned. */ - int objects_len; - Object **objects; - StitchState **states; - - int active_object_index; + /* clear seams of stitched edges after stitch */ + bool clear_seams; + /* use limit flag */ + bool use_limit; + /* limit to operator, same as original operator */ + float limit_dist; + /* snap uv islands together during stitching */ + bool snap_islands; + /* stitch at midpoints or at islands */ + bool midpoints; + /* vert or edge mode used for stitching */ + char mode; + /* handle for drawing */ + void *draw_handle; + /* island that stays in place */ + int static_island; + + /* Objects and states are aligned. */ + int objects_len; + Object **objects; + StitchState **states; + + int active_object_index; } StitchStateContainer; typedef struct PreviewPosition { - int data_position; - int polycount_position; + int data_position; + int polycount_position; } PreviewPosition; /* * defines for UvElement/UcEdge flags @@ -223,2529 +220,2614 @@ typedef struct PreviewPosition { #define STITCH_NO_PREVIEW -1 enum StitchModes { - STITCH_VERT, - STITCH_EDGE, + STITCH_VERT, + STITCH_EDGE, }; /* UvElement identification. */ typedef struct UvElementID { - int faceIndex; - int elementIndex; + int faceIndex; + int elementIndex; } UvElementID; /* StitchState initializition. */ typedef struct StitchStateInit { - int uv_selected_count; - UvElementID *to_select; + int uv_selected_count; + UvElementID *to_select; } StitchStateInit; /* constructor */ static StitchPreviewer *stitch_preview_init(void) { - StitchPreviewer *stitch_preview; + StitchPreviewer *stitch_preview; - stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer"); - stitch_preview->preview_polys = NULL; - stitch_preview->preview_stitchable = NULL; - stitch_preview->preview_unstitchable = NULL; - stitch_preview->uvs_per_polygon = NULL; + stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer"); + stitch_preview->preview_polys = NULL; + stitch_preview->preview_stitchable = NULL; + stitch_preview->preview_unstitchable = NULL; + stitch_preview->uvs_per_polygon = NULL; - stitch_preview->preview_uvs = 0; - stitch_preview->num_polys = 0; - stitch_preview->num_stitchable = 0; - stitch_preview->num_unstitchable = 0; + stitch_preview->preview_uvs = 0; + stitch_preview->num_polys = 0; + stitch_preview->num_stitchable = 0; + stitch_preview->num_unstitchable = 0; - stitch_preview->static_tris = NULL; + stitch_preview->static_tris = NULL; - stitch_preview->num_static_tris = 0; + stitch_preview->num_static_tris = 0; - return stitch_preview; + return stitch_preview; } /* destructor...yeah this should be C++ :) */ static void stitch_preview_delete(StitchPreviewer *stitch_preview) { - if (stitch_preview) { - if (stitch_preview->preview_polys) { - MEM_freeN(stitch_preview->preview_polys); - stitch_preview->preview_polys = NULL; - } - if (stitch_preview->uvs_per_polygon) { - MEM_freeN(stitch_preview->uvs_per_polygon); - stitch_preview->uvs_per_polygon = NULL; - } - if (stitch_preview->preview_stitchable) { - MEM_freeN(stitch_preview->preview_stitchable); - stitch_preview->preview_stitchable = NULL; - } - if (stitch_preview->preview_unstitchable) { - MEM_freeN(stitch_preview->preview_unstitchable); - stitch_preview->preview_unstitchable = NULL; - } - if (stitch_preview->static_tris) { - MEM_freeN(stitch_preview->static_tris); - stitch_preview->static_tris = NULL; - } - MEM_freeN(stitch_preview); - } + if (stitch_preview) { + if (stitch_preview->preview_polys) { + MEM_freeN(stitch_preview->preview_polys); + stitch_preview->preview_polys = NULL; + } + if (stitch_preview->uvs_per_polygon) { + MEM_freeN(stitch_preview->uvs_per_polygon); + stitch_preview->uvs_per_polygon = NULL; + } + if (stitch_preview->preview_stitchable) { + MEM_freeN(stitch_preview->preview_stitchable); + stitch_preview->preview_stitchable = NULL; + } + if (stitch_preview->preview_unstitchable) { + MEM_freeN(stitch_preview->preview_unstitchable); + stitch_preview->preview_unstitchable = NULL; + } + if (stitch_preview->static_tris) { + MEM_freeN(stitch_preview->static_tris); + stitch_preview->static_tris = NULL; + } + MEM_freeN(stitch_preview); + } } /* This function updates the header of the UV editor when the stitch tool updates its settings */ static void stitch_update_header(StitchStateContainer *ssc, bContext *C) { - const char *str = IFACE_( - "Mode(TAB) %s, " - "(S)nap %s, " - "(M)idpoints %s, " - "(L)imit %.2f (Alt Wheel adjust) %s, " - "Switch (I)sland, " - "shift select vertices" - ); - - char msg[UI_MAX_DRAW_STR]; - ScrArea *sa = CTX_wm_area(C); - - if (sa) { - BLI_snprintf( - msg, sizeof(msg), str, - ssc->mode == STITCH_VERT ? IFACE_("Vertex") : IFACE_("Edge"), - WM_bool_as_string(ssc->snap_islands), - WM_bool_as_string(ssc->midpoints), - ssc->limit_dist, - WM_bool_as_string(ssc->use_limit)); - - ED_workspace_status_text(C, msg); - } + const char *str = IFACE_( + "Mode(TAB) %s, " + "(S)nap %s, " + "(M)idpoints %s, " + "(L)imit %.2f (Alt Wheel adjust) %s, " + "Switch (I)sland, " + "shift select vertices"); + + char msg[UI_MAX_DRAW_STR]; + ScrArea *sa = CTX_wm_area(C); + + if (sa) { + BLI_snprintf(msg, + sizeof(msg), + str, + ssc->mode == STITCH_VERT ? IFACE_("Vertex") : IFACE_("Edge"), + WM_bool_as_string(ssc->snap_islands), + WM_bool_as_string(ssc->midpoints), + ssc->limit_dist, + WM_bool_as_string(ssc->use_limit)); + + ED_workspace_status_text(C, msg); + } } static int getNumOfIslandUvs(UvElementMap *elementMap, int island) { - if (island == elementMap->totalIslands - 1) { - return elementMap->totalUVs - elementMap->islandIndices[island]; - } - else { - return elementMap->islandIndices[island + 1] - elementMap->islandIndices[island]; - } + if (island == elementMap->totalIslands - 1) { + return elementMap->totalUVs - elementMap->islandIndices[island]; + } + else { + return elementMap->islandIndices[island + 1] - elementMap->islandIndices[island]; + } } static void stitch_uv_rotate(float mat[2][2], float medianPoint[2], float uv[2], float aspect) { - float uv_rotation_result[2]; + float uv_rotation_result[2]; - uv[1] /= aspect; + uv[1] /= aspect; - sub_v2_v2(uv, medianPoint); - mul_v2_m2v2(uv_rotation_result, mat, uv); - add_v2_v2v2(uv, uv_rotation_result, medianPoint); + sub_v2_v2(uv, medianPoint); + mul_v2_m2v2(uv_rotation_result, mat, uv); + add_v2_v2v2(uv, uv_rotation_result, medianPoint); - uv[1] *= aspect; + uv[1] *= aspect; } /* check if two uvelements are stitchable. * This should only operate on -different- separate UvElements */ -static bool stitch_check_uvs_stitchable( - UvElement *element, UvElement *element_iter, - StitchStateContainer *ssc, StitchState *state) +static bool stitch_check_uvs_stitchable(UvElement *element, + UvElement *element_iter, + StitchStateContainer *ssc, + StitchState *state) { - BMesh *bm = state->em->bm; - float limit; - - if (element_iter == element) { - return 0; - } - - limit = ssc->limit_dist; - - if (ssc->use_limit) { - MLoopUV *luv, *luv_iter; - BMLoop *l; - - - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - l = element_iter->l; - luv_iter = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - if (fabsf(luv->uv[0] - luv_iter->uv[0]) < limit && - fabsf(luv->uv[1] - luv_iter->uv[1]) < limit) - { - return 1; - } - else { - return 0; - } - } - else { - return 1; - } + BMesh *bm = state->em->bm; + float limit; + + if (element_iter == element) { + return 0; + } + + limit = ssc->limit_dist; + + if (ssc->use_limit) { + MLoopUV *luv, *luv_iter; + BMLoop *l; + + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + l = element_iter->l; + luv_iter = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + if (fabsf(luv->uv[0] - luv_iter->uv[0]) < limit && + fabsf(luv->uv[1] - luv_iter->uv[1]) < limit) { + return 1; + } + else { + return 0; + } + } + else { + return 1; + } } -static bool stitch_check_edges_stitchable( - UvEdge *edge, UvEdge *edge_iter, - StitchStateContainer *ssc, StitchState *state) +static bool stitch_check_edges_stitchable(UvEdge *edge, + UvEdge *edge_iter, + StitchStateContainer *ssc, + StitchState *state) { - BMesh *bm = state->em->bm; - float limit; - - if (edge_iter == edge) { - return 0; - } - - limit = ssc->limit_dist; - - if (ssc->use_limit) { - BMLoop *l; - MLoopUV *luv_orig1, *luv_iter1; - MLoopUV *luv_orig2, *luv_iter2; - - l = state->uvs[edge->uv1]->l; - luv_orig1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - l = state->uvs[edge_iter->uv1]->l; - luv_iter1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - l = state->uvs[edge->uv2]->l; - luv_orig2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - l = state->uvs[edge_iter->uv2]->l; - luv_iter2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - if (fabsf(luv_orig1->uv[0] - luv_iter1->uv[0]) < limit && - fabsf(luv_orig1->uv[1] - luv_iter1->uv[1]) < limit && - fabsf(luv_orig2->uv[0] - luv_iter2->uv[0]) < limit && - fabsf(luv_orig2->uv[1] - luv_iter2->uv[1]) < limit) - { - return 1; - } - else { - return 0; - } - } - else { - return 1; - } + BMesh *bm = state->em->bm; + float limit; + + if (edge_iter == edge) { + return 0; + } + + limit = ssc->limit_dist; + + if (ssc->use_limit) { + BMLoop *l; + MLoopUV *luv_orig1, *luv_iter1; + MLoopUV *luv_orig2, *luv_iter2; + + l = state->uvs[edge->uv1]->l; + luv_orig1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + l = state->uvs[edge_iter->uv1]->l; + luv_iter1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + l = state->uvs[edge->uv2]->l; + luv_orig2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + l = state->uvs[edge_iter->uv2]->l; + luv_iter2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + if (fabsf(luv_orig1->uv[0] - luv_iter1->uv[0]) < limit && + fabsf(luv_orig1->uv[1] - luv_iter1->uv[1]) < limit && + fabsf(luv_orig2->uv[0] - luv_iter2->uv[0]) < limit && + fabsf(luv_orig2->uv[1] - luv_iter2->uv[1]) < limit) { + return 1; + } + else { + return 0; + } + } + else { + return 1; + } } -static bool stitch_check_uvs_state_stitchable( - UvElement *element, UvElement *element_iter, - StitchStateContainer *ssc, StitchState *state) +static bool stitch_check_uvs_state_stitchable(UvElement *element, + UvElement *element_iter, + StitchStateContainer *ssc, + StitchState *state) { - if ((ssc->snap_islands && element->island == element_iter->island) || - (!ssc->midpoints && element->island == element_iter->island)) - { - return 0; - } + if ((ssc->snap_islands && element->island == element_iter->island) || + (!ssc->midpoints && element->island == element_iter->island)) { + return 0; + } - return stitch_check_uvs_stitchable(element, element_iter, ssc, state); + return stitch_check_uvs_stitchable(element, element_iter, ssc, state); } -static bool stitch_check_edges_state_stitchable( - UvEdge *edge, UvEdge *edge_iter, - StitchStateContainer *ssc, StitchState *state) +static bool stitch_check_edges_state_stitchable(UvEdge *edge, + UvEdge *edge_iter, + StitchStateContainer *ssc, + StitchState *state) { - if ((ssc->snap_islands && edge->element->island == edge_iter->element->island) || - (!ssc->midpoints && edge->element->island == edge_iter->element->island)) - { - return 0; - } + if ((ssc->snap_islands && edge->element->island == edge_iter->element->island) || + (!ssc->midpoints && edge->element->island == edge_iter->element->island)) { + return 0; + } - return stitch_check_edges_stitchable(edge, edge_iter, ssc, state); + return stitch_check_edges_stitchable(edge, edge_iter, ssc, state); } /* calculate snapping for islands */ -static void stitch_calculate_island_snapping( - StitchState *state, PreviewPosition *preview_position, StitchPreviewer *preview, - IslandStitchData *island_stitch_data, int final) +static void stitch_calculate_island_snapping(StitchState *state, + PreviewPosition *preview_position, + StitchPreviewer *preview, + IslandStitchData *island_stitch_data, + int final) { - BMesh *bm = state->em->bm; - int i; - UvElement *element; - - for (i = 0; i < state->element_map->totalIslands; i++) { - if (island_stitch_data[i].addedForPreview) { - int numOfIslandUVs = 0, j; - int totelem = island_stitch_data[i].num_rot_elements_neg + island_stitch_data[i].num_rot_elements; - float rotation; - float rotation_mat[2][2]; - - /* check to avoid divide by 0 */ - if (island_stitch_data[i].num_rot_elements > 1) - island_stitch_data[i].rotation /= island_stitch_data[i].num_rot_elements; - - if (island_stitch_data[i].num_rot_elements_neg > 1) - island_stitch_data[i].rotation_neg /= island_stitch_data[i].num_rot_elements_neg; - - if (island_stitch_data[i].numOfElements > 1) { - island_stitch_data[i].medianPoint[0] /= island_stitch_data[i].numOfElements; - island_stitch_data[i].medianPoint[1] /= island_stitch_data[i].numOfElements; - - island_stitch_data[i].translation[0] /= island_stitch_data[i].numOfElements; - island_stitch_data[i].translation[1] /= island_stitch_data[i].numOfElements; - } - - island_stitch_data[i].medianPoint[1] /= state->aspect; - if ((island_stitch_data[i].rotation + island_stitch_data[i].rotation_neg < (float)M_PI_2) || - island_stitch_data[i].num_rot_elements == 0 || island_stitch_data[i].num_rot_elements_neg == 0) - { - rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements - - island_stitch_data[i].rotation_neg * - island_stitch_data[i].num_rot_elements_neg) / totelem; - } - else { - rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements + - (2.0f * (float)M_PI - island_stitch_data[i].rotation_neg) * - island_stitch_data[i].num_rot_elements_neg) / totelem; - } - - angle_to_mat2(rotation_mat, rotation); - numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); - element = &state->element_map->buf[state->element_map->islandIndices[i]]; - for (j = 0; j < numOfIslandUVs; j++, element++) { - /* stitchable uvs have already been processed, don't process */ - if (!(element->flag & STITCH_PROCESSED)) { - MLoopUV *luv; - BMLoop *l; - - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - if (final) { - - stitch_uv_rotate(rotation_mat, island_stitch_data[i].medianPoint, luv->uv, state->aspect); - - add_v2_v2(luv->uv, island_stitch_data[i].translation); - } - - else { - - int face_preview_pos = preview_position[BM_elem_index_get(element->l->f)].data_position; - - stitch_uv_rotate(rotation_mat, island_stitch_data[i].medianPoint, - preview->preview_polys + face_preview_pos + 2 * element->loop_of_poly_index, - state->aspect); - - add_v2_v2(preview->preview_polys + face_preview_pos + 2 * element->loop_of_poly_index, - island_stitch_data[i].translation); - } - } - /* cleanup */ - element->flag &= STITCH_SELECTED; - } - } - } + BMesh *bm = state->em->bm; + int i; + UvElement *element; + + for (i = 0; i < state->element_map->totalIslands; i++) { + if (island_stitch_data[i].addedForPreview) { + int numOfIslandUVs = 0, j; + int totelem = island_stitch_data[i].num_rot_elements_neg + + island_stitch_data[i].num_rot_elements; + float rotation; + float rotation_mat[2][2]; + + /* check to avoid divide by 0 */ + if (island_stitch_data[i].num_rot_elements > 1) + island_stitch_data[i].rotation /= island_stitch_data[i].num_rot_elements; + + if (island_stitch_data[i].num_rot_elements_neg > 1) + island_stitch_data[i].rotation_neg /= island_stitch_data[i].num_rot_elements_neg; + + if (island_stitch_data[i].numOfElements > 1) { + island_stitch_data[i].medianPoint[0] /= island_stitch_data[i].numOfElements; + island_stitch_data[i].medianPoint[1] /= island_stitch_data[i].numOfElements; + + island_stitch_data[i].translation[0] /= island_stitch_data[i].numOfElements; + island_stitch_data[i].translation[1] /= island_stitch_data[i].numOfElements; + } + + island_stitch_data[i].medianPoint[1] /= state->aspect; + if ((island_stitch_data[i].rotation + island_stitch_data[i].rotation_neg < (float)M_PI_2) || + island_stitch_data[i].num_rot_elements == 0 || + island_stitch_data[i].num_rot_elements_neg == 0) { + rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements - + island_stitch_data[i].rotation_neg * + island_stitch_data[i].num_rot_elements_neg) / + totelem; + } + else { + rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements + + (2.0f * (float)M_PI - island_stitch_data[i].rotation_neg) * + island_stitch_data[i].num_rot_elements_neg) / + totelem; + } + + angle_to_mat2(rotation_mat, rotation); + numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); + element = &state->element_map->buf[state->element_map->islandIndices[i]]; + for (j = 0; j < numOfIslandUVs; j++, element++) { + /* stitchable uvs have already been processed, don't process */ + if (!(element->flag & STITCH_PROCESSED)) { + MLoopUV *luv; + BMLoop *l; + + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + if (final) { + + stitch_uv_rotate( + rotation_mat, island_stitch_data[i].medianPoint, luv->uv, state->aspect); + + add_v2_v2(luv->uv, island_stitch_data[i].translation); + } + + else { + + int face_preview_pos = + preview_position[BM_elem_index_get(element->l->f)].data_position; + + stitch_uv_rotate(rotation_mat, + island_stitch_data[i].medianPoint, + preview->preview_polys + face_preview_pos + + 2 * element->loop_of_poly_index, + state->aspect); + + add_v2_v2(preview->preview_polys + face_preview_pos + 2 * element->loop_of_poly_index, + island_stitch_data[i].translation); + } + } + /* cleanup */ + element->flag &= STITCH_SELECTED; + } + } + } } - - -static void stitch_island_calculate_edge_rotation( - UvEdge *edge, StitchStateContainer *ssc, StitchState *state, UVVertAverage *uv_average, - unsigned int *uvfinal_map, IslandStitchData *island_stitch_data) +static void stitch_island_calculate_edge_rotation(UvEdge *edge, + StitchStateContainer *ssc, + StitchState *state, + UVVertAverage *uv_average, + unsigned int *uvfinal_map, + IslandStitchData *island_stitch_data) { - BMesh *bm = state->em->bm; - UvElement *element1, *element2; - float uv1[2], uv2[2]; - float edgecos, edgesin; - int index1, index2; - float rotation; - MLoopUV *luv1, *luv2; - - element1 = state->uvs[edge->uv1]; - element2 = state->uvs[edge->uv2]; - - luv1 = CustomData_bmesh_get(&bm->ldata, element1->l->head.data, CD_MLOOPUV); - luv2 = CustomData_bmesh_get(&bm->ldata, element2->l->head.data, CD_MLOOPUV); - - if (ssc->mode == STITCH_VERT) { - index1 = uvfinal_map[element1 - state->element_map->buf]; - index2 = uvfinal_map[element2 - state->element_map->buf]; - } - else { - index1 = edge->uv1; - index2 = edge->uv2; - } - /* the idea here is to take the directions of the edges and find the rotation between - * final and initial direction. This, using inner and outer vector products, - * gives the angle. Directions are differences so... */ - uv1[0] = luv2->uv[0] - luv1->uv[0]; - uv1[1] = luv2->uv[1] - luv1->uv[1]; - - uv1[1] /= state->aspect; - - uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0]; - uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1]; - - uv2[1] /= state->aspect; - - normalize_v2(uv1); - normalize_v2(uv2); - - edgecos = dot_v2v2(uv1, uv2); - edgesin = cross_v2v2(uv1, uv2); - rotation = acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); - - if (edgesin > 0.0f) { - island_stitch_data[element1->island].num_rot_elements++; - island_stitch_data[element1->island].rotation += rotation; - } - else { - island_stitch_data[element1->island].num_rot_elements_neg++; - island_stitch_data[element1->island].rotation_neg += rotation; - } + BMesh *bm = state->em->bm; + UvElement *element1, *element2; + float uv1[2], uv2[2]; + float edgecos, edgesin; + int index1, index2; + float rotation; + MLoopUV *luv1, *luv2; + + element1 = state->uvs[edge->uv1]; + element2 = state->uvs[edge->uv2]; + + luv1 = CustomData_bmesh_get(&bm->ldata, element1->l->head.data, CD_MLOOPUV); + luv2 = CustomData_bmesh_get(&bm->ldata, element2->l->head.data, CD_MLOOPUV); + + if (ssc->mode == STITCH_VERT) { + index1 = uvfinal_map[element1 - state->element_map->buf]; + index2 = uvfinal_map[element2 - state->element_map->buf]; + } + else { + index1 = edge->uv1; + index2 = edge->uv2; + } + /* the idea here is to take the directions of the edges and find the rotation between + * final and initial direction. This, using inner and outer vector products, + * gives the angle. Directions are differences so... */ + uv1[0] = luv2->uv[0] - luv1->uv[0]; + uv1[1] = luv2->uv[1] - luv1->uv[1]; + + uv1[1] /= state->aspect; + + uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0]; + uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1]; + + uv2[1] /= state->aspect; + + normalize_v2(uv1); + normalize_v2(uv2); + + edgecos = dot_v2v2(uv1, uv2); + edgesin = cross_v2v2(uv1, uv2); + rotation = acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); + + if (edgesin > 0.0f) { + island_stitch_data[element1->island].num_rot_elements++; + island_stitch_data[element1->island].rotation += rotation; + } + else { + island_stitch_data[element1->island].num_rot_elements_neg++; + island_stitch_data[element1->island].rotation_neg += rotation; + } } - -static void stitch_island_calculate_vert_rotation( - UvElement *element, StitchStateContainer *ssc, StitchState *state, - IslandStitchData *island_stitch_data) +static void stitch_island_calculate_vert_rotation(UvElement *element, + StitchStateContainer *ssc, + StitchState *state, + IslandStitchData *island_stitch_data) { - float edgecos = 1.0f, edgesin = 0.0f; - int index; - UvElement *element_iter; - float rotation = 0, rotation_neg = 0; - int rot_elem = 0, rot_elem_neg = 0; - BMLoop *l; - - if (element->island == ssc->static_island && !ssc->midpoints) - return; - - l = element->l; - - index = BM_elem_index_get(l->v); - - element_iter = state->element_map->vert[index]; - - for (; element_iter; element_iter = element_iter->next) { - if (element_iter->separate && stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { - int index_tmp1, index_tmp2; - float normal[2]; - - /* only calculate rotation against static island uv verts */ - if (!ssc->midpoints && element_iter->island != ssc->static_island) - continue; - - index_tmp1 = element_iter - state->element_map->buf; - index_tmp1 = state->map[index_tmp1]; - index_tmp2 = element - state->element_map->buf; - index_tmp2 = state->map[index_tmp2]; - - negate_v2_v2(normal, state->normals + index_tmp2 * 2); - edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2); - edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2); - if (edgesin > 0.0f) { - rotation += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); - rot_elem++; - } - else { - rotation_neg += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); - rot_elem_neg++; - } - } - } - - if (ssc->midpoints) { - rotation /= 2.0f; - rotation_neg /= 2.0f; - } - island_stitch_data[element->island].num_rot_elements += rot_elem; - island_stitch_data[element->island].rotation += rotation; - island_stitch_data[element->island].num_rot_elements_neg += rot_elem_neg; - island_stitch_data[element->island].rotation_neg += rotation_neg; + float edgecos = 1.0f, edgesin = 0.0f; + int index; + UvElement *element_iter; + float rotation = 0, rotation_neg = 0; + int rot_elem = 0, rot_elem_neg = 0; + BMLoop *l; + + if (element->island == ssc->static_island && !ssc->midpoints) + return; + + l = element->l; + + index = BM_elem_index_get(l->v); + + element_iter = state->element_map->vert[index]; + + for (; element_iter; element_iter = element_iter->next) { + if (element_iter->separate && + stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { + int index_tmp1, index_tmp2; + float normal[2]; + + /* only calculate rotation against static island uv verts */ + if (!ssc->midpoints && element_iter->island != ssc->static_island) + continue; + + index_tmp1 = element_iter - state->element_map->buf; + index_tmp1 = state->map[index_tmp1]; + index_tmp2 = element - state->element_map->buf; + index_tmp2 = state->map[index_tmp2]; + + negate_v2_v2(normal, state->normals + index_tmp2 * 2); + edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2); + edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2); + if (edgesin > 0.0f) { + rotation += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); + rot_elem++; + } + else { + rotation_neg += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); + rot_elem_neg++; + } + } + } + + if (ssc->midpoints) { + rotation /= 2.0f; + rotation_neg /= 2.0f; + } + island_stitch_data[element->island].num_rot_elements += rot_elem; + island_stitch_data[element->island].rotation += rotation; + island_stitch_data[element->island].num_rot_elements_neg += rot_elem_neg; + island_stitch_data[element->island].rotation_neg += rotation_neg; } - static void state_delete(StitchState *state) { - if (state) { - if (state->island_is_stitchable) { - MEM_freeN(state->island_is_stitchable); - } - if (state->element_map) { - BM_uv_element_map_free(state->element_map); - } - if (state->uvs) { - MEM_freeN(state->uvs); - } - if (state->selection_stack) { - MEM_freeN(state->selection_stack); - } - if (state->tris_per_island) { - MEM_freeN(state->tris_per_island); - } - if (state->map) { - MEM_freeN(state->map); - } - if (state->normals) { - MEM_freeN(state->normals); - } - if (state->edges) { - MEM_freeN(state->edges); - } - if (state->stitch_preview) { - stitch_preview_delete(state->stitch_preview); - } - if (state->edge_hash) { - BLI_ghash_free(state->edge_hash, NULL, NULL); - } - MEM_freeN(state); - } + if (state) { + if (state->island_is_stitchable) { + MEM_freeN(state->island_is_stitchable); + } + if (state->element_map) { + BM_uv_element_map_free(state->element_map); + } + if (state->uvs) { + MEM_freeN(state->uvs); + } + if (state->selection_stack) { + MEM_freeN(state->selection_stack); + } + if (state->tris_per_island) { + MEM_freeN(state->tris_per_island); + } + if (state->map) { + MEM_freeN(state->map); + } + if (state->normals) { + MEM_freeN(state->normals); + } + if (state->edges) { + MEM_freeN(state->edges); + } + if (state->stitch_preview) { + stitch_preview_delete(state->stitch_preview); + } + if (state->edge_hash) { + BLI_ghash_free(state->edge_hash, NULL, NULL); + } + MEM_freeN(state); + } } static void state_delete_all(StitchStateContainer *ssc) { - if (ssc) { - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - state_delete(ssc->states[ob_index]); - } - MEM_freeN(ssc->states); - MEM_freeN(ssc->objects); - MEM_freeN(ssc); - } + if (ssc) { + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + state_delete(ssc->states[ob_index]); + } + MEM_freeN(ssc->states); + MEM_freeN(ssc->objects); + MEM_freeN(ssc); + } } static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState *state) { - UvEdge *edges = state->edges; - const int *map = state->map; - UvElementMap *element_map = state->element_map; - UvElement *first_element = element_map->buf; - int i; - - for (i = 0; i < state->total_separate_edges; i++) { - UvEdge *edge = edges + i; - - if (edge->first) - continue; - - /* only boundary edges can be stitched. Yes. Sorry about that :p */ - if (edge->flag & STITCH_BOUNDARY) { - UvElement *element1 = state->uvs[edge->uv1]; - UvElement *element2 = state->uvs[edge->uv2]; - - /* Now iterate through all faces and try to find edges sharing the same vertices */ - UvElement *iter1 = element_map->vert[BM_elem_index_get(element1->l->v)]; - UvEdge *last_set = edge; - int elemindex2 = BM_elem_index_get(element2->l->v); - - edge->first = edge; - - for (; iter1; iter1 = iter1->next) { - UvElement *iter2 = NULL; - - /* check to see if other vertex of edge belongs to same vertex as */ - if (BM_elem_index_get(iter1->l->next->v) == elemindex2) - iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->next); - else if (BM_elem_index_get(iter1->l->prev->v) == elemindex2) - iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->prev); - - if (iter2) { - int index1 = map[iter1 - first_element]; - int index2 = map[iter2 - first_element]; - UvEdge edgetmp; - UvEdge *edge2, *eiter; - bool valid = true; - - /* make sure the indices are well behaved */ - if (index1 > index2) { - SWAP(int, index1, index2); - } - - edgetmp.uv1 = index1; - edgetmp.uv2 = index2; - - /* get the edge from the hash */ - edge2 = BLI_ghash_lookup(edge_hash, &edgetmp); - - /* more iteration to make sure non-manifold case is handled nicely */ - for (eiter = edge; eiter; eiter = eiter->next) { - if (edge2 == eiter) { - valid = false; - break; - } - } - - if (valid) { - /* here I am taking care of non manifold case, assuming more than two matching edges. - * I am not too sure we want this though */ - last_set->next = edge2; - last_set = edge2; - /* set first, similarly to uv elements. - * Now we can iterate among common edges easily */ - edge2->first = edge; - } - } - } - } - else { - /* so stitchability code works */ - edge->first = edge; - } - } + UvEdge *edges = state->edges; + const int *map = state->map; + UvElementMap *element_map = state->element_map; + UvElement *first_element = element_map->buf; + int i; + + for (i = 0; i < state->total_separate_edges; i++) { + UvEdge *edge = edges + i; + + if (edge->first) + continue; + + /* only boundary edges can be stitched. Yes. Sorry about that :p */ + if (edge->flag & STITCH_BOUNDARY) { + UvElement *element1 = state->uvs[edge->uv1]; + UvElement *element2 = state->uvs[edge->uv2]; + + /* Now iterate through all faces and try to find edges sharing the same vertices */ + UvElement *iter1 = element_map->vert[BM_elem_index_get(element1->l->v)]; + UvEdge *last_set = edge; + int elemindex2 = BM_elem_index_get(element2->l->v); + + edge->first = edge; + + for (; iter1; iter1 = iter1->next) { + UvElement *iter2 = NULL; + + /* check to see if other vertex of edge belongs to same vertex as */ + if (BM_elem_index_get(iter1->l->next->v) == elemindex2) + iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->next); + else if (BM_elem_index_get(iter1->l->prev->v) == elemindex2) + iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->prev); + + if (iter2) { + int index1 = map[iter1 - first_element]; + int index2 = map[iter2 - first_element]; + UvEdge edgetmp; + UvEdge *edge2, *eiter; + bool valid = true; + + /* make sure the indices are well behaved */ + if (index1 > index2) { + SWAP(int, index1, index2); + } + + edgetmp.uv1 = index1; + edgetmp.uv2 = index2; + + /* get the edge from the hash */ + edge2 = BLI_ghash_lookup(edge_hash, &edgetmp); + + /* more iteration to make sure non-manifold case is handled nicely */ + for (eiter = edge; eiter; eiter = eiter->next) { + if (edge2 == eiter) { + valid = false; + break; + } + } + + if (valid) { + /* here I am taking care of non manifold case, assuming more than two matching edges. + * I am not too sure we want this though */ + last_set->next = edge2; + last_set = edge2; + /* set first, similarly to uv elements. + * Now we can iterate among common edges easily */ + edge2->first = edge; + } + } + } + } + else { + /* so stitchability code works */ + edge->first = edge; + } + } } - /* checks for remote uvs that may be stitched with a certain uv, flags them if stitchable. */ -static void determine_uv_stitchability( - UvElement *element, StitchStateContainer *ssc, StitchState *state, - IslandStitchData *island_stitch_data) +static void determine_uv_stitchability(UvElement *element, + StitchStateContainer *ssc, + StitchState *state, + IslandStitchData *island_stitch_data) { - int vert_index; - UvElement *element_iter; - BMLoop *l; - - l = element->l; - - vert_index = BM_elem_index_get(l->v); - element_iter = state->element_map->vert[vert_index]; - - for (; element_iter; element_iter = element_iter->next) { - if (element_iter->separate) { - if (stitch_check_uvs_stitchable(element, element_iter, ssc, state)) { - island_stitch_data[element_iter->island].stitchableCandidate = 1; - island_stitch_data[element->island].stitchableCandidate = 1; - element->flag |= STITCH_STITCHABLE_CANDIDATE; - } - } - } + int vert_index; + UvElement *element_iter; + BMLoop *l; + + l = element->l; + + vert_index = BM_elem_index_get(l->v); + element_iter = state->element_map->vert[vert_index]; + + for (; element_iter; element_iter = element_iter->next) { + if (element_iter->separate) { + if (stitch_check_uvs_stitchable(element, element_iter, ssc, state)) { + island_stitch_data[element_iter->island].stitchableCandidate = 1; + island_stitch_data[element->island].stitchableCandidate = 1; + element->flag |= STITCH_STITCHABLE_CANDIDATE; + } + } + } } -static void determine_uv_edge_stitchability( - UvEdge *edge, StitchStateContainer *ssc, StitchState *state, - IslandStitchData *island_stitch_data) +static void determine_uv_edge_stitchability(UvEdge *edge, + StitchStateContainer *ssc, + StitchState *state, + IslandStitchData *island_stitch_data) { - UvEdge *edge_iter = edge->first; - - for (; edge_iter; edge_iter = edge_iter->next) { - if (stitch_check_edges_stitchable(edge, edge_iter, ssc, state)) { - island_stitch_data[edge_iter->element->island].stitchableCandidate = 1; - island_stitch_data[edge->element->island].stitchableCandidate = 1; - edge->flag |= STITCH_STITCHABLE_CANDIDATE; - } - } + UvEdge *edge_iter = edge->first; + + for (; edge_iter; edge_iter = edge_iter->next) { + if (stitch_check_edges_stitchable(edge, edge_iter, ssc, state)) { + island_stitch_data[edge_iter->element->island].stitchableCandidate = 1; + island_stitch_data[edge->element->island].stitchableCandidate = 1; + edge->flag |= STITCH_STITCHABLE_CANDIDATE; + } + } } - /* set preview buffer position of UV face in editface->tmp.l */ -static void stitch_set_face_preview_buffer_position( - BMFace *efa, StitchPreviewer *preview, PreviewPosition *preview_position) +static void stitch_set_face_preview_buffer_position(BMFace *efa, + StitchPreviewer *preview, + PreviewPosition *preview_position) { - int index = BM_elem_index_get(efa); + int index = BM_elem_index_get(efa); - if (preview_position[index].data_position == STITCH_NO_PREVIEW) { - preview_position[index].data_position = preview->preview_uvs * 2; - preview_position[index].polycount_position = preview->num_polys++; - preview->preview_uvs += efa->len; - } + if (preview_position[index].data_position == STITCH_NO_PREVIEW) { + preview_position[index].data_position = preview->preview_uvs * 2; + preview_position[index].polycount_position = preview->num_polys++; + preview->preview_uvs += efa->len; + } } - /* setup face preview for all coincident uvs and their faces */ -static void stitch_setup_face_preview_for_uv_group( - UvElement *element, StitchStateContainer *ssc, StitchState *state, - IslandStitchData *island_stitch_data, PreviewPosition *preview_position) +static void stitch_setup_face_preview_for_uv_group(UvElement *element, + StitchStateContainer *ssc, + StitchState *state, + IslandStitchData *island_stitch_data, + PreviewPosition *preview_position) { - StitchPreviewer *preview = state->stitch_preview; + StitchPreviewer *preview = state->stitch_preview; - /* static island does not change so returning immediately */ - if (ssc->snap_islands && !ssc->midpoints && ssc->static_island == element->island) - return; + /* static island does not change so returning immediately */ + if (ssc->snap_islands && !ssc->midpoints && ssc->static_island == element->island) + return; - if (ssc->snap_islands) { - island_stitch_data[element->island].addedForPreview = 1; - } + if (ssc->snap_islands) { + island_stitch_data[element->island].addedForPreview = 1; + } - do { - stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position); - element = element->next; - } while (element && !element->separate); + do { + stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position); + element = element->next; + } while (element && !element->separate); } - /* checks if uvs are indeed stitchable and registers so that they can be shown in preview */ -static void stitch_validate_uv_stitchability( - UvElement *element, StitchStateContainer *ssc, StitchState *state, - IslandStitchData *island_stitch_data, PreviewPosition *preview_position) +static void stitch_validate_uv_stitchability(UvElement *element, + StitchStateContainer *ssc, + StitchState *state, + IslandStitchData *island_stitch_data, + PreviewPosition *preview_position) { - StitchPreviewer *preview = state->stitch_preview; - - /* If not the active object, then it's unstitchable */ - if (ssc->states[ssc->active_object_index] != state) { - preview->num_unstitchable++; - return; - } - - UvElement *element_iter; - int vert_index; - BMLoop *l; - - l = element->l; - - vert_index = BM_elem_index_get(l->v); - - element_iter = state->element_map->vert[vert_index]; - - for (; element_iter; element_iter = element_iter->next) { - if (element_iter->separate) { - if (element_iter == element) - continue; - if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { - if ((element_iter->island == ssc->static_island) || (element->island == ssc->static_island)) { - element->flag |= STITCH_STITCHABLE; - preview->num_stitchable++; - stitch_setup_face_preview_for_uv_group(element, ssc, state, island_stitch_data, preview_position); - return; - } - } - } - } - - /* this can happen if the uvs to be stitched are not on a stitchable island */ - if (!(element->flag & STITCH_STITCHABLE)) { - preview->num_unstitchable++; - } + StitchPreviewer *preview = state->stitch_preview; + + /* If not the active object, then it's unstitchable */ + if (ssc->states[ssc->active_object_index] != state) { + preview->num_unstitchable++; + return; + } + + UvElement *element_iter; + int vert_index; + BMLoop *l; + + l = element->l; + + vert_index = BM_elem_index_get(l->v); + + element_iter = state->element_map->vert[vert_index]; + + for (; element_iter; element_iter = element_iter->next) { + if (element_iter->separate) { + if (element_iter == element) + continue; + if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { + if ((element_iter->island == ssc->static_island) || + (element->island == ssc->static_island)) { + element->flag |= STITCH_STITCHABLE; + preview->num_stitchable++; + stitch_setup_face_preview_for_uv_group( + element, ssc, state, island_stitch_data, preview_position); + return; + } + } + } + } + + /* this can happen if the uvs to be stitched are not on a stitchable island */ + if (!(element->flag & STITCH_STITCHABLE)) { + preview->num_unstitchable++; + } } - -static void stitch_validate_edge_stitchability( - UvEdge *edge, StitchStateContainer *ssc, StitchState *state, - IslandStitchData *island_stitch_data, PreviewPosition *preview_position) +static void stitch_validate_edge_stitchability(UvEdge *edge, + StitchStateContainer *ssc, + StitchState *state, + IslandStitchData *island_stitch_data, + PreviewPosition *preview_position) { - StitchPreviewer *preview = state->stitch_preview; - - /* If not the active object, then it's unstitchable */ - if (ssc->states[ssc->active_object_index] != state) { - preview->num_unstitchable++; - return; - } - - UvEdge *edge_iter = edge->first; - - for (; edge_iter; edge_iter = edge_iter->next) { - if (edge_iter == edge) - continue; - if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) { - if ((edge_iter->element->island == ssc->static_island) || (edge->element->island == ssc->static_island)) { - edge->flag |= STITCH_STITCHABLE; - preview->num_stitchable++; - stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv1], - ssc, - state, - island_stitch_data, - preview_position); - stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv2], - ssc, - state, - island_stitch_data, - preview_position); - return; - } - } - } - - /* this can happen if the uvs to be stitched are not on a stitchable island */ - if (!(edge->flag & STITCH_STITCHABLE)) { - preview->num_unstitchable++; - } + StitchPreviewer *preview = state->stitch_preview; + + /* If not the active object, then it's unstitchable */ + if (ssc->states[ssc->active_object_index] != state) { + preview->num_unstitchable++; + return; + } + + UvEdge *edge_iter = edge->first; + + for (; edge_iter; edge_iter = edge_iter->next) { + if (edge_iter == edge) + continue; + if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) { + if ((edge_iter->element->island == ssc->static_island) || + (edge->element->island == ssc->static_island)) { + edge->flag |= STITCH_STITCHABLE; + preview->num_stitchable++; + stitch_setup_face_preview_for_uv_group( + state->uvs[edge->uv1], ssc, state, island_stitch_data, preview_position); + stitch_setup_face_preview_for_uv_group( + state->uvs[edge->uv2], ssc, state, island_stitch_data, preview_position); + return; + } + } + } + + /* this can happen if the uvs to be stitched are not on a stitchable island */ + if (!(edge->flag & STITCH_STITCHABLE)) { + preview->num_unstitchable++; + } } - -static void stitch_propagate_uv_final_position( - Scene *scene, - UvElement *element, int index, PreviewPosition *preview_position, - UVVertAverage *final_position, StitchStateContainer *ssc, StitchState *state, - const bool final) +static void stitch_propagate_uv_final_position(Scene *scene, + UvElement *element, + int index, + PreviewPosition *preview_position, + UVVertAverage *final_position, + StitchStateContainer *ssc, + StitchState *state, + const bool final) { - BMesh *bm = state->em->bm; - StitchPreviewer *preview = state->stitch_preview; - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - if (element->flag & STITCH_STITCHABLE) { - UvElement *element_iter = element; - /* propagate to coincident uvs */ - do { - BMLoop *l; - MLoopUV *luv; - - l = element_iter->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - element_iter->flag |= STITCH_PROCESSED; - /* either flush to preview or to the MTFace, if final */ - if (final) { - copy_v2_v2(luv->uv, final_position[index].uv); - - uvedit_uv_select_enable(state->em, scene, l, false, cd_loop_uv_offset); - } - else { - int face_preview_pos = preview_position[BM_elem_index_get(element_iter->l->f)].data_position; - if (face_preview_pos != STITCH_NO_PREVIEW) { - copy_v2_v2(preview->preview_polys + face_preview_pos + 2 * element_iter->loop_of_poly_index, - final_position[index].uv); - } - } - - /* end of calculations, keep only the selection flag */ - if ((!ssc->snap_islands) || ((!ssc->midpoints) && (element_iter->island == ssc->static_island))) { - element_iter->flag &= STITCH_SELECTED; - } - - element_iter = element_iter->next; - } while (element_iter && !element_iter->separate); - } + BMesh *bm = state->em->bm; + StitchPreviewer *preview = state->stitch_preview; + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + if (element->flag & STITCH_STITCHABLE) { + UvElement *element_iter = element; + /* propagate to coincident uvs */ + do { + BMLoop *l; + MLoopUV *luv; + + l = element_iter->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + element_iter->flag |= STITCH_PROCESSED; + /* either flush to preview or to the MTFace, if final */ + if (final) { + copy_v2_v2(luv->uv, final_position[index].uv); + + uvedit_uv_select_enable(state->em, scene, l, false, cd_loop_uv_offset); + } + else { + int face_preview_pos = + preview_position[BM_elem_index_get(element_iter->l->f)].data_position; + if (face_preview_pos != STITCH_NO_PREVIEW) { + copy_v2_v2(preview->preview_polys + face_preview_pos + + 2 * element_iter->loop_of_poly_index, + final_position[index].uv); + } + } + + /* end of calculations, keep only the selection flag */ + if ((!ssc->snap_islands) || + ((!ssc->midpoints) && (element_iter->island == ssc->static_island))) { + element_iter->flag &= STITCH_SELECTED; + } + + element_iter = element_iter->next; + } while (element_iter && !element_iter->separate); + } } /* main processing function. It calculates preview and final positions. */ -static int stitch_process_data( - StitchStateContainer *ssc, StitchState *state, Scene *scene, int final) +static int stitch_process_data(StitchStateContainer *ssc, + StitchState *state, + Scene *scene, + int final) { - int i; - StitchPreviewer *preview; - IslandStitchData *island_stitch_data = NULL; - int previous_island = ssc->static_island; - BMesh *bm = state->em->bm; - BMFace *efa; - BMIter iter; - UVVertAverage *final_position = NULL; - bool is_active_state = (state == ssc->states[ssc->active_object_index]); - - char stitch_midpoints = ssc->midpoints; - /* used to map uv indices to uvaverage indices for selection */ - unsigned int *uvfinal_map = NULL; - /* per face preview position in preview buffer */ - PreviewPosition *preview_position = NULL; - - /* cleanup previous preview */ - stitch_preview_delete(state->stitch_preview); - preview = state->stitch_preview = stitch_preview_init(); - if (preview == NULL) - return 0; - - preview_position = MEM_mallocN(bm->totface * sizeof(*preview_position), "stitch_face_preview_position"); - /* each face holds its position in the preview buffer in tmp. -1 is uninitialized */ - for (i = 0; i < bm->totface; i++) { - preview_position[i].data_position = STITCH_NO_PREVIEW; - } - - island_stitch_data = MEM_callocN(sizeof(*island_stitch_data) * state->element_map->totalIslands, - "stitch_island_data"); - if (!island_stitch_data) { - return 0; - } - - /* store indices to editVerts and Faces. May be unneeded but ensuring anyway */ - BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE); - - /**************************************** - * First determine stitchability of uvs * - ****************************************/ - - for (i = 0; i < state->selection_size; i++) { - if (ssc->mode == STITCH_VERT) { - UvElement *element = (UvElement *)state->selection_stack[i]; - determine_uv_stitchability(element, ssc, state, island_stitch_data); - } - else { - UvEdge *edge = (UvEdge *)state->selection_stack[i]; - determine_uv_edge_stitchability(edge, ssc, state, island_stitch_data); - } - } - - /* remember stitchable candidates as places the 'I' button */ - /* will stop at. */ - for (int island_idx = 0; island_idx < state->element_map->totalIslands; island_idx++) { - state->island_is_stitchable[island_idx] = island_stitch_data[island_idx].stitchableCandidate ? true : false; - } - - if (is_active_state) { - /* set static island to one that is added for preview */ - ssc->static_island %= state->element_map->totalIslands; - while (!(island_stitch_data[ssc->static_island].stitchableCandidate)) { - ssc->static_island++; - ssc->static_island %= state->element_map->totalIslands; - /* this is entirely possible if for example limit stitching - * with no stitchable verts or no selection */ - if (ssc->static_island == previous_island) { - break; - } - } - } - - for (i = 0; i < state->selection_size; i++) { - if (ssc->mode == STITCH_VERT) { - UvElement *element = (UvElement *)state->selection_stack[i]; - if (element->flag & STITCH_STITCHABLE_CANDIDATE) { - element->flag &= ~STITCH_STITCHABLE_CANDIDATE; - stitch_validate_uv_stitchability(element, ssc, state, island_stitch_data, preview_position); - } - else { - /* add to preview for unstitchable */ - preview->num_unstitchable++; - } - } - else { - UvEdge *edge = (UvEdge *)state->selection_stack[i]; - if (edge->flag & STITCH_STITCHABLE_CANDIDATE) { - edge->flag &= ~STITCH_STITCHABLE_CANDIDATE; - stitch_validate_edge_stitchability(edge, ssc, state, island_stitch_data, preview_position); - } - else { - preview->num_unstitchable++; - } - } - } - - /********************************************************************* - * Setup the stitchable & unstitchable preview buffers and fill * - * them with the appropriate data * - *********************************************************************/ - if (!final) { - BMLoop *l; - MLoopUV *luv; - int stitchBufferIndex = 0, unstitchBufferIndex = 0; - int preview_size = (ssc->mode == STITCH_VERT) ? 2 : 4; - /* initialize the preview buffers */ - preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable * sizeof(float) * preview_size, - "stitch_preview_stitchable_data"); - preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * sizeof(float) * preview_size, - "stitch_preview_unstitchable_data"); - - /* will cause cancel and freeing of all data structures so OK */ - if (!preview->preview_stitchable || !preview->preview_unstitchable) { - return 0; - } - - /* fill the appropriate preview buffers */ - if (ssc->mode == STITCH_VERT) { - for (i = 0; i < state->total_separate_uvs; i++) { - UvElement *element = (UvElement *)state->uvs[i]; - if (element->flag & STITCH_STITCHABLE) { - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv); - - stitchBufferIndex++; - } - else if (element->flag & STITCH_SELECTED) { - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv); - unstitchBufferIndex++; - } - } - } - else { - for (i = 0; i < state->total_separate_edges; i++) { - UvEdge *edge = state->edges + i; - UvElement *element1 = state->uvs[edge->uv1]; - UvElement *element2 = state->uvs[edge->uv2]; - - if (edge->flag & STITCH_STITCHABLE) { - l = element1->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4], luv->uv); - - l = element2->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4 + 2], luv->uv); - - stitchBufferIndex++; - BLI_assert(stitchBufferIndex <= preview->num_stitchable); - } - else if (edge->flag & STITCH_SELECTED) { - l = element1->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4], luv->uv); - - l = element2->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4 + 2], luv->uv); - - unstitchBufferIndex++; - BLI_assert(unstitchBufferIndex <= preview->num_unstitchable); - } - } - } - } - - if (ssc->states[ssc->active_object_index] != state) { - /* This is not the active object/state, exit here */ - MEM_freeN(island_stitch_data); - MEM_freeN(preview_position); - return 1; - } - - /**************************************** - * Setup preview for stitchable islands * - ****************************************/ - if (ssc->snap_islands) { - for (i = 0; i < state->element_map->totalIslands; i++) { - if (island_stitch_data[i].addedForPreview) { - int numOfIslandUVs = 0, j; - UvElement *element; - numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); - element = &state->element_map->buf[state->element_map->islandIndices[i]]; - for (j = 0; j < numOfIslandUVs; j++, element++) { - stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position); - } - } - } - } - - /********************************************************************* - * Setup the remaining preview buffers and fill them with the * - * appropriate data * - *********************************************************************/ - if (!final) { - BMIter liter; - BMLoop *l; - MLoopUV *luv; - unsigned int buffer_index = 0; - - /* initialize the preview buffers */ - preview->preview_polys = MEM_mallocN(preview->preview_uvs * sizeof(float) * 2, "tri_uv_stitch_prev"); - preview->uvs_per_polygon = MEM_mallocN(preview->num_polys * sizeof(*preview->uvs_per_polygon), - "tri_uv_stitch_prev"); - - preview->static_tris = MEM_mallocN(state->tris_per_island[ssc->static_island] * sizeof(float) * 6, - "static_island_preview_tris"); - - preview->num_static_tris = state->tris_per_island[ssc->static_island]; - /* will cause cancel and freeing of all data structures so OK */ - if (!preview->preview_polys) { - return 0; - } - - /* copy data from MLoopUVs to the preview display buffers */ - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - /* just to test if face was added for processing. - * uvs of unselected vertices will return NULL */ - UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa)); - - if (element) { - int numoftris = efa->len - 2; - int index = BM_elem_index_get(efa); - int face_preview_pos = preview_position[index].data_position; - if (face_preview_pos != STITCH_NO_PREVIEW) { - preview->uvs_per_polygon[preview_position[index].polycount_position] = efa->len; - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(preview->preview_polys + face_preview_pos + i * 2, luv->uv); - } - } - - /* if this is the static_island on the active object */ - if (element->island == ssc->static_island) { - BMLoop *fl = BM_FACE_FIRST_LOOP(efa); - MLoopUV *fuv = CustomData_bmesh_get(&bm->ldata, fl->head.data, CD_MLOOPUV); - - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - if (i < numoftris) { - /* using next since the first uv is already accounted for */ - BMLoop *lnext = l->next; - MLoopUV *luvnext = CustomData_bmesh_get(&bm->ldata, lnext->next->head.data, CD_MLOOPUV); - luv = CustomData_bmesh_get(&bm->ldata, lnext->head.data, CD_MLOOPUV); - - memcpy(preview->static_tris + buffer_index, fuv->uv, 2 * sizeof(float)); - memcpy(preview->static_tris + buffer_index + 2, luv->uv, 2 * sizeof(float)); - memcpy(preview->static_tris + buffer_index + 4, luvnext->uv, 2 * sizeof(float)); - buffer_index += 6; - } - else { - break; - } - } - } - } - } - } - - /****************************************************** - * Here we calculate the final coordinates of the uvs * - ******************************************************/ - - if (ssc->mode == STITCH_VERT) { - final_position = MEM_callocN(state->selection_size * sizeof(*final_position), "stitch_uv_average"); - uvfinal_map = MEM_mallocN(state->element_map->totalUVs * sizeof(*uvfinal_map), "stitch_uv_final_map"); - } - else { - final_position = MEM_callocN(state->total_separate_uvs * sizeof(*final_position), "stitch_uv_average"); - } - - /* first pass, calculate final position for stitchable uvs of the static island */ - for (i = 0; i < state->selection_size; i++) { - if (ssc->mode == STITCH_VERT) { - UvElement *element = state->selection_stack[i]; - - if (element->flag & STITCH_STITCHABLE) { - BMLoop *l; - MLoopUV *luv; - UvElement *element_iter; - - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - uvfinal_map[element - state->element_map->buf] = i; - - copy_v2_v2(final_position[i].uv, luv->uv); - final_position[i].count = 1; - - if (ssc->snap_islands && element->island == ssc->static_island && !stitch_midpoints) - continue; - - element_iter = state->element_map->vert[BM_elem_index_get(l->v)]; - - for ( ; element_iter; element_iter = element_iter->next) { - if (element_iter->separate) { - if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { - l = element_iter->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - if (stitch_midpoints) { - add_v2_v2(final_position[i].uv, luv->uv); - final_position[i].count++; - } - else if (element_iter->island == ssc->static_island) { - /* if multiple uvs on the static island exist, - * last checked remains. to disambiguate we need to limit or use - * edge stitch */ - copy_v2_v2(final_position[i].uv, luv->uv); - } - } - } - } - } - if (stitch_midpoints) { - final_position[i].uv[0] /= final_position[i].count; - final_position[i].uv[1] /= final_position[i].count; - } - } - else { - UvEdge *edge = state->selection_stack[i]; - - if (edge->flag & STITCH_STITCHABLE) { - MLoopUV *luv2, *luv1; - BMLoop *l; - UvEdge *edge_iter; - - l = state->uvs[edge->uv1]->l; - luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - l = state->uvs[edge->uv2]->l; - luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - copy_v2_v2(final_position[edge->uv1].uv, luv1->uv); - copy_v2_v2(final_position[edge->uv2].uv, luv2->uv); - final_position[edge->uv1].count = 1; - final_position[edge->uv2].count = 1; - - state->uvs[edge->uv1]->flag |= STITCH_STITCHABLE; - state->uvs[edge->uv2]->flag |= STITCH_STITCHABLE; - - if (ssc->snap_islands && edge->element->island == ssc->static_island && !stitch_midpoints) - continue; - - for (edge_iter = edge->first; edge_iter; edge_iter = edge_iter->next) { - if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) { - l = state->uvs[edge_iter->uv1]->l; - luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - l = state->uvs[edge_iter->uv2]->l; - luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - if (stitch_midpoints) { - add_v2_v2(final_position[edge->uv1].uv, luv1->uv); - final_position[edge->uv1].count++; - add_v2_v2(final_position[edge->uv2].uv, luv2->uv); - final_position[edge->uv2].count++; - } - else if (edge_iter->element->island == ssc->static_island) { - copy_v2_v2(final_position[edge->uv1].uv, luv1->uv); - copy_v2_v2(final_position[edge->uv2].uv, luv2->uv); - } - } - } - } - } - } - - /* take mean position here. - * For edge case, this can't be done inside the loop for shared uvverts */ - if (ssc->mode == STITCH_EDGE && stitch_midpoints) { - for (i = 0; i < state->total_separate_uvs; i++) { - final_position[i].uv[0] /= final_position[i].count; - final_position[i].uv[1] /= final_position[i].count; - } - } - - /* second pass, calculate island rotation and translation before modifying any uvs */ - if (ssc->snap_islands) { - if (ssc->mode == STITCH_VERT) { - for (i = 0; i < state->selection_size; i++) { - UvElement *element = state->selection_stack[i]; - - if (element->flag & STITCH_STITCHABLE) { - BMLoop *l; - MLoopUV *luv; - - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - /* accumulate each islands' translation from stitchable elements. it is important to do here - * because in final pass MTFaces get modified and result is zero. */ - island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - luv->uv[0]; - island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - luv->uv[1]; - island_stitch_data[element->island].medianPoint[0] += luv->uv[0]; - island_stitch_data[element->island].medianPoint[1] += luv->uv[1]; - island_stitch_data[element->island].numOfElements++; - } - } - - /* only calculate rotation when an edge has been fully selected */ - for (i = 0; i < state->total_separate_edges; i++) { - UvEdge *edge = state->edges + i; - if ((edge->flag & STITCH_BOUNDARY) && - (state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && - (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) - { - stitch_island_calculate_edge_rotation(edge, - ssc, - state, - final_position, - uvfinal_map, - island_stitch_data); - island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true; - } - } - - /* clear seams of stitched edges */ - if (final && ssc->clear_seams) { - for (i = 0; i < state->total_separate_edges; i++) { - UvEdge *edge = state->edges + i; - if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && - (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) - { - BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM); - } - } - } - - for (i = 0; i < state->selection_size; i++) { - UvElement *element = state->selection_stack[i]; - if (!island_stitch_data[element->island].use_edge_rotation) { - if (element->flag & STITCH_STITCHABLE) { - stitch_island_calculate_vert_rotation(element, ssc, state, island_stitch_data); - } - } - } - } - else { - for (i = 0; i < state->total_separate_uvs; i++) { - UvElement *element = state->uvs[i]; - - if (element->flag & STITCH_STITCHABLE) { - BMLoop *l; - MLoopUV *luv; - - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - /* accumulate each islands' translation from stitchable elements. it is important to do here - * because in final pass MTFaces get modified and result is zero. */ - island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - luv->uv[0]; - island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - luv->uv[1]; - island_stitch_data[element->island].medianPoint[0] += luv->uv[0]; - island_stitch_data[element->island].medianPoint[1] += luv->uv[1]; - island_stitch_data[element->island].numOfElements++; - } - } - - for (i = 0; i < state->selection_size; i++) { - UvEdge *edge = state->selection_stack[i]; - - if (edge->flag & STITCH_STITCHABLE) { - stitch_island_calculate_edge_rotation(edge, ssc, state, final_position, NULL, island_stitch_data); - island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true; - } - } - - /* clear seams of stitched edges */ - if (final && ssc->clear_seams) { - for (i = 0; i < state->selection_size; i++) { - UvEdge *edge = state->selection_stack[i]; - if (edge->flag & STITCH_STITCHABLE) { - BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM); - } - } - } - } - } - - /* third pass, propagate changes to coincident uvs */ - for (i = 0; i < state->selection_size; i++) { - if (ssc->mode == STITCH_VERT) { - UvElement *element = state->selection_stack[i]; - - stitch_propagate_uv_final_position(scene, element, i, preview_position, final_position, ssc, state, final); - } - else { - UvEdge *edge = state->selection_stack[i]; - - stitch_propagate_uv_final_position( - scene, state->uvs[edge->uv1], edge->uv1, preview_position, final_position, ssc, state, final); - stitch_propagate_uv_final_position( - scene, state->uvs[edge->uv2], edge->uv2, preview_position, final_position, ssc, state, final); - - edge->flag &= (STITCH_SELECTED | STITCH_BOUNDARY); - } - } - - /* final pass, calculate Island translation/rotation if needed */ - if (ssc->snap_islands) { - stitch_calculate_island_snapping(state, preview_position, preview, island_stitch_data, final); - } - - MEM_freeN(final_position); - if (ssc->mode == STITCH_VERT) { - MEM_freeN(uvfinal_map); - } - MEM_freeN(island_stitch_data); - MEM_freeN(preview_position); - - return 1; + int i; + StitchPreviewer *preview; + IslandStitchData *island_stitch_data = NULL; + int previous_island = ssc->static_island; + BMesh *bm = state->em->bm; + BMFace *efa; + BMIter iter; + UVVertAverage *final_position = NULL; + bool is_active_state = (state == ssc->states[ssc->active_object_index]); + + char stitch_midpoints = ssc->midpoints; + /* used to map uv indices to uvaverage indices for selection */ + unsigned int *uvfinal_map = NULL; + /* per face preview position in preview buffer */ + PreviewPosition *preview_position = NULL; + + /* cleanup previous preview */ + stitch_preview_delete(state->stitch_preview); + preview = state->stitch_preview = stitch_preview_init(); + if (preview == NULL) + return 0; + + preview_position = MEM_mallocN(bm->totface * sizeof(*preview_position), + "stitch_face_preview_position"); + /* each face holds its position in the preview buffer in tmp. -1 is uninitialized */ + for (i = 0; i < bm->totface; i++) { + preview_position[i].data_position = STITCH_NO_PREVIEW; + } + + island_stitch_data = MEM_callocN(sizeof(*island_stitch_data) * state->element_map->totalIslands, + "stitch_island_data"); + if (!island_stitch_data) { + return 0; + } + + /* store indices to editVerts and Faces. May be unneeded but ensuring anyway */ + BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE); + + /**************************************** + * First determine stitchability of uvs * + ****************************************/ + + for (i = 0; i < state->selection_size; i++) { + if (ssc->mode == STITCH_VERT) { + UvElement *element = (UvElement *)state->selection_stack[i]; + determine_uv_stitchability(element, ssc, state, island_stitch_data); + } + else { + UvEdge *edge = (UvEdge *)state->selection_stack[i]; + determine_uv_edge_stitchability(edge, ssc, state, island_stitch_data); + } + } + + /* remember stitchable candidates as places the 'I' button */ + /* will stop at. */ + for (int island_idx = 0; island_idx < state->element_map->totalIslands; island_idx++) { + state->island_is_stitchable[island_idx] = island_stitch_data[island_idx].stitchableCandidate ? + true : + false; + } + + if (is_active_state) { + /* set static island to one that is added for preview */ + ssc->static_island %= state->element_map->totalIslands; + while (!(island_stitch_data[ssc->static_island].stitchableCandidate)) { + ssc->static_island++; + ssc->static_island %= state->element_map->totalIslands; + /* this is entirely possible if for example limit stitching + * with no stitchable verts or no selection */ + if (ssc->static_island == previous_island) { + break; + } + } + } + + for (i = 0; i < state->selection_size; i++) { + if (ssc->mode == STITCH_VERT) { + UvElement *element = (UvElement *)state->selection_stack[i]; + if (element->flag & STITCH_STITCHABLE_CANDIDATE) { + element->flag &= ~STITCH_STITCHABLE_CANDIDATE; + stitch_validate_uv_stitchability( + element, ssc, state, island_stitch_data, preview_position); + } + else { + /* add to preview for unstitchable */ + preview->num_unstitchable++; + } + } + else { + UvEdge *edge = (UvEdge *)state->selection_stack[i]; + if (edge->flag & STITCH_STITCHABLE_CANDIDATE) { + edge->flag &= ~STITCH_STITCHABLE_CANDIDATE; + stitch_validate_edge_stitchability(edge, ssc, state, island_stitch_data, preview_position); + } + else { + preview->num_unstitchable++; + } + } + } + + /********************************************************************* + * Setup the stitchable & unstitchable preview buffers and fill * + * them with the appropriate data * + *********************************************************************/ + if (!final) { + BMLoop *l; + MLoopUV *luv; + int stitchBufferIndex = 0, unstitchBufferIndex = 0; + int preview_size = (ssc->mode == STITCH_VERT) ? 2 : 4; + /* initialize the preview buffers */ + preview->preview_stitchable = (float *)MEM_mallocN( + preview->num_stitchable * sizeof(float) * preview_size, "stitch_preview_stitchable_data"); + preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * + sizeof(float) * preview_size, + "stitch_preview_unstitchable_data"); + + /* will cause cancel and freeing of all data structures so OK */ + if (!preview->preview_stitchable || !preview->preview_unstitchable) { + return 0; + } + + /* fill the appropriate preview buffers */ + if (ssc->mode == STITCH_VERT) { + for (i = 0; i < state->total_separate_uvs; i++) { + UvElement *element = (UvElement *)state->uvs[i]; + if (element->flag & STITCH_STITCHABLE) { + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv); + + stitchBufferIndex++; + } + else if (element->flag & STITCH_SELECTED) { + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv); + unstitchBufferIndex++; + } + } + } + else { + for (i = 0; i < state->total_separate_edges; i++) { + UvEdge *edge = state->edges + i; + UvElement *element1 = state->uvs[edge->uv1]; + UvElement *element2 = state->uvs[edge->uv2]; + + if (edge->flag & STITCH_STITCHABLE) { + l = element1->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4], luv->uv); + + l = element2->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4 + 2], luv->uv); + + stitchBufferIndex++; + BLI_assert(stitchBufferIndex <= preview->num_stitchable); + } + else if (edge->flag & STITCH_SELECTED) { + l = element1->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4], luv->uv); + + l = element2->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4 + 2], luv->uv); + + unstitchBufferIndex++; + BLI_assert(unstitchBufferIndex <= preview->num_unstitchable); + } + } + } + } + + if (ssc->states[ssc->active_object_index] != state) { + /* This is not the active object/state, exit here */ + MEM_freeN(island_stitch_data); + MEM_freeN(preview_position); + return 1; + } + + /**************************************** + * Setup preview for stitchable islands * + ****************************************/ + if (ssc->snap_islands) { + for (i = 0; i < state->element_map->totalIslands; i++) { + if (island_stitch_data[i].addedForPreview) { + int numOfIslandUVs = 0, j; + UvElement *element; + numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); + element = &state->element_map->buf[state->element_map->islandIndices[i]]; + for (j = 0; j < numOfIslandUVs; j++, element++) { + stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position); + } + } + } + } + + /********************************************************************* + * Setup the remaining preview buffers and fill them with the * + * appropriate data * + *********************************************************************/ + if (!final) { + BMIter liter; + BMLoop *l; + MLoopUV *luv; + unsigned int buffer_index = 0; + + /* initialize the preview buffers */ + preview->preview_polys = MEM_mallocN(preview->preview_uvs * sizeof(float) * 2, + "tri_uv_stitch_prev"); + preview->uvs_per_polygon = MEM_mallocN(preview->num_polys * sizeof(*preview->uvs_per_polygon), + "tri_uv_stitch_prev"); + + preview->static_tris = MEM_mallocN(state->tris_per_island[ssc->static_island] * sizeof(float) * + 6, + "static_island_preview_tris"); + + preview->num_static_tris = state->tris_per_island[ssc->static_island]; + /* will cause cancel and freeing of all data structures so OK */ + if (!preview->preview_polys) { + return 0; + } + + /* copy data from MLoopUVs to the preview display buffers */ + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + /* just to test if face was added for processing. + * uvs of unselected vertices will return NULL */ + UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa)); + + if (element) { + int numoftris = efa->len - 2; + int index = BM_elem_index_get(efa); + int face_preview_pos = preview_position[index].data_position; + if (face_preview_pos != STITCH_NO_PREVIEW) { + preview->uvs_per_polygon[preview_position[index].polycount_position] = efa->len; + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) + { + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(preview->preview_polys + face_preview_pos + i * 2, luv->uv); + } + } + + /* if this is the static_island on the active object */ + if (element->island == ssc->static_island) { + BMLoop *fl = BM_FACE_FIRST_LOOP(efa); + MLoopUV *fuv = CustomData_bmesh_get(&bm->ldata, fl->head.data, CD_MLOOPUV); + + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) + { + if (i < numoftris) { + /* using next since the first uv is already accounted for */ + BMLoop *lnext = l->next; + MLoopUV *luvnext = CustomData_bmesh_get( + &bm->ldata, lnext->next->head.data, CD_MLOOPUV); + luv = CustomData_bmesh_get(&bm->ldata, lnext->head.data, CD_MLOOPUV); + + memcpy(preview->static_tris + buffer_index, fuv->uv, 2 * sizeof(float)); + memcpy(preview->static_tris + buffer_index + 2, luv->uv, 2 * sizeof(float)); + memcpy(preview->static_tris + buffer_index + 4, luvnext->uv, 2 * sizeof(float)); + buffer_index += 6; + } + else { + break; + } + } + } + } + } + } + + /****************************************************** + * Here we calculate the final coordinates of the uvs * + ******************************************************/ + + if (ssc->mode == STITCH_VERT) { + final_position = MEM_callocN(state->selection_size * sizeof(*final_position), + "stitch_uv_average"); + uvfinal_map = MEM_mallocN(state->element_map->totalUVs * sizeof(*uvfinal_map), + "stitch_uv_final_map"); + } + else { + final_position = MEM_callocN(state->total_separate_uvs * sizeof(*final_position), + "stitch_uv_average"); + } + + /* first pass, calculate final position for stitchable uvs of the static island */ + for (i = 0; i < state->selection_size; i++) { + if (ssc->mode == STITCH_VERT) { + UvElement *element = state->selection_stack[i]; + + if (element->flag & STITCH_STITCHABLE) { + BMLoop *l; + MLoopUV *luv; + UvElement *element_iter; + + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + uvfinal_map[element - state->element_map->buf] = i; + + copy_v2_v2(final_position[i].uv, luv->uv); + final_position[i].count = 1; + + if (ssc->snap_islands && element->island == ssc->static_island && !stitch_midpoints) + continue; + + element_iter = state->element_map->vert[BM_elem_index_get(l->v)]; + + for (; element_iter; element_iter = element_iter->next) { + if (element_iter->separate) { + if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { + l = element_iter->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + if (stitch_midpoints) { + add_v2_v2(final_position[i].uv, luv->uv); + final_position[i].count++; + } + else if (element_iter->island == ssc->static_island) { + /* if multiple uvs on the static island exist, + * last checked remains. to disambiguate we need to limit or use + * edge stitch */ + copy_v2_v2(final_position[i].uv, luv->uv); + } + } + } + } + } + if (stitch_midpoints) { + final_position[i].uv[0] /= final_position[i].count; + final_position[i].uv[1] /= final_position[i].count; + } + } + else { + UvEdge *edge = state->selection_stack[i]; + + if (edge->flag & STITCH_STITCHABLE) { + MLoopUV *luv2, *luv1; + BMLoop *l; + UvEdge *edge_iter; + + l = state->uvs[edge->uv1]->l; + luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + l = state->uvs[edge->uv2]->l; + luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + copy_v2_v2(final_position[edge->uv1].uv, luv1->uv); + copy_v2_v2(final_position[edge->uv2].uv, luv2->uv); + final_position[edge->uv1].count = 1; + final_position[edge->uv2].count = 1; + + state->uvs[edge->uv1]->flag |= STITCH_STITCHABLE; + state->uvs[edge->uv2]->flag |= STITCH_STITCHABLE; + + if (ssc->snap_islands && edge->element->island == ssc->static_island && !stitch_midpoints) + continue; + + for (edge_iter = edge->first; edge_iter; edge_iter = edge_iter->next) { + if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) { + l = state->uvs[edge_iter->uv1]->l; + luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + l = state->uvs[edge_iter->uv2]->l; + luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + if (stitch_midpoints) { + add_v2_v2(final_position[edge->uv1].uv, luv1->uv); + final_position[edge->uv1].count++; + add_v2_v2(final_position[edge->uv2].uv, luv2->uv); + final_position[edge->uv2].count++; + } + else if (edge_iter->element->island == ssc->static_island) { + copy_v2_v2(final_position[edge->uv1].uv, luv1->uv); + copy_v2_v2(final_position[edge->uv2].uv, luv2->uv); + } + } + } + } + } + } + + /* take mean position here. + * For edge case, this can't be done inside the loop for shared uvverts */ + if (ssc->mode == STITCH_EDGE && stitch_midpoints) { + for (i = 0; i < state->total_separate_uvs; i++) { + final_position[i].uv[0] /= final_position[i].count; + final_position[i].uv[1] /= final_position[i].count; + } + } + + /* second pass, calculate island rotation and translation before modifying any uvs */ + if (ssc->snap_islands) { + if (ssc->mode == STITCH_VERT) { + for (i = 0; i < state->selection_size; i++) { + UvElement *element = state->selection_stack[i]; + + if (element->flag & STITCH_STITCHABLE) { + BMLoop *l; + MLoopUV *luv; + + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + /* accumulate each islands' translation from stitchable elements. it is important to do here + * because in final pass MTFaces get modified and result is zero. */ + island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - + luv->uv[0]; + island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - + luv->uv[1]; + island_stitch_data[element->island].medianPoint[0] += luv->uv[0]; + island_stitch_data[element->island].medianPoint[1] += luv->uv[1]; + island_stitch_data[element->island].numOfElements++; + } + } + + /* only calculate rotation when an edge has been fully selected */ + for (i = 0; i < state->total_separate_edges; i++) { + UvEdge *edge = state->edges + i; + if ((edge->flag & STITCH_BOUNDARY) && (state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && + (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) { + stitch_island_calculate_edge_rotation( + edge, ssc, state, final_position, uvfinal_map, island_stitch_data); + island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true; + } + } + + /* clear seams of stitched edges */ + if (final && ssc->clear_seams) { + for (i = 0; i < state->total_separate_edges; i++) { + UvEdge *edge = state->edges + i; + if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && + (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) { + BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM); + } + } + } + + for (i = 0; i < state->selection_size; i++) { + UvElement *element = state->selection_stack[i]; + if (!island_stitch_data[element->island].use_edge_rotation) { + if (element->flag & STITCH_STITCHABLE) { + stitch_island_calculate_vert_rotation(element, ssc, state, island_stitch_data); + } + } + } + } + else { + for (i = 0; i < state->total_separate_uvs; i++) { + UvElement *element = state->uvs[i]; + + if (element->flag & STITCH_STITCHABLE) { + BMLoop *l; + MLoopUV *luv; + + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + /* accumulate each islands' translation from stitchable elements. it is important to do here + * because in final pass MTFaces get modified and result is zero. */ + island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - + luv->uv[0]; + island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - + luv->uv[1]; + island_stitch_data[element->island].medianPoint[0] += luv->uv[0]; + island_stitch_data[element->island].medianPoint[1] += luv->uv[1]; + island_stitch_data[element->island].numOfElements++; + } + } + + for (i = 0; i < state->selection_size; i++) { + UvEdge *edge = state->selection_stack[i]; + + if (edge->flag & STITCH_STITCHABLE) { + stitch_island_calculate_edge_rotation( + edge, ssc, state, final_position, NULL, island_stitch_data); + island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true; + } + } + + /* clear seams of stitched edges */ + if (final && ssc->clear_seams) { + for (i = 0; i < state->selection_size; i++) { + UvEdge *edge = state->selection_stack[i]; + if (edge->flag & STITCH_STITCHABLE) { + BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM); + } + } + } + } + } + + /* third pass, propagate changes to coincident uvs */ + for (i = 0; i < state->selection_size; i++) { + if (ssc->mode == STITCH_VERT) { + UvElement *element = state->selection_stack[i]; + + stitch_propagate_uv_final_position( + scene, element, i, preview_position, final_position, ssc, state, final); + } + else { + UvEdge *edge = state->selection_stack[i]; + + stitch_propagate_uv_final_position(scene, + state->uvs[edge->uv1], + edge->uv1, + preview_position, + final_position, + ssc, + state, + final); + stitch_propagate_uv_final_position(scene, + state->uvs[edge->uv2], + edge->uv2, + preview_position, + final_position, + ssc, + state, + final); + + edge->flag &= (STITCH_SELECTED | STITCH_BOUNDARY); + } + } + + /* final pass, calculate Island translation/rotation if needed */ + if (ssc->snap_islands) { + stitch_calculate_island_snapping(state, preview_position, preview, island_stitch_data, final); + } + + MEM_freeN(final_position); + if (ssc->mode == STITCH_VERT) { + MEM_freeN(uvfinal_map); + } + MEM_freeN(island_stitch_data); + MEM_freeN(preview_position); + + return 1; } static int stitch_process_data_all(StitchStateContainer *ssc, Scene *scene, int final) { - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - if (!stitch_process_data(ssc, ssc->states[ob_index], scene, final)) { - return 0; - } - } + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + if (!stitch_process_data(ssc, ssc->states[ob_index], scene, final)) { + return 0; + } + } - return 1; + return 1; } /* Stitch hash initialization functions */ static unsigned int uv_edge_hash(const void *key) { - const UvEdge *edge = key; - return (BLI_ghashutil_uinthash(edge->uv2) + - BLI_ghashutil_uinthash(edge->uv1)); + const UvEdge *edge = key; + return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1)); } static bool uv_edge_compare(const void *a, const void *b) { - const UvEdge *edge1 = a; - const UvEdge *edge2 = b; + const UvEdge *edge1 = a; + const UvEdge *edge2 = b; - if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) { - return 0; - } - return 1; + if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) { + return 0; + } + return 1; } /* select all common edges */ static void stitch_select_edge(UvEdge *edge, StitchState *state, int always_select) { - UvEdge *eiter; - UvEdge **selection_stack = (UvEdge **)state->selection_stack; - - for (eiter = edge->first; eiter; eiter = eiter->next) { - if (eiter->flag & STITCH_SELECTED) { - int i; - if (always_select) - continue; - - eiter->flag &= ~STITCH_SELECTED; - for (i = 0; i < state->selection_size; i++) { - if (selection_stack[i] == eiter) { - (state->selection_size)--; - selection_stack[i] = selection_stack[state->selection_size]; - break; - } - } - } - else { - eiter->flag |= STITCH_SELECTED; - selection_stack[state->selection_size++] = eiter; - } - } + UvEdge *eiter; + UvEdge **selection_stack = (UvEdge **)state->selection_stack; + + for (eiter = edge->first; eiter; eiter = eiter->next) { + if (eiter->flag & STITCH_SELECTED) { + int i; + if (always_select) + continue; + + eiter->flag &= ~STITCH_SELECTED; + for (i = 0; i < state->selection_size; i++) { + if (selection_stack[i] == eiter) { + (state->selection_size)--; + selection_stack[i] = selection_stack[state->selection_size]; + break; + } + } + } + else { + eiter->flag |= STITCH_SELECTED; + selection_stack[state->selection_size++] = eiter; + } + } } - /* Select all common uvs */ static void stitch_select_uv(UvElement *element, StitchState *state, int always_select) { - BMLoop *l; - UvElement *element_iter; - UvElement **selection_stack = (UvElement **)state->selection_stack; - - l = element->l; - - element_iter = state->element_map->vert[BM_elem_index_get(l->v)]; - /* first deselect all common uvs */ - for (; element_iter; element_iter = element_iter->next) { - if (element_iter->separate) { - /* only separators go to selection */ - if (element_iter->flag & STITCH_SELECTED) { - int i; - if (always_select) - continue; - - element_iter->flag &= ~STITCH_SELECTED; - for (i = 0; i < state->selection_size; i++) { - if (selection_stack[i] == element_iter) { - (state->selection_size)--; - selection_stack[i] = selection_stack[state->selection_size]; - break; - } - } - } - else { - element_iter->flag |= STITCH_SELECTED; - selection_stack[state->selection_size++] = element_iter; - } - } - } + BMLoop *l; + UvElement *element_iter; + UvElement **selection_stack = (UvElement **)state->selection_stack; + + l = element->l; + + element_iter = state->element_map->vert[BM_elem_index_get(l->v)]; + /* first deselect all common uvs */ + for (; element_iter; element_iter = element_iter->next) { + if (element_iter->separate) { + /* only separators go to selection */ + if (element_iter->flag & STITCH_SELECTED) { + int i; + if (always_select) + continue; + + element_iter->flag &= ~STITCH_SELECTED; + for (i = 0; i < state->selection_size; i++) { + if (selection_stack[i] == element_iter) { + (state->selection_size)--; + selection_stack[i] = selection_stack[state->selection_size]; + break; + } + } + } + else { + element_iter->flag |= STITCH_SELECTED; + selection_stack[state->selection_size++] = element_iter; + } + } + } } static void stitch_set_selection_mode(StitchState *state, const char from_stitch_mode) { - void **old_selection_stack = state->selection_stack; - int old_selection_size = state->selection_size; - state->selection_size = 0; - - if (from_stitch_mode == STITCH_VERT) { - int i; - state->selection_stack = MEM_mallocN(state->total_separate_edges * sizeof(*state->selection_stack), - "stitch_new_edge_selection_stack"); - - /* check if both elements of an edge are selected */ - for (i = 0; i < state->total_separate_edges; i++) { - UvEdge *edge = state->edges + i; - UvElement *element1 = state->uvs[edge->uv1]; - UvElement *element2 = state->uvs[edge->uv2]; - - if ((element1->flag & STITCH_SELECTED) && (element2->flag & STITCH_SELECTED)) - stitch_select_edge(edge, state, true); - } - - /* unselect selected uvelements */ - for (i = 0; i < old_selection_size; i++) { - UvElement *element = old_selection_stack[i]; - - element->flag &= ~STITCH_SELECTED; - } - } - else { - int i; - state->selection_stack = MEM_mallocN(state->total_separate_uvs * sizeof(*state->selection_stack), - "stitch_new_vert_selection_stack"); - - for (i = 0; i < old_selection_size; i++) { - UvEdge *edge = old_selection_stack[i]; - UvElement *element1 = state->uvs[edge->uv1]; - UvElement *element2 = state->uvs[edge->uv2]; - - stitch_select_uv(element1, state, true); - stitch_select_uv(element2, state, true); - - edge->flag &= ~STITCH_SELECTED; - } - } - MEM_freeN(old_selection_stack); + void **old_selection_stack = state->selection_stack; + int old_selection_size = state->selection_size; + state->selection_size = 0; + + if (from_stitch_mode == STITCH_VERT) { + int i; + state->selection_stack = MEM_mallocN(state->total_separate_edges * + sizeof(*state->selection_stack), + "stitch_new_edge_selection_stack"); + + /* check if both elements of an edge are selected */ + for (i = 0; i < state->total_separate_edges; i++) { + UvEdge *edge = state->edges + i; + UvElement *element1 = state->uvs[edge->uv1]; + UvElement *element2 = state->uvs[edge->uv2]; + + if ((element1->flag & STITCH_SELECTED) && (element2->flag & STITCH_SELECTED)) + stitch_select_edge(edge, state, true); + } + + /* unselect selected uvelements */ + for (i = 0; i < old_selection_size; i++) { + UvElement *element = old_selection_stack[i]; + + element->flag &= ~STITCH_SELECTED; + } + } + else { + int i; + state->selection_stack = MEM_mallocN(state->total_separate_uvs * + sizeof(*state->selection_stack), + "stitch_new_vert_selection_stack"); + + for (i = 0; i < old_selection_size; i++) { + UvEdge *edge = old_selection_stack[i]; + UvElement *element1 = state->uvs[edge->uv1]; + UvElement *element2 = state->uvs[edge->uv2]; + + stitch_select_uv(element1, state, true); + stitch_select_uv(element2, state, true); + + edge->flag &= ~STITCH_SELECTED; + } + } + MEM_freeN(old_selection_stack); } static void stitch_switch_selection_mode_all(StitchStateContainer *ssc) { - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - stitch_set_selection_mode(ssc->states[ob_index], ssc->mode); - } - - if (ssc->mode == STITCH_VERT) { - ssc->mode = STITCH_EDGE; - } - else { - ssc->mode = STITCH_VERT; - } + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + stitch_set_selection_mode(ssc->states[ob_index], ssc->mode); + } + + if (ssc->mode == STITCH_VERT) { + ssc->mode = STITCH_EDGE; + } + else { + ssc->mode = STITCH_VERT; + } } -static void stitch_calculate_edge_normal( - BMEditMesh *em, UvEdge *edge, float *normal, float aspect) +static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal, float aspect) { - BMLoop *l1 = edge->element->l; - MLoopUV *luv1, *luv2; - float tangent[2]; + BMLoop *l1 = edge->element->l; + MLoopUV *luv1, *luv2; + float tangent[2]; - luv1 = CustomData_bmesh_get(&em->bm->ldata, l1->head.data, CD_MLOOPUV); - luv2 = CustomData_bmesh_get(&em->bm->ldata, l1->next->head.data, CD_MLOOPUV); + luv1 = CustomData_bmesh_get(&em->bm->ldata, l1->head.data, CD_MLOOPUV); + luv2 = CustomData_bmesh_get(&em->bm->ldata, l1->next->head.data, CD_MLOOPUV); - sub_v2_v2v2(tangent, luv2->uv, luv1->uv); + sub_v2_v2v2(tangent, luv2->uv, luv1->uv); - tangent[1] /= aspect; + tangent[1] /= aspect; - normal[0] = tangent[1]; - normal[1] = -tangent[0]; + normal[0] = tangent[1]; + normal[1] = -tangent[0]; - normalize_v2(normal); + normalize_v2(normal); } /** */ static void stitch_draw_vbo(GPUVertBuf *vbo, GPUPrimType prim_type, const float col[4]) { - GPUBatch *batch = GPU_batch_create_ex(prim_type, vbo, NULL, GPU_BATCH_OWNS_VBO); - GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR); - GPU_batch_uniform_4fv(batch, "color", col); - GPU_batch_draw(batch); - GPU_batch_discard(batch); + GPUBatch *batch = GPU_batch_create_ex(prim_type, vbo, NULL, GPU_BATCH_OWNS_VBO); + GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR); + GPU_batch_uniform_4fv(batch, "color", col); + GPU_batch_draw(batch); + GPU_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) { - StitchStateContainer *ssc = (StitchStateContainer *)arg; - - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - int j, index = 0; - unsigned int num_line = 0, num_tri, tri_idx = 0, line_idx = 0; - StitchState *state = ssc->states[ob_index]; - StitchPreviewer *stitch_preview = state->stitch_preview; - GPUVertBuf *vbo, *vbo_line; - float col[4]; - - static GPUVertFormat format = { 0 }; - static unsigned int pos_id; - if (format.attr_len == 0) { - pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - } - - GPU_blend(true); - - /* Static Tris */ - if (stitch_preview->static_tris) { - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_ACTIVE, col); - vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, stitch_preview->num_static_tris * 3); - for (int i = 0; i < stitch_preview->num_static_tris * 3; i++) { - GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->static_tris[i * 2]); - } - stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col); - } - - /* Preview Polys */ - if (stitch_preview->preview_polys) { - for (int i = 0; i < stitch_preview->num_polys; i++) - num_line += stitch_preview->uvs_per_polygon[i]; - - num_tri = num_line - 2 * stitch_preview->num_polys; - - /* we need to convert the polys into triangles / lines */ - vbo = GPU_vertbuf_create_with_format(&format); - vbo_line = GPU_vertbuf_create_with_format(&format); - - GPU_vertbuf_data_alloc(vbo, num_tri * 3); - GPU_vertbuf_data_alloc(vbo_line, num_line * 2); - - - for (int i = 0; i < stitch_preview->num_polys; i++) { - BLI_assert(stitch_preview->uvs_per_polygon[i] >= 3); - - /* Start line */ - GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]); - GPU_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) { - GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]); - GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]); - GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]); - - GPU_vertbuf_attr_set(vbo_line, - pos_id, - line_idx++, - &stitch_preview->preview_polys[index + (j + 0) * 2]); - GPU_vertbuf_attr_set(vbo_line, - pos_id, - line_idx++, - &stitch_preview->preview_polys[index + (j + 1) * 2]); - } - - /* Closing line */ - GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]); - /* j = uvs_per_polygon[i] - 1*/ - GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + j * 2]); - - index += stitch_preview->uvs_per_polygon[i] * 2; - } - - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_FACE, col); - stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col); - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_EDGE, col); - stitch_draw_vbo(vbo_line, GPU_PRIM_LINES, col); - } - - GPU_blend(false); - - /* draw stitch vert/lines preview */ - if (ssc->mode == STITCH_VERT) { - GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f); - - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col); - vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable); - for (int i = 0; i < stitch_preview->num_stitchable; i++) { - GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]); - } - stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col); - - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col); - vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable); - for (int i = 0; i < stitch_preview->num_unstitchable; i++) { - GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]); - } - stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col); - } - else { - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col); - vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable * 2); - for (int i = 0; i < stitch_preview->num_stitchable * 2; i++) { - GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]); - } - stitch_draw_vbo(vbo, GPU_PRIM_LINES, col); - - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col); - vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable * 2); - for (int i = 0; i < stitch_preview->num_unstitchable * 2; i++) { - GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]); - } - stitch_draw_vbo(vbo, GPU_PRIM_LINES, col); - } - } + StitchStateContainer *ssc = (StitchStateContainer *)arg; + + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + int j, index = 0; + unsigned int num_line = 0, num_tri, tri_idx = 0, line_idx = 0; + StitchState *state = ssc->states[ob_index]; + StitchPreviewer *stitch_preview = state->stitch_preview; + GPUVertBuf *vbo, *vbo_line; + float col[4]; + + static GPUVertFormat format = {0}; + static unsigned int pos_id; + if (format.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + } + + GPU_blend(true); + + /* Static Tris */ + if (stitch_preview->static_tris) { + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_ACTIVE, col); + vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, stitch_preview->num_static_tris * 3); + for (int i = 0; i < stitch_preview->num_static_tris * 3; i++) { + GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->static_tris[i * 2]); + } + stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col); + } + + /* Preview Polys */ + if (stitch_preview->preview_polys) { + for (int i = 0; i < stitch_preview->num_polys; i++) + num_line += stitch_preview->uvs_per_polygon[i]; + + num_tri = num_line - 2 * stitch_preview->num_polys; + + /* we need to convert the polys into triangles / lines */ + vbo = GPU_vertbuf_create_with_format(&format); + vbo_line = GPU_vertbuf_create_with_format(&format); + + GPU_vertbuf_data_alloc(vbo, num_tri * 3); + GPU_vertbuf_data_alloc(vbo_line, num_line * 2); + + for (int i = 0; i < stitch_preview->num_polys; i++) { + BLI_assert(stitch_preview->uvs_per_polygon[i] >= 3); + + /* Start line */ + GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]); + GPU_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) { + GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]); + GPU_vertbuf_attr_set( + vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]); + GPU_vertbuf_attr_set( + vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]); + + GPU_vertbuf_attr_set( + vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]); + GPU_vertbuf_attr_set( + vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]); + } + + /* Closing line */ + GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]); + /* j = uvs_per_polygon[i] - 1*/ + GPU_vertbuf_attr_set( + vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + j * 2]); + + index += stitch_preview->uvs_per_polygon[i] * 2; + } + + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_FACE, col); + stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col); + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_EDGE, col); + stitch_draw_vbo(vbo_line, GPU_PRIM_LINES, col); + } + + GPU_blend(false); + + /* draw stitch vert/lines preview */ + if (ssc->mode == STITCH_VERT) { + GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f); + + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col); + vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable); + for (int i = 0; i < stitch_preview->num_stitchable; i++) { + GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]); + } + stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col); + + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col); + vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable); + for (int i = 0; i < stitch_preview->num_unstitchable; i++) { + GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]); + } + stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col); + } + else { + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col); + vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable * 2); + for (int i = 0; i < stitch_preview->num_stitchable * 2; i++) { + GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]); + } + stitch_draw_vbo(vbo, GPU_PRIM_LINES, col); + + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col); + vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable * 2); + for (int i = 0; i < stitch_preview->num_unstitchable * 2; i++) { + GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]); + } + stitch_draw_vbo(vbo, GPU_PRIM_LINES, col); + } + } } static UvEdge *uv_edge_get(BMLoop *l, StitchState *state) { - UvEdge tmp_edge; + UvEdge tmp_edge; - UvElement *element1 = BM_uv_element_get(state->element_map, l->f, l); - UvElement *element2 = BM_uv_element_get(state->element_map, l->f, l->next); + UvElement *element1 = BM_uv_element_get(state->element_map, l->f, l); + UvElement *element2 = BM_uv_element_get(state->element_map, l->f, l->next); - int uv1 = state->map[element1 - state->element_map->buf]; - int uv2 = state->map[element2 - state->element_map->buf]; + int uv1 = state->map[element1 - state->element_map->buf]; + int uv2 = state->map[element2 - state->element_map->buf]; - if (uv1 < uv2) { - tmp_edge.uv1 = uv1; - tmp_edge.uv2 = uv2; - } - else { - tmp_edge.uv1 = uv2; - tmp_edge.uv2 = uv1; - } + if (uv1 < uv2) { + tmp_edge.uv1 = uv1; + tmp_edge.uv2 = uv2; + } + else { + tmp_edge.uv1 = uv2; + tmp_edge.uv2 = uv1; + } - return BLI_ghash_lookup(state->edge_hash, &tmp_edge); + return BLI_ghash_lookup(state->edge_hash, &tmp_edge); } -static StitchState *stitch_init( - bContext *C, wmOperator *op, - StitchStateContainer *ssc, Object *obedit, StitchStateInit *state_init) +static StitchState *stitch_init(bContext *C, + wmOperator *op, + StitchStateContainer *ssc, + Object *obedit, + StitchStateInit *state_init) { - /* for fast edge lookup... */ - GHash *edge_hash; - /* ...and actual edge storage */ - UvEdge *edges; - int total_edges; - /* maps uvelements to their first coincident uv */ - int *map; - int counter = 0, i; - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - GHashIterator gh_iter; - UvEdge *all_edges; - StitchState *state; - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - float aspx, aspy; - - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - state = MEM_callocN(sizeof(StitchState), "stitch state obj"); - - /* initialize state */ - state->obedit = obedit; - state->em = em; - - /* in uv synch selection, all uv's are visible */ - if (ts->uv_flag & UV_SYNC_SELECTION) { - state->element_map = BM_uv_element_map_create(state->em->bm, false, true, true); - } - else { - state->element_map = BM_uv_element_map_create(state->em->bm, true, true, true); - } - if (!state->element_map) { - state_delete(state); - return NULL; - } - - ED_uvedit_get_aspect(scene, obedit, em->bm, &aspx, &aspy); - state->aspect = aspx / aspy; - - /* Count 'unique' uvs */ - for (i = 0; i < state->element_map->totalUVs; i++) { - if (state->element_map->buf[i].separate) { - counter++; - } - } - - /* explicitly set preview to NULL, - * to avoid deleting an invalid pointer on stitch_process_data */ - state->stitch_preview = NULL; - /* Allocate the unique uv buffers */ - state->uvs = MEM_mallocN(sizeof(*state->uvs) * counter, "uv_stitch_unique_uvs"); - /* internal uvs need no normals but it is hard and slow to keep a map of - * normals only for boundary uvs, so allocating for all uvs */ - state->normals = MEM_callocN(sizeof(*state->normals) * counter * 2, "uv_stitch_normals"); - state->total_separate_uvs = counter; - state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->totalUVs, "uv_stitch_unique_map"); - /* Allocate the edge stack */ - edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash"); - all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->totalUVs, "ssc_edges"); - - if (!state->uvs || !map || !edge_hash || !all_edges) { - state_delete(state); - return NULL; - } - - /* So that we can use this as index for the UvElements */ - counter = -1; - /* initialize the unique UVs and map */ - for (i = 0; i < em->bm->totvert; i++) { - UvElement *element = state->element_map->vert[i]; - for (; element; element = element->next) { - if (element->separate) { - counter++; - state->uvs[counter] = element; - } - /* pointer arithmetic to the rescue, as always :)*/ - map[element - state->element_map->buf] = counter; - } - } - - counter = 0; - /* Now, on to generate our uv connectivity data */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!(ts->uv_flag & UV_SYNC_SELECTION) && - ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT))) - { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - UvElement *element = BM_uv_element_get(state->element_map, efa, l); - int offset1, itmp1 = element - state->element_map->buf; - int offset2, itmp2 = BM_uv_element_get(state->element_map, efa, l->next) - state->element_map->buf; - UvEdge *edge; - - offset1 = map[itmp1]; - offset2 = map[itmp2]; - - all_edges[counter].next = NULL; - all_edges[counter].first = NULL; - all_edges[counter].flag = 0; - all_edges[counter].element = element; - /* using an order policy, sort uvs according to address space. This avoids - * Having two different UvEdges with the same uvs on different positions */ - if (offset1 < offset2) { - all_edges[counter].uv1 = offset1; - all_edges[counter].uv2 = offset2; - } - else { - all_edges[counter].uv1 = offset2; - all_edges[counter].uv2 = offset1; - } - - edge = BLI_ghash_lookup(edge_hash, &all_edges[counter]); - if (edge) { - edge->flag = 0; - } - else { - BLI_ghash_insert(edge_hash, &all_edges[counter], &all_edges[counter]); - all_edges[counter].flag = STITCH_BOUNDARY; - } - counter++; - } - } - - total_edges = BLI_ghash_len(edge_hash); - state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges"); - - /* I assume any system will be able to at least allocate an iterator :p */ - if (!edges) { - state_delete(state); - return NULL; - } - - state->total_separate_edges = total_edges; - - /* fill the edges with data */ - i = 0; - GHASH_ITER (gh_iter, edge_hash) { - edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter)); - } - - /* cleanup temporary stuff */ - MEM_freeN(all_edges); - - BLI_ghash_free(edge_hash, NULL, NULL); - - /* refill an edge hash to create edge connnectivity data */ - state->edge_hash = edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash"); - for (i = 0; i < total_edges; i++) { - BLI_ghash_insert(edge_hash, edges + i, edges + i); - } - stitch_uv_edge_generate_linked_edges(edge_hash, state); - - /***** calculate 2D normals for boundary uvs *****/ - - /* we use boundary edges to calculate 2D normals. - * to disambiguate the direction of the normal, we also need - * a point "inside" the island, that can be provided by - * the winding of the polygon (assuming counter-clockwise flow). */ - - for (i = 0; i < total_edges; i++) { - UvEdge *edge = edges + i; - float normal[2]; - if (edge->flag & STITCH_BOUNDARY) { - stitch_calculate_edge_normal(em, edge, normal, state->aspect); - - add_v2_v2(state->normals + edge->uv1 * 2, normal); - add_v2_v2(state->normals + edge->uv2 * 2, normal); - - normalize_v2(state->normals + edge->uv1 * 2); - normalize_v2(state->normals + edge->uv2 * 2); - } - } - - - /***** fill selection stack *******/ - - state->selection_size = 0; - - /* Load old selection if redoing operator with different settings */ - if (state_init != NULL) { - int faceIndex, elementIndex; - UvElement *element; - enum StitchModes stored_mode = RNA_enum_get(op->ptr, "stored_mode"); - - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - - int selected_count = state_init->uv_selected_count; - - if (stored_mode == STITCH_VERT) { - state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs, - "uv_stitch_selection_stack"); - - while (selected_count--) { - faceIndex = state_init->to_select[selected_count].faceIndex; - elementIndex = state_init->to_select[selected_count].elementIndex; - efa = BM_face_at_index(em->bm, faceIndex); - element = BM_uv_element_get(state->element_map, - efa, - BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex)); - stitch_select_uv(element, state, 1); - } - } - else { - state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges, - "uv_stitch_selection_stack"); - - while (selected_count--) { - UvEdge tmp_edge, *edge; - int uv1, uv2; - faceIndex = state_init->to_select[selected_count].faceIndex; - elementIndex = state_init->to_select[selected_count].elementIndex; - efa = BM_face_at_index(em->bm, faceIndex); - element = BM_uv_element_get(state->element_map, - efa, - BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex)); - uv1 = map[element - state->element_map->buf]; - - element = BM_uv_element_get(state->element_map, - efa, - BM_iter_at_index(NULL, - BM_LOOPS_OF_FACE, - efa, - (elementIndex + 1) % efa->len)); - uv2 = map[element - state->element_map->buf]; - - if (uv1 < uv2) { - tmp_edge.uv1 = uv1; - tmp_edge.uv2 = uv2; - } - else { - tmp_edge.uv1 = uv2; - tmp_edge.uv2 = uv1; - } - - edge = BLI_ghash_lookup(edge_hash, &tmp_edge); - - stitch_select_edge(edge, state, true); - } - } - /* if user has switched the operator mode after operation, we need to convert - * the stored format */ - if (ssc->mode != stored_mode) { - stitch_set_selection_mode(state, stored_mode); - } - } - else { - if (ssc->mode == STITCH_VERT) { - state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs, - "uv_stitch_selection_stack"); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - UvElement *element = BM_uv_element_get(state->element_map, efa, l); - if (element) { - stitch_select_uv(element, state, 1); - } - } - } - } - } - else { - state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges, - "uv_stitch_selection_stack"); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!(ts->uv_flag & UV_SYNC_SELECTION) && - ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT))) - { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) { - UvEdge *edge = uv_edge_get(l, state); - if (edge) { - stitch_select_edge(edge, state, true); - } - } - } - } - } - } - - /***** initialize static island preview data *****/ - - state->tris_per_island = MEM_mallocN(sizeof(*state->tris_per_island) * state->element_map->totalIslands, - "stitch island tris"); - for (i = 0; i < state->element_map->totalIslands; i++) { - state->tris_per_island[i] = 0; - } - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa)); - - if (element) { - state->tris_per_island[element->island] += (efa->len > 2) ? efa->len - 2 : 0; - } - } - - state->island_is_stitchable = MEM_callocN(sizeof(bool) * state->element_map->totalIslands, "stitch I stops"); - if (!state->island_is_stitchable) { - state_delete(state); - return NULL; - } - - if (!stitch_process_data(ssc, state, scene, false)) { - state_delete(state); - return NULL; - } - - return state; + /* for fast edge lookup... */ + GHash *edge_hash; + /* ...and actual edge storage */ + UvEdge *edges; + int total_edges; + /* maps uvelements to their first coincident uv */ + int *map; + int counter = 0, i; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + GHashIterator gh_iter; + UvEdge *all_edges; + StitchState *state; + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + float aspx, aspy; + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + state = MEM_callocN(sizeof(StitchState), "stitch state obj"); + + /* initialize state */ + state->obedit = obedit; + state->em = em; + + /* in uv synch selection, all uv's are visible */ + if (ts->uv_flag & UV_SYNC_SELECTION) { + state->element_map = BM_uv_element_map_create(state->em->bm, false, true, true); + } + else { + state->element_map = BM_uv_element_map_create(state->em->bm, true, true, true); + } + if (!state->element_map) { + state_delete(state); + return NULL; + } + + ED_uvedit_get_aspect(scene, obedit, em->bm, &aspx, &aspy); + state->aspect = aspx / aspy; + + /* Count 'unique' uvs */ + for (i = 0; i < state->element_map->totalUVs; i++) { + if (state->element_map->buf[i].separate) { + counter++; + } + } + + /* explicitly set preview to NULL, + * to avoid deleting an invalid pointer on stitch_process_data */ + state->stitch_preview = NULL; + /* Allocate the unique uv buffers */ + state->uvs = MEM_mallocN(sizeof(*state->uvs) * counter, "uv_stitch_unique_uvs"); + /* internal uvs need no normals but it is hard and slow to keep a map of + * normals only for boundary uvs, so allocating for all uvs */ + state->normals = MEM_callocN(sizeof(*state->normals) * counter * 2, "uv_stitch_normals"); + state->total_separate_uvs = counter; + state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->totalUVs, + "uv_stitch_unique_map"); + /* Allocate the edge stack */ + edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash"); + all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->totalUVs, "ssc_edges"); + + if (!state->uvs || !map || !edge_hash || !all_edges) { + state_delete(state); + return NULL; + } + + /* So that we can use this as index for the UvElements */ + counter = -1; + /* initialize the unique UVs and map */ + for (i = 0; i < em->bm->totvert; i++) { + UvElement *element = state->element_map->vert[i]; + for (; element; element = element->next) { + if (element->separate) { + counter++; + state->uvs[counter] = element; + } + /* pointer arithmetic to the rescue, as always :)*/ + map[element - state->element_map->buf] = counter; + } + } + + counter = 0; + /* Now, on to generate our uv connectivity data */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!(ts->uv_flag & UV_SYNC_SELECTION) && + ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT))) { + continue; + } + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + UvElement *element = BM_uv_element_get(state->element_map, efa, l); + int offset1, itmp1 = element - state->element_map->buf; + int offset2, + itmp2 = BM_uv_element_get(state->element_map, efa, l->next) - state->element_map->buf; + UvEdge *edge; + + offset1 = map[itmp1]; + offset2 = map[itmp2]; + + all_edges[counter].next = NULL; + all_edges[counter].first = NULL; + all_edges[counter].flag = 0; + all_edges[counter].element = element; + /* using an order policy, sort uvs according to address space. This avoids + * Having two different UvEdges with the same uvs on different positions */ + if (offset1 < offset2) { + all_edges[counter].uv1 = offset1; + all_edges[counter].uv2 = offset2; + } + else { + all_edges[counter].uv1 = offset2; + all_edges[counter].uv2 = offset1; + } + + edge = BLI_ghash_lookup(edge_hash, &all_edges[counter]); + if (edge) { + edge->flag = 0; + } + else { + BLI_ghash_insert(edge_hash, &all_edges[counter], &all_edges[counter]); + all_edges[counter].flag = STITCH_BOUNDARY; + } + counter++; + } + } + + total_edges = BLI_ghash_len(edge_hash); + state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges"); + + /* I assume any system will be able to at least allocate an iterator :p */ + if (!edges) { + state_delete(state); + return NULL; + } + + state->total_separate_edges = total_edges; + + /* fill the edges with data */ + i = 0; + GHASH_ITER (gh_iter, edge_hash) { + edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter)); + } + + /* cleanup temporary stuff */ + MEM_freeN(all_edges); + + BLI_ghash_free(edge_hash, NULL, NULL); + + /* refill an edge hash to create edge connnectivity data */ + state->edge_hash = edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash"); + for (i = 0; i < total_edges; i++) { + BLI_ghash_insert(edge_hash, edges + i, edges + i); + } + stitch_uv_edge_generate_linked_edges(edge_hash, state); + + /***** calculate 2D normals for boundary uvs *****/ + + /* we use boundary edges to calculate 2D normals. + * to disambiguate the direction of the normal, we also need + * a point "inside" the island, that can be provided by + * the winding of the polygon (assuming counter-clockwise flow). */ + + for (i = 0; i < total_edges; i++) { + UvEdge *edge = edges + i; + float normal[2]; + if (edge->flag & STITCH_BOUNDARY) { + stitch_calculate_edge_normal(em, edge, normal, state->aspect); + + add_v2_v2(state->normals + edge->uv1 * 2, normal); + add_v2_v2(state->normals + edge->uv2 * 2, normal); + + normalize_v2(state->normals + edge->uv1 * 2); + normalize_v2(state->normals + edge->uv2 * 2); + } + } + + /***** fill selection stack *******/ + + state->selection_size = 0; + + /* Load old selection if redoing operator with different settings */ + if (state_init != NULL) { + int faceIndex, elementIndex; + UvElement *element; + enum StitchModes stored_mode = RNA_enum_get(op->ptr, "stored_mode"); + + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + + int selected_count = state_init->uv_selected_count; + + if (stored_mode == STITCH_VERT) { + state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * + state->total_separate_uvs, + "uv_stitch_selection_stack"); + + while (selected_count--) { + faceIndex = state_init->to_select[selected_count].faceIndex; + elementIndex = state_init->to_select[selected_count].elementIndex; + efa = BM_face_at_index(em->bm, faceIndex); + element = BM_uv_element_get( + state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex)); + stitch_select_uv(element, state, 1); + } + } + else { + state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * + state->total_separate_edges, + "uv_stitch_selection_stack"); + + while (selected_count--) { + UvEdge tmp_edge, *edge; + int uv1, uv2; + faceIndex = state_init->to_select[selected_count].faceIndex; + elementIndex = state_init->to_select[selected_count].elementIndex; + efa = BM_face_at_index(em->bm, faceIndex); + element = BM_uv_element_get( + state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex)); + uv1 = map[element - state->element_map->buf]; + + element = BM_uv_element_get( + state->element_map, + efa, + BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, (elementIndex + 1) % efa->len)); + uv2 = map[element - state->element_map->buf]; + + if (uv1 < uv2) { + tmp_edge.uv1 = uv1; + tmp_edge.uv2 = uv2; + } + else { + tmp_edge.uv1 = uv2; + tmp_edge.uv2 = uv1; + } + + edge = BLI_ghash_lookup(edge_hash, &tmp_edge); + + stitch_select_edge(edge, state, true); + } + } + /* if user has switched the operator mode after operation, we need to convert + * the stored format */ + if (ssc->mode != stored_mode) { + stitch_set_selection_mode(state, stored_mode); + } + } + else { + if (ssc->mode == STITCH_VERT) { + state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * + state->total_separate_uvs, + "uv_stitch_selection_stack"); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) + { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + UvElement *element = BM_uv_element_get(state->element_map, efa, l); + if (element) { + stitch_select_uv(element, state, 1); + } + } + } + } + } + else { + state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * + state->total_separate_edges, + "uv_stitch_selection_stack"); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!(ts->uv_flag & UV_SYNC_SELECTION) && ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || + !BM_elem_flag_test(efa, BM_ELEM_SELECT))) { + continue; + } + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) { + UvEdge *edge = uv_edge_get(l, state); + if (edge) { + stitch_select_edge(edge, state, true); + } + } + } + } + } + } + + /***** initialize static island preview data *****/ + + state->tris_per_island = MEM_mallocN( + sizeof(*state->tris_per_island) * state->element_map->totalIslands, "stitch island tris"); + for (i = 0; i < state->element_map->totalIslands; i++) { + state->tris_per_island[i] = 0; + } + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa)); + + if (element) { + state->tris_per_island[element->island] += (efa->len > 2) ? efa->len - 2 : 0; + } + } + + state->island_is_stitchable = MEM_callocN(sizeof(bool) * state->element_map->totalIslands, + "stitch I stops"); + if (!state->island_is_stitchable) { + state_delete(state); + return NULL; + } + + if (!stitch_process_data(ssc, state, scene, false)) { + state_delete(state); + return NULL; + } + + return state; } static bool goto_next_island(StitchStateContainer *ssc) { - StitchState *active_state = ssc->states[ssc->active_object_index]; - StitchState *original_active_state = active_state; - - int original_island = ssc->static_island; - - do { - ssc->static_island++; - if (ssc->static_island >= active_state->element_map->totalIslands) { - /* go to next object */ - ssc->active_object_index++; - ssc->active_object_index %= ssc->objects_len; - - active_state = ssc->states[ssc->active_object_index]; - ssc->static_island = 0; - } - - if (active_state->island_is_stitchable[ssc->static_island]) { - /* We're at an island to make active */ - return true; - } - } while (!(active_state == original_active_state && - ssc->static_island == original_island)); - - return false; + StitchState *active_state = ssc->states[ssc->active_object_index]; + StitchState *original_active_state = active_state; + + int original_island = ssc->static_island; + + do { + ssc->static_island++; + if (ssc->static_island >= active_state->element_map->totalIslands) { + /* go to next object */ + ssc->active_object_index++; + ssc->active_object_index %= ssc->objects_len; + + active_state = ssc->states[ssc->active_object_index]; + ssc->static_island = 0; + } + + if (active_state->island_is_stitchable[ssc->static_island]) { + /* We're at an island to make active */ + return true; + } + } while (!(active_state == original_active_state && ssc->static_island == original_island)); + + return false; } static int stitch_init_all(bContext *C, wmOperator *op) { - ARegion *ar = CTX_wm_region(C); - if (!ar) - return 0; - - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - - StitchStateContainer *ssc = MEM_callocN(sizeof(StitchStateContainer), "stitch collection"); - - op->customdata = ssc; - - ssc->use_limit = RNA_boolean_get(op->ptr, "use_limit"); - ssc->limit_dist = RNA_float_get(op->ptr, "limit"); - ssc->snap_islands = RNA_boolean_get(op->ptr, "snap_islands"); - ssc->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap"); - ssc->clear_seams = RNA_boolean_get(op->ptr, "clear_seams"); - ssc->active_object_index = RNA_int_get(op->ptr, "active_object_index"); - ssc->static_island = 0; - - if (RNA_struct_property_is_set(op->ptr, "mode")) { - ssc->mode = RNA_enum_get(op->ptr, "mode"); - } - else { - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_VERTEX) - ssc->mode = STITCH_VERT; - else - ssc->mode = STITCH_EDGE; - } - else { - if (ts->uv_selectmode & UV_SELECT_VERTEX) { - ssc->mode = STITCH_VERT; - } - else { - ssc->mode = STITCH_EDGE; - } - } - } - - ssc->objects_len = 0; - ssc->states = NULL; - - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, &objects_len); - - if (objects_len == 0) { - MEM_freeN(objects); - state_delete_all(ssc); - return 0; - } - - ssc->objects = MEM_callocN(sizeof(Object *) * objects_len, "Object *ssc->objects"); - ssc->states = MEM_callocN(sizeof(StitchState *) * objects_len, "StitchState"); - ssc->objects_len = 0; - - int *objs_selection_count = NULL; - UvElementID *selected_uvs_arr = NULL; - StitchStateInit *state_init = NULL; - - if (RNA_struct_property_is_set(op->ptr, "selection") && - RNA_struct_property_is_set(op->ptr, "objects_selection_count")) - { - /* Retrieve list of selected UVs, one list contains all selected UVs - * for all objects. */ - - objs_selection_count = MEM_mallocN(sizeof(int *) * objects_len, "objects_selection_count"); - RNA_int_get_array(op->ptr, "objects_selection_count", objs_selection_count); - - int total_selected = 0; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - total_selected += objs_selection_count[ob_index]; - } - - selected_uvs_arr = MEM_callocN(sizeof(UvElementID) * total_selected, "selected_uvs_arr"); - int sel_idx = 0; - RNA_BEGIN (op->ptr, itemptr, "selection") - { - BLI_assert(sel_idx < total_selected); - selected_uvs_arr[sel_idx].faceIndex = RNA_int_get(&itemptr, "face_index"); - selected_uvs_arr[sel_idx].elementIndex = RNA_int_get(&itemptr, "element_index"); - sel_idx++; - } - RNA_END; - - RNA_collection_clear(op->ptr, "selection"); - - state_init = MEM_callocN(sizeof(StitchStateInit), "UV_init_selected"); - state_init->to_select = selected_uvs_arr; - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - - if (state_init != NULL) { - state_init->uv_selected_count = objs_selection_count[ob_index]; - } - - StitchState *stitch_state_ob = stitch_init(C, op, ssc, obedit, state_init); - - if (state_init != NULL) { - /* Move pointer to beginning of next object's data. */ - state_init->to_select += state_init->uv_selected_count; - } - - if (stitch_state_ob) { - ssc->objects[ssc->objects_len] = obedit; - ssc->states[ssc->objects_len] = stitch_state_ob; - ssc->objects_len++; - } - } - - MEM_freeN(objects); - MEM_SAFE_FREE(selected_uvs_arr); - MEM_SAFE_FREE(objs_selection_count); - MEM_SAFE_FREE(state_init); - - if (ssc->objects_len == 0) { - state_delete_all(ssc); - return 0; - } - - ssc->active_object_index %= ssc->objects_len; - - ssc->static_island = RNA_int_get(op->ptr, "static_island"); - - StitchState *state = ssc->states[ssc->active_object_index]; - ssc->static_island %= state->element_map->totalIslands; - - /* If the initial active object doesn't have any stitchable islands */ - /* then no active island will be seen in the UI. Make sure we're on */ - /* a stitchable object and island. */ - if (!state->island_is_stitchable[ssc->static_island]) { - goto_next_island(ssc); - state = ssc->states[ssc->active_object_index]; - } - - /* process active stitchobj again now that it can detect it's the active stitchobj */ - stitch_process_data(ssc, state, scene, false); - - stitch_update_header(ssc, C); - - ssc->draw_handle = ED_region_draw_cb_activate(ar->type, stitch_draw, ssc, REGION_DRAW_POST_VIEW); - - return 1; + ARegion *ar = CTX_wm_region(C); + if (!ar) + return 0; + + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + + StitchStateContainer *ssc = MEM_callocN(sizeof(StitchStateContainer), "stitch collection"); + + op->customdata = ssc; + + ssc->use_limit = RNA_boolean_get(op->ptr, "use_limit"); + ssc->limit_dist = RNA_float_get(op->ptr, "limit"); + ssc->snap_islands = RNA_boolean_get(op->ptr, "snap_islands"); + ssc->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap"); + ssc->clear_seams = RNA_boolean_get(op->ptr, "clear_seams"); + ssc->active_object_index = RNA_int_get(op->ptr, "active_object_index"); + ssc->static_island = 0; + + if (RNA_struct_property_is_set(op->ptr, "mode")) { + ssc->mode = RNA_enum_get(op->ptr, "mode"); + } + else { + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_VERTEX) + ssc->mode = STITCH_VERT; + else + ssc->mode = STITCH_EDGE; + } + else { + if (ts->uv_selectmode & UV_SELECT_VERTEX) { + ssc->mode = STITCH_VERT; + } + else { + ssc->mode = STITCH_EDGE; + } + } + } + + ssc->objects_len = 0; + ssc->states = NULL; + + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, v3d, &objects_len); + + if (objects_len == 0) { + MEM_freeN(objects); + state_delete_all(ssc); + return 0; + } + + ssc->objects = MEM_callocN(sizeof(Object *) * objects_len, "Object *ssc->objects"); + ssc->states = MEM_callocN(sizeof(StitchState *) * objects_len, "StitchState"); + ssc->objects_len = 0; + + int *objs_selection_count = NULL; + UvElementID *selected_uvs_arr = NULL; + StitchStateInit *state_init = NULL; + + if (RNA_struct_property_is_set(op->ptr, "selection") && + RNA_struct_property_is_set(op->ptr, "objects_selection_count")) { + /* Retrieve list of selected UVs, one list contains all selected UVs + * for all objects. */ + + objs_selection_count = MEM_mallocN(sizeof(int *) * objects_len, "objects_selection_count"); + RNA_int_get_array(op->ptr, "objects_selection_count", objs_selection_count); + + int total_selected = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + total_selected += objs_selection_count[ob_index]; + } + + selected_uvs_arr = MEM_callocN(sizeof(UvElementID) * total_selected, "selected_uvs_arr"); + int sel_idx = 0; + RNA_BEGIN (op->ptr, itemptr, "selection") { + BLI_assert(sel_idx < total_selected); + selected_uvs_arr[sel_idx].faceIndex = RNA_int_get(&itemptr, "face_index"); + selected_uvs_arr[sel_idx].elementIndex = RNA_int_get(&itemptr, "element_index"); + sel_idx++; + } + RNA_END; + + RNA_collection_clear(op->ptr, "selection"); + + state_init = MEM_callocN(sizeof(StitchStateInit), "UV_init_selected"); + state_init->to_select = selected_uvs_arr; + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + + if (state_init != NULL) { + state_init->uv_selected_count = objs_selection_count[ob_index]; + } + + StitchState *stitch_state_ob = stitch_init(C, op, ssc, obedit, state_init); + + if (state_init != NULL) { + /* Move pointer to beginning of next object's data. */ + state_init->to_select += state_init->uv_selected_count; + } + + if (stitch_state_ob) { + ssc->objects[ssc->objects_len] = obedit; + ssc->states[ssc->objects_len] = stitch_state_ob; + ssc->objects_len++; + } + } + + MEM_freeN(objects); + MEM_SAFE_FREE(selected_uvs_arr); + MEM_SAFE_FREE(objs_selection_count); + MEM_SAFE_FREE(state_init); + + if (ssc->objects_len == 0) { + state_delete_all(ssc); + return 0; + } + + ssc->active_object_index %= ssc->objects_len; + + ssc->static_island = RNA_int_get(op->ptr, "static_island"); + + StitchState *state = ssc->states[ssc->active_object_index]; + ssc->static_island %= state->element_map->totalIslands; + + /* If the initial active object doesn't have any stitchable islands */ + /* then no active island will be seen in the UI. Make sure we're on */ + /* a stitchable object and island. */ + if (!state->island_is_stitchable[ssc->static_island]) { + goto_next_island(ssc); + state = ssc->states[ssc->active_object_index]; + } + + /* process active stitchobj again now that it can detect it's the active stitchobj */ + stitch_process_data(ssc, state, scene, false); + + stitch_update_header(ssc, C); + + ssc->draw_handle = ED_region_draw_cb_activate(ar->type, stitch_draw, ssc, REGION_DRAW_POST_VIEW); + + return 1; } static int stitch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (!stitch_init_all(C, op)) - return OPERATOR_CANCELLED; + if (!stitch_init_all(C, op)) + return OPERATOR_CANCELLED; - WM_event_add_modal_handler(C, op); + WM_event_add_modal_handler(C, op); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - StitchStateContainer *ssc = (StitchStateContainer *)op->customdata; + StitchStateContainer *ssc = (StitchStateContainer *)op->customdata; - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - StitchState *state = ssc->states[ob_index]; - Object *obedit = state->obedit; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + StitchState *state = ssc->states[ob_index]; + Object *obedit = state->obedit; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } - return OPERATOR_RUNNING_MODAL; + return OPERATOR_RUNNING_MODAL; } static void stitch_exit(bContext *C, wmOperator *op, int finished) { - Scene *scene = CTX_data_scene(C); - SpaceImage *sima = CTX_wm_space_image(C); - ScrArea *sa = CTX_wm_area(C); - - StitchStateContainer *ssc = (StitchStateContainer *)op->customdata; - - if (finished) { - RNA_float_set(op->ptr, "limit", ssc->limit_dist); - RNA_boolean_set(op->ptr, "use_limit", ssc->use_limit); - RNA_boolean_set(op->ptr, "snap_islands", ssc->snap_islands); - RNA_boolean_set(op->ptr, "midpoint_snap", ssc->midpoints); - RNA_boolean_set(op->ptr, "clear_seams", ssc->clear_seams); - RNA_enum_set(op->ptr, "mode", ssc->mode); - RNA_enum_set(op->ptr, "stored_mode", ssc->mode); - RNA_int_set(op->ptr, "active_object_index", ssc->active_object_index); - - RNA_int_set(op->ptr, "static_island", ssc->static_island); - - int *objs_selection_count = NULL; - objs_selection_count = MEM_mallocN(sizeof(int *) * ssc->objects_len, "objects_selection_count"); - - /* Store selection for re-execution of stitch - * - Store all selected UVs in "selection" - * - Store how many each object has in "objects_selection_count". */ - RNA_collection_clear(op->ptr, "selection"); - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - StitchState *state = ssc->states[ob_index]; - Object *obedit = state->obedit; - - PointerRNA itemptr; - for (int i = 0; i < state->selection_size; i++) { - UvElement *element; - - if (ssc->mode == STITCH_VERT) { - element = state->selection_stack[i]; - } - else { - element = ((UvEdge *)state->selection_stack[i])->element; - } - RNA_collection_add(op->ptr, "selection", &itemptr); - - RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->l->f)); - RNA_int_set(&itemptr, "element_index", element->loop_of_poly_index); - } - uvedit_live_unwrap_update(sima, scene, obedit); - - objs_selection_count[ob_index] = state->selection_size; - } - - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "objects_selection_count"); - RNA_def_property_array(prop, ssc->objects_len); - RNA_int_set_array(op->ptr, "objects_selection_count", objs_selection_count); - MEM_freeN(objs_selection_count); - } - - if (sa) - ED_workspace_status_text(C, NULL); - - ED_region_draw_cb_exit(CTX_wm_region(C)->type, ssc->draw_handle); - - ToolSettings *ts = scene->toolsettings; - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - StitchState *state = ssc->states[ob_index]; - Object *obedit = state->obedit; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - - state_delete_all(ssc); - - op->customdata = NULL; + Scene *scene = CTX_data_scene(C); + SpaceImage *sima = CTX_wm_space_image(C); + ScrArea *sa = CTX_wm_area(C); + + StitchStateContainer *ssc = (StitchStateContainer *)op->customdata; + + if (finished) { + RNA_float_set(op->ptr, "limit", ssc->limit_dist); + RNA_boolean_set(op->ptr, "use_limit", ssc->use_limit); + RNA_boolean_set(op->ptr, "snap_islands", ssc->snap_islands); + RNA_boolean_set(op->ptr, "midpoint_snap", ssc->midpoints); + RNA_boolean_set(op->ptr, "clear_seams", ssc->clear_seams); + RNA_enum_set(op->ptr, "mode", ssc->mode); + RNA_enum_set(op->ptr, "stored_mode", ssc->mode); + RNA_int_set(op->ptr, "active_object_index", ssc->active_object_index); + + RNA_int_set(op->ptr, "static_island", ssc->static_island); + + int *objs_selection_count = NULL; + objs_selection_count = MEM_mallocN(sizeof(int *) * ssc->objects_len, + "objects_selection_count"); + + /* Store selection for re-execution of stitch + * - Store all selected UVs in "selection" + * - Store how many each object has in "objects_selection_count". */ + RNA_collection_clear(op->ptr, "selection"); + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + StitchState *state = ssc->states[ob_index]; + Object *obedit = state->obedit; + + PointerRNA itemptr; + for (int i = 0; i < state->selection_size; i++) { + UvElement *element; + + if (ssc->mode == STITCH_VERT) { + element = state->selection_stack[i]; + } + else { + element = ((UvEdge *)state->selection_stack[i])->element; + } + RNA_collection_add(op->ptr, "selection", &itemptr); + + RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->l->f)); + RNA_int_set(&itemptr, "element_index", element->loop_of_poly_index); + } + uvedit_live_unwrap_update(sima, scene, obedit); + + objs_selection_count[ob_index] = state->selection_size; + } + + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "objects_selection_count"); + RNA_def_property_array(prop, ssc->objects_len); + RNA_int_set_array(op->ptr, "objects_selection_count", objs_selection_count); + MEM_freeN(objs_selection_count); + } + + if (sa) + ED_workspace_status_text(C, NULL); + + ED_region_draw_cb_exit(CTX_wm_region(C)->type, ssc->draw_handle); + + ToolSettings *ts = scene->toolsettings; + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + StitchState *state = ssc->states[ob_index]; + Object *obedit = state->obedit; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } + + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + + state_delete_all(ssc); + + op->customdata = NULL; } - static void stitch_cancel(bContext *C, wmOperator *op) { - stitch_exit(C, op, 0); + stitch_exit(C, op, 0); } - static int stitch_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - - if (!stitch_init_all(C, op)) - return OPERATOR_CANCELLED; - if (stitch_process_data_all((StitchStateContainer *)op->customdata, scene, 1)) { - stitch_exit(C, op, 1); - return OPERATOR_FINISHED; - } - else { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } + Scene *scene = CTX_data_scene(C); + + if (!stitch_init_all(C, op)) + return OPERATOR_CANCELLED; + if (stitch_process_data_all((StitchStateContainer *)op->customdata, scene, 1)) { + stitch_exit(C, op, 1); + return OPERATOR_FINISHED; + } + else { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } } -static StitchState *stitch_select( - bContext *C, Scene *scene, const wmEvent *event, StitchStateContainer *ssc) +static StitchState *stitch_select(bContext *C, + Scene *scene, + const wmEvent *event, + StitchStateContainer *ssc) { - /* add uv under mouse to processed uv's */ - float co[2]; - UvNearestHit hit = UV_NEAREST_HIT_INIT; - ARegion *ar = CTX_wm_region(C); - Image *ima = CTX_data_edit_image(C); - - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); - - if (ssc->mode == STITCH_VERT) { - if (uv_find_nearest_vert_multi(scene, ima, ssc->objects, ssc->objects_len, 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 you can do stuff like deselect - * the opposite stitchable vertex and the initial still gets deselected */ - - /* find StitchState from hit->ob */ - StitchState *state = NULL; - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - if (hit.ob == ssc->objects[ob_index]) { - state = ssc->states[ob_index]; - break; - } - } - - /* This works due to setting of tmp in find nearest uv vert */ - UvElement *element = BM_uv_element_get(state->element_map, hit.efa, hit.l); - stitch_select_uv(element, state, false); - - return state; - } - } - else if (uv_find_nearest_edge_multi(scene, ima, ssc->objects, ssc->objects_len, co, &hit)) { - /* find StitchState from hit->ob */ - StitchState *state = NULL; - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - if (hit.ob == ssc->objects[ob_index]) { - state = ssc->states[ob_index]; - break; - } - } - - UvEdge *edge = uv_edge_get(hit.l, state); - stitch_select_edge(edge, state, false); - - return state; - } - - return NULL; + /* add uv under mouse to processed uv's */ + float co[2]; + UvNearestHit hit = UV_NEAREST_HIT_INIT; + ARegion *ar = CTX_wm_region(C); + Image *ima = CTX_data_edit_image(C); + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + + if (ssc->mode == STITCH_VERT) { + if (uv_find_nearest_vert_multi(scene, ima, ssc->objects, ssc->objects_len, 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 you can do stuff like deselect + * the opposite stitchable vertex and the initial still gets deselected */ + + /* find StitchState from hit->ob */ + StitchState *state = NULL; + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + if (hit.ob == ssc->objects[ob_index]) { + state = ssc->states[ob_index]; + break; + } + } + + /* This works due to setting of tmp in find nearest uv vert */ + UvElement *element = BM_uv_element_get(state->element_map, hit.efa, hit.l); + stitch_select_uv(element, state, false); + + return state; + } + } + else if (uv_find_nearest_edge_multi(scene, ima, ssc->objects, ssc->objects_len, co, &hit)) { + /* find StitchState from hit->ob */ + StitchState *state = NULL; + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + if (hit.ob == ssc->objects[ob_index]) { + state = ssc->states[ob_index]; + break; + } + } + + UvEdge *edge = uv_edge_get(hit.l, state); + stitch_select_edge(edge, state, false); + + return state; + } + + return NULL; } static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event) { - StitchStateContainer *ssc; - Scene *scene = CTX_data_scene(C); - - ssc = op->customdata; - StitchState *active_state = ssc->states[ssc->active_object_index]; - - switch (event->type) { - case MIDDLEMOUSE: - return OPERATOR_PASS_THROUGH; - - /* Cancel */ - case ESCKEY: - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - - case LEFTMOUSE: - case PADENTER: - case RETKEY: - if (event->val == KM_PRESS) { - if (stitch_process_data(ssc, active_state, scene, true)) { - stitch_exit(C, op, 1); - return OPERATOR_FINISHED; - } - else { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - } - else { - return OPERATOR_PASS_THROUGH; - } - /* Increase limit */ - case PADPLUSKEY: - case WHEELUPMOUSE: - if (event->val == KM_PRESS && event->alt) { - ssc->limit_dist += 0.01f; - if (!stitch_process_data(ssc, active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - break; - } - else { - return OPERATOR_PASS_THROUGH; - } - /* Decrease limit */ - case PADMINUS: - case WHEELDOWNMOUSE: - if (event->val == KM_PRESS && event->alt) { - ssc->limit_dist -= 0.01f; - ssc->limit_dist = MAX2(0.01f, ssc->limit_dist); - if (!stitch_process_data(ssc, active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - break; - } - else { - return OPERATOR_PASS_THROUGH; - } - - /* Use Limit (Default off) */ - case LKEY: - if (event->val == KM_PRESS) { - ssc->use_limit = !ssc->use_limit; - if (!stitch_process_data(ssc, active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - break; - } - return OPERATOR_RUNNING_MODAL; - - case IKEY: - if (event->val == KM_PRESS) { - /* Move to next island and maybe next object */ - - if (goto_next_island(ssc)) { - StitchState *new_active_state = ssc->states[ssc->active_object_index]; - - /* active_state is the original active state */ - if (active_state != new_active_state) { - if (!stitch_process_data(ssc, active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - } - - if (!stitch_process_data(ssc, new_active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - } - break; - } - return OPERATOR_RUNNING_MODAL; - - case MKEY: - if (event->val == KM_PRESS) { - ssc->midpoints = !ssc->midpoints; - if (!stitch_process_data(ssc, active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - } - break; - - /* Select geometry */ - case RIGHTMOUSE: - if (!event->shift) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - if (event->val == KM_PRESS) { - StitchState *selected_state = stitch_select(C, scene, event, ssc); - - if (selected_state && !stitch_process_data(ssc, selected_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - break; - } - return OPERATOR_RUNNING_MODAL; - - /* snap islands on/off */ - case SKEY: - if (event->val == KM_PRESS) { - ssc->snap_islands = !ssc->snap_islands; - if (!stitch_process_data(ssc, active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - break; - } - else { - return OPERATOR_RUNNING_MODAL; - } - - /* switch between edge/vertex mode */ - case TABKEY: - if (event->val == KM_PRESS) { - stitch_switch_selection_mode_all(ssc); - - if (!stitch_process_data_all(ssc, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - } - break; - - default: - return OPERATOR_RUNNING_MODAL; - } - - /* if updated settings, renew feedback message */ - stitch_update_header(ssc, C); - ED_region_tag_redraw(CTX_wm_region(C)); - - return OPERATOR_RUNNING_MODAL; + StitchStateContainer *ssc; + Scene *scene = CTX_data_scene(C); + + ssc = op->customdata; + StitchState *active_state = ssc->states[ssc->active_object_index]; + + switch (event->type) { + case MIDDLEMOUSE: + return OPERATOR_PASS_THROUGH; + + /* Cancel */ + case ESCKEY: + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + + case LEFTMOUSE: + case PADENTER: + case RETKEY: + if (event->val == KM_PRESS) { + if (stitch_process_data(ssc, active_state, scene, true)) { + stitch_exit(C, op, 1); + return OPERATOR_FINISHED; + } + else { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + } + else { + return OPERATOR_PASS_THROUGH; + } + /* Increase limit */ + case PADPLUSKEY: + case WHEELUPMOUSE: + if (event->val == KM_PRESS && event->alt) { + ssc->limit_dist += 0.01f; + if (!stitch_process_data(ssc, active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + break; + } + else { + return OPERATOR_PASS_THROUGH; + } + /* Decrease limit */ + case PADMINUS: + case WHEELDOWNMOUSE: + if (event->val == KM_PRESS && event->alt) { + ssc->limit_dist -= 0.01f; + ssc->limit_dist = MAX2(0.01f, ssc->limit_dist); + if (!stitch_process_data(ssc, active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + break; + } + else { + return OPERATOR_PASS_THROUGH; + } + + /* Use Limit (Default off) */ + case LKEY: + if (event->val == KM_PRESS) { + ssc->use_limit = !ssc->use_limit; + if (!stitch_process_data(ssc, active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + break; + } + return OPERATOR_RUNNING_MODAL; + + case IKEY: + if (event->val == KM_PRESS) { + /* Move to next island and maybe next object */ + + if (goto_next_island(ssc)) { + StitchState *new_active_state = ssc->states[ssc->active_object_index]; + + /* active_state is the original active state */ + if (active_state != new_active_state) { + if (!stitch_process_data(ssc, active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + } + + if (!stitch_process_data(ssc, new_active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + } + break; + } + return OPERATOR_RUNNING_MODAL; + + case MKEY: + if (event->val == KM_PRESS) { + ssc->midpoints = !ssc->midpoints; + if (!stitch_process_data(ssc, active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + } + break; + + /* Select geometry */ + case RIGHTMOUSE: + if (!event->shift) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + if (event->val == KM_PRESS) { + StitchState *selected_state = stitch_select(C, scene, event, ssc); + + if (selected_state && !stitch_process_data(ssc, selected_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + break; + } + return OPERATOR_RUNNING_MODAL; + + /* snap islands on/off */ + case SKEY: + if (event->val == KM_PRESS) { + ssc->snap_islands = !ssc->snap_islands; + if (!stitch_process_data(ssc, active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + break; + } + else { + return OPERATOR_RUNNING_MODAL; + } + + /* switch between edge/vertex mode */ + case TABKEY: + if (event->val == KM_PRESS) { + stitch_switch_selection_mode_all(ssc); + + if (!stitch_process_data_all(ssc, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + } + break; + + default: + return OPERATOR_RUNNING_MODAL; + } + + /* if updated settings, renew feedback message */ + stitch_update_header(ssc, C); + ED_region_tag_redraw(CTX_wm_region(C)); + + return OPERATOR_RUNNING_MODAL; } void UV_OT_stitch(wmOperatorType *ot) { - PropertyRNA *prop; - - static const EnumPropertyItem stitch_modes[] = { - {STITCH_VERT, "VERTEX", 0, "Vertex", ""}, - {STITCH_EDGE, "EDGE", 0, "Edge", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Stitch"; - ot->description = "Stitch selected UV vertices by proximity"; - ot->idname = "UV_OT_stitch"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->invoke = stitch_invoke; - ot->modal = stitch_modal; - ot->exec = stitch_exec; - ot->cancel = stitch_cancel; - ot->poll = ED_operator_uvedit; - - /* properties */ - RNA_def_boolean(ot->srna, "use_limit", 0, "Use Limit", "Stitch UVs within a specified limit distance"); - RNA_def_boolean(ot->srna, "snap_islands", 1, "Snap Islands", - "Snap islands together (on edge stitch mode, rotates the islands too)"); - - RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", - "Limit distance in normalized coordinates", 0.0, FLT_MAX); - RNA_def_int(ot->srna, "static_island", 0, 0, INT_MAX, "Static Island", - "Island that stays in place when stitching islands", 0, INT_MAX); - RNA_def_int(ot->srna, "active_object_index", 0, 0, INT_MAX, "Active Object", - "Index of the active object", 0, INT_MAX); - RNA_def_boolean(ot->srna, "midpoint_snap", 0, "Snap At Midpoint", - "UVs are stitched at midpoint instead of at static island"); - RNA_def_boolean(ot->srna, "clear_seams", 1, "Clear Seams", - "Clear seams of stitched edges"); - RNA_def_enum(ot->srna, "mode", stitch_modes, STITCH_VERT, "Operation Mode", - "Use vertex or edge stitching"); - prop = RNA_def_enum(ot->srna, "stored_mode", stitch_modes, STITCH_VERT, "Stored Operation Mode", - "Use vertex or edge stitching"); - RNA_def_property_flag(prop, PROP_HIDDEN); - prop = RNA_def_collection_runtime(ot->srna, "selection", &RNA_SelectedUvElement, "Selection", ""); - /* Selection should not be editable or viewed in toolbar */ - RNA_def_property_flag(prop, PROP_HIDDEN); - - /* test should not be editable or viewed in toolbar */ - prop = RNA_def_int_array(ot->srna, "objects_selection_count", 1, NULL, 0, INT_MAX, "Objects Selection Count", - "", 0, INT_MAX); - RNA_def_property_array(prop, 6); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop; + + static const EnumPropertyItem stitch_modes[] = { + {STITCH_VERT, "VERTEX", 0, "Vertex", ""}, + {STITCH_EDGE, "EDGE", 0, "Edge", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Stitch"; + ot->description = "Stitch selected UV vertices by proximity"; + ot->idname = "UV_OT_stitch"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->invoke = stitch_invoke; + ot->modal = stitch_modal; + ot->exec = stitch_exec; + ot->cancel = stitch_cancel; + ot->poll = ED_operator_uvedit; + + /* properties */ + RNA_def_boolean( + ot->srna, "use_limit", 0, "Use Limit", "Stitch UVs within a specified limit distance"); + RNA_def_boolean(ot->srna, + "snap_islands", + 1, + "Snap Islands", + "Snap islands together (on edge stitch mode, rotates the islands too)"); + + RNA_def_float(ot->srna, + "limit", + 0.01f, + 0.0f, + FLT_MAX, + "Limit", + "Limit distance in normalized coordinates", + 0.0, + FLT_MAX); + RNA_def_int(ot->srna, + "static_island", + 0, + 0, + INT_MAX, + "Static Island", + "Island that stays in place when stitching islands", + 0, + INT_MAX); + RNA_def_int(ot->srna, + "active_object_index", + 0, + 0, + INT_MAX, + "Active Object", + "Index of the active object", + 0, + INT_MAX); + RNA_def_boolean(ot->srna, + "midpoint_snap", + 0, + "Snap At Midpoint", + "UVs are stitched at midpoint instead of at static island"); + RNA_def_boolean(ot->srna, "clear_seams", 1, "Clear Seams", "Clear seams of stitched edges"); + RNA_def_enum(ot->srna, + "mode", + stitch_modes, + STITCH_VERT, + "Operation Mode", + "Use vertex or edge stitching"); + prop = RNA_def_enum(ot->srna, + "stored_mode", + stitch_modes, + STITCH_VERT, + "Stored Operation Mode", + "Use vertex or edge stitching"); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_collection_runtime( + ot->srna, "selection", &RNA_SelectedUvElement, "Selection", ""); + /* Selection should not be editable or viewed in toolbar */ + RNA_def_property_flag(prop, PROP_HIDDEN); + + /* test should not be editable or viewed in toolbar */ + prop = RNA_def_int_array(ot->srna, + "objects_selection_count", + 1, + NULL, + 0, + INT_MAX, + "Objects Selection Count", + "", + 0, + INT_MAX); + RNA_def_property_array(prop, 6); + RNA_def_property_flag(prop, PROP_HIDDEN); } diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 19925c2fcd7..0caa478ffa9 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -21,7 +21,6 @@ * \ingroup eduv */ - #include <string.h> #include <stdlib.h> #include <math.h> @@ -70,7 +69,6 @@ #include "RNA_access.h" #include "RNA_define.h" - #include "WM_api.h" #include "WM_types.h" @@ -79,1333 +77,1432 @@ static void modifier_unwrap_state(Object *obedit, Scene *scene, bool *r_use_subsurf) { - ModifierData *md; - bool subsurf = (scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF) != 0; + ModifierData *md; + bool subsurf = (scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF) != 0; - md = obedit->modifiers.first; + md = obedit->modifiers.first; - /* subsurf will take the modifier settings only if modifier is first or right after mirror */ - if (subsurf) { - if (md && md->type == eModifierType_Subsurf) - subsurf = true; - else - subsurf = false; - } + /* subsurf will take the modifier settings only if modifier is first or right after mirror */ + if (subsurf) { + if (md && md->type == eModifierType_Subsurf) + subsurf = true; + else + subsurf = false; + } - *r_use_subsurf = subsurf; + *r_use_subsurf = subsurf; } static bool ED_uvedit_ensure_uvs(bContext *C, Scene *UNUSED(scene), Object *obedit) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMIter iter; - Image *ima; - bScreen *sc; - ScrArea *sa; - SpaceLink *slink; - SpaceImage *sima; - int cd_loop_uv_offset; - - if (ED_uvedit_test(obedit)) - return 1; - - if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) - ED_mesh_uv_texture_add(obedit->data, NULL, true, true); - - if (!ED_uvedit_test(obedit)) - return 0; - - cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - ima = CTX_data_edit_image(C); - - if (!ima) { - /* no image in context in the 3d view, we find first image window .. */ - sc = CTX_wm_screen(C); - - for (sa = sc->areabase.first; sa; sa = sa->next) { - slink = sa->spacedata.first; - if (slink->spacetype == SPACE_IMAGE) { - sima = (SpaceImage *)slink; - - ima = sima->image; - if (ima) { - if (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE) - ima = NULL; - else - break; - } - } - } - } - - /* select new UV's (ignore UV_SYNC_SELECTION in this case) */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - 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->flag |= MLOOPUV_VERTSEL; - } - } - - return 1; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMIter iter; + Image *ima; + bScreen *sc; + ScrArea *sa; + SpaceLink *slink; + SpaceImage *sima; + int cd_loop_uv_offset; + + if (ED_uvedit_test(obedit)) + return 1; + + if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) + ED_mesh_uv_texture_add(obedit->data, NULL, true, true); + + if (!ED_uvedit_test(obedit)) + return 0; + + cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + ima = CTX_data_edit_image(C); + + if (!ima) { + /* no image in context in the 3d view, we find first image window .. */ + sc = CTX_wm_screen(C); + + for (sa = sc->areabase.first; sa; sa = sa->next) { + slink = sa->spacedata.first; + if (slink->spacetype == SPACE_IMAGE) { + sima = (SpaceImage *)slink; + + ima = sima->image; + if (ima) { + if (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE) + ima = NULL; + else + break; + } + } + } + } + + /* select new UV's (ignore UV_SYNC_SELECTION in this case) */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + 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->flag |= MLOOPUV_VERTSEL; + } + } + + return 1; } /****************** Parametrizer Conversion ***************/ typedef struct UnwrapOptions { - bool topology_from_uvs; /* Connectivity based on UV coordinates instead of seams. */ - bool only_selected; /* Only affect selected faces. */ - bool fill_holes; /* Fill holes to better preserve shape. */ - bool correct_aspect; /* Correct for mapped image texture aspect ratio. */ + bool topology_from_uvs; /* Connectivity based on UV coordinates instead of seams. */ + bool only_selected; /* Only affect selected faces. */ + bool fill_holes; /* Fill holes to better preserve shape. */ + bool correct_aspect; /* Correct for mapped image texture aspect ratio. */ } UnwrapOptions; static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, const UnwrapOptions *options) { - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if (cd_loop_uv_offset == -1) { - return (em->bm->totfacesel != 0); - } - - /* verify if we have any selected uv's before unwrapping, - * so we can cancel the operator early */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { - if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) - continue; - } - else if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) - continue; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) - break; - } - - if (options->topology_from_uvs && !l) - continue; - - return true; - } - - return false; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (cd_loop_uv_offset == -1) { + return (em->bm->totfacesel != 0); + } + + /* verify if we have any selected uv's before unwrapping, + * so we can cancel the operator early */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { + if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) + continue; + } + else if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) + continue; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) + break; + } + + if (options->topology_from_uvs && !l) + continue; + + return true; + } + + return false; } -static bool uvedit_have_selection_multi( - Scene *scene, Object **objects, const uint objects_len, - const UnwrapOptions *options) +static bool uvedit_have_selection_multi(Scene *scene, + Object **objects, + const uint objects_len, + const UnwrapOptions *options) { - 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, options)) { - have_select = true; - break; - } - } - return have_select; + 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, options)) { + 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; - BMFace *efa; - Image *ima; - - efa = BM_mesh_active_face_get(bm, sloppy, selected); - - if (efa) { - ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL); - - ED_image_get_uv_aspect(ima, NULL, aspx, aspy); - } - else { - *aspx = 1.0f; - *aspy = 1.0f; - } + bool sloppy = true; + bool selected = false; + BMFace *efa; + Image *ima; + + efa = BM_mesh_active_face_get(bm, sloppy, selected); + + if (efa) { + ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL); + + ED_image_get_uv_aspect(ima, NULL, aspx, aspy); + } + else { + *aspx = 1.0f; + *aspy = 1.0f; + } } -static void construct_param_handle_face_add(ParamHandle *handle, Scene *scene, - BMFace *efa, int face_index, const int cd_loop_uv_offset) +static void construct_param_handle_face_add( + ParamHandle *handle, Scene *scene, BMFace *efa, int face_index, const int cd_loop_uv_offset) { - ParamKey key; - ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len); - ParamBool *pin = BLI_array_alloca(pin, efa->len); - ParamBool *select = BLI_array_alloca(select, efa->len); - float **co = BLI_array_alloca(co, efa->len); - float **uv = BLI_array_alloca(uv, efa->len); - int i; - - BMIter liter; - BMLoop *l; - - key = (ParamKey)face_index; - - /* let parametrizer split the ngon, it can make better decisions - * about which split is best for unwrapping than scanfill */ - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - vkeys[i] = (ParamKey)BM_elem_index_get(l->v); - co[i] = l->v->co; - uv[i] = luv->uv; - pin[i] = (luv->flag & MLOOPUV_PINNED) != 0; - select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); - } - - param_face_add(handle, key, i, vkeys, co, uv, pin, select); + ParamKey key; + ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len); + ParamBool *pin = BLI_array_alloca(pin, efa->len); + ParamBool *select = BLI_array_alloca(select, efa->len); + float **co = BLI_array_alloca(co, efa->len); + float **uv = BLI_array_alloca(uv, efa->len); + int i; + + BMIter liter; + BMLoop *l; + + key = (ParamKey)face_index; + + /* let parametrizer split the ngon, it can make better decisions + * about which split is best for unwrapping than scanfill */ + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) + { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + vkeys[i] = (ParamKey)BM_elem_index_get(l->v); + co[i] = l->v->co; + uv[i] = luv->uv; + pin[i] = (luv->flag & MLOOPUV_PINNED) != 0; + select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + } + + param_face_add(handle, key, i, vkeys, co, uv, pin, select); } /* See: construct_param_handle_multi to handle multiple objects at once. */ -static ParamHandle *construct_param_handle( - Scene *scene, Object *ob, BMesh *bm, - const UnwrapOptions *options) +static ParamHandle *construct_param_handle(Scene *scene, + Object *ob, + BMesh *bm, + const UnwrapOptions *options) { - ParamHandle *handle; - BMFace *efa; - BMLoop *l; - BMEdge *eed; - BMIter iter, liter; - int i; - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - handle = param_construct_begin(); - - if (options->correct_aspect) { - 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 */ - BM_mesh_elem_index_ensure(bm, BM_VERT); - - BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { - - if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || - (options->only_selected && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) - { - continue; - } - - if (options->topology_from_uvs) { - 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, cd_loop_uv_offset); - } - - if (!options->topology_from_uvs) { - 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); - } - } - } - - param_construct_end(handle, options->fill_holes, options->topology_from_uvs); - - return handle; + ParamHandle *handle; + BMFace *efa; + BMLoop *l; + BMEdge *eed; + BMIter iter, liter; + int i; + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + handle = param_construct_begin(); + + if (options->correct_aspect) { + 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 */ + BM_mesh_elem_index_ensure(bm, BM_VERT); + + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { + + if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || + (options->only_selected && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) { + continue; + } + + if (options->topology_from_uvs) { + 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, cd_loop_uv_offset); + } + + if (!options->topology_from_uvs) { + 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); + } + } + } + + param_construct_end(handle, options->fill_holes, options->topology_from_uvs); + + 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 UnwrapOptions *options) +static ParamHandle *construct_param_handle_multi(Scene *scene, + Object **objects, + const uint objects_len, + const UnwrapOptions *options) { - ParamHandle *handle; - BMFace *efa; - BMLoop *l; - BMEdge *eed; - BMIter iter, liter; - int i; - - handle = param_construct_begin(); - - if (options->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)) || - (options->only_selected && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) - { - continue; - } - - if (options->topology_from_uvs) { - 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 (!options->topology_from_uvs) { - 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, options->fill_holes, options->topology_from_uvs); - - return handle; + ParamHandle *handle; + BMFace *efa; + BMLoop *l; + BMEdge *eed; + BMIter iter, liter; + int i; + + handle = param_construct_begin(); + + if (options->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)) || + (options->only_selected && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) { + continue; + } + + if (options->topology_from_uvs) { + 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 (!options->topology_from_uvs) { + 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, options->fill_holes, options->topology_from_uvs); + + 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) +static void texface_from_original_index(BMFace *efa, + int index, + float **uv, + ParamBool *pin, + ParamBool *select, + Scene *scene, + const int cd_loop_uv_offset) { - BMLoop *l; - BMIter liter; - MLoopUV *luv; - - *uv = NULL; - *pin = 0; - *select = 1; - - if (index == ORIGINDEX_NONE) - return; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_index_get(l->v) == index) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - *uv = luv->uv; - *pin = (luv->flag & MLOOPUV_PINNED) ? 1 : 0; - *select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); - break; - } - } + BMLoop *l; + BMIter liter; + MLoopUV *luv; + + *uv = NULL; + *pin = 0; + *select = 1; + + if (index == ORIGINDEX_NONE) + return; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_index_get(l->v) == index) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + *uv = luv->uv; + *pin = (luv->flag & MLOOPUV_PINNED) ? 1 : 0; + *select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + break; + } + } } /* unwrap handle initialization for subsurf aware-unwrapper. The many modifications required to make the original function(see above) * work justified the existence of a new function. */ -static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, BMEditMesh *em, const UnwrapOptions *options) +static ParamHandle *construct_param_handle_subsurfed(Scene *scene, + Object *ob, + BMEditMesh *em, + const UnwrapOptions *options) { - ParamHandle *handle; - /* index pointers */ - MPoly *mpoly; - MLoop *mloop; - MEdge *edge; - int i; - - /* pointers to modifier data for unwrap control */ - ModifierData *md; - SubsurfModifierData *smd_real; - /* modifier initialization data, will control what type of subdivision will happen*/ - SubsurfModifierData smd = {{NULL}}; - /* Used to hold subsurfed Mesh */ - DerivedMesh *derivedMesh, *initialDerived; - /* holds original indices for subsurfed mesh */ - const int *origVertIndices, *origEdgeIndices, *origPolyIndices; - /* Holds vertices of subsurfed mesh */ - MVert *subsurfedVerts; - MEdge *subsurfedEdges; - MPoly *subsurfedPolys; - MLoop *subsurfedLoops; - /* number of vertices and faces for subsurfed mesh*/ - int numOfEdges, numOfFaces; - - /* holds a map to editfaces for every subsurfed MFace. - * These will be used to get hidden/ selected flags etc. */ - BMFace **faceMap; - /* similar to the above, we need a way to map edges to their original ones */ - BMEdge **edgeMap; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - handle = param_construct_begin(); - - if (options->correct_aspect) { - float aspx, aspy; - - ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy); - - if (aspx != aspy) - param_aspect_ratio(handle, aspx, aspy); - } - - /* number of subdivisions to perform */ - md = ob->modifiers.first; - smd_real = (SubsurfModifierData *)md; - - smd.levels = smd_real->levels; - smd.subdivType = smd_real->subdivType; - - initialDerived = CDDM_from_editbmesh(em, false, false); - derivedMesh = subsurf_make_derived_from_derived(initialDerived, &smd, scene, - NULL, SUBSURF_IN_EDIT_MODE); - - initialDerived->release(initialDerived); - - /* get the derived data */ - subsurfedVerts = derivedMesh->getVertArray(derivedMesh); - subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh); - subsurfedPolys = derivedMesh->getPolyArray(derivedMesh); - subsurfedLoops = derivedMesh->getLoopArray(derivedMesh); - - origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX); - origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX); - origPolyIndices = derivedMesh->getPolyDataArray(derivedMesh, CD_ORIGINDEX); - - numOfEdges = derivedMesh->getNumEdges(derivedMesh); - numOfFaces = derivedMesh->getNumPolys(derivedMesh); - - faceMap = MEM_mallocN(numOfFaces * sizeof(BMFace *), "unwrap_edit_face_map"); - - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_FACE); - - /* map subsurfed faces to original editFaces */ - for (i = 0; i < numOfFaces; i++) - faceMap[i] = BM_face_at_index(em->bm, origPolyIndices[i]); - - edgeMap = MEM_mallocN(numOfEdges * sizeof(BMEdge *), "unwrap_edit_edge_map"); - - /* map subsurfed edges to original editEdges */ - for (i = 0; i < numOfEdges; i++) { - /* not all edges correspond to an old edge */ - edgeMap[i] = (origEdgeIndices[i] != ORIGINDEX_NONE) ? - BM_edge_at_index(em->bm, origEdgeIndices[i]) : NULL; - } - - /* Prepare and feed faces to the solver */ - for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) { - ParamKey key, vkeys[4]; - ParamBool pin[4], select[4]; - float *co[4]; - float *uv[4]; - BMFace *origFace = faceMap[i]; - - if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { - if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN)) - continue; - } - else { - if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN) || - (options->only_selected && !BM_elem_flag_test(origFace, BM_ELEM_SELECT))) - { - continue; - } - } - - mloop = &subsurfedLoops[mpoly->loopstart]; - - /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */ - BLI_assert(mpoly->totloop == 4); - key = (ParamKey)i; - vkeys[0] = (ParamKey)mloop[0].v; - vkeys[1] = (ParamKey)mloop[1].v; - vkeys[2] = (ParamKey)mloop[2].v; - vkeys[3] = (ParamKey)mloop[3].v; - - co[0] = subsurfedVerts[mloop[0].v].co; - co[1] = subsurfedVerts[mloop[1].v].co; - co[2] = subsurfedVerts[mloop[2].v].co; - co[3] = subsurfedVerts[mloop[3].v].co; - - /* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus - * flushing the solution to the edit mesh. */ - texface_from_original_index(origFace, origVertIndices[mloop[0].v], &uv[0], &pin[0], &select[0], scene, cd_loop_uv_offset); - texface_from_original_index(origFace, origVertIndices[mloop[1].v], &uv[1], &pin[1], &select[1], scene, cd_loop_uv_offset); - texface_from_original_index(origFace, origVertIndices[mloop[2].v], &uv[2], &pin[2], &select[2], scene, cd_loop_uv_offset); - texface_from_original_index(origFace, origVertIndices[mloop[3].v], &uv[3], &pin[3], &select[3], scene, cd_loop_uv_offset); - - param_face_add(handle, key, 4, vkeys, co, uv, pin, select); - } - - /* these are calculated from original mesh too */ - for (edge = subsurfedEdges, i = 0; i < numOfEdges; i++, edge++) { - if ((edgeMap[i] != NULL) && BM_elem_flag_test(edgeMap[i], BM_ELEM_SEAM)) { - ParamKey vkeys[2]; - vkeys[0] = (ParamKey)edge->v1; - vkeys[1] = (ParamKey)edge->v2; - param_edge_set_seam(handle, vkeys); - } - } - - param_construct_end(handle, options->fill_holes, options->topology_from_uvs); - - /* cleanup */ - MEM_freeN(faceMap); - MEM_freeN(edgeMap); - derivedMesh->release(derivedMesh); - - return handle; + ParamHandle *handle; + /* index pointers */ + MPoly *mpoly; + MLoop *mloop; + MEdge *edge; + int i; + + /* pointers to modifier data for unwrap control */ + ModifierData *md; + SubsurfModifierData *smd_real; + /* modifier initialization data, will control what type of subdivision will happen*/ + SubsurfModifierData smd = {{NULL}}; + /* Used to hold subsurfed Mesh */ + DerivedMesh *derivedMesh, *initialDerived; + /* holds original indices for subsurfed mesh */ + const int *origVertIndices, *origEdgeIndices, *origPolyIndices; + /* Holds vertices of subsurfed mesh */ + MVert *subsurfedVerts; + MEdge *subsurfedEdges; + MPoly *subsurfedPolys; + MLoop *subsurfedLoops; + /* number of vertices and faces for subsurfed mesh*/ + int numOfEdges, numOfFaces; + + /* holds a map to editfaces for every subsurfed MFace. + * These will be used to get hidden/ selected flags etc. */ + BMFace **faceMap; + /* similar to the above, we need a way to map edges to their original ones */ + BMEdge **edgeMap; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + handle = param_construct_begin(); + + if (options->correct_aspect) { + float aspx, aspy; + + ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy); + + if (aspx != aspy) + param_aspect_ratio(handle, aspx, aspy); + } + + /* number of subdivisions to perform */ + md = ob->modifiers.first; + smd_real = (SubsurfModifierData *)md; + + smd.levels = smd_real->levels; + smd.subdivType = smd_real->subdivType; + + initialDerived = CDDM_from_editbmesh(em, false, false); + derivedMesh = subsurf_make_derived_from_derived( + initialDerived, &smd, scene, NULL, SUBSURF_IN_EDIT_MODE); + + initialDerived->release(initialDerived); + + /* get the derived data */ + subsurfedVerts = derivedMesh->getVertArray(derivedMesh); + subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh); + subsurfedPolys = derivedMesh->getPolyArray(derivedMesh); + subsurfedLoops = derivedMesh->getLoopArray(derivedMesh); + + origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX); + origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX); + origPolyIndices = derivedMesh->getPolyDataArray(derivedMesh, CD_ORIGINDEX); + + numOfEdges = derivedMesh->getNumEdges(derivedMesh); + numOfFaces = derivedMesh->getNumPolys(derivedMesh); + + faceMap = MEM_mallocN(numOfFaces * sizeof(BMFace *), "unwrap_edit_face_map"); + + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_FACE); + + /* map subsurfed faces to original editFaces */ + for (i = 0; i < numOfFaces; i++) + faceMap[i] = BM_face_at_index(em->bm, origPolyIndices[i]); + + edgeMap = MEM_mallocN(numOfEdges * sizeof(BMEdge *), "unwrap_edit_edge_map"); + + /* map subsurfed edges to original editEdges */ + for (i = 0; i < numOfEdges; i++) { + /* not all edges correspond to an old edge */ + edgeMap[i] = (origEdgeIndices[i] != ORIGINDEX_NONE) ? + BM_edge_at_index(em->bm, origEdgeIndices[i]) : + NULL; + } + + /* Prepare and feed faces to the solver */ + for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) { + ParamKey key, vkeys[4]; + ParamBool pin[4], select[4]; + float *co[4]; + float *uv[4]; + BMFace *origFace = faceMap[i]; + + if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { + if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN)) + continue; + } + else { + if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN) || + (options->only_selected && !BM_elem_flag_test(origFace, BM_ELEM_SELECT))) { + continue; + } + } + + mloop = &subsurfedLoops[mpoly->loopstart]; + + /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */ + BLI_assert(mpoly->totloop == 4); + key = (ParamKey)i; + vkeys[0] = (ParamKey)mloop[0].v; + vkeys[1] = (ParamKey)mloop[1].v; + vkeys[2] = (ParamKey)mloop[2].v; + vkeys[3] = (ParamKey)mloop[3].v; + + co[0] = subsurfedVerts[mloop[0].v].co; + co[1] = subsurfedVerts[mloop[1].v].co; + co[2] = subsurfedVerts[mloop[2].v].co; + co[3] = subsurfedVerts[mloop[3].v].co; + + /* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus + * flushing the solution to the edit mesh. */ + texface_from_original_index(origFace, + origVertIndices[mloop[0].v], + &uv[0], + &pin[0], + &select[0], + scene, + cd_loop_uv_offset); + texface_from_original_index(origFace, + origVertIndices[mloop[1].v], + &uv[1], + &pin[1], + &select[1], + scene, + cd_loop_uv_offset); + texface_from_original_index(origFace, + origVertIndices[mloop[2].v], + &uv[2], + &pin[2], + &select[2], + scene, + cd_loop_uv_offset); + texface_from_original_index(origFace, + origVertIndices[mloop[3].v], + &uv[3], + &pin[3], + &select[3], + scene, + cd_loop_uv_offset); + + param_face_add(handle, key, 4, vkeys, co, uv, pin, select); + } + + /* these are calculated from original mesh too */ + for (edge = subsurfedEdges, i = 0; i < numOfEdges; i++, edge++) { + if ((edgeMap[i] != NULL) && BM_elem_flag_test(edgeMap[i], BM_ELEM_SEAM)) { + ParamKey vkeys[2]; + vkeys[0] = (ParamKey)edge->v1; + vkeys[1] = (ParamKey)edge->v2; + param_edge_set_seam(handle, vkeys); + } + } + + param_construct_end(handle, options->fill_holes, options->topology_from_uvs); + + /* cleanup */ + MEM_freeN(faceMap); + MEM_freeN(edgeMap); + derivedMesh->release(derivedMesh); + + return handle; } /* ******************** Minimize Stretch operator **************** */ typedef struct MinStretch { - Scene *scene; - Object **objects_edit; - uint objects_len; - ParamHandle *handle; - float blend; - double lasttime; - int i, iterations; - wmTimer *timer; + Scene *scene; + Object **objects_edit; + uint objects_len; + ParamHandle *handle; + float blend; + double lasttime; + int i, iterations; + wmTimer *timer; } MinStretch; static bool minimize_stretch_init(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - - const UnwrapOptions options = { - .topology_from_uvs = true, - .fill_holes = RNA_boolean_get(op->ptr, "fill_holes"), - .only_selected = true, - .correct_aspect = true, - }; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, CTX_wm_view3d(C), &objects_len); - - if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) { - MEM_freeN(objects); - return false; - } - - MinStretch *ms = MEM_callocN(sizeof(MinStretch), "MinStretch"); - ms->scene = scene; - ms->objects_edit = objects; - ms->objects_len = objects_len; - ms->blend = RNA_float_get(op->ptr, "blend"); - ms->iterations = RNA_int_get(op->ptr, "iterations"); - ms->i = 0; - ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options); - ms->lasttime = PIL_check_seconds_timer(); - - param_stretch_begin(ms->handle); - if (ms->blend != 0.0f) - param_stretch_blend(ms->handle, ms->blend); - - op->customdata = ms; - - return true; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + const UnwrapOptions options = { + .topology_from_uvs = true, + .fill_holes = RNA_boolean_get(op->ptr, "fill_holes"), + .only_selected = true, + .correct_aspect = true, + }; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, CTX_wm_view3d(C), &objects_len); + + if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) { + MEM_freeN(objects); + return false; + } + + MinStretch *ms = MEM_callocN(sizeof(MinStretch), "MinStretch"); + ms->scene = scene; + ms->objects_edit = objects; + ms->objects_len = objects_len; + ms->blend = RNA_float_get(op->ptr, "blend"); + ms->iterations = RNA_int_get(op->ptr, "iterations"); + ms->i = 0; + ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options); + ms->lasttime = PIL_check_seconds_timer(); + + param_stretch_begin(ms->handle); + if (ms->blend != 0.0f) + param_stretch_blend(ms->handle, ms->blend); + + op->customdata = ms; + + return true; } static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interactive) { - MinStretch *ms = op->customdata; - ScrArea *sa = CTX_wm_area(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + MinStretch *ms = op->customdata; + ScrArea *sa = CTX_wm_area(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - param_stretch_blend(ms->handle, ms->blend); - param_stretch_iter(ms->handle); + param_stretch_blend(ms->handle, ms->blend); + param_stretch_iter(ms->handle); - ms->i++; - RNA_int_set(op->ptr, "iterations", ms->i); + ms->i++; + RNA_int_set(op->ptr, "iterations", ms->i); - if (interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) { - char str[UI_MAX_DRAW_STR]; + if (interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) { + char str[UI_MAX_DRAW_STR]; - param_flush(ms->handle); + param_flush(ms->handle); - if (sa) { - 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")); - } + if (sa) { + 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(); + ms->lasttime = PIL_check_seconds_timer(); - for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) { - Object *obedit = ms->objects_edit[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) { + Object *obedit = ms->objects_edit[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (synced_selection && (em->bm->totfacesel == 0)) { - continue; - } + if (synced_selection && (em->bm->totfacesel == 0)) { + continue; + } - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - } + DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + } } static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel) { - MinStretch *ms = op->customdata; - ScrArea *sa = CTX_wm_area(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + MinStretch *ms = op->customdata; + ScrArea *sa = CTX_wm_area(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - ED_area_status_text(sa, NULL); - ED_workspace_status_text(C, NULL); + 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); + if (ms->timer) + WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ms->timer); - if (cancel) - param_flush_restore(ms->handle); - else - param_flush(ms->handle); + if (cancel) + param_flush_restore(ms->handle); + else + param_flush(ms->handle); - param_stretch_end(ms->handle); - param_delete(ms->handle); + param_stretch_end(ms->handle); + param_delete(ms->handle); - for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) { - Object *obedit = ms->objects_edit[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) { + Object *obedit = ms->objects_edit[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (synced_selection && (em->bm->totfacesel == 0)) { - continue; - } + if (synced_selection && (em->bm->totfacesel == 0)) { + continue; + } - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } + DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } - MEM_freeN(ms->objects_edit); - MEM_freeN(ms); - op->customdata = NULL; + MEM_freeN(ms->objects_edit); + MEM_freeN(ms); + op->customdata = NULL; } static int minimize_stretch_exec(bContext *C, wmOperator *op) { - int i, iterations; + int i, iterations; - if (!minimize_stretch_init(C, op)) - return OPERATOR_CANCELLED; + if (!minimize_stretch_init(C, op)) + return OPERATOR_CANCELLED; - iterations = RNA_int_get(op->ptr, "iterations"); - for (i = 0; i < iterations; i++) - minimize_stretch_iteration(C, op, false); - minimize_stretch_exit(C, op, false); + iterations = RNA_int_get(op->ptr, "iterations"); + for (i = 0; i < iterations; i++) + minimize_stretch_iteration(C, op, false); + minimize_stretch_exit(C, op, false); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static int minimize_stretch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - MinStretch *ms; + MinStretch *ms; - if (!minimize_stretch_init(C, op)) - return OPERATOR_CANCELLED; + if (!minimize_stretch_init(C, op)) + return OPERATOR_CANCELLED; - minimize_stretch_iteration(C, op, true); + minimize_stretch_iteration(C, op, true); - ms = op->customdata; - WM_event_add_modal_handler(C, op); - ms->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); + ms = op->customdata; + WM_event_add_modal_handler(C, op); + ms->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); - return OPERATOR_RUNNING_MODAL; + return OPERATOR_RUNNING_MODAL; } static int minimize_stretch_modal(bContext *C, wmOperator *op, const wmEvent *event) { - MinStretch *ms = op->customdata; - - switch (event->type) { - case ESCKEY: - case RIGHTMOUSE: - minimize_stretch_exit(C, op, true); - return OPERATOR_CANCELLED; - case RETKEY: - case PADENTER: - case LEFTMOUSE: - minimize_stretch_exit(C, op, false); - return OPERATOR_FINISHED; - case PADPLUSKEY: - case WHEELUPMOUSE: - if (event->val == KM_PRESS) { - if (ms->blend < 0.95f) { - ms->blend += 0.1f; - ms->lasttime = 0.0f; - RNA_float_set(op->ptr, "blend", ms->blend); - minimize_stretch_iteration(C, op, true); - } - } - break; - case PADMINUS: - case WHEELDOWNMOUSE: - if (event->val == KM_PRESS) { - if (ms->blend > 0.05f) { - ms->blend -= 0.1f; - ms->lasttime = 0.0f; - RNA_float_set(op->ptr, "blend", ms->blend); - minimize_stretch_iteration(C, op, true); - } - } - break; - case TIMER: - if (ms->timer == event->customdata) { - double start = PIL_check_seconds_timer(); - - do { - minimize_stretch_iteration(C, op, true); - } while (PIL_check_seconds_timer() - start < 0.01); - } - break; - } - - if (ms->iterations && ms->i >= ms->iterations) { - minimize_stretch_exit(C, op, false); - return OPERATOR_FINISHED; - } - - return OPERATOR_RUNNING_MODAL; + MinStretch *ms = op->customdata; + + switch (event->type) { + case ESCKEY: + case RIGHTMOUSE: + minimize_stretch_exit(C, op, true); + return OPERATOR_CANCELLED; + case RETKEY: + case PADENTER: + case LEFTMOUSE: + minimize_stretch_exit(C, op, false); + return OPERATOR_FINISHED; + case PADPLUSKEY: + case WHEELUPMOUSE: + if (event->val == KM_PRESS) { + if (ms->blend < 0.95f) { + ms->blend += 0.1f; + ms->lasttime = 0.0f; + RNA_float_set(op->ptr, "blend", ms->blend); + minimize_stretch_iteration(C, op, true); + } + } + break; + case PADMINUS: + case WHEELDOWNMOUSE: + if (event->val == KM_PRESS) { + if (ms->blend > 0.05f) { + ms->blend -= 0.1f; + ms->lasttime = 0.0f; + RNA_float_set(op->ptr, "blend", ms->blend); + minimize_stretch_iteration(C, op, true); + } + } + break; + case TIMER: + if (ms->timer == event->customdata) { + double start = PIL_check_seconds_timer(); + + do { + minimize_stretch_iteration(C, op, true); + } while (PIL_check_seconds_timer() - start < 0.01); + } + break; + } + + if (ms->iterations && ms->i >= ms->iterations) { + minimize_stretch_exit(C, op, false); + return OPERATOR_FINISHED; + } + + return OPERATOR_RUNNING_MODAL; } static void minimize_stretch_cancel(bContext *C, wmOperator *op) { - minimize_stretch_exit(C, op, true); + minimize_stretch_exit(C, op, true); } void UV_OT_minimize_stretch(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Minimize Stretch"; - ot->idname = "UV_OT_minimize_stretch"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; - ot->description = "Reduce UV stretching by relaxing angles"; - - /* api callbacks */ - ot->exec = minimize_stretch_exec; - ot->invoke = minimize_stretch_invoke; - ot->modal = minimize_stretch_modal; - ot->cancel = minimize_stretch_cancel; - ot->poll = ED_operator_uvedit; - - /* properties */ - RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry"); - RNA_def_float_factor(ot->srna, "blend", 0.0f, 0.0f, 1.0f, "Blend", "Blend factor between stretch minimized and original", 0.0f, 1.0f); - RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively", 0, 100); + /* identifiers */ + ot->name = "Minimize Stretch"; + ot->idname = "UV_OT_minimize_stretch"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; + ot->description = "Reduce UV stretching by relaxing angles"; + + /* api callbacks */ + ot->exec = minimize_stretch_exec; + ot->invoke = minimize_stretch_invoke; + ot->modal = minimize_stretch_modal; + ot->cancel = minimize_stretch_cancel; + ot->poll = ED_operator_uvedit; + + /* properties */ + RNA_def_boolean(ot->srna, + "fill_holes", + 1, + "Fill Holes", + "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and " + "preserve symmetry"); + RNA_def_float_factor(ot->srna, + "blend", + 0.0f, + 0.0f, + 1.0f, + "Blend", + "Blend factor between stretch minimized and original", + 0.0f, + 1.0f); + RNA_def_int(ot->srna, + "iterations", + 0, + 0, + INT_MAX, + "Iterations", + "Number of iterations to run, 0 is unlimited when run interactively", + 0, + 100); } /* ******************** Pack Islands operator **************** */ static void uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm) { - const UnwrapOptions options = { - .topology_from_uvs = true, - .only_selected = false, - .fill_holes = false, - .correct_aspect = false, - }; - - bool rotate = true; - bool ignore_pinned = false; - - ParamHandle *handle; - handle = construct_param_handle(scene, ob, bm, &options); - param_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned); - param_flush(handle); - param_delete(handle); + const UnwrapOptions options = { + .topology_from_uvs = true, + .only_selected = false, + .fill_holes = false, + .correct_aspect = false, + }; + + bool rotate = true; + bool ignore_pinned = false; + + ParamHandle *handle; + handle = construct_param_handle(scene, ob, bm, &options); + param_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned); + param_flush(handle); + param_delete(handle); } -static void uvedit_pack_islands_multi( - Scene *scene, Object **objects, const uint objects_len, - const UnwrapOptions *options, bool rotate, bool ignore_pinned) +static void uvedit_pack_islands_multi(Scene *scene, + Object **objects, + const uint objects_len, + const UnwrapOptions *options, + bool rotate, + bool ignore_pinned) { - ParamHandle *handle; - handle = construct_param_handle_multi(scene, objects, objects_len, options); - param_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned); - param_flush(handle); - param_delete(handle); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data); - } + ParamHandle *handle; + handle = construct_param_handle_multi(scene, objects, objects_len, options); + param_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned); + param_flush(handle); + param_delete(handle); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data); + } } static int pack_islands_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Scene *scene = CTX_data_scene(C); - const UnwrapOptions options = { - .topology_from_uvs = true, - .only_selected = true, - .fill_holes = false, - .correct_aspect = true, - }; + const UnwrapOptions options = { + .topology_from_uvs = true, + .only_selected = true, + .fill_holes = false, + .correct_aspect = true, + }; - bool rotate = RNA_boolean_get(op->ptr, "rotate"); - bool ignore_pinned = false; + bool rotate = RNA_boolean_get(op->ptr, "rotate"); + bool ignore_pinned = false; - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, CTX_wm_view3d(C), &objects_len); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, CTX_wm_view3d(C), &objects_len); - if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) { - MEM_freeN(objects); - return OPERATOR_CANCELLED; - } + if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) { + MEM_freeN(objects); + return OPERATOR_CANCELLED; + } - if (RNA_struct_property_is_set(op->ptr, "margin")) - scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin"); - else - RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin); + if (RNA_struct_property_is_set(op->ptr, "margin")) + scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin"); + else + RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin); - uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); + uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); - MEM_freeN(objects); + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void UV_OT_pack_islands(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Pack Islands"; - ot->idname = "UV_OT_pack_islands"; - ot->description = "Transform all islands so that they fill up the UV space as much as possible"; + /* identifiers */ + ot->name = "Pack Islands"; + ot->idname = "UV_OT_pack_islands"; + ot->description = "Transform all islands so that they fill up the UV space as much as possible"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = pack_islands_exec; - ot->poll = ED_operator_uvedit; + /* api callbacks */ + ot->exec = pack_islands_exec; + ot->poll = ED_operator_uvedit; - /* properties */ - RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit"); - RNA_def_float_factor(ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f); + /* properties */ + RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit"); + RNA_def_float_factor( + ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f); } /* ******************** Average Islands Scale operator **************** */ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - ToolSettings *ts = scene->toolsettings; - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - - const UnwrapOptions options = { - .topology_from_uvs = true, - .only_selected = true, - .fill_holes = false, - .correct_aspect = true, - }; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, CTX_wm_view3d(C), &objects_len); - - if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) { - MEM_freeN(objects); - return OPERATOR_CANCELLED; - } - - ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options); - param_average(handle, false); - param_flush(handle); - param_delete(handle); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - MEM_freeN(objects); - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + ToolSettings *ts = scene->toolsettings; + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + + const UnwrapOptions options = { + .topology_from_uvs = true, + .only_selected = true, + .fill_holes = false, + .correct_aspect = true, + }; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, CTX_wm_view3d(C), &objects_len); + + if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) { + MEM_freeN(objects); + return OPERATOR_CANCELLED; + } + + ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options); + param_average(handle, false); + param_flush(handle); + param_delete(handle); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } + + DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + MEM_freeN(objects); + return OPERATOR_FINISHED; } void UV_OT_average_islands_scale(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Average Islands Scale"; - ot->idname = "UV_OT_average_islands_scale"; - ot->description = "Average the size of separate UV islands, based on their area in 3D space"; + /* identifiers */ + ot->name = "Average Islands Scale"; + ot->idname = "UV_OT_average_islands_scale"; + ot->description = "Average the size of separate UV islands, based on their area in 3D space"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = average_islands_scale_exec; - ot->poll = ED_operator_uvedit; + /* api callbacks */ + ot->exec = average_islands_scale_exec; + ot->poll = ED_operator_uvedit; } /**************** Live Unwrap *****************/ static struct { - ParamHandle **handles; - uint len, len_alloc; + ParamHandle **handles; + uint len, len_alloc; } g_live_unwrap = {NULL}; void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit) { - ParamHandle *handle = NULL; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const bool abf = (scene->toolsettings->unwrapper == 0); - bool use_subsurf; - - modifier_unwrap_state(obedit, scene, &use_subsurf); - - if (!ED_uvedit_test(obedit)) { - return; - } - - const UnwrapOptions options = { - .topology_from_uvs = false, - .only_selected = false, - .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0, - .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0, - }; - - if (use_subsurf) - handle = construct_param_handle_subsurfed(scene, obedit, em, &options); - else - handle = construct_param_handle(scene, obedit, em->bm, &options); - - param_lscm_begin(handle, PARAM_TRUE, abf); - - /* Create or increase size of g_live_unwrap.handles array */ - if (g_live_unwrap.handles == NULL) { - g_live_unwrap.len_alloc = 32; - g_live_unwrap.handles = MEM_mallocN(sizeof(ParamHandle *) * g_live_unwrap.len_alloc, "uvedit_live_unwrap_liveHandles"); - g_live_unwrap.len = 0; - } - if (g_live_unwrap.len >= g_live_unwrap.len_alloc) { - g_live_unwrap.len_alloc *= 2; - g_live_unwrap.handles = MEM_reallocN(g_live_unwrap.handles, sizeof(ParamHandle *) * g_live_unwrap.len_alloc); - } - g_live_unwrap.handles[g_live_unwrap.len] = handle; - g_live_unwrap.len++; + ParamHandle *handle = NULL; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const bool abf = (scene->toolsettings->unwrapper == 0); + bool use_subsurf; + + modifier_unwrap_state(obedit, scene, &use_subsurf); + + if (!ED_uvedit_test(obedit)) { + return; + } + + const UnwrapOptions options = { + .topology_from_uvs = false, + .only_selected = false, + .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0, + .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0, + }; + + if (use_subsurf) + handle = construct_param_handle_subsurfed(scene, obedit, em, &options); + else + handle = construct_param_handle(scene, obedit, em->bm, &options); + + param_lscm_begin(handle, PARAM_TRUE, abf); + + /* Create or increase size of g_live_unwrap.handles array */ + if (g_live_unwrap.handles == NULL) { + g_live_unwrap.len_alloc = 32; + g_live_unwrap.handles = MEM_mallocN(sizeof(ParamHandle *) * g_live_unwrap.len_alloc, + "uvedit_live_unwrap_liveHandles"); + g_live_unwrap.len = 0; + } + if (g_live_unwrap.len >= g_live_unwrap.len_alloc) { + g_live_unwrap.len_alloc *= 2; + g_live_unwrap.handles = MEM_reallocN(g_live_unwrap.handles, + sizeof(ParamHandle *) * g_live_unwrap.len_alloc); + } + g_live_unwrap.handles[g_live_unwrap.len] = handle; + g_live_unwrap.len++; } void ED_uvedit_live_unwrap_re_solve(void) { - if (g_live_unwrap.handles) { - for (int i = 0; i < g_live_unwrap.len; i++) { - param_lscm_solve(g_live_unwrap.handles[i]); - param_flush(g_live_unwrap.handles[i]); - } - } + if (g_live_unwrap.handles) { + for (int i = 0; i < g_live_unwrap.len; i++) { + param_lscm_solve(g_live_unwrap.handles[i]); + param_flush(g_live_unwrap.handles[i]); + } + } } void ED_uvedit_live_unwrap_end(short cancel) { - if (g_live_unwrap.handles) { - for (int i = 0; i < g_live_unwrap.len; i++) { - param_lscm_end(g_live_unwrap.handles[i]); - if (cancel) - param_flush_restore(g_live_unwrap.handles[i]); - param_delete(g_live_unwrap.handles[i]); - } - MEM_freeN(g_live_unwrap.handles); - g_live_unwrap.handles = NULL; - g_live_unwrap.len = 0; - g_live_unwrap.len_alloc = 0; - } + if (g_live_unwrap.handles) { + for (int i = 0; i < g_live_unwrap.len; i++) { + param_lscm_end(g_live_unwrap.handles[i]); + if (cancel) + param_flush_restore(g_live_unwrap.handles[i]); + param_delete(g_live_unwrap.handles[i]); + } + MEM_freeN(g_live_unwrap.handles); + g_live_unwrap.handles = NULL; + g_live_unwrap.len = 0; + g_live_unwrap.len_alloc = 0; + } } /*************** UV Map Common Transforms *****************/ #define VIEW_ON_EQUATOR 0 -#define VIEW_ON_POLES 1 +#define VIEW_ON_POLES 1 #define ALIGN_TO_OBJECT 2 -#define POLAR_ZX 0 -#define POLAR_ZY 1 +#define POLAR_ZX 0 +#define POLAR_ZY 1 static void uv_map_transform_calc_bounds(BMEditMesh *em, float r_min[3], float r_max[3]) { - BMFace *efa; - BMIter iter; - INIT_MINMAX(r_min, r_max); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - BM_face_calc_bounds_expand(efa, r_min, r_max); - } - } + BMFace *efa; + BMIter iter; + INIT_MINMAX(r_min, r_max); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_face_calc_bounds_expand(efa, r_min, r_max); + } + } } static void uv_map_transform_calc_center_median(BMEditMesh *em, float r_center[3]) { - BMFace *efa; - BMIter iter; - uint center_accum_num = 0; - zero_v3(r_center); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - float center[3]; - BM_face_calc_center_median(efa, center); - add_v3_v3(r_center, center); - center_accum_num += 1; - } - } - mul_v3_fl(r_center, 1.0f / (float)center_accum_num); + BMFace *efa; + BMIter iter; + uint center_accum_num = 0; + zero_v3(r_center); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + float center[3]; + BM_face_calc_center_median(efa, center); + add_v3_v3(r_center, center); + center_accum_num += 1; + } + } + mul_v3_fl(r_center, 1.0f / (float)center_accum_num); } static void uv_map_transform_center( - Scene *scene, View3D *v3d, Object *ob, BMEditMesh *em, - float r_center[3], - float r_bounds[2][3]) + Scene *scene, View3D *v3d, Object *ob, BMEditMesh *em, float r_center[3], float r_bounds[2][3]) { - /* only operates on the edit object - this is all that's needed now */ - const int around = (v3d) ? scene->toolsettings->transform_pivot_point : V3D_AROUND_CENTER_BOUNDS; - - float bounds[2][3]; - INIT_MINMAX(bounds[0], bounds[1]); - bool is_minmax_set = false; - - switch (around) { - case V3D_AROUND_CENTER_BOUNDS: /* bounding box center */ - { - uv_map_transform_calc_bounds(em, bounds[0], bounds[1]); - is_minmax_set = true; - mid_v3_v3v3(r_center, bounds[0], bounds[1]); - break; - } - case V3D_AROUND_CENTER_MEDIAN: - { - uv_map_transform_calc_center_median(em, r_center); - break; - } - case V3D_AROUND_CURSOR: /* cursor center */ - { - invert_m4_m4(ob->imat, ob->obmat); - mul_v3_m4v3(r_center, ob->imat, scene->cursor.location); - break; - } - case V3D_AROUND_ACTIVE: - { - BMEditSelection ese; - if (BM_select_history_active_get(em->bm, &ese)) { - BM_editselection_center(&ese, r_center); - break; - } - ATTR_FALLTHROUGH; - } - case V3D_AROUND_LOCAL_ORIGINS: /* object center */ - default: - zero_v3(r_center); - break; - } - - /* if this is passed, always set! */ - if (r_bounds) { - if (!is_minmax_set) { - uv_map_transform_calc_bounds(em, bounds[0], bounds[1]); - } - copy_v3_v3(r_bounds[0], bounds[0]); - copy_v3_v3(r_bounds[1], bounds[1]); - } + /* only operates on the edit object - this is all that's needed now */ + const int around = (v3d) ? scene->toolsettings->transform_pivot_point : V3D_AROUND_CENTER_BOUNDS; + + float bounds[2][3]; + INIT_MINMAX(bounds[0], bounds[1]); + bool is_minmax_set = false; + + switch (around) { + case V3D_AROUND_CENTER_BOUNDS: /* bounding box center */ + { + uv_map_transform_calc_bounds(em, bounds[0], bounds[1]); + is_minmax_set = true; + mid_v3_v3v3(r_center, bounds[0], bounds[1]); + break; + } + case V3D_AROUND_CENTER_MEDIAN: { + uv_map_transform_calc_center_median(em, r_center); + break; + } + case V3D_AROUND_CURSOR: /* cursor center */ + { + invert_m4_m4(ob->imat, ob->obmat); + mul_v3_m4v3(r_center, ob->imat, scene->cursor.location); + break; + } + case V3D_AROUND_ACTIVE: { + BMEditSelection ese; + if (BM_select_history_active_get(em->bm, &ese)) { + BM_editselection_center(&ese, r_center); + break; + } + ATTR_FALLTHROUGH; + } + case V3D_AROUND_LOCAL_ORIGINS: /* object center */ + default: + zero_v3(r_center); + break; + } + + /* if this is passed, always set! */ + if (r_bounds) { + if (!is_minmax_set) { + uv_map_transform_calc_bounds(em, bounds[0], bounds[1]); + } + copy_v3_v3(r_bounds[0], bounds[0]); + copy_v3_v3(r_bounds[1], bounds[1]); + } } -static void uv_map_rotation_matrix_ex( - float result[4][4], RegionView3D *rv3d, Object *ob, - float upangledeg, float sideangledeg, float radius, float offset[4]) +static void uv_map_rotation_matrix_ex(float result[4][4], + RegionView3D *rv3d, + Object *ob, + float upangledeg, + float sideangledeg, + float radius, + float offset[4]) { - float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4]; - float sideangle = 0.0f, upangle = 0.0f; - - /* get rotation of the current view matrix */ - if (rv3d) - copy_m4_m4(viewmatrix, rv3d->viewmat); - else - unit_m4(viewmatrix); - - /* but shifting */ - copy_v4_fl(viewmatrix[3], 0.0f); - - /* get rotation of the current object matrix */ - copy_m4_m4(rotobj, ob->obmat); - - /* but shifting */ - add_v4_v4(rotobj[3], offset); - rotobj[3][3] = 0.0f; - - zero_m4(rotup); - zero_m4(rotside); - - /* compensate front/side.. against opengl x,y,z world definition */ - /* this is "kanonen gegen spatzen", a few plus minus 1 will do here */ - /* i wanted to keep the reason here, so we're rotating*/ - sideangle = (float)M_PI * (sideangledeg + 180.0f) / 180.0f; - rotside[0][0] = cosf(sideangle); - rotside[0][1] = -sinf(sideangle); - rotside[1][0] = sinf(sideangle); - rotside[1][1] = cosf(sideangle); - rotside[2][2] = 1.0f; - - upangle = (float)M_PI * upangledeg / 180.0f; - rotup[1][1] = cosf(upangle) / radius; - rotup[1][2] = -sinf(upangle) / radius; - rotup[2][1] = sinf(upangle) / radius; - rotup[2][2] = cosf(upangle) / radius; - rotup[0][0] = 1.0f / radius; - - /* calculate transforms*/ - mul_m4_series(result, rotup, rotside, viewmatrix, rotobj); + float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4]; + float sideangle = 0.0f, upangle = 0.0f; + + /* get rotation of the current view matrix */ + if (rv3d) + copy_m4_m4(viewmatrix, rv3d->viewmat); + else + unit_m4(viewmatrix); + + /* but shifting */ + copy_v4_fl(viewmatrix[3], 0.0f); + + /* get rotation of the current object matrix */ + copy_m4_m4(rotobj, ob->obmat); + + /* but shifting */ + add_v4_v4(rotobj[3], offset); + rotobj[3][3] = 0.0f; + + zero_m4(rotup); + zero_m4(rotside); + + /* compensate front/side.. against opengl x,y,z world definition */ + /* this is "kanonen gegen spatzen", a few plus minus 1 will do here */ + /* i wanted to keep the reason here, so we're rotating*/ + sideangle = (float)M_PI * (sideangledeg + 180.0f) / 180.0f; + rotside[0][0] = cosf(sideangle); + rotside[0][1] = -sinf(sideangle); + rotside[1][0] = sinf(sideangle); + rotside[1][1] = cosf(sideangle); + rotside[2][2] = 1.0f; + + upangle = (float)M_PI * upangledeg / 180.0f; + rotup[1][1] = cosf(upangle) / radius; + rotup[1][2] = -sinf(upangle) / radius; + rotup[2][1] = sinf(upangle) / radius; + rotup[2][2] = cosf(upangle) / radius; + rotup[0][0] = 1.0f / radius; + + /* calculate transforms*/ + mul_m4_series(result, rotup, rotside, viewmatrix, rotobj); } -static void uv_map_rotation_matrix( - float result[4][4], RegionView3D *rv3d, Object *ob, - float upangledeg, float sideangledeg, float radius) +static void uv_map_rotation_matrix(float result[4][4], + RegionView3D *rv3d, + Object *ob, + float upangledeg, + float sideangledeg, + float radius) { - float offset[4] = {0}; - uv_map_rotation_matrix_ex(result, rv3d, ob, upangledeg, sideangledeg, radius, offset); + float offset[4] = {0}; + uv_map_rotation_matrix_ex(result, rv3d, ob, upangledeg, sideangledeg, radius, offset); } static void uv_map_transform(bContext *C, wmOperator *op, float rotmat[4][4]) { - /* context checks are messy here, making it work in both 3d view and uv editor */ - Object *obedit = CTX_data_edit_object(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - /* common operator properties */ - int align = RNA_enum_get(op->ptr, "align"); - int direction = RNA_enum_get(op->ptr, "direction"); - float radius = RNA_struct_find_property(op->ptr, "radius") ? RNA_float_get(op->ptr, "radius") : 1.0f; - float upangledeg, sideangledeg; - - if (direction == VIEW_ON_EQUATOR) { - upangledeg = 90.0f; - sideangledeg = 0.0f; - } - else { - upangledeg = 0.0f; - if (align == POLAR_ZY) sideangledeg = 0.0f; - else sideangledeg = 90.0f; - } - - /* be compatible to the "old" sphere/cylinder mode */ - if (direction == ALIGN_TO_OBJECT) - unit_m4(rotmat); - else - uv_map_rotation_matrix(rotmat, rv3d, obedit, upangledeg, sideangledeg, radius); - + /* context checks are messy here, making it work in both 3d view and uv editor */ + Object *obedit = CTX_data_edit_object(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + /* common operator properties */ + int align = RNA_enum_get(op->ptr, "align"); + int direction = RNA_enum_get(op->ptr, "direction"); + float radius = RNA_struct_find_property(op->ptr, "radius") ? RNA_float_get(op->ptr, "radius") : + 1.0f; + float upangledeg, sideangledeg; + + if (direction == VIEW_ON_EQUATOR) { + upangledeg = 90.0f; + sideangledeg = 0.0f; + } + else { + upangledeg = 0.0f; + if (align == POLAR_ZY) + sideangledeg = 0.0f; + else + sideangledeg = 90.0f; + } + + /* be compatible to the "old" sphere/cylinder mode */ + if (direction == ALIGN_TO_OBJECT) + unit_m4(rotmat); + else + uv_map_rotation_matrix(rotmat, rv3d, obedit, upangledeg, sideangledeg, radius); } static void uv_transform_properties(wmOperatorType *ot, int radius) { - static const EnumPropertyItem direction_items[] = { - {VIEW_ON_EQUATOR, "VIEW_ON_EQUATOR", 0, "View on Equator", "3D view is on the equator"}, - {VIEW_ON_POLES, "VIEW_ON_POLES", 0, "View on Poles", "3D view is on the poles"}, - {ALIGN_TO_OBJECT, "ALIGN_TO_OBJECT", 0, "Align to Object", "Align according to object transform"}, - {0, NULL, 0, NULL, NULL}, - }; - static const EnumPropertyItem align_items[] = { - {POLAR_ZX, "POLAR_ZX", 0, "Polar ZX", "Polar 0 is X"}, - {POLAR_ZY, "POLAR_ZY", 0, "Polar ZY", "Polar 0 is Y"}, - {0, NULL, 0, NULL, NULL}, - }; - - RNA_def_enum(ot->srna, "direction", direction_items, VIEW_ON_EQUATOR, "Direction", - "Direction of the sphere or cylinder"); - RNA_def_enum(ot->srna, "align", align_items, VIEW_ON_EQUATOR, "Align", - "How to determine rotation around the pole"); - if (radius) - RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", - "Radius of the sphere or cylinder", 0.0001f, 100.0f); + static const EnumPropertyItem direction_items[] = { + {VIEW_ON_EQUATOR, "VIEW_ON_EQUATOR", 0, "View on Equator", "3D view is on the equator"}, + {VIEW_ON_POLES, "VIEW_ON_POLES", 0, "View on Poles", "3D view is on the poles"}, + {ALIGN_TO_OBJECT, + "ALIGN_TO_OBJECT", + 0, + "Align to Object", + "Align according to object transform"}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem align_items[] = { + {POLAR_ZX, "POLAR_ZX", 0, "Polar ZX", "Polar 0 is X"}, + {POLAR_ZY, "POLAR_ZY", 0, "Polar ZY", "Polar 0 is Y"}, + {0, NULL, 0, NULL, NULL}, + }; + + RNA_def_enum(ot->srna, + "direction", + direction_items, + VIEW_ON_EQUATOR, + "Direction", + "Direction of the sphere or cylinder"); + RNA_def_enum(ot->srna, + "align", + align_items, + VIEW_ON_EQUATOR, + "Align", + "How to determine rotation around the pole"); + if (radius) + RNA_def_float(ot->srna, + "radius", + 1.0f, + 0.0f, + FLT_MAX, + "Radius", + "Radius of the sphere or cylinder", + 0.0001f, + 100.0f); } static void correct_uv_aspect(Scene *scene, Object *ob, BMEditMesh *em) { - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - BMFace *efa; - float scale, aspx, aspy; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy); - - if (aspx == aspy) - return; - - if (aspx > aspy) { - scale = aspy / aspx; - - 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); - luv->uv[0] = ((luv->uv[0] - 0.5f) * scale) + 0.5f; - } - } - } - else { - scale = aspx / aspy; - - 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); - luv->uv[1] = ((luv->uv[1] - 0.5f) * scale) + 0.5f; - } - } - } + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + BMFace *efa; + float scale, aspx, aspy; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy); + + if (aspx == aspy) + return; + + if (aspx > aspy) { + scale = aspy / aspx; + + 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); + luv->uv[0] = ((luv->uv[0] - 0.5f) * scale) + 0.5f; + } + } + } + else { + scale = aspx / aspy; + + 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); + luv->uv[1] = ((luv->uv[1] - 0.5f) * scale) + 0.5f; + } + } + } } /******************** Map Clip & Correct ******************/ static void uv_map_clip_correct_properties(wmOperatorType *ot) { - RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect", - "Map UVs taking image aspect ratio into account"); - RNA_def_boolean(ot->srna, "clip_to_bounds", 0, "Clip to Bounds", - "Clip UV coordinates to bounds after unwrapping"); - RNA_def_boolean(ot->srna, "scale_to_bounds", 0, "Scale to Bounds", - "Scale UV coordinates to bounds after unwrapping"); + RNA_def_boolean(ot->srna, + "correct_aspect", + 1, + "Correct Aspect", + "Map UVs taking image aspect ratio into account"); + RNA_def_boolean(ot->srna, + "clip_to_bounds", + 0, + "Clip to Bounds", + "Clip UV coordinates to bounds after unwrapping"); + RNA_def_boolean(ot->srna, + "scale_to_bounds", + 0, + "Scale to Bounds", + "Scale UV coordinates to bounds after unwrapping"); } -static void uv_map_clip_correct_multi(Scene *scene, Object **objects, uint objects_len, wmOperator *op) +static void uv_map_clip_correct_multi(Scene *scene, + Object **objects, + uint objects_len, + wmOperator *op) { - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - float dx, dy, min[2], max[2]; - const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"); - 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"); - - INIT_MINMAX2(min, max); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - - BMEditMesh *em = BKE_editmesh_from_object(ob); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* correct for image aspect ratio */ - if (correct_aspect) - correct_uv_aspect(scene, ob, em); - - 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]); - - if (dx > 0.0f) - dx = 1.0f / dx; - if (dy > 0.0f) - dy = 1.0f / dy; - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - - 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; - - 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; - } - } - } - } + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + float dx, dy, min[2], max[2]; + const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"); + 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"); + + INIT_MINMAX2(min, max); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + + BMEditMesh *em = BKE_editmesh_from_object(ob); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* correct for image aspect ratio */ + if (correct_aspect) + correct_uv_aspect(scene, ob, em); + + 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]); + + if (dx > 0.0f) + dx = 1.0f / dx; + if (dy > 0.0f) + dy = 1.0f / dy; + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + + 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; + + 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); + uv_map_clip_correct_multi(scene, &ob, 1, op); } /* ******************** Unwrap operator **************** */ @@ -1413,195 +1510,228 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, wmOperator *op) /* Assumes UV Map exists, doesn't run update funcs. */ static void uvedit_unwrap(Scene *scene, Object *obedit, const UnwrapOptions *options) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (!CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) { - return; - } + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (!CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) { + return; + } - bool use_subsurf; - modifier_unwrap_state(obedit, scene, &use_subsurf); + bool use_subsurf; + modifier_unwrap_state(obedit, scene, &use_subsurf); - ParamHandle *handle; - if (use_subsurf) - handle = construct_param_handle_subsurfed(scene, obedit, em, options); - else - handle = construct_param_handle(scene, obedit, em->bm, options); + ParamHandle *handle; + if (use_subsurf) + handle = construct_param_handle_subsurfed(scene, obedit, em, options); + else + handle = construct_param_handle(scene, obedit, em->bm, options); - param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0); - param_lscm_solve(handle); - param_lscm_end(handle); + param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0); + param_lscm_solve(handle); + param_lscm_end(handle); - param_average(handle, true); + param_average(handle, true); - param_flush(handle); + param_flush(handle); - param_delete(handle); + param_delete(handle); } -static void uvedit_unwrap_multi(Scene *scene, Object **objects, const int objects_len, const UnwrapOptions *options) +static void uvedit_unwrap_multi(Scene *scene, + Object **objects, + const int objects_len, + const UnwrapOptions *options) { - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - uvedit_unwrap(scene, obedit, options); - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data); - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + uvedit_unwrap(scene, obedit, options); + DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data); + } } void ED_uvedit_live_unwrap(Scene *scene, Object **objects, int objects_len) { - if (scene->toolsettings->edge_mode_live_unwrap) { - const UnwrapOptions options = { - .topology_from_uvs = false, - .only_selected = false, - .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0, - .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0, - }; - - bool rotate = true; - bool ignore_pinned = true; - - uvedit_unwrap_multi(scene, objects, objects_len, &options); - uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); - } + if (scene->toolsettings->edge_mode_live_unwrap) { + const UnwrapOptions options = { + .topology_from_uvs = false, + .only_selected = false, + .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0, + .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0, + }; + + bool rotate = true; + bool ignore_pinned = true; + + uvedit_unwrap_multi(scene, objects, objects_len, &options); + uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); + } } enum { - UNWRAP_ERROR_NONUNIFORM = (1 << 0), - UNWRAP_ERROR_NEGATIVE = (1 << 1), + UNWRAP_ERROR_NONUNIFORM = (1 << 0), + UNWRAP_ERROR_NEGATIVE = (1 << 1), }; static int unwrap_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - Scene *scene = CTX_data_scene(C); - int method = RNA_enum_get(op->ptr, "method"); - const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data"); - int reported_errors = 0; - /* We will report an error unless at least one object - * has the subsurf modifier in the right place. */ - bool subsurf_error = use_subsurf; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - - const UnwrapOptions options = { - .topology_from_uvs = false, - .only_selected = true, - .fill_holes = RNA_boolean_get(op->ptr, "fill_holes"), - .correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"), - }; - - bool rotate = true; - bool ignore_pinned = true; - - if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) { - MEM_freeN(objects); - return OPERATOR_CANCELLED; - } - - /* add uvs if they don't exist yet */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - float obsize[3]; - bool use_subsurf_final; - - if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { - continue; - } - - if (subsurf_error) { - /* Double up the check here but better keep uvedit_unwrap interface simple and not - * pass operator for warning append. */ - modifier_unwrap_state(obedit, scene, &use_subsurf_final); - if (use_subsurf_final) { - subsurf_error = false; - } - } - - if (reported_errors & (UNWRAP_ERROR_NONUNIFORM | UNWRAP_ERROR_NEGATIVE)) { - continue; - } - - mat4_to_size(obsize, obedit->obmat); - if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f)) { - if ((reported_errors & UNWRAP_ERROR_NONUNIFORM) == 0) { - BKE_report(op->reports, RPT_INFO, - "Object has non-uniform scale, unwrap will operate on a non-scaled version of the mesh"); - reported_errors |= UNWRAP_ERROR_NONUNIFORM; - } - } - else if (is_negative_m4(obedit->obmat)) { - if ((reported_errors & UNWRAP_ERROR_NEGATIVE) == 0) { - BKE_report(op->reports, RPT_INFO, - "Object has negative scale, unwrap will operate on a non-flipped version of the mesh"); - reported_errors |= UNWRAP_ERROR_NEGATIVE; - } - } - } - - if (subsurf_error) { - 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")) - scene->toolsettings->unwrapper = method; - else - RNA_enum_set(op->ptr, "method", scene->toolsettings->unwrapper); - - /* remember packing margin */ - if (RNA_struct_property_is_set(op->ptr, "margin")) - scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin"); - else - RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin); - - if (options.fill_holes) scene->toolsettings->uvcalc_flag |= UVCALC_FILLHOLES; - else scene->toolsettings->uvcalc_flag &= ~UVCALC_FILLHOLES; - - if (options.correct_aspect) scene->toolsettings->uvcalc_flag &= ~UVCALC_NO_ASPECT_CORRECT; - else scene->toolsettings->uvcalc_flag |= UVCALC_NO_ASPECT_CORRECT; - - if (use_subsurf) scene->toolsettings->uvcalc_flag |= UVCALC_USESUBSURF; - else scene->toolsettings->uvcalc_flag &= ~UVCALC_USESUBSURF; - - /* execute unwrap */ - uvedit_unwrap_multi(scene, objects, objects_len, &options); - uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); - - MEM_freeN(objects); - - return OPERATOR_FINISHED; + ViewLayer *view_layer = CTX_data_view_layer(C); + Scene *scene = CTX_data_scene(C); + int method = RNA_enum_get(op->ptr, "method"); + const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data"); + int reported_errors = 0; + /* We will report an error unless at least one object + * has the subsurf modifier in the right place. */ + bool subsurf_error = use_subsurf; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + const UnwrapOptions options = { + .topology_from_uvs = false, + .only_selected = true, + .fill_holes = RNA_boolean_get(op->ptr, "fill_holes"), + .correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"), + }; + + bool rotate = true; + bool ignore_pinned = true; + + if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) { + MEM_freeN(objects); + return OPERATOR_CANCELLED; + } + + /* add uvs if they don't exist yet */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + float obsize[3]; + bool use_subsurf_final; + + if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { + continue; + } + + if (subsurf_error) { + /* Double up the check here but better keep uvedit_unwrap interface simple and not + * pass operator for warning append. */ + modifier_unwrap_state(obedit, scene, &use_subsurf_final); + if (use_subsurf_final) { + subsurf_error = false; + } + } + + if (reported_errors & (UNWRAP_ERROR_NONUNIFORM | UNWRAP_ERROR_NEGATIVE)) { + continue; + } + + mat4_to_size(obsize, obedit->obmat); + if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f)) { + if ((reported_errors & UNWRAP_ERROR_NONUNIFORM) == 0) { + BKE_report(op->reports, + RPT_INFO, + "Object has non-uniform scale, unwrap will operate on a non-scaled version of " + "the mesh"); + reported_errors |= UNWRAP_ERROR_NONUNIFORM; + } + } + else if (is_negative_m4(obedit->obmat)) { + if ((reported_errors & UNWRAP_ERROR_NEGATIVE) == 0) { + BKE_report( + op->reports, + RPT_INFO, + "Object has negative scale, unwrap will operate on a non-flipped version of the mesh"); + reported_errors |= UNWRAP_ERROR_NEGATIVE; + } + } + } + + if (subsurf_error) { + 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")) + scene->toolsettings->unwrapper = method; + else + RNA_enum_set(op->ptr, "method", scene->toolsettings->unwrapper); + + /* remember packing margin */ + if (RNA_struct_property_is_set(op->ptr, "margin")) + scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin"); + else + RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin); + + if (options.fill_holes) + scene->toolsettings->uvcalc_flag |= UVCALC_FILLHOLES; + else + scene->toolsettings->uvcalc_flag &= ~UVCALC_FILLHOLES; + + if (options.correct_aspect) + scene->toolsettings->uvcalc_flag &= ~UVCALC_NO_ASPECT_CORRECT; + else + scene->toolsettings->uvcalc_flag |= UVCALC_NO_ASPECT_CORRECT; + + if (use_subsurf) + scene->toolsettings->uvcalc_flag |= UVCALC_USESUBSURF; + else + scene->toolsettings->uvcalc_flag &= ~UVCALC_USESUBSURF; + + /* execute unwrap */ + uvedit_unwrap_multi(scene, objects, objects_len, &options); + uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); + + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void UV_OT_unwrap(wmOperatorType *ot) { - static const EnumPropertyItem method_items[] = { - {0, "ANGLE_BASED", 0, "Angle Based", ""}, - {1, "CONFORMAL", 0, "Conformal", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Unwrap"; - ot->description = "Unwrap the mesh of the object being edited"; - ot->idname = "UV_OT_unwrap"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = unwrap_exec; - ot->poll = ED_operator_uvmap; - - /* properties */ - RNA_def_enum(ot->srna, "method", method_items, 0, "Method", - "Unwrapping method (Angle Based usually gives better results than Conformal, while being somewhat slower)"); - RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", - "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry"); - RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect", - "Map UVs taking image aspect ratio into account"); - RNA_def_boolean(ot->srna, "use_subsurf_data", 0, "Use Subsurf Modifier", - "Map UVs taking vertex position after Subdivision Surface modifier has been applied"); - RNA_def_float_factor(ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f); + static const EnumPropertyItem method_items[] = { + {0, "ANGLE_BASED", 0, "Angle Based", ""}, + {1, "CONFORMAL", 0, "Conformal", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Unwrap"; + ot->description = "Unwrap the mesh of the object being edited"; + ot->idname = "UV_OT_unwrap"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = unwrap_exec; + ot->poll = ED_operator_uvmap; + + /* properties */ + RNA_def_enum(ot->srna, + "method", + method_items, + 0, + "Method", + "Unwrapping method (Angle Based usually gives better results than Conformal, while " + "being somewhat slower)"); + RNA_def_boolean(ot->srna, + "fill_holes", + 1, + "Fill Holes", + "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and " + "preserve symmetry"); + RNA_def_boolean(ot->srna, + "correct_aspect", + 1, + "Correct Aspect", + "Map UVs taking image aspect ratio into account"); + RNA_def_boolean( + ot->srna, + "use_subsurf_data", + 0, + "Use Subsurf Modifier", + "Map UVs taking vertex position after Subdivision Surface modifier has been applied"); + RNA_def_float_factor( + ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f); } /**************** Project From View operator **************/ @@ -1609,574 +1739,605 @@ static int uv_from_view_exec(bContext *C, wmOperator *op); static int uv_from_view_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - Camera *camera = ED_view3d_camera_data_get(v3d, rv3d); - PropertyRNA *prop; - - prop = RNA_struct_find_property(op->ptr, "camera_bounds"); - if (!RNA_property_is_set(op->ptr, prop)) RNA_property_boolean_set(op->ptr, prop, (camera != NULL)); - prop = RNA_struct_find_property(op->ptr, "correct_aspect"); - if (!RNA_property_is_set(op->ptr, prop)) RNA_property_boolean_set(op->ptr, prop, (camera == NULL)); - - return uv_from_view_exec(C, op); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + Camera *camera = ED_view3d_camera_data_get(v3d, rv3d); + PropertyRNA *prop; + + prop = RNA_struct_find_property(op->ptr, "camera_bounds"); + if (!RNA_property_is_set(op->ptr, prop)) + RNA_property_boolean_set(op->ptr, prop, (camera != NULL)); + prop = RNA_struct_find_property(op->ptr, "correct_aspect"); + if (!RNA_property_is_set(op->ptr, prop)) + RNA_property_boolean_set(op->ptr, prop, (camera == NULL)); + + return uv_from_view_exec(C, op); } static int uv_from_view_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - Scene *scene = CTX_data_scene(C); - ARegion *ar = CTX_wm_region(C); - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - Camera *camera = ED_view3d_camera_data_get(v3d, rv3d); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - float rotmat[4][4]; - float objects_pos_offset[4]; - bool changed_multi = false; - - const bool use_orthographic = RNA_boolean_get(op->ptr, "orthographic"); - - /* 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, v3d, &objects_len); - - if (use_orthographic) { - /* Calculate average object position. */ - float objects_pos_avg[4] = {0}; - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - add_v4_v4(objects_pos_avg, objects[ob_index]->obmat[3]); - } - - mul_v4_fl(objects_pos_avg, 1.0f / objects_len); - negate_v4_v4(objects_pos_offset, objects_pos_avg); - } - - 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; - } - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if (use_orthographic) { - uv_map_rotation_matrix_ex(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f, objects_pos_offset); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) - continue; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - BLI_uvproject_from_view_ortho(luv->uv, l->v->co, rotmat); - } - changed = true; - } - } - else if (camera) { - const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds"); - struct ProjCameraInfo *uci = BLI_uvproject_camera_info( - v3d->camera, obedit->obmat, - camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f, - camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f); - - if (uci) { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) - continue; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - BLI_uvproject_from_camera(luv->uv, l->v->co, uci); - } - changed = true; - } - - MEM_freeN(uci); - } - } - 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); - } - changed = true; - } - } - - if (changed) { - changed_multi = true; - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - 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; - } - } - - if (changed_multi) { - uv_map_clip_correct_multi(scene, objects, objects_len, op); - } - - MEM_freeN(objects); - - if (changed_multi) { - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + ViewLayer *view_layer = CTX_data_view_layer(C); + Scene *scene = CTX_data_scene(C); + ARegion *ar = CTX_wm_region(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + Camera *camera = ED_view3d_camera_data_get(v3d, rv3d); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + float rotmat[4][4]; + float objects_pos_offset[4]; + bool changed_multi = false; + + const bool use_orthographic = RNA_boolean_get(op->ptr, "orthographic"); + + /* 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, v3d, &objects_len); + + if (use_orthographic) { + /* Calculate average object position. */ + float objects_pos_avg[4] = {0}; + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + add_v4_v4(objects_pos_avg, objects[ob_index]->obmat[3]); + } + + mul_v4_fl(objects_pos_avg, 1.0f / objects_len); + negate_v4_v4(objects_pos_offset, objects_pos_avg); + } + + 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; + } + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (use_orthographic) { + uv_map_rotation_matrix_ex(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f, objects_pos_offset); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) + continue; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + BLI_uvproject_from_view_ortho(luv->uv, l->v->co, rotmat); + } + changed = true; + } + } + else if (camera) { + const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds"); + struct ProjCameraInfo *uci = BLI_uvproject_camera_info( + v3d->camera, + obedit->obmat, + camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f, + camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f); + + if (uci) { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) + continue; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + BLI_uvproject_from_camera(luv->uv, l->v->co, uci); + } + changed = true; + } + + MEM_freeN(uci); + } + } + 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); + } + changed = true; + } + } + + if (changed) { + changed_multi = true; + DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); + 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; + } + } + + if (changed_multi) { + uv_map_clip_correct_multi(scene, objects, objects_len, op); + } + + MEM_freeN(objects); + + if (changed_multi) { + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } static bool uv_from_view_poll(bContext *C) { - RegionView3D *rv3d = CTX_wm_region_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); - if (!ED_operator_uvmap(C)) - return 0; + if (!ED_operator_uvmap(C)) + return 0; - return (rv3d != NULL); + return (rv3d != NULL); } void UV_OT_project_from_view(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Project From View"; - ot->idname = "UV_OT_project_from_view"; - ot->description = "Project the UV vertices of the mesh as seen in current 3D view"; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->invoke = uv_from_view_invoke; - ot->exec = uv_from_view_exec; - ot->poll = uv_from_view_poll; - - /* properties */ - RNA_def_boolean(ot->srna, "orthographic", 0, "Orthographic", - "Use orthographic projection"); - RNA_def_boolean(ot->srna, "camera_bounds", 1, "Camera Bounds", - "Map UVs to the camera region taking resolution and aspect into account"); - uv_map_clip_correct_properties(ot); + /* identifiers */ + ot->name = "Project From View"; + ot->idname = "UV_OT_project_from_view"; + ot->description = "Project the UV vertices of the mesh as seen in current 3D view"; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->invoke = uv_from_view_invoke; + ot->exec = uv_from_view_exec; + ot->poll = uv_from_view_poll; + + /* properties */ + RNA_def_boolean(ot->srna, "orthographic", 0, "Orthographic", "Use orthographic projection"); + RNA_def_boolean(ot->srna, + "camera_bounds", + 1, + "Camera Bounds", + "Map UVs to the camera region taking resolution and aspect into account"); + uv_map_clip_correct_properties(ot); } /********************** Reset operator ********************/ static int reset_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &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); - - if (em->bm->totfacesel == 0) { - continue; - } - - /* 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, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, v3d, &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); + + if (em->bm->totfacesel == 0) { + continue; + } + + /* 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, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void UV_OT_reset(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Reset"; - ot->idname = "UV_OT_reset"; - ot->description = "Reset UV projection"; + /* identifiers */ + ot->name = "Reset"; + ot->idname = "UV_OT_reset"; + ot->description = "Reset UV projection"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = reset_exec; - ot->poll = ED_operator_uvmap; + /* api callbacks */ + ot->exec = reset_exec; + ot->poll = ED_operator_uvmap; } /****************** Sphere Project operator ***************/ -static void uv_sphere_project(float target[2], float source[3], float center[3], float rotmat[4][4]) +static void uv_sphere_project(float target[2], + float source[3], + float center[3], + float rotmat[4][4]) { - float pv[3]; + float pv[3]; - sub_v3_v3v3(pv, source, center); - mul_m4_v3(rotmat, pv); + sub_v3_v3v3(pv, source, center); + mul_m4_v3(rotmat, pv); - map_to_sphere(&target[0], &target[1], pv[0], pv[1], pv[2]); + map_to_sphere(&target[0], &target[1], pv[0], pv[1], pv[2]); - /* split line is always zero */ - if (target[0] >= 1.0f) - target[0] -= 1.0f; + /* split line is always zero */ + if (target[0] >= 1.0f) + target[0] -= 1.0f; } static void uv_map_mirror(BMEditMesh *em, BMFace *efa) { - BMLoop *l; - BMIter liter; - MLoopUV *luv; - float **uvs = BLI_array_alloca(uvs, efa->len); - float dx; - int i, mi; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - uvs[i] = luv->uv; - } - - mi = 0; - for (i = 1; i < efa->len; i++) - if (uvs[i][0] > uvs[mi][0]) - mi = i; - - for (i = 0; i < efa->len; i++) { - if (i != mi) { - dx = uvs[mi][0] - uvs[i][0]; - if (dx > 0.5f) uvs[i][0] += 1.0f; - } - } + BMLoop *l; + BMIter liter; + MLoopUV *luv; + float **uvs = BLI_array_alloca(uvs, efa->len); + float dx; + int i, mi; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) + { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + uvs[i] = luv->uv; + } + + mi = 0; + for (i = 1; i < efa->len; i++) + if (uvs[i][0] > uvs[mi][0]) + mi = i; + + for (i = 0; i < efa->len; i++) { + if (i != mi) { + dx = uvs[mi][0] - uvs[i][0]; + if (dx > 0.5f) + uvs[i][0] += 1.0f; + } + } } static int sphere_project_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(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(view_layer, v3d, &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; + 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, v3d, &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; - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - /* add uvs if they don't exist yet */ - if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { - continue; - } + /* add uvs if they don't exist yet */ + if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { + continue; + } - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - float center[3], rotmat[4][4]; + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + float center[3], rotmat[4][4]; - uv_map_transform(C, op, rotmat); - uv_map_transform_center(scene, v3d, obedit, em, center, NULL); + uv_map_transform(C, op, rotmat); + uv_map_transform_center(scene, v3d, obedit, em, center, NULL); - 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); + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - uv_sphere_project(luv->uv, l->v->co, center, rotmat); - } + uv_sphere_project(luv->uv, l->v->co, center, rotmat); + } - uv_map_mirror(em, efa); - } + uv_map_mirror(em, efa); + } - uv_map_clip_correct(scene, obedit, op); + uv_map_clip_correct(scene, obedit, op); - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - MEM_freeN(objects); + DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void UV_OT_sphere_project(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Sphere Projection"; - ot->idname = "UV_OT_sphere_project"; - ot->description = "Project the UV vertices of the mesh over the curved surface of a sphere"; + /* identifiers */ + ot->name = "Sphere Projection"; + ot->idname = "UV_OT_sphere_project"; + ot->description = "Project the UV vertices of the mesh over the curved surface of a sphere"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = sphere_project_exec; - ot->poll = ED_operator_uvmap; + /* api callbacks */ + ot->exec = sphere_project_exec; + ot->poll = ED_operator_uvmap; - /* properties */ - uv_transform_properties(ot, 0); - uv_map_clip_correct_properties(ot); + /* properties */ + uv_transform_properties(ot, 0); + uv_map_clip_correct_properties(ot); } /***************** Cylinder Project operator **************/ -static void uv_cylinder_project(float target[2], float source[3], float center[3], float rotmat[4][4]) +static void uv_cylinder_project(float target[2], + float source[3], + float center[3], + float rotmat[4][4]) { - float pv[3]; + float pv[3]; - sub_v3_v3v3(pv, source, center); - mul_m4_v3(rotmat, pv); + sub_v3_v3v3(pv, source, center); + mul_m4_v3(rotmat, pv); - map_to_tube(&target[0], &target[1], pv[0], pv[1], pv[2]); + map_to_tube(&target[0], &target[1], pv[0], pv[1], pv[2]); - /* split line is always zero */ - if (target[0] >= 1.0f) - target[0] -= 1.0f; + /* split line is always zero */ + if (target[0] >= 1.0f) + target[0] -= 1.0f; } static int cylinder_project_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(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(view_layer, v3d, &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; + 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, v3d, &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; - if (em->bm->totfacesel == 0) { - continue; - } + if (em->bm->totfacesel == 0) { + continue; + } - /* add uvs if they don't exist yet */ - if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { - continue; - } + /* add uvs if they don't exist yet */ + if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { + continue; + } - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - float center[3], rotmat[4][4]; + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + float center[3], rotmat[4][4]; - uv_map_transform(C, op, rotmat); - uv_map_transform_center(scene, v3d, obedit, em, center, NULL); + uv_map_transform(C, op, rotmat); + uv_map_transform_center(scene, v3d, obedit, em, center, NULL); - 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); + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - uv_cylinder_project(luv->uv, l->v->co, center, rotmat); - } + uv_cylinder_project(luv->uv, l->v->co, center, rotmat); + } - uv_map_mirror(em, efa); - } + uv_map_mirror(em, efa); + } - uv_map_clip_correct(scene, obedit, op); + uv_map_clip_correct(scene, obedit, op); - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - MEM_freeN(objects); + DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + MEM_freeN(objects); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void UV_OT_cylinder_project(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Cylinder Projection"; - ot->idname = "UV_OT_cylinder_project"; - ot->description = "Project the UV vertices of the mesh over the curved wall of a cylinder"; + /* identifiers */ + ot->name = "Cylinder Projection"; + ot->idname = "UV_OT_cylinder_project"; + ot->description = "Project the UV vertices of the mesh over the curved wall of a cylinder"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* api callbacks */ - ot->exec = cylinder_project_exec; - ot->poll = ED_operator_uvmap; + /* api callbacks */ + ot->exec = cylinder_project_exec; + ot->poll = ED_operator_uvmap; - /* properties */ - uv_transform_properties(ot, 1); - uv_map_clip_correct_properties(ot); + /* properties */ + uv_transform_properties(ot, 1); + uv_map_clip_correct_properties(ot); } /******************* Cube Project operator ****************/ -static void uvedit_unwrap_cube_project(BMesh *bm, float cube_size, bool use_select, const float center[3]) +static void uvedit_unwrap_cube_project(BMesh *bm, + float cube_size, + bool use_select, + const float center[3]) { - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - float loc[3]; - int cox, coy; - - int cd_loop_uv_offset; - - cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - if (center) { - copy_v3_v3(loc, center); - } - else { - zero_v3(loc); - } - - /* choose x,y,z axis for projection depending on the largest normal - * component, but clusters all together around the center of map. */ - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */ - if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) - continue; - - axis_dominant_v3(&cox, &coy, efa->no); - - 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] = 0.5f + 0.5f * cube_size * (l->v->co[cox] - loc[cox]); - luv->uv[1] = 0.5f + 0.5f * cube_size * (l->v->co[coy] - loc[coy]); - } - } + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + float loc[3]; + int cox, coy; + + int cd_loop_uv_offset; + + cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + if (center) { + copy_v3_v3(loc, center); + } + else { + zero_v3(loc); + } + + /* choose x,y,z axis for projection depending on the largest normal + * component, but clusters all together around the center of map. */ + + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */ + if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) + continue; + + axis_dominant_v3(&cox, &coy, efa->no); + + 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] = 0.5f + 0.5f * cube_size * (l->v->co[cox] - loc[cox]); + luv->uv[1] = 0.5f + 0.5f * cube_size * (l->v->co[coy] - loc[coy]); + } + } } static int cube_project_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - - PropertyRNA *prop_cube_size = RNA_struct_find_property(op->ptr, "cube_size"); - const float cube_size_init = RNA_property_float_get(op->ptr, prop_cube_size); - - 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, v3d, &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 (em->bm->totfacesel == 0) { - continue; - } - - /* add uvs if they don't exist yet */ - if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { - continue; - } - - 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); - } - } - - uvedit_unwrap_cube_project(em->bm, cube_size, true, center); - - uv_map_clip_correct(scene, obedit, op); - - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + + PropertyRNA *prop_cube_size = RNA_struct_find_property(op->ptr, "cube_size"); + const float cube_size_init = RNA_property_float_get(op->ptr, prop_cube_size); + + 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, v3d, &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 (em->bm->totfacesel == 0) { + continue; + } + + /* add uvs if they don't exist yet */ + if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { + continue; + } + + 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); + } + } + + uvedit_unwrap_cube_project(em->bm, cube_size, true, center); + + uv_map_clip_correct(scene, obedit, op); + + DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; } void UV_OT_cube_project(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Cube Projection"; - ot->idname = "UV_OT_cube_project"; - ot->description = "Project the UV vertices of the mesh over the six faces of a cube"; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = cube_project_exec; - ot->poll = ED_operator_uvmap; - - /* properties */ - RNA_def_float(ot->srna, "cube_size", 1.0f, 0.0f, FLT_MAX, "Cube Size", "Size of the cube to project on", 0.001f, 100.0f); - uv_map_clip_correct_properties(ot); + /* identifiers */ + ot->name = "Cube Projection"; + ot->idname = "UV_OT_cube_project"; + ot->description = "Project the UV vertices of the mesh over the six faces of a cube"; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = cube_project_exec; + ot->poll = ED_operator_uvmap; + + /* properties */ + RNA_def_float(ot->srna, + "cube_size", + 1.0f, + 0.0f, + FLT_MAX, + "Cube Size", + "Size of the cube to project on", + 0.001f, + 100.0f); + uv_map_clip_correct_properties(ot); } /************************* Simple UVs for texture painting *****************/ void ED_uvedit_add_simple_uvs(Main *bmain, Scene *scene, Object *ob) { - Mesh *me = ob->data; - bool sync_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0; - - BMesh *bm = BM_mesh_create( - &bm_mesh_allocsize_default, - &((struct BMeshCreateParams){.use_toolflags = false,})); - - /* turn sync selection off, - * since we are not in edit mode we need to ensure only the uv flags are tested */ - scene->toolsettings->uv_flag &= ~UV_SYNC_SELECTION; - - ED_mesh_uv_texture_ensure(me, NULL); - - BM_mesh_bm_from_me( - bm, me, (&(struct BMeshFromMeshParams){ - .calc_face_normal = true, - })); - /* select all uv loops first - pack parameters needs this to make sure charts are registered */ - ED_uvedit_select_all(bm); - uvedit_unwrap_cube_project(bm, 1.0, false, NULL); - /* set the margin really quickly before the packing operation*/ - scene->toolsettings->uvcalc_margin = 0.001f; - uvedit_pack_islands(scene, ob, bm); - BM_mesh_bm_to_me(bmain, bm, me, (&(struct BMeshToMeshParams){0})); - BM_mesh_free(bm); - - if (sync_selection) - scene->toolsettings->uv_flag |= UV_SYNC_SELECTION; + Mesh *me = ob->data; + bool sync_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0; + + BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default, + &((struct BMeshCreateParams){ + .use_toolflags = false, + })); + + /* turn sync selection off, + * since we are not in edit mode we need to ensure only the uv flags are tested */ + scene->toolsettings->uv_flag &= ~UV_SYNC_SELECTION; + + ED_mesh_uv_texture_ensure(me, NULL); + + BM_mesh_bm_from_me(bm, + me, + (&(struct BMeshFromMeshParams){ + .calc_face_normal = true, + })); + /* select all uv loops first - pack parameters needs this to make sure charts are registered */ + ED_uvedit_select_all(bm); + uvedit_unwrap_cube_project(bm, 1.0, false, NULL); + /* set the margin really quickly before the packing operation*/ + scene->toolsettings->uvcalc_margin = 0.001f; + uvedit_pack_islands(scene, ob, bm); + BM_mesh_bm_to_me(bmain, bm, me, (&(struct BMeshToMeshParams){0})); + BM_mesh_free(bm); + + if (sync_selection) + scene->toolsettings->uv_flag |= UV_SYNC_SELECTION; } |