[Bf-blender-cvs] [e5ab28d3921] soc-2021-uv-editor-improvements: UV : Pack islands to box area
Siddhartha Jejurkar
noreply at git.blender.org
Sat Jun 19 18:49:49 CEST 2021
Commit: e5ab28d3921e77bac464c717610e2bf1b5c58b5c
Author: Siddhartha Jejurkar
Date: Sat Jun 19 22:10:34 2021 +0530
Branches: soc-2021-uv-editor-improvements
https://developer.blender.org/rBe5ab28d3921e77bac464c717610e2bf1b5c58b5c
UV : Pack islands to box area
Adds a new operator to the UV editor - Pack islands to area
Allows the users to pack selected UV islands to a specified
area in the UV editor
Refer T78398
===================================================================
M release/scripts/startup/bl_ui/space_image.py
M source/blender/blenlib/BLI_boxpack_2d.h
M source/blender/blenlib/intern/boxpack_2d.c
M source/blender/editors/include/ED_uvedit.h
M source/blender/editors/uvedit/uvedit_intern.h
M source/blender/editors/uvedit/uvedit_islands.c
M source/blender/editors/uvedit/uvedit_ops.c
M source/blender/editors/uvedit/uvedit_unwrap_ops.c
M source/blender/windowmanager/intern/wm_operators.c
===================================================================
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index 3fafa328289..54b7dab5d1b 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -436,6 +436,7 @@ class IMAGE_MT_uvs(Menu):
layout.separator()
layout.operator("uv.pack_islands")
+ layout.operator("uv.pack_islands_to_area")
layout.operator("uv.average_islands_scale")
layout.separator()
diff --git a/source/blender/blenlib/BLI_boxpack_2d.h b/source/blender/blenlib/BLI_boxpack_2d.h
index 7e347d0b0d7..5b70cd3f410 100644
--- a/source/blender/blenlib/BLI_boxpack_2d.h
+++ b/source/blender/blenlib/BLI_boxpack_2d.h
@@ -52,11 +52,23 @@ typedef struct FixedSizeBoxPack {
int w, h;
} FixedSizeBoxPack;
+/* Similar to FixedSizeBoxPack. Uses float variables */
+typedef struct RectSizeBoxPack {
+ struct RectSizeBoxPack *next, *prev;
+ float x, y;
+ float w, h;
+} RectSizeBoxPack;
+
void BLI_box_pack_2d_fixedarea(struct ListBase *boxes,
int width,
int height,
struct ListBase *packed);
+void BLI_rect_pack_2d(BoxPack *boxarray,
+ const uint len,
+ const float rect_width,
+ const float rect_height);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/intern/boxpack_2d.c b/source/blender/blenlib/intern/boxpack_2d.c
index 84b3f728884..4f2d9747975 100644
--- a/source/blender/blenlib/intern/boxpack_2d.c
+++ b/source/blender/blenlib/intern/boxpack_2d.c
@@ -784,3 +784,90 @@ void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, int height, ListBase
BLI_freelistN(&spaces);
}
+
+/* Similar implementation of BLI_box_pack_2d_fixedarea() that works with BoxPack array and float
+ * variables.
+ * A current problem with the algorithm is that boxes that do not fit are not packed (skipped), so
+ * that finally causes those boxes to be placed at the bottom left position overlapping with other
+ * boxes.
+ * TODO : Fix this issue by setting a callback that cancels the operator (and possibly prints an
+ * error message saying the area is too small for packing islands without scaling) when a
+ * particular box does not fit any empty space */
+void BLI_rect_pack_2d(BoxPack *boxarray,
+ const uint len,
+ const float rect_width,
+ const float rect_height)
+{
+ ListBase spaces = {NULL};
+ RectSizeBoxPack *full_rect = MEM_callocN(sizeof(RectSizeBoxPack), __func__);
+ full_rect->w = rect_width;
+ full_rect->h = rect_height;
+
+ BLI_addhead(&spaces, full_rect);
+ qsort(boxarray, (size_t)len, sizeof(BoxPack), box_areasort);
+
+ for (uint i = 0; i < len; i++) {
+ LISTBASE_FOREACH (RectSizeBoxPack *, space, &spaces) {
+ /* Skip this space if it's too small. */
+ if (boxarray[i].w > space->w || boxarray[i].h > space->h) {
+ continue;
+ }
+
+ /* Pack this box into this space. */
+ boxarray[i].x = space->x;
+ boxarray[i].y = space->y;
+
+ if (boxarray[i].w == space->w && boxarray[i].h == space->h) {
+ /* Box exactly fills space, so just remove the space. */
+ BLI_remlink(&spaces, space);
+ MEM_freeN(space);
+ }
+ else if (boxarray[i].w == space->w) {
+ /* Box fills the entire width, so we can just contract the box
+ * to the upper part that remains. */
+ space->y += boxarray[i].h;
+ space->h -= boxarray[i].h;
+ }
+ else if (boxarray[i].h == space->h) {
+ /* Box fills the entire height, so we can just contract the box
+ * to the right part that remains. */
+ space->x += boxarray[i].w;
+ space->w -= boxarray[i].w;
+ }
+ else {
+ /* Split the remaining L-shaped space into two spaces.
+ * There are two ways to do so, we pick the one that produces the biggest
+ * remaining space */
+ float area_hsplit_large = space->w * (space->h - boxarray[i].h);
+ float area_vsplit_large = (space->w - boxarray[i].w) * space->h;
+
+ /* Perform split. This space becomes the larger space,
+ * while the new smaller space is inserted _before_ it. */
+ RectSizeBoxPack *new_space = MEM_callocN(sizeof(RectSizeBoxPack), __func__);
+ if (area_hsplit_large > area_vsplit_large) {
+ new_space->x = space->x + boxarray[i].w;
+ new_space->y = space->y;
+ new_space->w = space->w - boxarray[i].w;
+ new_space->h = boxarray[i].h;
+
+ space->y += boxarray[i].h;
+ space->h -= boxarray[i].h;
+ }
+ else {
+ new_space->x = space->x;
+ new_space->y = space->y + boxarray[i].h;
+ new_space->w = boxarray[i].w;
+ new_space->h = space->h - boxarray[i].h;
+
+ space->x += boxarray[i].w;
+ space->w -= boxarray[i].w;
+ }
+ BLI_addhead(&spaces, new_space);
+ }
+
+ break;
+ }
+ }
+
+ BLI_freelistN(&spaces);
+}
\ No newline at end of file
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index dd61768a312..2dc9635a494 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -253,6 +253,14 @@ void ED_uvedit_pack_islands_multi(const struct Scene *scene,
bool use_target,
const struct UVPackIsland_Params *params);
+void ED_uvedit_pack_islands_to_area_multi(const struct Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ const float min_co[2],
+ const float max_co[2],
+ const bool scale_islands,
+ const struct UVPackIsland_Params *params);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index cd8fbd00316..c78ad0f0345 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -137,6 +137,7 @@ void UV_OT_cylinder_project(struct wmOperatorType *ot);
void UV_OT_project_from_view(struct wmOperatorType *ot);
void UV_OT_minimize_stretch(struct wmOperatorType *ot);
void UV_OT_pack_islands(struct wmOperatorType *ot);
+void UV_OT_pack_islands_to_area(struct wmOperatorType *ot);
void UV_OT_reset(struct wmOperatorType *ot);
void UV_OT_sphere_project(struct wmOperatorType *ot);
void UV_OT_unwrap(struct wmOperatorType *ot);
diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c
index a03b6670dae..07c8263d618 100644
--- a/source/blender/editors/uvedit/uvedit_islands.c
+++ b/source/blender/editors/uvedit/uvedit_islands.c
@@ -589,3 +589,173 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
}
/** \} */
+
+/* Almost similar to ED_uvedit_pack_islands_multi().
+ * TODO : Break some of the code into smaller functions since same operations are being done in
+ * both ED_uvedit_pack_islands_to_area_multi() and ED_uvedit_pack_islands_multi() */
+void ED_uvedit_pack_islands_to_area_multi(const Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ const float min_co[2],
+ const float max_co[2],
+ const bool scale_islands,
+ const struct UVPackIsland_Params *params)
+{
+ /* Align to the Y axis, could make this configurable. */
+ const int rotate_align_axis = 1;
+ ListBase island_list = {NULL};
+ int island_list_len = 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);
+ if (cd_loop_uv_offset == -1) {
+ continue;
+ }
+
+ island_list_len += bm_mesh_calc_uv_islands(scene,
+ bm,
+ &island_list,
+ params->only_selected_faces,
+ params->only_selected_uvs,
+ params->use_seams,
+ 1.0f,
+ cd_loop_uv_offset);
+ }
+
+ /* This check could probably be removed */
+ if (island_list_len == 0) {
+ return;
+ }
+
+ float margin = scene->toolsettings->uvcalc_margin;
+ double area = 0.0f;
+
+ struct FaceIsland **island_array = MEM_mallocN(sizeof(*island_array) * island_list_len,
+ __func__);
+ BoxPack *boxarray = MEM_mallocN(sizeof(*boxarray) * island_list_len, __func__);
+
+ int index;
+ LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) {
+ /* For now using the same conditions for rotating islands when scaling is enabled and disabled.
+ * TODO : New heuristic for rotating islands when scaling is disabled (using the
+ * RectPack2D algorithm) */
+ if (params->rotate) {
+ if (island->aspect_y != 1.0f) {
+ bm_face_array_uv_scale_y(
+ island->faces, island->faces_len, 1.0f / island->aspect_y, island->cd_loop_uv_offset);
+ }
+
+ // AABB - Axis Aligned Bounding Box
+ bm_face_array_uv_rotate_fit_aabb(
+ island->faces, island->faces_len, rotate_align_axis, island->cd_loop_uv_offset);
+
+ if (island->aspect_y != 1.0f) {
+ bm_face_array_uv_scale_y(
+ island->faces, island->faces_len, island->aspect_y, island->cd_loop_uv_offset);
+ }
+ }
+
+ bm_face_array_calc_bounds(
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list