diff options
Diffstat (limited to 'source/blender/editors/uvedit/uvedit_unwrap_ops.c')
-rw-r--r-- | source/blender/editors/uvedit/uvedit_unwrap_ops.c | 258 |
1 files changed, 157 insertions, 101 deletions
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 84dca352c9f..2c7ad012dd2 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -204,6 +204,8 @@ typedef struct UnwrapOptions { bool fill_holes; /** Correct for mapped image texture aspect ratio. */ bool correct_aspect; + /** Treat unselected uvs as if they were pinned. */ + bool pin_unselected; } UnwrapOptions; typedef struct UnwrapResultInfo { @@ -240,7 +242,7 @@ static bool uvedit_have_selection(const Scene *scene, BMEditMesh *em, const Unwr } } - if (options->topology_from_uvs && !l) { + if (options->only_selected_uvs && !l) { continue; } @@ -298,41 +300,133 @@ void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy) ED_uvedit_get_aspect_from_material(ob, efa->mat_nr, r_aspx, r_aspy); } +static bool uvedit_is_face_affected(const Scene *scene, + BMFace *efa, + const UnwrapOptions *options, + const int cd_loop_uv_offset) +{ + if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + return false; + } + + if (options->only_selected_faces && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + return false; + } + + if (options->only_selected_uvs) { + BMLoop *l; + BMIter iter; + BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + return true; + } + } + return false; + } + + return true; +} + +/* Prepare unique indices for each unique pinned UV, even if it shares a BMVert. + */ +static void uvedit_prepare_pinned_indices(ParamHandle *handle, + const Scene *scene, + BMFace *efa, + const UnwrapOptions *options, + const int cd_loop_uv_offset) +{ + 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); + bool pin = luv->flag & MLOOPUV_PINNED; + if (options->pin_unselected && !pin) { + pin = !uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + } + if (pin) { + int bmvertindex = BM_elem_index_get(l->v); + GEO_uv_prepare_pin_index(handle, bmvertindex, luv->uv); + } + } +} + static void construct_param_handle_face_add(ParamHandle *handle, const Scene *scene, BMFace *efa, - int face_index, + ParamKey face_index, + const UnwrapOptions *options, 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); + bool *pin = BLI_array_alloca(pin, efa->len); + bool *select = BLI_array_alloca(select, efa->len); + const 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 poly-fill. */ 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); + vkeys[i] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->v), luv->uv); 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); + if (options->pin_unselected && !select[i]) { + pin[i] = true; + } } - GEO_uv_parametrizer_face_add(handle, key, i, vkeys, co, uv, pin, select); + GEO_uv_parametrizer_face_add(handle, face_index, i, vkeys, co, uv, pin, select); +} + +/* Set seams on UV Parametrizer based on options. */ +static void construct_param_edge_set_seams(ParamHandle *handle, + BMesh *bm, + const UnwrapOptions *options) +{ + if (options->topology_from_uvs && !options->topology_from_uvs_use_seams) { + return; /* Seams are not required with these options. */ + } + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + if (cd_loop_uv_offset == -1) { + return; /* UVs aren't present on BMesh. Nothing to do. */ + } + + BMEdge *edge; + BMIter iter; + BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { + if (!BM_elem_flag_test(edge, BM_ELEM_SEAM)) { + continue; /* No seam on this edge, nothing to do. */ + } + + /* Pinned vertices might have more than one ParamKey per BMVert. + * Check all the BM_LOOPS_OF_EDGE to find all the ParamKeys. + */ + BMLoop *l; + BMIter liter; + BM_ITER_ELEM (l, &liter, edge, BM_LOOPS_OF_EDGE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + ParamKey vkeys[2]; + vkeys[0] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->v), luv->uv); + vkeys[1] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->next->v), luv_next->uv); + + /* Set the seam. */ + GEO_uv_parametrizer_edge_set_seam(handle, vkeys); + } + } } -/* See: construct_param_handle_multi to handle multiple objects at once. */ +/* + * Version of #construct_param_handle_multi with a separate BMesh parameter. + */ static ParamHandle *construct_param_handle(const Scene *scene, Object *ob, BMesh *bm, @@ -340,13 +434,9 @@ static ParamHandle *construct_param_handle(const Scene *scene, UnwrapResultInfo *result_info) { BMFace *efa; - BMLoop *l; - BMEdge *eed; - BMIter iter, liter; + BMIter iter; int i; - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - ParamHandle *handle = GEO_uv_parametrizer_construct_begin(); if (options->correct_aspect) { @@ -362,43 +452,21 @@ static ParamHandle *construct_param_handle(const Scene *scene, /* we need the vert indices */ BM_mesh_elem_index_ensure(bm, BM_VERT); + 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_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) { - continue; + if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) { + uvedit_prepare_pinned_indices(handle, scene, efa, options, cd_loop_uv_offset); } - - if (options->topology_from_uvs) { - bool is_loopsel = false; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (options->only_selected_uvs && - (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) { - continue; - } - 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 || options->topology_from_uvs_use_seams) { - 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); - GEO_uv_parametrizer_edge_set_seam(handle, vkeys); - } + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { + if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) { + construct_param_handle_face_add(handle, scene, efa, i, options, cd_loop_uv_offset); } } + construct_param_edge_set_seams(handle, bm, options); + GEO_uv_parametrizer_construct_end(handle, options->fill_holes, options->topology_from_uvs, @@ -408,18 +476,15 @@ static ParamHandle *construct_param_handle(const Scene *scene, } /** - * Version of #construct_param_handle_single that handles multiple objects. + * Version of #construct_param_handle that handles multiple objects. */ static ParamHandle *construct_param_handle_multi(const Scene *scene, Object **objects, const uint objects_len, - const UnwrapOptions *options, - int *count_fail) + const UnwrapOptions *options) { BMFace *efa; - BMLoop *l; - BMEdge *eed; - BMIter iter, liter; + BMIter iter; int i; ParamHandle *handle = GEO_uv_parametrizer_construct_begin(); @@ -451,46 +516,24 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene, } BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { - - if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) || - (options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) { - continue; + if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) { + uvedit_prepare_pinned_indices(handle, scene, efa, options, cd_loop_uv_offset); } - - if (options->topology_from_uvs) { - bool is_loopsel = false; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (options->only_selected_uvs && - (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) { - continue; - } - 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 || options->topology_from_uvs_use_seams) { - 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); - GEO_uv_parametrizer_edge_set_seam(handle, vkeys); - } + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { + if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) { + construct_param_handle_face_add( + handle, scene, efa, i + offset, options, cd_loop_uv_offset); } } + + construct_param_edge_set_seams(handle, bm, options); + offset += bm->totface; } - GEO_uv_parametrizer_construct_end( - handle, options->fill_holes, options->topology_from_uvs, count_fail); + GEO_uv_parametrizer_construct_end(handle, options->fill_holes, options->topology_from_uvs, NULL); return handle; } @@ -500,8 +543,8 @@ static void texface_from_original_index(const Scene *scene, BMFace *efa, int index, float **r_uv, - ParamBool *r_pin, - ParamBool *r_select) + bool *r_pin, + bool *r_select) { BMLoop *l; BMIter liter; @@ -633,8 +676,8 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene, /* 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]; + bool pin[4], select[4]; + const float *co[4]; float *uv[4]; BMFace *origFace = faceMap[i]; @@ -652,7 +695,7 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene, mloop = &subsurfedLoops[mpoly->loopstart]; - /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */ + /* We will not check for v4 here. Sub-surface faces always have 4 vertices. */ BLI_assert(mpoly->totloop == 4); key = (ParamKey)i; vkeys[0] = (ParamKey)mloop[0].v; @@ -769,7 +812,7 @@ static bool minimize_stretch_init(bContext *C, wmOperator *op) 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, NULL); + ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options); ms->lasttime = PIL_check_seconds_timer(); GEO_uv_parametrizer_stretch_begin(ms->handle); @@ -1039,7 +1082,7 @@ static void uvedit_pack_islands_multi(const Scene *scene, bool rotate, bool ignore_pinned) { - ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options, NULL); + ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options); GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned); GEO_uv_parametrizer_flush(handle); GEO_uv_parametrizer_delete(handle); @@ -1148,7 +1191,7 @@ void UV_OT_pack_islands(wmOperatorType *ot) /** \name Average UV Islands Scale Operator * \{ */ -static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op)) +static int average_islands_scale_exec(bContext *C, wmOperator *op) { const Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -1172,8 +1215,12 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } - ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options, NULL); - GEO_uv_parametrizer_average(handle, false); + /* RNA props */ + const bool scale_uv = RNA_boolean_get(op->ptr, "scale_uv"); + const bool shear = RNA_boolean_get(op->ptr, "shear"); + + ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options); + GEO_uv_parametrizer_average(handle, false, scale_uv, shear); GEO_uv_parametrizer_flush(handle); GEO_uv_parametrizer_delete(handle); @@ -1204,6 +1251,10 @@ void UV_OT_average_islands_scale(wmOperatorType *ot) /* api callbacks */ ot->exec = average_islands_scale_exec; ot->poll = ED_operator_uvedit; + + /* properties */ + RNA_def_boolean(ot->srna, "scale_uv", false, "Non-Uniform", "Scale U and V independently"); + RNA_def_boolean(ot->srna, "shear", false, "Shear", "Reduce shear within islands"); } /** \} */ @@ -1233,7 +1284,7 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit) const UnwrapOptions options = { .topology_from_uvs = false, .only_selected_faces = false, - .only_selected_uvs = true, + .only_selected_uvs = false, .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0, .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0, }; @@ -1245,7 +1296,7 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit) handle = construct_param_handle(scene, obedit, em->bm, &options, NULL); } - GEO_uv_parametrizer_lscm_begin(handle, PARAM_TRUE, abf); + GEO_uv_parametrizer_lscm_begin(handle, true, abf); /* Create or increase size of g_live_unwrap.handles array */ if (g_live_unwrap.handles == NULL) { @@ -1796,13 +1847,13 @@ static void uvedit_unwrap(const Scene *scene, handle = construct_param_handle(scene, obedit, em->bm, options, result_info); } - GEO_uv_parametrizer_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0); + GEO_uv_parametrizer_lscm_begin(handle, false, scene->toolsettings->unwrapper == 0); GEO_uv_parametrizer_lscm_solve(handle, result_info ? &result_info->count_changed : NULL, result_info ? &result_info->count_failed : NULL); GEO_uv_parametrizer_lscm_end(handle); - GEO_uv_parametrizer_average(handle, true); + GEO_uv_parametrizer_average(handle, true, false, false); GEO_uv_parametrizer_flush(handle); @@ -1829,7 +1880,7 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len const UnwrapOptions options = { .topology_from_uvs = false, .only_selected_faces = false, - .only_selected_uvs = true, + .only_selected_uvs = false, .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0, .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0, }; @@ -1862,16 +1913,21 @@ static int unwrap_exec(bContext *C, wmOperator *op) Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( view_layer, CTX_wm_view3d(C), &objects_len); - const UnwrapOptions options = { + UnwrapOptions options = { .topology_from_uvs = false, .only_selected_faces = true, - .only_selected_uvs = true, + .only_selected_uvs = false, .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 (CTX_wm_space_image(C)) { + /* Inside the UV Editor, only unwrap selected UVs. */ + options.only_selected_uvs = true; + options.pin_unselected = true; + } if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) { MEM_freeN(objects); |