diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.cc b/source/blender/editors/uvedit/uvedit_unwrap_ops.cc index d16e34593c6..95e736d5424 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.cc +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.cc @@ -1507,7 +1507,8 @@ static int pack_islands_exec(bContext *C, wmOperator *op) } pack_island_params.setFromUnwrapOptions(options); - pack_island_params.rotate = RNA_boolean_get(op->ptr, "rotate"); + pack_island_params.rotate_method = eUVPackIsland_RotationMethod( + RNA_enum_get(op->ptr, "rotate_method")); pack_island_params.scale_to_fit = RNA_boolean_get(op->ptr, "scale"); pack_island_params.merge_overlap = RNA_boolean_get(op->ptr, "merge_overlap"); pack_island_params.pin_method = eUVPackIsland_PinMethod(RNA_enum_get(op->ptr, "pin_method")); @@ -1564,6 +1565,23 @@ static const EnumPropertyItem pack_margin_method_items[] = { {0, nullptr, 0, nullptr, nullptr}, }; +static const EnumPropertyItem pack_rotate_method_items[] = { + {ED_UVPACK_ROTATION_NONE, "NONE", 0, "No rotation", "No rotation is applied to the islands"}, + RNA_ENUM_ITEM_SEPR, + {ED_UVPACK_ROTATION_AXIS_ALIGNED, + "AXIS_ALIGNED", + 0, + "Axis-aligned", + "Rotated to a minimal rectangle, either vertical or horizontal"}, + {ED_UVPACK_ROTATION_CARDINAL, + "CARDINAL", + 0, + "Cardinal", + "Only 90 degree rotations are allowed"}, + {ED_UVPACK_ROTATION_ANY, "ANY", 0, "Any", "Any angle is allowed for rotation"}, + {0, nullptr, 0, nullptr, nullptr}, +}; + static const EnumPropertyItem pack_shape_method_items[] = { {ED_UVPACK_SHAPE_CONCAVE, "CONCAVE", 0, "Exact shape (Concave)", "Uses exact geometry"}, {ED_UVPACK_SHAPE_CONVEX, "CONVEX", 0, "Boundary shape (Convex)", "Uses convex hull"}, @@ -1627,7 +1645,12 @@ void UV_OT_pack_islands(wmOperatorType *ot) /* properties */ RNA_def_enum(ot->srna, "udim_source", pack_target, PACK_UDIM_SRC_CLOSEST, "Pack to", ""); - RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit"); + RNA_def_enum(ot->srna, + "rotate_method", + pack_rotate_method_items, + ED_UVPACK_ROTATION_ANY, + "Rotation Method", + ""); RNA_def_boolean(ot->srna, "scale", true, "Scale", "Scale islands to fill unit square"); RNA_def_boolean( ot->srna, "merge_overlap", false, "Merge Overlapped", "Overlapping islands stick together"); @@ -2360,7 +2383,7 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len blender::geometry::UVPackIsland_Params pack_island_params; pack_island_params.setFromUnwrapOptions(options); - pack_island_params.rotate = true; + pack_island_params.rotate_method = ED_UVPACK_ROTATION_ANY; pack_island_params.pin_method = ED_UVPACK_PIN_IGNORED; pack_island_params.margin_method = ED_UVPACK_MARGIN_SCALED; pack_island_params.margin = scene->toolsettings->uvcalc_margin; @@ -2502,7 +2525,7 @@ static int unwrap_exec(bContext *C, wmOperator *op) blender::geometry::UVPackIsland_Params pack_island_params; pack_island_params.setFromUnwrapOptions(options); - pack_island_params.rotate = true; + pack_island_params.rotate_method = ED_UVPACK_ROTATION_ANY; pack_island_params.pin_method = ED_UVPACK_PIN_IGNORED; pack_island_params.margin_method = eUVPackIsland_MarginMethod( RNA_enum_get(op->ptr, "margin_method")); @@ -2882,7 +2905,7 @@ static int smart_project_exec(bContext *C, wmOperator *op) const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"); blender::geometry::UVPackIsland_Params params; - params.rotate = true; + params.rotate_method = ED_UVPACK_ROTATION_ANY; params.only_selected_uvs = only_selected_uvs; params.only_selected_faces = true; params.correct_aspect = correct_aspect; @@ -3871,7 +3894,7 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob) /* Pack UVs. */ blender::geometry::UVPackIsland_Params params; - params.rotate = true; + params.rotate_method = ED_UVPACK_ROTATION_ANY; params.only_selected_uvs = false; params.only_selected_faces = false; params.correct_aspect = false; diff --git a/source/blender/geometry/GEO_uv_pack.hh b/source/blender/geometry/GEO_uv_pack.hh index 2ebcdfa8fe9..8584aebd723 100644 --- a/source/blender/geometry/GEO_uv_pack.hh +++ b/source/blender/geometry/GEO_uv_pack.hh @@ -26,6 +26,17 @@ enum eUVPackIsland_MarginMethod { ED_UVPACK_MARGIN_FRACTION, }; +enum eUVPackIsland_RotationMethod { + /** No rotation. */ + ED_UVPACK_ROTATION_NONE = 0, + /** Rotated to a minimal rectangle, either vertical or horizontal. */ + ED_UVPACK_ROTATION_AXIS_ALIGNED, + /** Only 90 degree rotations are allowed. */ + ED_UVPACK_ROTATION_CARDINAL, + /** Any angle. */ + ED_UVPACK_ROTATION_ANY, +}; + enum eUVPackIsland_ShapeMethod { /** Use Axis-Aligned Bounding-Boxes. */ ED_UVPACK_SHAPE_AABB = 0, @@ -57,8 +68,8 @@ class UVPackIsland_Params { void setUDIMOffsetFromSpaceImage(const SpaceImage *sima); bool isCancelled() const; - /** Islands can be rotated to improve packing. */ - bool rotate; + /** Restrictions around island rotation. */ + eUVPackIsland_RotationMethod rotate_method; /** Resize islands to fill the unit square. */ bool scale_to_fit; /** (In UV Editor) only pack islands which have one or more selected UVs. */ diff --git a/source/blender/geometry/intern/uv_pack.cc b/source/blender/geometry/intern/uv_pack.cc index 4c9b932091a..409b8bc689f 100644 --- a/source/blender/geometry/intern/uv_pack.cc +++ b/source/blender/geometry/intern/uv_pack.cc @@ -211,6 +211,12 @@ void PackIsland::calculate_pre_rotation_(const UVPackIsland_Params ¶ms) if (!can_rotate_(params)) { return; /* Nothing to do. */ } + if (params.rotate_method == ED_UVPACK_ROTATION_CARDINAL) { + /* Arbitrary rotations are not allowed. */ + return; + } + BLI_assert(params.rotate_method == ED_UVPACK_ROTATION_ANY || + params.rotate_method == ED_UVPACK_ROTATION_AXIS_ALIGNED); /* As a heuristic to improve layout efficiency, #PackIsland's are first rotated by an arbitrary * angle to minimize the area of the enclosing AABB. This angle is stored in the `pre_rotate_` @@ -325,7 +331,7 @@ void PackIsland::place_(const float scale, const uv_phi phi) UVPackIsland_Params::UVPackIsland_Params() { - rotate = false; + rotate_method = ED_UVPACK_ROTATION_NONE; scale_to_fit = true; only_selected_uvs = false; only_selected_faces = false; @@ -1095,8 +1101,8 @@ static bool rotate_inside_square(const Span island_indices, if (island_indices.size() == 0) { return false; /* Nothing to do. */ } - if (!params.rotate) { - return false; /* Unable to rotate. */ + if (params.rotate_method != ED_UVPACK_ROTATION_ANY) { + return false; /* Unable to rotate by arbitrary angle. */ } if (params.shape_method == ED_UVPACK_SHAPE_AABB) { /* AABB margin calculations are not preserved under rotations. */ @@ -1927,7 +1933,7 @@ void PackIsland::build_inverse_transformation(const float scale, bool PackIsland::can_rotate_(const UVPackIsland_Params ¶ms) const { - if (!params.rotate) { + if (params.rotate_method == ED_UVPACK_ROTATION_NONE) { return false; } if (!pinned) { diff --git a/source/blender/geometry/intern/uv_parametrizer.cc b/source/blender/geometry/intern/uv_parametrizer.cc index 6b71e89c962..0237a8a53dc 100644 --- a/source/blender/geometry/intern/uv_parametrizer.cc +++ b/source/blender/geometry/intern/uv_parametrizer.cc @@ -4113,7 +4113,7 @@ void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, boo Vector pack_island_vector; UVPackIsland_Params params; - params.rotate = do_rotate; + params.rotate_method = do_rotate ? ED_UVPACK_ROTATION_ANY : ED_UVPACK_ROTATION_NONE; params.margin = margin; params.margin_method = ED_UVPACK_MARGIN_SCALED;