From e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 17 Apr 2019 06:17:24 +0200 Subject: 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 --- source/blender/editors/uvedit/uvedit_unwrap_ops.c | 3645 +++++++++++---------- 1 file changed, 1903 insertions(+), 1742 deletions(-) (limited to 'source/blender/editors/uvedit/uvedit_unwrap_ops.c') 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 #include #include @@ -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; } -- cgit v1.2.3