Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_follow_active.py4
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_lightmap.py4
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_smart_project.py1
-rw-r--r--release/scripts/startup/bl_ui/space_image.py24
-rw-r--r--source/blender/blenlib/BLI_math_geom.h2
-rw-r--r--source/blender/blenlib/intern/math_geom.c17
-rw-r--r--source/blender/editors/include/ED_mesh.h3
-rw-r--r--source/blender/editors/include/ED_uvedit.h10
-rw-r--r--source/blender/editors/mesh/editmesh_path.c5
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c62
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h13
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c543
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c2047
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.h28
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c468
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h1
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
17 files changed, 3121 insertions, 112 deletions
diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
index 25ee5cafe81..7a4a1bc3601 100644
--- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py
+++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
@@ -217,6 +217,8 @@ def extend(obj, operator, EXTEND_MODE):
def main(context, operator):
obj = context.active_object
+ bpy.ops.uv.reveal()
+
extend(obj, operator, operator.properties.mode)
@@ -252,4 +254,4 @@ class FollowActiveQuads(Operator):
classes = (
FollowActiveQuads,
-) \ No newline at end of file
+)
diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
index 8ee29d15d1b..173fe823b50 100644
--- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py
+++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
@@ -557,7 +557,9 @@ def lightmap_uvpack(meshes,
def unwrap(operator, context, **kwargs):
is_editmode = (context.object.mode == 'EDIT')
+
if is_editmode:
+ bpy.ops.uv.reveal()
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
PREF_ACT_ONLY = kwargs.pop("PREF_ACT_ONLY")
@@ -672,4 +674,4 @@ class LightMapPack(Operator):
classes = (
LightMapPack,
-) \ No newline at end of file
+)
diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
index cc590ac9502..0ae600c8046 100644
--- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py
+++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
@@ -750,6 +750,7 @@ def main(context,
is_editmode = (context.active_object.mode == 'EDIT')
if is_editmode:
+ bpy.ops.uv.reveal()
obList = [ob for ob in [context.active_object] if ob and ob.type == 'MESH']
else:
obList = [ob for ob in context.selected_editable_objects if ob and ob.type == 'MESH']
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index 340a6c807df..9868186e39c 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -130,6 +130,12 @@ class IMAGE_MT_view(Menu):
layout.operator("screen.screen_full_area")
layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
+class IMAGE_MT_uvs_select_by_trait(Menu):
+ bl_label = "Select All by Trait"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator("uv.select_overlapping")
class IMAGE_MT_select(Menu):
bl_label = "Select"
@@ -150,8 +156,11 @@ class IMAGE_MT_select(Menu):
layout.operator("uv.select_pinned")
layout.operator("uv.select_linked").extend = False
+ layout.operator("uv.select_shortest_path")
layout.separator()
+ layout.menu("IMAGE_MT_uvs_select_by_trait")
+ layout.separator()
layout.operator("uv.select_less", text="Less")
layout.operator("uv.select_more", text="More")
@@ -259,6 +268,16 @@ class IMAGE_MT_uvs_showhide(Menu):
layout.operator("uv.hide", text="Hide Selected").unselected = False
layout.operator("uv.hide", text="Hide Unselected").unselected = True
+class IMAGE_MT_uvs_deselect_mesh(Menu):
+ bl_label = "De/Select 3D Mesh"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("uv.select_mesh")
+ layout.operator("uv.deselect_mesh", text="Deselect 3D Mesh (Selected)").unselected = False
+ layout.operator("uv.deselect_mesh", text="Deselect 3D Mesh (Unselected)").unselected = True
+
class IMAGE_MT_uvs_proportional(Menu):
bl_label = "Proportional Editing"
@@ -357,6 +376,7 @@ class IMAGE_MT_uvs(Menu):
layout.separator()
+ layout.operator("uv.irregular_pack_islands")
layout.operator("uv.pack_islands")
layout.operator("uv.average_islands_scale")
layout.operator("uv.minimize_stretch")
@@ -365,6 +385,7 @@ class IMAGE_MT_uvs(Menu):
layout.operator("uv.mark_seam", text="Clear Seam").clear = True
layout.operator("uv.seams_from_islands")
layout.operator("mesh.faces_mirror_uv")
+ layout.operator("uv.scale_to_bounds")
layout.separator()
@@ -380,6 +401,9 @@ class IMAGE_MT_uvs(Menu):
layout.separator()
layout.menu("IMAGE_MT_uvs_showhide")
+
+ layout.menu("IMAGE_MT_uvs_deselect_mesh")
+
class IMAGE_MT_uvs_select_mode(Menu):
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 0fef849c8fa..2893da9bce8 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -401,6 +401,8 @@ void accumulate_vertex_normals_poly(
float **vertnos, const float polyno[3],
const float **vertcos, float vdiffs[][3], const int nverts);
+void edge_normal_v2_v2v2(float r[2], const float a[2], const float b[2], const bool left);
+
/********************************* Tangents **********************************/
void tangent_from_uv(
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 53fcf9c745c..30164ff9f6a 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -4014,6 +4014,23 @@ void accumulate_vertex_normals_poly(float **vertnos, const float polyno[3],
}
}
+/* Calculates the 2d normal for an edge ab.
+ * if left is true calculates the left normal (viewed in winding direction) */
+void edge_normal_v2_v2v2(float r[2], const float a[2], const float b[2], const bool left)
+{
+ float dx = b[0] - a[0];
+ float dy = b[1] - a[1];
+
+ if (left) {
+ r[0] = -dy;
+ r[1] = dx;
+ }
+ else {
+ r[0] = dy;
+ r[1] = -dx;
+ }
+}
+
/********************************* Tangents **********************************/
void tangent_from_uv(
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index c867df2d01a..b5e54a56996 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -128,6 +128,9 @@ void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e,
struct ARegion *ar, struct View3D *v3d, struct Object *obedit);
+/* editmesh_path.c*/
+int EDBM_shortest_path_select(struct bContext *C, struct wmOperator *op);
+
/* editmesh_select.c */
void EDBM_select_mirrored(
struct BMEditMesh *em, const int axis, const bool extend,
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 535683823bf..9c920d33053 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -59,6 +59,8 @@ void ED_object_assign_active_image(struct Main *bmain, struct Object *ob, int ma
bool ED_uvedit_test(struct Object *obedit);
+void ED_uvedit_reveal(struct BMEditMesh *em);
+
/* visibility and selection */
bool uvedit_face_visible_test(struct Scene *scene, struct Image *ima, struct BMFace *efa, struct MTexPoly *tf);
bool uvedit_face_select_test(struct Scene *scene, struct BMFace *efa,
@@ -106,6 +108,14 @@ void ED_uvedit_unwrap_cube_project(struct Object *ob, struct BMesh *bm, float cu
/* single call up unwrap using scene settings, used for edge tag unwrapping */
void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel);
+/* select by trait */
+void ED_uvedit_overlapping_select(struct Scene *scene, struct Object *ob, struct BMesh *bm, const bool extend);
+
+/* select shortest path */
+bool ED_uvedit_shortest_path_select(struct Scene *scene, struct Object *ob, struct BMesh *bm, bool topo_dist);
+
+/* scale to bounds */
+void ED_uvedit_scale_to_bounds(struct Scene *scene, struct Object *ob, struct BMesh *bm);
/* uvedit_draw.c */
void ED_image_draw_cursor(struct ARegion *ar, const float cursor[2]);
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 4431712e720..a044cb263e5 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -779,6 +779,11 @@ static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
}
}
+int EDBM_shortest_path_select(struct bContext *C, struct wmOperator *op)
+{
+ return edbm_shortest_path_select_exec(C, op);
+}
+
void MESH_OT_shortest_path_select(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 15be6ab3b78..d4ceaa39d3c 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -222,7 +222,9 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
glBegin(GL_POLYGON);
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
+ if (!(luv->flag & MLOOPUV_HIDDEN)) {
+ glVertex2fv(luv->uv);
+ }
}
glEnd();
}
@@ -260,7 +262,9 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
glBegin(GL_POLYGON);
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
+ if (!(luv->flag & MLOOPUV_HIDDEN)) {
+ glVertex2fv(luv->uv);
+ }
}
glEnd();
}
@@ -323,10 +327,12 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
glBegin(GL_POLYGON);
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- a = fabsf(uvang[i] - ang[i]) / (float)M_PI;
- weight_to_rgb(col, 1.0f - pow2f(1.0f - a));
- glColor3fv(col);
- glVertex2fv(luv->uv);
+ if (!(luv->flag & MLOOPUV_HIDDEN)) {
+ a = fabsf(uvang[i] - ang[i]) / (float)M_PI;
+ weight_to_rgb(col, 1.0f - pow2f(1.0f - a));
+ glColor3fv(col);
+ glVertex2fv(luv->uv);
+ }
}
glEnd();
}
@@ -359,7 +365,9 @@ static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset)
glBegin(GL_LINE_LOOP);
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
+ if (!(luv->flag & MLOOPUV_HIDDEN)) {
+ glVertex2fv(luv->uv);
+ }
}
glEnd();
}
@@ -372,7 +380,7 @@ static void draw_uvs_lineloop_mpoly(Mesh *me, MPoly *mpoly)
glBegin(GL_LINE_LOOP);
mloopuv = &me->mloopuv[mpoly->loopstart];
for (i = mpoly->totloop; i != 0; i--, mloopuv++) {
- glVertex2fv(mloopuv->uv);
+ glVertex2fv(mloopuv->uv); /* We don't check MLOOPUV_HIDDEN here since we always want to see other UVs */
}
glEnd();
}
@@ -537,7 +545,9 @@ static void draw_uvs_looptri(BMEditMesh *em, unsigned int *r_loop_index, const i
unsigned int j;
for (j = 0; j < 3; j++) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(em->looptris[i][j], cd_loop_uv_offset);
- glVertex2fv(luv->uv);
+ if (!(luv->flag & MLOOPUV_HIDDEN)) {
+ glVertex2fv(luv->uv);
+ }
}
i++;
} while (i != em->tottri && (f == em->looptris[i][0]->f));
@@ -813,7 +823,9 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2);
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
+ if (!(luv->flag & MLOOPUV_HIDDEN)) {
+ glVertex2fv(luv->uv);
+ }
}
glEnd();
}
@@ -831,9 +843,13 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
lastsel = sel;
}
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
+ if (!(luv->flag & MLOOPUV_HIDDEN)) {
+ glVertex2fv(luv->uv);
+ }
luv = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
+ if (!(luv->flag & MLOOPUV_HIDDEN)) {
+ glVertex2fv(luv->uv);
+ }
}
glEnd();
}
@@ -874,9 +890,13 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
+ tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+
if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- glVertex2fv(cent);
+ if (uv_poly_visible(efa, cd_loop_uv_offset)) {
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ glVertex2fv(cent);
+ }
}
}
@@ -887,9 +907,13 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
+ tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+
if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- glVertex2fv(cent);
+ if (uv_poly_visible(efa, cd_loop_uv_offset)) {
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ glVertex2fv(cent);
+ }
}
}
@@ -911,7 +935,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
+ if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset) && !(luv->flag & MLOOPUV_HIDDEN))
glVertex2fv(luv->uv);
}
}
@@ -930,7 +954,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_PINNED)
+ if (luv->flag & MLOOPUV_PINNED && !(luv->flag & MLOOPUV_HIDDEN))
glVertex2fv(luv->uv);
}
}
@@ -948,7 +972,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) && !(luv->flag & MLOOPUV_HIDDEN))
glVertex2fv(luv->uv);
}
}
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index e028c08091c..5d02c68718c 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -48,6 +48,7 @@ bool uvedit_face_visible_nolocal(struct Scene *scene, struct BMFace *efa);
/* geometric utilities */
void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len);
void uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_offset);
+bool uv_poly_visible(struct BMFace *f, const int cd_loop_uv_offset);
/* find nearest */
@@ -59,6 +60,14 @@ typedef struct NearestHit {
int lindex; /* index of loop within face */
} NearestHit;
+enum {
+ HANDLE_IMPLICIT = (1 << 0),
+ HANDLE_FILL = (1 << 1),
+ HANDLE_SELECTED = (1 << 2),
+ HANDLE_CORRECT_ASPECT = (1 << 3),
+ HANDLE_ALL_FACES = (1 << 4)
+};
+
void uv_find_nearest_vert(struct Scene *scene, struct Image *ima, struct BMEditMesh *em,
const float co[2], const float penalty[2], struct NearestHit *hit);
void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct BMEditMesh *em,
@@ -76,9 +85,13 @@ 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_irregular_pack_islands(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);
void UV_OT_stitch(struct wmOperatorType *ot);
+/* XXX (SaphireS): Remove */
+void UV_OT_test(struct wmOperatorType *ot);
+
#endif /* __UVEDIT_INTERN_H__ */
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 75294af08f9..9ae5145e53a 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -407,7 +407,9 @@ bool uvedit_face_select_enable(Scene *scene, BMEditMesh *em, BMFace *efa, const
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag |= MLOOPUV_VERTSEL;
+ if (!(luv->flag & MLOOPUV_HIDDEN)) {
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
}
return true;
@@ -505,8 +507,12 @@ void uvedit_edge_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l, const bo
luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
- luv1->flag |= MLOOPUV_VERTSEL;
- luv2->flag |= MLOOPUV_VERTSEL;
+ if (!(luv1->flag & MLOOPUV_HIDDEN)) {
+ luv1->flag |= MLOOPUV_VERTSEL;
+ }
+ if (!(luv2->flag & MLOOPUV_HIDDEN)) {
+ luv2->flag |= MLOOPUV_VERTSEL;
+ }
}
}
@@ -582,7 +588,9 @@ void uvedit_uv_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l,
}
else {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag |= MLOOPUV_VERTSEL;
+ if (!(luv->flag & MLOOPUV_HIDDEN)) {
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
}
}
@@ -631,6 +639,24 @@ void uv_poly_center(BMFace *f, float r_cent[2], const int cd_loop_uv_offset)
mul_v2_fl(r_cent, 1.0f / (float)f->len);
}
+bool uv_poly_visible(BMFace *f, const int cd_loop_uv_offset)
+{
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+ bool visible = false;
+
+ BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (!(luv->flag & MLOOPUV_HIDDEN)) {
+ visible = true;
+ break;
+ }
+ }
+
+ return visible;
+}
+
void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
{
int i;
@@ -1477,6 +1503,246 @@ static void UV_OT_select_less(wmOperatorType *ot)
ot->poll = ED_operator_uvedit_space_image;
}
+/*********************** shortest path ***********************/
+static int uv_shortest_path_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ Image *ima = CTX_data_edit_image(C);
+ ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMFace *efa;
+ BMEdge *e;
+ BMIter iter, liter;
+ BMLoop *l;
+ MLoopUV *luv_src = NULL, *luv_dst = NULL;
+ BMElem *elem_src = NULL, *elem_dst = NULL;
+ int elem_sel = 0;
+ const bool topological_distance = RNA_boolean_get(op->ptr, "topological_distance");
+
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return EDBM_shortest_path_select(C, op);
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
+
+ /* -------- Check for 2 selected elements of same type on the same UV island ---------- */
+ /* Note: Only vertex path computation implemented for now, but Edge/Face checks already there*/
+ if (ts->uv_selectmode & UV_SELECT_FACE) {
+ /* clear tags */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ }
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+
+ if (uvedit_face_visible_test(scene, ima, efa, tf)) {
+ if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ elem_sel++;
+
+ if (elem_src == NULL) {
+ elem_src = (BMElem *)efa;
+ }
+ else if ((elem_dst == NULL)) {
+ elem_dst = (BMElem *)efa;
+ }
+ }
+ }
+ }
+ }
+ else if (ts->uv_selectmode & UV_SELECT_EDGE) {
+ /* clear tags */
+ BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ }
+
+ BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (uvedit_edge_select_test(scene, e->l, cd_loop_uv_offset)) {
+
+ elem_sel++;
+
+ if (elem_src == NULL) {
+ elem_src = (BMElem *)e;
+ }
+ else if ((elem_dst == NULL)) {
+ elem_dst = (BMElem *)e;
+ }
+ }
+ }
+ }
+
+ else if (ts->uv_selectmode & UV_SELECT_VERTEX) {
+ /* clear tags */
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_disable(l, BM_ELEM_TAG);
+ }
+ }
+
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+
+ if (uvedit_face_visible_test(scene, ima, efa, tf)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if ((luv->flag & MLOOPUV_VERTSEL) != 0) {
+ if (luv_src == NULL) {
+ luv_src = luv;
+ elem_sel++;
+ }
+ else if ((luv_dst == NULL) && (!compare_v2v2(luv->uv, luv_src->uv, 0.000003f))) {
+ luv_dst = luv;
+ elem_sel++;
+ }
+ else if ((!compare_v2v2(luv->uv, luv_src->uv, 0.000003f)) &&
+ (!compare_v2v2(luv->uv, luv_dst->uv, 0.000003f))) {
+ elem_sel++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (elem_sel != 2 || !(ts->uv_selectmode & UV_SELECT_VERTEX)) {
+ /* Not exactly 2 elements of same typ selected */
+ BKE_report(op->reports, RPT_WARNING,
+ "Path selection requires exactly two vertices of the same island to be selected");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* -------- Now select shortest path between the 2 found elements ---------- */
+
+ if (ED_uvedit_shortest_path_select(scene, obedit, bm, topological_distance)) {
+
+ DAG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT | ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ /* No path found because the selected elements aren't part of the same uv island */
+ BKE_report(op->reports, RPT_WARNING,
+ "Path selection requires exactly two vertices of the same island to be selected");
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void UV_OT_select_shortest_path(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Shortest Vertex Path";
+ ot->description = "Select the shortest path between the current selected vertices";
+ ot->idname = "UV_OT_select_shortest_path";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_shortest_path_exec;
+ ot->poll = ED_operator_uvedit;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "topological_distance", 0, "Topological Distance",
+ "Find the minimum number of steps, ignoring spatial distance");
+}
+/* ******************** scale to bounds operator **************** */
+
+static int uv_scale_to_bounds_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ Image *ima = CTX_data_edit_image(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MTexPoly *tf;
+ float dx, dy, min[2], max[2];
+
+ const bool keep_aspect = RNA_boolean_get(op->ptr, "keep_aspect_ratio");
+ const bool individual = RNA_boolean_get(op->ptr, "individual_islands");
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
+
+ if (individual) {
+ ED_uvedit_scale_to_bounds(scene, obedit, bm);
+
+ return OPERATOR_FINISHED;
+ }
+
+ INIT_MINMAX2(min, max);
+
+ BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
+ tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+
+ if (!uvedit_face_visible_test(scene, ima, efa, tf) || !uvedit_face_select_test(scene, efa, cd_loop_uv_offset))
+ continue;
+
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ minmax_v2v2_v2(min, max, luv->uv);
+ }
+ }
+
+ /* 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;
+
+ if (keep_aspect) {
+ if (dx >= dy) dx = dy;
+ else if (dy > dx) dy = dx;
+ }
+
+ BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
+ tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+
+ if (!uvedit_face_visible_test(scene, ima, efa, tf) || !uvedit_face_select_test(scene, efa, cd_loop_uv_offset))
+ continue;
+
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *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;
+ }
+ }
+
+ DAG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static void UV_OT_scale_to_bounds(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Scale To Bounds";
+ ot->description = "Scale the selection to fit UV boundaries";
+ ot->idname = "UV_OT_scale_to_bounds";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_scale_to_bounds_exec;
+ ot->poll = ED_operator_uvedit;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "keep_aspect_ratio", 1, "Keep Aspect Ratio", "Keep the current aspect ratio of the selection");
+ RNA_def_boolean(ot->srna, "individual_islands", 0, "Individual", "Scale individual islands or the selection as a whole");
+}
+
/* ******************** align operator **************** */
static void uv_weld_align(bContext *C, int tool)
@@ -1990,13 +2256,19 @@ static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int
switch (action) {
case SEL_SELECT:
- luv->flag |= MLOOPUV_VERTSEL;
+ if (!(luv->flag & MLOOPUV_HIDDEN)) { /* Skip hidden loops */
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
break;
case SEL_DESELECT:
- luv->flag &= ~MLOOPUV_VERTSEL;
+ if (!(luv->flag & MLOOPUV_HIDDEN)) {
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
break;
case SEL_INVERT:
- luv->flag ^= MLOOPUV_VERTSEL;
+ if (!(luv->flag & MLOOPUV_HIDDEN)) {
+ luv->flag ^= MLOOPUV_VERTSEL;
+ }
break;
}
}
@@ -3628,13 +3900,138 @@ static void UV_OT_select_pinned(wmOperatorType *ot)
/********************** hide operator *********************/
+static int uv_hide_exec(bContext *C, wmOperator *op)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Object *obedit = CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ MTexPoly *tf;
+ const bool swap = RNA_boolean_get(op->ptr, "unselected");
+ Image *ima = sima ? sima->image : NULL;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ EDBM_mesh_hide(em, swap);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+ }
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+
+ tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+
+ if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if ((luv->flag & MLOOPUV_VERTSEL && !swap) || (!(luv->flag & MLOOPUV_VERTSEL) && swap)) {
+ luv->flag |= MLOOPUV_HIDDEN;
+ luv->flag &= ~MLOOPUV_VERTSEL; /* Deselect after hiding to avoid unwanted behaviour */
+ }
+ }
+ }
+
+ BM_select_history_validate(em->bm);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT | ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+#undef UV_SEL_TEST
+
+static void UV_OT_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hide Selected";
+ ot->description = "Hide (un)selected UV vertices";
+ ot->idname = "UV_OT_hide";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_hide_exec;
+ ot->poll = ED_operator_uvmap;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Hide Unselected", "Hide unselected rather than selected");
+}
+
+/****************** reveal operator ******************/
+
+void ED_uvedit_reveal(BMEditMesh *em)
+{
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ 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_HIDDEN)) {
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_HIDDEN;
+ }
+ }
+ }
+}
+
+static int uv_reveal_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ /* call the mesh function if we are in mesh sync sel */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ EDBM_mesh_reveal(em);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+ }
+
+ ED_uvedit_reveal(em);
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static void UV_OT_reveal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Reveal Hidden";
+ ot->description = "Reveal all hidden UV vertices";
+ ot->idname = "UV_OT_reveal";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_reveal_exec;
+ ot->poll = ED_operator_uvmap;
+}
+
+/********************** Deselect Mesh operator *********************/
+
/* check if we are selected or unselected based on 'bool_test' arg,
- * needed for select swap support */
+* needed for select swap support */
#define UV_SEL_TEST(luv, bool_test) ((((luv)->flag & MLOOPUV_VERTSEL) == MLOOPUV_VERTSEL) == bool_test)
/* is every UV vert selected or unselected depending on bool_test */
static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test,
- const int cd_loop_uv_offset)
+ const int cd_loop_uv_offset)
{
BMLoop *l_iter;
BMLoop *l_first;
@@ -3650,7 +4047,7 @@ static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test,
return true;
}
-static int uv_hide_exec(bContext *C, wmOperator *op)
+static int uv_deselect_mesh_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
Object *obedit = CTX_data_edit_object(C);
@@ -3666,7 +4063,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
Image *ima = sima ? sima->image : NULL;
const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
if (ts->uv_flag & UV_SYNC_SELECTION) {
@@ -3676,7 +4073,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
int hide = 0;
tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
@@ -3685,7 +4082,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
continue;
}
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (UV_SEL_TEST(luv, !swap)) {
@@ -3696,7 +4093,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
if (hide) {
/* note, a special case for edges could be used,
- * for now edges act like verts and get flushed */
+ * for now edges act like verts and get flushed */
if (use_face_center) {
if (em->selectmode == SCE_SELECT_FACE) {
/* check that every UV is selected */
@@ -3707,7 +4104,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
}
else {
if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (UV_SEL_TEST(luv, !swap)) {
BM_vert_select_set(em->bm, l->v, false);
@@ -3725,7 +4122,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
}
}
else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (UV_SEL_TEST(luv, !swap)) {
BM_vert_select_set(em->bm, l->v, false);
@@ -3739,7 +4136,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
/* flush vertex selection changes */
if (em->selectmode != SCE_SELECT_FACE)
EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX | SCE_SELECT_EDGE);
-
+
BM_select_history_validate(em->bm);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -3748,25 +4145,26 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
#undef UV_SEL_TEST
-static void UV_OT_hide(wmOperatorType *ot)
+static void UV_OT_deselect_mesh(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Hide Selected";
- ot->description = "Hide (un)selected UV vertices";
- ot->idname = "UV_OT_hide";
+ ot->name = "Deselect 3D Mesh";
+ ot->description = "Deselect 3D mesh vertices corresponding to (un)selected UV vertices";
+ ot->idname = "UV_OT_deselect_mesh";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* api callbacks */
- ot->exec = uv_hide_exec;
+ ot->exec = uv_deselect_mesh_exec;
ot->poll = ED_operator_uvedit;
/* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
+ /* ToDo (SaphireS): Wording ... */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Deselect unselected rather than selected");
}
-/****************** reveal operator ******************/
+/********************** Select Mesh operator *********************/
-static int uv_reveal_exec(bContext *C, wmOperator *UNUSED(op))
+static int uv_select_mesh_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceImage *sima = CTX_wm_space_image(C);
Object *obedit = CTX_data_edit_object(C);
@@ -3780,10 +4178,10 @@ static int uv_reveal_exec(bContext *C, wmOperator *UNUSED(op))
const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
const int stickymode = sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
/* note on tagging, selecting faces needs to be delayed so it doesn't select the verts and
- * confuse our checks on selected verts. */
+ * confuse our checks on selected verts. */
/* call the mesh function if we are in mesh sync sel */
if (ts->uv_flag & UV_SYNC_SELECTION) {
@@ -3794,10 +4192,10 @@ static int uv_reveal_exec(bContext *C, wmOperator *UNUSED(op))
}
if (use_face_center) {
if (em->selectmode == SCE_SELECT_FACE) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
luv->flag |= MLOOPUV_VERTSEL;
}
@@ -3809,16 +4207,16 @@ static int uv_reveal_exec(bContext *C, wmOperator *UNUSED(op))
else {
/* enable adjacent faces to have disconnected UV selections if sticky is disabled */
if (!stickymode) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
int totsel = 0;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT);
}
-
+
if (!totsel) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
luv->flag |= MLOOPUV_VERTSEL;
}
@@ -3829,10 +4227,10 @@ static int uv_reveal_exec(bContext *C, wmOperator *UNUSED(op))
}
}
else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
luv->flag |= MLOOPUV_VERTSEL;
@@ -3846,10 +4244,10 @@ static int uv_reveal_exec(bContext *C, wmOperator *UNUSED(op))
}
}
else if (em->selectmode == SCE_SELECT_FACE) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
luv->flag |= MLOOPUV_VERTSEL;
}
@@ -3859,10 +4257,10 @@ static int uv_reveal_exec(bContext *C, wmOperator *UNUSED(op))
}
}
else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
luv->flag |= MLOOPUV_VERTSEL;
@@ -3873,7 +4271,7 @@ static int uv_reveal_exec(bContext *C, wmOperator *UNUSED(op))
}
}
}
-
+
/* re-select tagged faces */
BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
@@ -3882,17 +4280,49 @@ static int uv_reveal_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static void UV_OT_reveal(wmOperatorType *ot)
+static void UV_OT_select_mesh(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Reveal Hidden";
- ot->description = "Reveal all hidden UV vertices";
- ot->idname = "UV_OT_reveal";
+ ot->name = "Select 3D Mesh";
+ ot->description = "Select all of the 3D mesh vertices";
+ ot->idname = "UV_OT_select_mesh";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* api callbacks */
- ot->exec = uv_reveal_exec;
+ ot->exec = uv_select_mesh_exec;
+ ot->poll = ED_operator_uvedit;
+}
+
+/******************** select overlapping operator ********************/
+
+static int UV_OT_select_overlapping_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ ED_uvedit_overlapping_select(scene, obedit, bm, extend);
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+static void UV_OT_select_overlapping(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Overlapping UVs";
+ ot->description = "Select all overlapping UV islands";
+ ot->idname = "UV_OT_select_overlapping";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = UV_OT_select_overlapping_exec;
ot->poll = ED_operator_uvedit;
+
+ RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend current selection");
}
/******************** set 3d cursor operator ********************/
@@ -4251,10 +4681,13 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_circle_select);
WM_operatortype_append(UV_OT_select_more);
WM_operatortype_append(UV_OT_select_less);
+ WM_operatortype_append(UV_OT_select_shortest_path);
+ WM_operatortype_append(UV_OT_select_overlapping);
WM_operatortype_append(UV_OT_snap_cursor);
WM_operatortype_append(UV_OT_snap_selected);
+ WM_operatortype_append(UV_OT_scale_to_bounds);
WM_operatortype_append(UV_OT_align);
WM_operatortype_append(UV_OT_stitch);
@@ -4271,15 +4704,20 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_project_from_view);
WM_operatortype_append(UV_OT_minimize_stretch);
WM_operatortype_append(UV_OT_pack_islands);
+ WM_operatortype_append(UV_OT_irregular_pack_islands);
WM_operatortype_append(UV_OT_reset);
WM_operatortype_append(UV_OT_sphere_project);
WM_operatortype_append(UV_OT_unwrap);
WM_operatortype_append(UV_OT_reveal);
WM_operatortype_append(UV_OT_hide);
+ WM_operatortype_append(UV_OT_deselect_mesh);
+ WM_operatortype_append(UV_OT_select_mesh);
WM_operatortype_append(UV_OT_cursor_set);
WM_operatortype_append(UV_OT_tile_set);
+
+ WM_operatortype_append(UV_OT_test);
}
void ED_keymap_uvedit(wmKeyConfig *keyconf)
@@ -4347,6 +4785,7 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "UV_OT_unwrap", EKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "UV_OT_minimize_stretch", VKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "UV_OT_pack_islands", PKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "UV_OT_irregular_pack_islands", PKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
WM_keymap_add_item(keymap, "UV_OT_average_islands_scale", AKEY, KM_PRESS, KM_CTRL, 0);
/* hide */
@@ -4355,8 +4794,18 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "UV_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "unselected", true);
+ /* reveal */
WM_keymap_add_item(keymap, "UV_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
+ /* deselect 3d mesh */
+ kmi = WM_keymap_add_item(keymap, "UV_OT_deselect_mesh", HKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "unselected", false);
+ kmi = WM_keymap_add_item(keymap, "UV_OT_deselect_mesh", HKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "unselected", true);
+
+ /* select 3d mesh */
+ WM_keymap_add_item(keymap, "UV_OT_select_mesh", HKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
+
/* cursor */
WM_keymap_add_item(keymap, "UV_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "UV_OT_tile_set", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 8c76d03035a..212c4c5ab7a 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -34,6 +34,8 @@
#include "BLI_heap.h"
#include "BLI_boxpack2d.h"
#include "BLI_convexhull2d.h"
+#include "BLI_linklist.h"
+#include "BLI_polyfill2d.h"
#include "uvedit_parametrizer.h"
@@ -59,6 +61,8 @@
{ /*printf("Assertion %s:%d\n", __FILE__, __LINE__); abort();*/ } (void)0
# define param_warning(message) \
{ /*printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);*/ } (void)0
+# define RAND_NFP_POS
+
# if 0
# define param_test_equals_ptr(str, a, b) \
if (a != b) \
@@ -95,6 +99,8 @@ struct PEdge;
struct PFace;
struct PChart;
struct PHandle;
+struct PConvexHull;
+struct PNoFitPolygon;
/* Simplices */
@@ -103,9 +109,10 @@ typedef struct PVert {
union PVertUnion {
PHashKey key; /* construct */
- int id; /* abf/lscm matrix index */
+ int id; /* abf/lscm matrix index, also used for shortest path computation */
float distortion; /* area smoothing */
HeapNode *heaplink; /* edge collapsing */
+ float delta_edge[2]; /* no fit polygon - packing */
} u;
struct PEdge *edge;
@@ -123,6 +130,7 @@ typedef struct PEdge {
int id; /* abf matrix index */
HeapNode *heaplink; /* fill holes */
struct PEdge *nextcollapse; /* simplification */
+ float horizontal_angle; /* No Fit Polygon construction */
} u;
struct PVert *vert;
@@ -130,6 +138,7 @@ typedef struct PEdge {
struct PEdge *next;
struct PFace *face;
float *orig_uv, old_uv[2];
+ int *orig_flag;
unsigned short flag;
} PEdge;
@@ -148,12 +157,36 @@ typedef struct PFace {
unsigned char flag;
} PFace;
+typedef struct PPointUV{
+ float x;
+ float y;
+ float angle; /* irregular packing */
+ float delta_edge[2]; /* irregular packing */
+} PPointUV;
+
+typedef struct PConvexHull {
+ struct PVert **h_verts; /* ToDo SaphireS: Get rid of this since now verts is in place */
+ struct PPointUV **verts;
+ unsigned int nverts;
+ int right; /* ToDo Saphires: Can we get rid of this? */
+ int ref_vert_index; /* vert with the highest y value, lowest y if reversed */
+ float min_v[2];
+ float max_v[2];
+ bool placed;
+} PConvexHull;
+
+typedef struct PNoFitPolygon {
+ unsigned int nverts;
+ struct PPointUV **final_pos;
+} PNoFitPolygon;
+
enum PVertFlag {
PVERT_PIN = 1,
PVERT_SELECT = 2,
PVERT_INTERIOR = 4,
PVERT_COLLAPSE = 8,
- PVERT_SPLIT = 16
+ PVERT_SPLIT = 16,
+ PVERT_MARKED = 32
};
enum PEdgeFlag {
@@ -165,7 +198,8 @@ enum PEdgeFlag {
PEDGE_FILLED = 32,
PEDGE_COLLAPSE = 64,
PEDGE_COLLAPSE_EDGE = 128,
- PEDGE_COLLAPSE_PAIR = 256
+ PEDGE_COLLAPSE_PAIR = 256,
+ PEDGE_DIAG = 512
};
/* for flipping faces */
@@ -199,6 +233,15 @@ typedef struct PChart {
float rescale, area;
float size[2] /* , trans[2] */;
} pack;
+ struct PChartIrregularPack {
+ PConvexHull *convex_hull; /* ToDo (SaphireS): Only convex for now */
+ PConvexHull **tris;
+ PPointUV *best_pos, *cur_pos;
+ float area, last_scale;
+ float sa_params[3]; /* 0 = Theta, 1 = r, 2 = f according to Rotational placement of irregular polygons over containers with fixed dimensions using simulated annealing and no-fit polygons*/
+ int ntris;
+ bool decomposed;
+ } ipack;
} u;
unsigned char flag;
@@ -213,7 +256,8 @@ enum PHandleState {
PHANDLE_STATE_ALLOCATED,
PHANDLE_STATE_CONSTRUCTED,
PHANDLE_STATE_LSCM,
- PHANDLE_STATE_STRETCH
+ PHANDLE_STATE_STRETCH,
+ PHANDLE_STATE_PACK
};
typedef struct PHandle {
@@ -421,6 +465,31 @@ static float p_face_uv_area_signed(PFace *f)
((v3->uv[0] - v1->uv[0]) * (v2->uv[1] - v1->uv[1])));
}
+static float p_chart_uv_area_signed(PChart *chart)
+{
+ PFace *f;
+ float used_area = 0.0f;
+ for (f = chart->faces; f; f = f->nextlink) {
+ used_area += fabsf(p_face_uv_area_signed(f));
+ }
+
+ return used_area;
+}
+
+/* returns the sum of the areas of all charts */
+static float p_face_uv_area_combined(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle *)handle;
+ float used_area = 0.0f;
+ int i;
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ used_area += p_chart_uv_area_signed(phandle->charts[i]);
+ }
+
+ return used_area;
+}
+
static float p_edge_length(PEdge *e)
{
PVert *v1 = e->vert, *v2 = e->next->vert;
@@ -459,6 +528,8 @@ static void p_chart_uv_scale(PChart *chart, float scale)
{
PVert *v;
+ printf("--uv_scaling chart with factor %f\n", scale);
+
for (v = chart->verts; v; v = v->nextlink) {
v->uv[0] *= scale;
v->uv[1] *= scale;
@@ -504,6 +575,69 @@ static void p_chart_uv_to_array(PChart *chart, float (*points)[2])
}
}
+static void p_chart_uv_scale_origin(PChart *chart, float scale)
+{
+ float minv[2], maxv[2], trans[2];
+
+ /* Get the island center */
+ p_chart_uv_bbox(chart, minv, maxv);
+ trans[0] = (minv[0] + maxv[0]) / -2.0f;
+ trans[1] = (minv[1] + maxv[1]) / -2.0f;
+
+ /* Move center to 0,0 */
+ p_chart_uv_translate(chart, trans);
+ p_chart_uv_scale(chart, scale);
+
+ /* Move to original center */
+ trans[0] = -trans[0];
+ trans[1] = -trans[1];
+ p_chart_uv_translate(chart, trans);
+}
+
+static void p_chart_uv_rotate(PChart *chart, float angle)
+{
+ float sine = sinf(angle);
+ float cosine = cosf(angle);
+ PVert *v;
+
+ for (v = chart->verts; v; v = v->nextlink) {
+ float oldu = v->uv[0], oldv = v->uv[1];
+ v->uv[0] = cosine * oldu - sine * oldv;
+ v->uv[1] = sine * oldu + cosine * oldv;
+ }
+}
+
+static void p_chart_uv_rotate_origin(PChart *chart, float angle)
+{
+ float minv[2], maxv[2], trans[2];
+
+ /* Get the island center */
+ p_chart_uv_bbox(chart, minv, maxv);
+ trans[0] = (minv[0] + maxv[0]) / -2.0f;
+ trans[1] = (minv[1] + maxv[1]) / -2.0f;
+
+ /* Move center to 0,0 */
+ p_chart_uv_translate(chart, trans);
+ p_chart_uv_rotate(chart, angle);
+
+ /* Move to original center */
+ trans[0] = -trans[0];
+ trans[1] = -trans[1];
+ p_chart_uv_translate(chart, trans);
+}
+
+static void UNUSED_FUNCTION(p_scale_charts)(PHandle *handle, float scale)
+{
+ PChart *chart;
+ int i;
+
+ for (i = 0; i < handle->ncharts; i++) {
+ chart = handle->charts[i];
+
+ p_chart_uv_scale_origin(chart, scale);
+ }
+}
+
static void UNUSED_FUNCTION(p_chart_uv_from_array)(PChart *chart, float (*points)[2])
{
PVert *v;
@@ -531,8 +665,7 @@ static PBool p_intersect_line_2d_dir(float *v1, float *dir1, float *v2, float *d
return P_TRUE;
}
-#if 0
-static PBool p_intersect_line_2d(float *v1, float *v2, float *v3, float *v4, float *isect)
+static PBool UNUSED_FUNCTION(p_intersect_line_2d)(float *v1, float *v2, float *v3, float *v4, float *isect)
{
float dir1[2], dir2[2];
@@ -552,7 +685,56 @@ static PBool p_intersect_line_2d(float *v1, float *v2, float *v3, float *v4, flo
return P_TRUE;
}
-#endif
+
+static PBool p_intersect_line_segments_2d(float *a, float *b, float *c, float *d)
+{
+ float D = (b[0] - a[0]) * (d[1] - c[1]) - (b[1] - a[1]) * (d[0] - c[0]);
+
+ if (compare_ff(D, 0.0f, FLT_EPSILON)) {
+ /* Line segments are parallel */
+ return P_FALSE;
+ }
+
+ float r = ((a[1] - c[1]) * (d[0] - c[0]) - (a[0] - c[0]) * (d[1] - c[1])) / D;
+ float s = ((a[1] - c[1]) * (b[0] - a[0]) - (a[0] - c[0]) * (b[1] - a[1])) / D;
+
+ if (((-FLT_EPSILON <= r) && (r <= (1.0f + FLT_EPSILON))) &&
+ ((-FLT_EPSILON <= s) && (s <= (1.0f + FLT_EPSILON)))) {
+ /* ToDo (SaphireS): return actual intersection data ?*/
+
+ return P_TRUE;
+ }
+
+ return P_FALSE;
+}
+
+static bool p_rect_intersect(float min1[2], float max1[2], float min2[2], float max2[2])
+{
+ if (min1[0] > max2[0] ||
+ max1[0] < min2[0] ||
+ min1[1] > max2[1] ||
+ max1[1] < min2[1]) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Returns the interval of range in which f falls in */
+static int p_float_to_int_range(float f, int range)
+{
+ return (int)(f * (float)(range));
+}
+
+/* Returns the interval of range in which f falls in */
+/* re contains the remainder of f, linearized to 0-1 range */
+static int p_float_to_int_range_remainder(float f, int range, float *re)
+{
+ int val = p_float_to_int_range(f, range);
+ *re = f * range - val;
+
+ return val;
+}
/* Topological Utilities */
@@ -685,6 +867,36 @@ static void p_flush_uvs(PHandle *handle, PChart *chart)
}
}
+static void p_flush_uvs_selection(PHandle *handle, PChart *chart)
+{
+ PEdge *e;
+ int sel_flag = 0;
+ /* ToDo (SaphireS): Find sensible variable names*/
+ int MLOOPEDGE_SELECTED = (1 << 0); /* MLOOPUV_EDGESEL*/
+ int MLOOPVERT_SELECTED = (1 << 1); /* MLOOPUV_VERTSEL*/
+
+ for (e = chart->edges; e; e = e->nextlink) {
+ if (e->orig_uv) {
+ e->orig_uv[0] = e->vert->uv[0] / handle->aspx;
+ e->orig_uv[1] = e->vert->uv[1] / handle->aspy;
+ }
+
+ if (e->flag & PEDGE_SELECT) {
+
+ sel_flag = *e->orig_flag;
+ sel_flag |= MLOOPEDGE_SELECTED;/* MLOOPUV_EDGESEL*/
+ sel_flag |= MLOOPVERT_SELECTED; /* MLOOPUV_VERTSEL*/
+ *(e->orig_flag) = sel_flag;
+ }
+ else {
+ sel_flag = *e->orig_flag;
+ sel_flag &= ~MLOOPEDGE_SELECTED;/* MLOOPUV_EDGESEL*/
+ sel_flag &= ~MLOOPVERT_SELECTED; /* MLOOPUV_VERTSEL*/
+ *(e->orig_flag) = sel_flag;
+ }
+ }
+}
+
static void p_flush_uvs_blend(PHandle *handle, PChart *chart, float blend)
{
PEdge *e;
@@ -1108,7 +1320,7 @@ static PFace *p_face_add(PHandle *handle)
static PFace *p_face_add_construct(PHandle *handle, ParamKey key, ParamKey *vkeys,
float *co[4], float *uv[4], int i1, int i2, int i3,
- ParamBool *pin, ParamBool *select)
+ ParamBool *pin, ParamBool *select, int **flag, int diag_edge)
{
PFace *f = p_face_add(handle);
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
@@ -1121,6 +1333,10 @@ static PFace *p_face_add_construct(PHandle *handle, ParamKey key, ParamKey *vkey
e2->orig_uv = uv[i2];
e3->orig_uv = uv[i3];
+ e1->orig_flag = flag[i1];
+ e2->orig_flag = flag[i2];
+ e3->orig_flag = flag[i3];
+
if (pin) {
if (pin[i1]) e1->flag |= PEDGE_PIN;
if (pin[i2]) e2->flag |= PEDGE_PIN;
@@ -1145,6 +1361,28 @@ static PFace *p_face_add_construct(PHandle *handle, ParamKey key, ParamKey *vkey
phash_insert(handle->hash_edges, (PHashLink *)e2);
phash_insert(handle->hash_edges, (PHashLink *)e3);
+ if (diag_edge != -1) {
+ switch (diag_edge) {
+ case 0:
+ {
+ e1->flag |= PEDGE_DIAG;
+ break;
+ }
+ case 1:
+ {
+ e2->flag |= PEDGE_DIAG;
+ break;
+ }
+ case 2: /* fall through */
+ case 3:
+ {
+ e3->flag |= PEDGE_DIAG;
+ break;
+ }
+ default: break;
+ }
+ }
+
return f;
}
@@ -1363,6 +1601,48 @@ static void p_chart_fill_boundaries(PChart *chart, PEdge *outer)
}
}
+static bool p_charts_intersect(PChart* a, PChart *b)
+{
+ PEdge *e1, *e2;
+ float min1[2], min2[2], max1[2], max2[2];
+
+ /* Check for overlapping bounding rectangles */
+ p_chart_uv_bbox(a, min1, max1);
+ p_chart_uv_bbox(b, min2, max2);
+
+ if (!p_rect_intersect(min1, max1, min2, max2)) {
+ return false;
+ }
+
+ /* Check edges for intersections */
+ for (e1 = a->edges; e1; e1 = e1->nextlink) {
+ for (e2 = b->edges; e2; e2 = e2->nextlink) {
+ if (e1->nextlink && e2->nextlink) {
+ if (p_intersect_line_segments_2d(e1->vert->uv,
+ e1->nextlink->vert->uv,
+ e2->vert->uv,
+ e2->nextlink->vert->uv)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+static void p_chart_select(PChart *chart, bool select)
+{
+ PEdge *e;
+
+ for (e = chart->edges; e; e = e->nextlink) {
+ if (select)
+ e->flag |= PEDGE_SELECT;
+ else
+ e->flag &= ~PEDGE_SELECT;
+ }
+}
+
#if 0
/* Polygon kernel for inserting uv's non overlapping */
@@ -3600,15 +3880,7 @@ static float p_chart_minimum_area_angle(PChart *chart)
static void p_chart_rotate_minimum_area(PChart *chart)
{
float angle = p_chart_minimum_area_angle(chart);
- float sine = sinf(angle);
- float cosine = cosf(angle);
- PVert *v;
-
- for (v = chart->verts; v; v = v->nextlink) {
- float oldu = v->uv[0], oldv = v->uv[1];
- v->uv[0] = cosine * oldu - sine * oldv;
- v->uv[1] = sine * oldu + cosine * oldv;
- }
+ p_chart_uv_rotate(chart, angle);
}
/* Area Smoothing */
@@ -3670,6 +3942,19 @@ static PBool p_triangle_inside(SmoothTriangle *t, float co[2])
return P_FALSE;
}
+static PBool p_triangle_inside_v3_v2(float tri_v1[2], float tri_v2[2], float tri_v3[2], float co[2])
+{
+ float b[3];
+
+ p_barycentric_2d(tri_v1, tri_v2, tri_v3, co, b);
+
+ if ((b[0] >= 0.0f) && (b[1] >= 0.0f) && (b[2] >= 0.0f)) {
+ return P_TRUE;
+ }
+
+ return P_FALSE;
+}
+
static SmoothNode *p_node_new(MemArena *arena, SmoothTriangle **tri, int ntri, float *bmin, float *bmax, int depth)
{
SmoothNode *node = BLI_memarena_alloc(arena, sizeof(*node));
@@ -4167,7 +4452,7 @@ void param_delete(ParamHandle *handle)
static void p_add_ngon(ParamHandle *handle, ParamKey key, int nverts,
ParamKey *vkeys, float **co, float **uv,
- ParamBool *pin, ParamBool *select, const float normal[3])
+ ParamBool *pin, ParamBool *select, const float normal[3], int **flag)
{
int *boundary = BLI_array_alloca(boundary, nverts);
@@ -4221,10 +4506,11 @@ static void p_add_ngon(ParamHandle *handle, ParamKey key, int nverts,
ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]};
float *tri_co[3] = {co[v0], co[v1], co[v2]};
float *tri_uv[3] = {uv[v0], uv[v1], uv[v2]};
+ int *tri_flag[3] = {flag[v0], flag[v1], flag[v2]};
ParamBool tri_pin[3] = {pin[v0], pin[v1], pin[v2]};
ParamBool tri_select[3] = {select[v0], select[v1], select[v2]};
- param_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select, NULL);
+ param_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select, NULL, tri_flag);
}
/* remove corner */
@@ -4237,7 +4523,7 @@ static void p_add_ngon(ParamHandle *handle, ParamKey key, int nverts,
void param_face_add(ParamHandle *handle, ParamKey key, int nverts,
ParamKey *vkeys, float *co[4], float *uv[4],
- ParamBool *pin, ParamBool *select, float normal[3])
+ ParamBool *pin, ParamBool *select, float normal[3], int **flag)
{
PHandle *phandle = (PHandle *)handle;
@@ -4247,22 +4533,22 @@ void param_face_add(ParamHandle *handle, ParamKey key, int nverts,
if (nverts > 4) {
/* ngon */
- p_add_ngon(handle, key, nverts, vkeys, co, uv, pin, select, normal);
+ p_add_ngon(handle, key, nverts, vkeys, co, uv, pin, select, normal, flag);
}
else if (nverts == 4) {
/* quad */
if (p_quad_split_direction(phandle, co, vkeys)) {
- p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select);
- p_face_add_construct(phandle, key, vkeys, co, uv, 0, 2, 3, pin, select);
+ p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select, flag, 2);
+ p_face_add_construct(phandle, key, vkeys, co, uv, 0, 2, 3, pin, select, flag, 0);
}
else {
- p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 3, pin, select);
- p_face_add_construct(phandle, key, vkeys, co, uv, 1, 2, 3, pin, select);
+ p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 3, pin, select, flag, 1);
+ p_face_add_construct(phandle, key, vkeys, co, uv, 1, 2, 3, pin, select, flag, 3);
}
}
else if (!p_face_exists(phandle, vkeys, 0, 1, 2)) {
/* triangle */
- p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select);
+ p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select, flag, -1);
}
}
@@ -4593,6 +4879,1346 @@ void param_pack(ParamHandle *handle, float margin, bool do_rotate)
param_scale(handle, phandle->aspx, phandle->aspy);
}
+/* qsort function - sort largest to smallest */
+static int UNUSED_FUNCTION(vert_anglesort)(const void *p1, const void *p2)
+{
+ PVert *const* v1 = p1, *const* v2 = p2;
+ const float a1 = (*v1)->edge->u.horizontal_angle;
+ const float a2 = (*v2)->edge->u.horizontal_angle;
+
+ if (a1 > a2) return -1;
+ else if (a1 < a2) return 1;
+ return 0;
+}
+
+/* qsort function - sort largest to smallest */
+static int point_anglesort(const void *p1, const void *p2)
+{
+ PPointUV *const* v1 = p1, *const* v2 = p2;
+ const float a1 = (*v1)->angle;
+ const float a2 = (*v2)->angle;
+
+ if (a1 > a2) return -1;
+ else if (a1 < a2) return 1;
+ return 0;
+}
+
+/* qsort function - sort largest to smallest */
+static int chart_areasort(const void *p1, const void *p2)
+{
+ PChart *const* c1 = p1, *const* c2 = p2;
+ const float a1 = (*c1)->u.ipack.area;
+ const float a2 = (*c2)->u.ipack.area;
+
+ if (a1 > a2) return -1;
+ else if (a1 < a2) return 1;
+ return 0;
+}
+
+/* ToDo SaphireS: Make this function part of math_vector.c */
+static float UNUSED_FUNCTION(p_edge_horizontal_angle)(PVert *a, PVert *b)
+{
+ float angle = 0.0f;
+ float hori[2];
+ hori[1] = a->uv[1];
+
+ if (a->uv[1] > b->uv[1] && !(compare_ff(a->uv[1], b->uv[1], FLT_EPSILON))) {
+ hori[0] = a->uv[0] - 1.0f;
+ angle = angle_v2v2v2(b->uv, a->uv, hori);
+ angle += M_PI;
+ }
+ else {
+ hori[0] = a->uv[0] + 1.0f;
+ angle = angle_v2v2v2(b->uv, a->uv, hori);
+ }
+
+ return angle;
+}
+
+static float p_edge_horizontal_angle_ppointuv(PPointUV *a, PPointUV *b)
+{
+ float angle = 0.0f;
+ float hori[2], pa[2], pb[2];
+ hori[1] = a->y;
+ pa[0] = a->x;
+ pa[1] = a->y;
+ pb[0] = b->x;
+ pb[1] = b->y;
+ if (a->y > b->y && !(compare_ff(a->y, b->y, FLT_EPSILON))) {
+ hori[0] = a->x - 1.0f;
+ angle = angle_v2v2v2(pb, pa, hori);
+ angle += M_PI;
+ }
+ else {
+ hori[0] = a->x + 1.0f;
+ angle = angle_v2v2v2(pb, pa, hori);
+ }
+
+ return angle;
+}
+
+/* ToDo SaphireS: Put ConvexHull/NFP stuff in own file*/
+static PConvexHull *p_convex_hull_new(PChart *chart)
+{
+ PConvexHull *conv_hull = (PConvexHull *)MEM_callocN(sizeof(*conv_hull), "PConvexHull");
+ PVert **points;
+ float maxy = -1.0e30f;
+ int npoint, right, i;
+
+ if (!p_chart_convex_hull(chart, &points, &npoint, &right))
+ printf("convex hull for chart failed!\n");
+
+ conv_hull->h_verts = points;
+ conv_hull->verts = (PPointUV **)MEM_callocN(sizeof(*conv_hull->verts) * npoint, "PConvexHullVerts");
+ conv_hull->nverts = npoint;
+ conv_hull->right = right;
+ conv_hull->placed = false;
+ conv_hull->ref_vert_index = 0;
+
+ /* Fill max/min for initial positioning, with this we also know the bounding rectangle */
+ p_chart_uv_bbox(chart, conv_hull->min_v, conv_hull->max_v);
+
+ /* get reference vertex */
+ for (i = 0; i < conv_hull->nverts; i++) {
+ PPointUV *p = (PPointUV *)MEM_callocN(sizeof(*p), "PPointUV");
+ p->x = conv_hull->h_verts[i]->uv[0];
+ p->y = conv_hull->h_verts[i]->uv[1];
+ conv_hull->verts[i] = p;
+
+ /* Note: FLT_EPSILON is to exact and produces wrong results in this context, use custom max_diff instead */
+ if (compare_ff(maxy, conv_hull->verts[i]->y, 0.00001f)) {
+ /* same y value, only take if x value is lower than for current ref vert */
+ if (conv_hull->verts[i]->x < conv_hull->verts[conv_hull->ref_vert_index]->x) {
+ maxy = conv_hull->verts[i]->y;
+ conv_hull->ref_vert_index = i;
+ }
+ }
+ else if (conv_hull->verts[i]->y > maxy) {
+ /* higher y value */
+ maxy = conv_hull->verts[i]->y;
+ conv_hull->ref_vert_index = i;
+ }
+ }
+
+ return conv_hull;
+}
+
+static PConvexHull *p_convex_hull_new_tri(PChart *chart, const float(*coords)[2])
+{
+ PConvexHull *conv_hull = (PConvexHull *)MEM_callocN(sizeof(*conv_hull), "PConvexHull");
+ PVert *v;
+ float pos[2], maxy = -1.0e30f;
+ int npoint = 3, right = 0, i;
+
+ //printf("p_convex_hull_new_tri!\n");
+
+ conv_hull->h_verts = (PVert **)MEM_callocN(sizeof(conv_hull->h_verts) * npoint, "PConvHullPVerts");
+ conv_hull->verts = (PPointUV **)MEM_callocN(sizeof(*conv_hull->verts) * npoint, "PConvexHullVerts");
+ conv_hull->nverts = npoint;
+ conv_hull->right = right;
+ conv_hull->placed = false;
+ conv_hull->ref_vert_index = 0;
+
+ /* Fill max/min for initial positioning, with this we also know the bounding rectangle */
+ /* p_chart_uv_bbox(chart, conv_hull->min_v, conv_hull->max_v); */
+ INIT_MINMAX2(conv_hull->min_v, conv_hull->max_v);
+
+ //printf("-p_convex_hull_new_tri: inits done!\n");
+
+ /* get reference vertex */
+ for (i = 0; i < conv_hull->nverts; i++) {
+
+ /* ToDo Saphires: Also fill verts_h, needed for margin support */
+ PPointUV *p = (PPointUV *)MEM_callocN(sizeof(*p), "PPointUV");
+ p->x = coords[i][0];
+ p->y = coords[i][1];
+ //printf("-p_convex_hull_new_tri: p coords updated!\n");
+ conv_hull->verts[i] = p;
+ //printf("-p_convex_hull_new_tri: p assigned to verts!\n");
+
+ /*PVert *v = (PVert *)MEM_callocN(sizeof(*v), "PVert");
+ v->uv[0] = coords[i][0];
+ v->uv[1] = coords[i][1];
+ conv_hull->h_verts[i] = v;
+ printf("-p_convex_hull_new_tri: v assigned to verts_h!\n");*/
+
+ for (v = chart->verts; v; v = v->nextlink) {
+ if (compare_ff(v->uv[0],coords[i][0], 0.0001f)) {
+ if (compare_ff(v->uv[1], coords[i][1], 0.0001f)) {
+ conv_hull->h_verts[i] = v;
+ //printf("-p_convex_hull_new_tri: v assigned to verts_h!\n");
+ }
+ }
+ }
+
+ /* Update bounds */
+ pos[0] = conv_hull->verts[i]->x;
+ pos[1] = conv_hull->verts[i]->y;
+ minmax_v2v2_v2(conv_hull->min_v, conv_hull->max_v, pos);
+ //printf("-p_convex_hull_new_tri: bounds updated!\n");
+
+ /* Note: FLT_EPSILON is to exact and produces wrong results in this context, use custom max_diff instead */
+ if (compare_ff(maxy, conv_hull->verts[i]->y, 0.00001f)) {
+ /* same y value, only take if x value is lower than for current ref vert */
+ if (conv_hull->verts[i]->x < conv_hull->verts[conv_hull->ref_vert_index]->x) {
+ maxy = conv_hull->verts[i]->y;
+ conv_hull->ref_vert_index = i;
+ }
+ }
+ else if (conv_hull->verts[i]->y > maxy) {
+ /* higher y value */
+ maxy = conv_hull->verts[i]->y;
+ conv_hull->ref_vert_index = i;
+ }
+ //printf("-p_convex_hull_new_tri: ref vert updated!\n");
+ }
+
+ return conv_hull;
+}
+
+/* Update bounds and recalculate ref vertex (highest y value) */
+static void p_convex_hull_update(PConvexHull *conv_hull, bool update_points)
+{
+ int i;
+ float maxy = -1.0e30f, p[2];
+ conv_hull->ref_vert_index = 0;
+
+
+ for (i = 0; i < conv_hull->nverts; i++) {
+ /* update points */
+ if (update_points) {
+ conv_hull->verts[i]->x = conv_hull->h_verts[i]->uv[0];
+ conv_hull->verts[i]->y = conv_hull->h_verts[i]->uv[1];
+ }
+
+ /* Update bounds */
+ p[0] = conv_hull->verts[i]->x;
+ p[1] = conv_hull->verts[i]->y;
+ minmax_v2v2_v2(conv_hull->min_v, conv_hull->max_v, p);
+
+ /* get reference vertex */
+ /* Note: FLT_EPSILON is to exact and produces wrong results in this context, use custom max_diff instead */
+ if (compare_ff(maxy, conv_hull->verts[i]->y, 0.00001f)) {
+ /* same y value, only take if x value is lower than for current ref vert */
+ if (conv_hull->verts[i]->x < conv_hull->verts[conv_hull->ref_vert_index]->x) {
+ maxy = conv_hull->verts[i]->y;
+ conv_hull->ref_vert_index = i;
+ }
+ }
+ else if (conv_hull->verts[i]->y > maxy) {
+ /* higher y value */
+ maxy = conv_hull->verts[i]->y;
+ conv_hull->ref_vert_index = i;
+ }
+ }
+}
+
+static void p_convex_hull_delete(PConvexHull *c_hull)
+{
+ int i;
+ for (i = 0; i < c_hull->nverts; i++) {
+ if (c_hull->verts[i]) {
+ MEM_freeN(c_hull->verts[i]);
+ }
+ }
+
+ MEM_freeN(c_hull->verts);
+ MEM_freeN(c_hull->h_verts);
+ MEM_freeN(c_hull);
+ c_hull = NULL;
+}
+
+static bool p_convex_hull_intersect(PConvexHull *chull_a, PConvexHull *chull_b)
+{
+ /* Preliminary bounds check */
+ if (!p_rect_intersect(chull_a->min_v, chull_a->max_v, chull_b->min_v, chull_b->max_v)) {
+ return false;
+ }
+
+ int i, j;
+
+ /* Check edges for intersctions */
+ for (i = 0; i < chull_a->nverts; i++) {
+ for (j = 0; j < chull_b->nverts; j++) {
+ /* ToDo SaphireS: Use chull_a->verts instead */
+ if (p_intersect_line_segments_2d(chull_a->h_verts[i]->uv,
+ chull_a->h_verts[i+1]->uv,
+ chull_b->h_verts[j]->uv,
+ chull_b->h_verts[j+1]->uv)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static void p_convex_hull_compute_horizontal_angles(PConvexHull *hull)
+{
+ int j;
+ //printf("*p_convex_hull_compute_horizontal_angles\n");
+ for (j = 0; j < hull->nverts; j++) {
+
+ /* Compute horizontal angle for each edge of hull (Needed for NFP) */
+ /* ToDo SaphireS: Get rid of h_verts */
+ if (j == (hull->nverts - 1)) {
+ //hull->h_verts[j]->edge->u.horizontal_angle = p_edge_horizontal_angle(hull->h_verts[j], hull->h_verts[0]);
+ hull->verts[j]->angle = p_edge_horizontal_angle_ppointuv(hull->verts[j], hull->verts[0]);
+ }
+ else {
+ //hull->h_verts[j]->edge->u.horizontal_angle = p_edge_horizontal_angle(hull->h_verts[j], hull->h_verts[j + 1]);
+ hull->verts[j]->angle = p_edge_horizontal_angle_ppointuv(hull->verts[j], hull->verts[j + 1]);
+ }
+
+ /* Note: FLT_EPSILON is to exact and produces wrong results in this context, use custom max_diff instead */
+ /* Since we're counting edges in CW winding we have to set 0.0 to 2*pi */
+ /*if (compare_ff(hull->h_verts[j]->edge->u.horizontal_angle, 0.0f, 0.00001f)) {
+ hull->h_verts[j]->edge->u.horizontal_angle += 2 * M_PI;
+ }*/
+ if (compare_ff(hull->verts[j]->angle, 0.0f, 0.00001f)) {
+ hull->verts[j]->angle += 2 * M_PI;
+ }
+
+ /*printf("---horizontal angle of edge [%i]: %f\n", j, hull->h_verts[j]->edge->u.horizontal_angle);*/
+ }
+}
+
+static void p_convex_hull_compute_edge_components(PConvexHull *hull)
+{
+ int j;
+ //printf("*p_convex_hull_compute_edge_lengths\n");
+ for (j = 0; j < hull->nverts; j++) {
+
+ /* Compute edge components for each edge of hull (Needed for NFP) */
+ /* ToDo SaphireS: Get rid of h_verts */
+ if (j == (hull->nverts - 1)) {
+ hull->h_verts[j]->u.delta_edge[0] = hull->h_verts[0]->uv[0] - hull->h_verts[j]->uv[0];
+ hull->h_verts[j]->u.delta_edge[1] = hull->h_verts[0]->uv[1] - hull->h_verts[j]->uv[1];
+ }
+ else {
+ hull->h_verts[j]->u.delta_edge[0] = hull->h_verts[j + 1]->uv[0] - hull->h_verts[j]->uv[0];
+ hull->h_verts[j]->u.delta_edge[1] = hull->h_verts[j + 1]->uv[1] - hull->h_verts[j]->uv[1];
+ }
+ /* verts */
+ if (j == (hull->nverts - 1)) {
+ hull->verts[j]->delta_edge[0] = hull->verts[0]->x - hull->verts[j]->x;
+ hull->verts[j]->delta_edge[1] = hull->verts[0]->y - hull->verts[j]->y;
+ }
+ else {
+ hull->verts[j]->delta_edge[0] = hull->verts[j + 1]->x - hull->verts[j]->x;
+ hull->verts[j]->delta_edge[1] = hull->verts[j + 1]->y - hull->verts[j]->y;
+ }
+
+ //printf("--- edge [%i]: x: %f, y: %f\n", j, hull->h_verts[j]->u.delta_edge[0], hull->h_verts[j]->u.delta_edge[1]);
+ }
+}
+
+static PConvexHull *p_convex_hull_reverse_vert_order(PConvexHull *hull)
+{
+ PConvexHull *conv_hull_inv = (PConvexHull *)MEM_callocN(sizeof(*conv_hull_inv), "PConvexHullInverse");
+ conv_hull_inv->nverts = hull->nverts;
+ conv_hull_inv->h_verts = (PVert **)MEM_mallocN(sizeof(PVert *) * conv_hull_inv->nverts, "PConvexHullInversePoints");
+ conv_hull_inv->verts = (PPointUV **)MEM_callocN(sizeof(*conv_hull_inv->verts) * conv_hull_inv->nverts, "PConvexHullVerts");
+ conv_hull_inv->right = hull->right;
+ conv_hull_inv->placed = false;
+ int i, j;
+ float miny = 1.0e30f, b[2];
+
+ /* reverse vert order */
+ for (j = 0; j < hull->nverts; j++) {
+ conv_hull_inv->h_verts[j] = hull->h_verts[hull->nverts - (j + 1)];
+ PPointUV *p = (PPointUV *)MEM_callocN(sizeof(*p), "PPointUV");
+ p->x = hull->verts[hull->nverts - (j + 1)]->x;
+ p->y = hull->verts[hull->nverts - (j + 1)]->y;
+ conv_hull_inv->verts[j] = p;
+ }
+
+ INIT_MINMAX2(conv_hull_inv->min_v, conv_hull_inv->max_v);
+
+ /* reference vertex, for inverse winding direction that's the one with lowest y value */
+ for (i = 0; i < conv_hull_inv->nverts; i++) {
+
+ /* Note: FLT_EPSILON is to exact and produces wrong results in this context, use custom max_diff instead */
+ if (compare_ff(miny, conv_hull_inv->verts[i]->y, 0.00001f)) {
+ /* same y value, only take if x value is higher than for current ref vert */
+ if (conv_hull_inv->verts[i]->x > conv_hull_inv->verts[conv_hull_inv->ref_vert_index]->x) {
+ miny = conv_hull_inv->verts[i]->y;
+ conv_hull_inv->ref_vert_index = i;
+ //printf("--p_convex_hull_reverse_vert_order: EQUAL min_y : x = %f, y = %f\n", conv_hull_inv->verts[i]->x, conv_hull_inv->verts[i]->y);
+ }
+ }
+ else if (conv_hull_inv->verts[i]->y < miny) {
+ /* lower y value */
+ miny = conv_hull_inv->verts[i]->y;
+ conv_hull_inv->ref_vert_index = i;
+ //printf("--p_convex_hull_reverse_vert_order: SMALLER min_y : x = %f, y = %f\n", conv_hull_inv->verts[i]->x, conv_hull_inv->verts[i]->y);
+ }
+
+ /* compute bounds */
+ b[0] = conv_hull_inv->verts[i]->x;
+ b[1] = conv_hull_inv->verts[i]->y;
+ minmax_v2v2_v2(conv_hull_inv->min_v, conv_hull_inv->max_v, b);
+ }
+
+ //printf("--p_convex_hull_reverse_vert_order: FINAL min_y: x: %f, y: %f\n", conv_hull_inv->verts[conv_hull_inv->ref_vert_index]->x, conv_hull_inv->verts[conv_hull_inv->ref_vert_index]->y);
+
+ return conv_hull_inv;
+}
+
+/* Grow hull by margin amount */
+static void p_convex_hull_grow(PConvexHull *chull, float margin)
+{
+ /* ToDo SaphireS */
+ PVert *v1, *v2, *v3;
+ //PPointUV *p1, *p2, *p3;
+ float vec1[2], vec2[2], vec3[2];
+ float dist_fac;
+ float a[2], b[2], dir[2], end_pos[2], a_n[2], b_n[2];
+ int i;
+
+ for (i = 0; i < chull->nverts; i++) {
+ v1 = chull->h_verts[(i ? i : chull->nverts) - 1];
+ v2 = chull->h_verts[i];
+ v3 = chull->h_verts[(i + 1) < chull->nverts ? (i + 1) : 0];
+
+ //p1 = chull->verts[(i ? i : chull->nverts) - 1];
+ //p2 = chull->verts[i];
+ //p3 = chull->verts[(i + 1) < chull->nverts ? (i + 1) : 0];
+
+ vec1[0] = v1->uv[0];
+ vec1[1] = v1->uv[1];
+
+ vec2[0] = v2->uv[0];
+ vec2[1] = v2->uv[1];
+
+ vec3[0] = v3->uv[0];
+ vec3[1] = v3->uv[1];
+
+ sub_v2_v2v2(a, vec1, vec2);
+ sub_v2_v2v2(b, vec2, vec3);
+
+ //printf("--a x: %f, y: %f\n", a[0], a[1]);
+ //printf("--b x: %f, y: %f\n", b[0], b[1]);
+
+ normalize_v2(a);
+ normalize_v2(b);
+
+ /* distance to offset */
+ dist_fac = shell_v2v2_mid_normalized_to_dist(a, b);
+
+ /* direction to offset */
+ edge_normal_v2_v2v2(a_n, vec1, vec2, true);
+ edge_normal_v2_v2v2(b_n, vec2, vec3, true);
+
+ normalize_v2(a_n);
+ normalize_v2(b_n);
+
+ //printf("--a_n x: %f, y: %f\n", a_n[0], a_n[1]);
+ //printf("--b_n x: %f, y: %f\n", b_n[0], b_n[1]);
+
+ add_v2_v2v2(dir, a_n, b_n);
+
+ normalize_v2(dir);
+
+ //printf("--dirx: %f, diry: %f, dist_fac: %f, margin: %f\n", dir[0], dir[1], dist_fac, margin);
+
+ /* offset point */
+ madd_v2_v2v2fl(end_pos, v2->uv, dir, dist_fac * margin);
+
+ /*ToDo: apply end_pos */
+ chull->verts[i]->x = end_pos[0];
+ chull->verts[i]->y = end_pos[1];
+
+ //printf("-growing end_pos[%i]: x: %f, y: %f\n", i, end_pos[0], end_pos[1]);
+ }
+}
+
+static PConvexHull *p_convex_hull_reverse_direction(PConvexHull *item)
+{
+ /* Invert direction of one convex hull -> CCW */
+ //printf("inversing direction start\n");
+ /* ref_vert_index now contains the vert with the lowest y value */
+ PConvexHull *item_inv = p_convex_hull_reverse_vert_order(item);
+ //printf("angles start\n");
+ p_convex_hull_compute_horizontal_angles(item_inv);
+ //printf("components start\n");
+ p_convex_hull_compute_edge_components(item_inv);
+ //printf("inversing direction done!\n");
+
+ return item_inv;
+}
+
+/* ToDo SaphireS: store edge angle/edge components in different way so this isn't necessary */
+static void p_convex_hull_restore_direction(PConvexHull *item, float margin)
+{
+ p_convex_hull_update(item, true);
+ p_convex_hull_grow(item, margin);
+ p_convex_hull_update(item, false);
+ p_convex_hull_compute_horizontal_angles(item);
+ p_convex_hull_compute_edge_components(item);
+}
+
+static void p_convex_hull_update_all(PConvexHull *hull, float margin)
+{
+ p_convex_hull_update(hull, true);
+ p_convex_hull_grow(hull, margin);
+ p_convex_hull_update(hull, false);
+ p_convex_hull_compute_horizontal_angles(hull); /* ToDo: Shouldn't be necessary! */
+ p_convex_hull_compute_edge_components(hull);
+}
+
+static PNoFitPolygon *p_inner_fit_polygon_create(PHandle *phandle, PConvexHull *item)
+{
+ PNoFitPolygon *nfp = (PNoFitPolygon *)MEM_callocN(sizeof(*nfp), "PNoFitPolygon");
+ /* Simplification, since we're not dealing with arbitrary shaped outer bounds */
+ /* we can assume the inner fit polygon to always be a rectangle */
+ nfp->nverts = 4;
+ PVert **points = (PVert **)MEM_mallocN(sizeof(PVert *) * nfp->nverts, "PNFPPoints");
+ nfp->final_pos = (PPointUV **)MEM_callocN(sizeof(*nfp->final_pos) * nfp->nverts, "PNFPFinalPos");
+
+ PPointUV *p1 = (PPointUV *)MEM_callocN(sizeof(*p1), "PPointUV");
+ PPointUV *p2 = (PPointUV *)MEM_callocN(sizeof(*p2), "PPointUV");
+ PPointUV *p3 = (PPointUV *)MEM_callocN(sizeof(*p3), "PPointUV");
+ PPointUV *p4 = (PPointUV *)MEM_callocN(sizeof(*p4), "PPointUV");
+
+ /* reference point for item hull is the one with the lowest y value*/
+
+ /* Aspect Ratio compensation */
+ float bounds_height = phandle->aspy;
+ float bounds_width = phandle->aspx;
+
+ p1->x = item->verts[item->ref_vert_index]->x - item->min_v[0];
+ //printf("item_ref_x: %f, %f, min_v[0]: %f\n", item->verts[item->ref_vert_index]->x, item->verts[item->ref_vert_index]->y, item->min_v[0]);
+ p1->y = 0.0f;
+ nfp->final_pos[0] = p1;
+
+ p2->x = p1->x;
+ p2->y = bounds_height - (item->max_v[1] - item->min_v[1]); /* ToDo Saphires: ConvexHull should store relative bounds (width/height) ?*/
+ nfp->final_pos[1] = p2;
+
+ p3->x = bounds_width - (item->max_v[0] - item->min_v[0] - (item->verts[item->ref_vert_index]->x - item->min_v[0]));
+ p3->y = p2->y;
+ nfp->final_pos[2] = p3;
+
+ p4->x = p3->x;
+ p4->y = 0.0f;
+ nfp->final_pos[3] = p4;
+
+ /* CleanUp */
+ MEM_freeN(points);
+
+ return nfp;
+}
+
+static PConvexHull** p_decompose_triangulate_chart(PChart *chart, const float(*hull_points)[2], const int nbounds)
+{
+ int i, ntris = nbounds - 2;
+ unsigned int(*r_tris)[3] = BLI_array_alloca(r_tris, ntris);
+ float cur_tri[3][2];
+ /* ToDo Saphires: Could make this function void if we have the chart as parameter anyway */
+ PConvexHull **chull_tris = (PConvexHull **)MEM_mallocN(sizeof(PConvexHull *) * ntris, "PNFPs");
+ chart->u.ipack.ntris = ntris;
+
+ //printf("p_decompose_triangulate_chart!\n");
+
+ /* triangulate */
+ BLI_polyfill_calc((const float(*)[2])hull_points, nbounds, -1, r_tris);
+
+ /* write r_tris to convex hulls */
+ for (i = 0; i < ntris; i++){
+ cur_tri[0][0] = hull_points[r_tris[i][0]][0];
+ cur_tri[0][1] = hull_points[r_tris[i][0]][1];
+ //printf("p_decompose_triangulate_chart: tri[0]x: %f, y: %f\n", hull_points[r_tris[i][0]][0], hull_points[r_tris[i][0]][1]);
+
+ cur_tri[1][0] = hull_points[r_tris[i][1]][0];
+ cur_tri[1][1] = hull_points[r_tris[i][1]][1];
+ //printf("p_decompose_triangulate_chart: tri[0]x: %f, y: %f\n", hull_points[r_tris[i][1]][0], hull_points[r_tris[i][1]][1]);
+
+ cur_tri[2][0] = hull_points[r_tris[i][2]][0];
+ cur_tri[2][1] = hull_points[r_tris[i][2]][1];
+ //printf("p_decompose_triangulate_chart: tri[0]x: %f, y: %f\n", hull_points[r_tris[i][2]][0], hull_points[r_tris[i][2]][1]);
+
+ chull_tris[i] = p_convex_hull_new_tri(chart, cur_tri);
+ }
+
+ return chull_tris;
+}
+
+static bool p_point_inside_nfp(PNoFitPolygon *nfp, float p[2])
+{
+ /* raycast to the right of vert, odd number of intersections means inside */
+ int i, j, c = 0;
+
+ for (i = 0, j = nfp->nverts - 1; i < nfp->nverts; j = i++) {
+ if (((nfp->final_pos[i]->y > p[1]) != (nfp->final_pos[j]->y > p[1])) &&
+ (p[0] < (nfp->final_pos[j]->x - nfp->final_pos[i]->x) * (p[1] - nfp->final_pos[i]->y) / (nfp->final_pos[j]->y - nfp->final_pos[i]->y) + nfp->final_pos[i]->x))
+ c = !c;
+ }
+
+ return c;
+}
+
+static bool p_is_concave(PChart *chart, const float(*hull_points)[2], int nboundaries)
+{
+ if (nboundaries <= 4) {
+ //printf("<= 4 boundary edges, convex\n");
+ return false;
+ }
+
+ /* ToDo SaphireS */
+ if (is_poly_convex_v2((const float(*)[2])hull_points, nboundaries)){
+ //printf("is_poly_convex true, convex\n");
+ return false;
+ }
+ else {
+ //printf("is_poly_convex false, concave\n");
+ return true;
+ }
+}
+
+static bool p_temp_cfr_check(PNoFitPolygon **nfps, PNoFitPolygon *ifp, PPointUV *pp, int nfp_count, int index)
+{
+ float v1[2], v2[2], v3[2], p[2];
+ int i;
+
+ p[0] = pp->x;
+ p[1] = pp->y;
+
+ /* Make sure point is inside IFP */
+ if (p[0] < ifp->final_pos[0]->x ||
+ p[1] < ifp->final_pos[0]->y ||
+ p[0] > ifp->final_pos[2]->x ||
+ p[1] > ifp->final_pos[2]->y) {
+ /*printf("--end_pos outside IFP!\n");*/
+ return false;
+ }
+
+ /* Make sure point is outside other NFPs */
+ for (i = 0; i < nfp_count; i++) {
+ if (nfps[i] && (i != index)) {
+ if (nfps[i]->nverts == 3) {
+ v1[0] = nfps[i]->final_pos[0]->x;
+ v1[1] = nfps[i]->final_pos[0]->y;
+
+ v2[0] = nfps[i]->final_pos[1]->x;
+ v2[1] = nfps[i]->final_pos[1]->y;
+
+ v3[0] = nfps[i]->final_pos[2]->x;
+ v3[1] = nfps[i]->final_pos[2]->y;
+
+ /*if (p_triangle_inside_v3_v2(nfps[i]->final_pos[0],
+ nfps[i]->final_pos[1],
+ nfps[i]->final_pos[2], p)) {*/
+ if (p_triangle_inside_v3_v2(v1, v2, v3, p)) {
+ /*printf("--end_pos x: %f y: %f is inside nfps[%i]!\n", p[0], p[1], i);*/
+ return false;
+ }
+ }
+ else {
+ if (p_point_inside_nfp(nfps[i], p)) {
+ /*printf("--end_pos x: %f y: %f is inside nfps[%i]!\n", p[0], p[1], i);*/
+ return false;
+ }
+ }
+ }
+ }
+
+ printf("--end_pos inside IFP and outside of other NFPs!\n");
+ return true;
+}
+
+#ifndef RAND_NFP_POS
+static PNoFitPolygon *p_collision_free_region_create(PNoFitPolygon **nfps, PNoFitPolygon *ifp, int n_nfps)
+{
+ PNoFitPolygon *cfr = (PNoFitPolygon *)MEM_callocN(sizeof(*cfr), "PCollisionFreeRegion");
+ cfr->nverts = 100;
+ cfr->final_pos = (PVert **)MEM_mallocN(sizeof(PPointUV *) * cfr->nverts, "PNFPPoints");;
+ PPointUV *p;
+ int i, j, k = 0;
+ float pos[2];
+
+ for (i = 0; i <= n_nfps; i++) {
+ if (nfps[i]){
+ for (j = 0; j < nfps[i]->nverts; j++) {
+ p = nfps[i]->final_pos[j];
+ pos[0] = p->x;
+ pos[1] = p->y;
+ if (p_temp_cfr_check(nfps, ifp, pos, n_nfps, i)) {
+ /* Add point to CFR */
+ cfr->final_pos[k] = p;
+ k++;
+ if (k == (cfr->nverts - 1)) {
+ /* realloc */
+ cfr->nverts += 100;
+ cfr->final_pos = MEM_recallocN_id(cfr->final_pos, sizeof(PPointUV *) * cfr->nverts, "PNFPPoints");
+ }
+ }
+ }
+ }
+ }
+
+ /*for (i = k; i < cfr->nverts; i++) {
+ MEM_freeN(cfr->final_pos[i]);
+ } */
+
+ cfr->nverts = k;
+
+ /* ToDo SaphireS: Add intersection points of nfps */
+
+ return cfr;
+}
+#endif
+
+/* Make sure vert order for item is CCW and for fixed is CW! */
+static PNoFitPolygon *p_no_fit_polygon_create(PConvexHull *item, PConvexHull *fixed)
+{
+ PNoFitPolygon *nfp = (PNoFitPolygon *)MEM_callocN(sizeof(*nfp), "PNoFitPolygon");
+ nfp->nverts = item->nverts + fixed->nverts;
+ PVert **points = (PVert **)MEM_mallocN(sizeof(PVert *) * nfp->nverts, "PNFPPoints");
+ PPointUV **fpoints = (PPointUV **)MEM_mallocN(sizeof(PPointUV *) * nfp->nverts, "PNFPFPoints");
+ nfp->final_pos = (PPointUV **)MEM_callocN(sizeof(*nfp->final_pos) * nfp->nverts, "PNFPFinalPos");
+ int i, j;
+
+ /* Assign verts of hulls to NFP */
+ for (i = 0; i < nfp->nverts; i++) {
+ if (i < item->nverts) {
+ points[i] = item->h_verts[i];
+ fpoints[i] = item->verts[i];
+ }
+ else {
+ points[i] = fixed->h_verts[i - item->nverts];
+ fpoints[i] = fixed->verts[i - item->nverts];
+ }
+ }
+ //printf("-Assignment to points done\n");
+
+ /* sort edges according to horizontal angle, biggest to smallest */
+ /*qsort(points, (size_t)nfp->nverts, sizeof(PVert *), vert_anglesort);*/
+ qsort(fpoints, (size_t)nfp->nverts, sizeof(PPointUV *), point_anglesort);
+ //printf("-Sorting done\n");
+
+ for (i = 0; i < nfp->nverts; i++) {
+ /*printf("-- horizontal angle of points[%i]: %f\n", i, points[i]->edge->u.horizontal_angle);*/
+ //printf("-- horizontal angle of fpoints[%i]: %f\n", i, fpoints[i]->angle);
+ }
+
+ //printf("***item ref h_vertex: x: %f, y: %f\n", item->h_verts[item->ref_vert_index]->uv[0], item->h_verts[item->ref_vert_index]->uv[1]);
+ //printf("***fixed ref h_vertex: x: %f, y: %f\n", fixed->h_verts[fixed->ref_vert_index]->uv[0], fixed->h_verts[fixed->ref_vert_index]->uv[1]);
+ //printf("***item ref vertex: x: %f, y: %f\n", item->verts[item->ref_vert_index]->x, item->verts[item->ref_vert_index]->y);
+ //printf("***fixed ref vertex: x: %f, y: %f\n", fixed->verts[fixed->ref_vert_index]->x, fixed->verts[fixed->ref_vert_index]->y);
+
+
+ /* Minkowski sum computation */
+ //printf("-PPointUV creation started!\n");
+ PPointUV *p = (PPointUV *)MEM_callocN(sizeof(*p), "PPointUV");
+ p->x = fixed->verts[fixed->ref_vert_index]->x;
+ p->y = fixed->verts[fixed->ref_vert_index]->y;
+ //p = fixed->verts[fixed->ref_vert_index]; /* ToDo SaphireS: Good way? */
+ nfp->final_pos[0] = p;
+
+ for (j = 1; j < nfp->nverts; j++) {
+ PPointUV *p1 = (PPointUV *)MEM_callocN(sizeof(*p1), "PPointUV1");
+ p1->x = nfp->final_pos[j - 1]->x + fpoints[j - 1]->delta_edge[0];
+ p1->y = nfp->final_pos[j - 1]->y + fpoints[j - 1]->delta_edge[1];
+ nfp->final_pos[j] = p1;
+ }
+ //printf("-PPointUV creation done!\n");
+
+ for (i = 0; i < nfp->nverts; i++) {
+ //printf("--NFP Vert (offset == 0): x: %f, y: %f\n", nfp->final_pos[i]->x, nfp->final_pos[i]->y);
+ }
+
+ /* free memory */
+ MEM_freeN(points);
+ MEM_freeN(fpoints);
+
+ return nfp;
+}
+
+static void p_no_fit_polygon_delete(PNoFitPolygon *nfp)
+{
+ int i;
+ for (i = 0; i < nfp->nverts; i++) {
+ if (nfp->final_pos[i])
+ MEM_freeN(nfp->final_pos[i]);
+ }
+ MEM_freeN(nfp->final_pos);
+ MEM_freeN(nfp);
+}
+
+static void p_place_chart(PChart* item, PConvexHull *ch_item, PPointUV *pos)
+{
+ float cur_pos[2], trans[2];
+
+ cur_pos[0] = ch_item->verts[ch_item->ref_vert_index]->x;
+ cur_pos[1] = ch_item->verts[ch_item->ref_vert_index]->y;
+
+ //printf("-ref_vert x: %f\n", cur_pos[0]);
+ //printf("-ref_vert y: %f\n", cur_pos[1]);
+ //printf("-end_pos x: %f\n", pos->x);
+ //printf("-end_pos y: %f\n", pos->y);
+
+ trans[0] = cur_pos[0] - pos->x;
+ trans[1] = cur_pos[1] - pos->y;
+
+ trans[0] = -trans[0];
+ trans[1] = -trans[1];
+
+ p_chart_uv_translate(item, trans);
+ //printf("-translation done!\n");
+}
+
+static bool p_chart_pack_individual(PHandle *phandle, PChart *item, float margin)
+{
+ /* compute number of NFPs */
+ int num_nfp = 0, k;
+ for(k = 0; k < phandle->ncharts; k++) {
+ PChart *chart = phandle->charts[k];
+ if (chart->u.ipack.decomposed) {
+ num_nfp += chart->u.ipack.ntris;
+ }
+ else {
+ num_nfp++;
+ }
+ }
+ PNoFitPolygon **nfps = (PNoFitPolygon **)MEM_callocN(sizeof(PNoFitPolygon *) * (num_nfp + 1), "PNoFitPolygons");
+#ifndef RAND_NFP_POS
+ PNoFitPolygon *cfr;
+#endif
+ PConvexHull *ch_item = item->u.ipack.convex_hull;
+ PChart *fixed;
+ printf("end_pos create\n");
+ PPointUV *end_pos = (PPointUV *)MEM_callocN(sizeof(PPointUV *), "PPointUV end_pos");
+ float delta_edge[2], randf1, randf2, r = 0.0f;
+ int i, j, cur_nfp = 0, cur_iter = 0, max_iter = 100;
+ unsigned int rand1, rand2;
+ bool found = false, init = true;
+
+ /* Reverse winding direction of item convex hull */
+ /* ref_vert_index now contains the vert with the lowest y value */
+ PConvexHull *item_inv = p_convex_hull_reverse_direction(ch_item);
+
+ /* compute no fit polygons (NFPs) of item with already placed charts */
+ //printf("NFPs construction start!\n");
+ for (i = 0; i < phandle->ncharts; i++) {
+ fixed = phandle->charts[i];
+ /* ToDo SaphireS: Do not create NFP with self */
+ /*Since placed=false it won't happen, but may be better to make sure? */
+ if (fixed->u.ipack.convex_hull->placed) {
+ if (fixed->u.ipack.decomposed) {
+ for (j = 0; j < fixed->u.ipack.ntris; j++) {
+ PConvexHull *ch_fixed = fixed->u.ipack.tris[j];
+ PNoFitPolygon *nfp = p_no_fit_polygon_create(item_inv, ch_fixed);
+ nfps[cur_nfp] = nfp;
+ cur_nfp++;
+ }
+ init = false;
+ }
+ else {
+ PConvexHull *ch_fixed = fixed->u.ipack.convex_hull;
+ PNoFitPolygon *nfp = p_no_fit_polygon_create(item_inv, ch_fixed);
+ nfps[cur_nfp] = nfp;
+ cur_nfp++;
+ init = false;
+ }
+ }
+ else {
+ nfps[cur_nfp] = NULL;
+ cur_nfp++;
+ }
+ }
+ printf("NFPs construction done!\n");
+
+ /* compute inner fit polygon (IFP) */
+ //printf("IFP construction start!\n");
+ PNoFitPolygon *ifp = p_inner_fit_polygon_create(phandle, item_inv);
+ /*nfps[phandle->ncharts] = ifp;*/
+ nfps[cur_nfp] = ifp;
+ //printf("IFP construction done!\n");
+
+#ifndef RAND_NFP_POS
+ /* compute collsion free region (CFR) */
+ cfr = p_collision_free_region_create(nfps, ifp, phandle->ncharts);
+#endif
+
+ /* Choose placement point */
+ if (init) {
+ /* First item, place in bottom left corner */
+ end_pos->x = ifp->final_pos[0]->x;
+ end_pos->y = ifp->final_pos[0]->y;
+ //printf("Placing initial chart according to IFP!\n");
+ found = true;
+ }
+ else {
+#ifdef RAND_NFP_POS
+ while (!found) {
+ /* Old method, randomly choosing a point */
+ cur_iter++;
+ randf1 = BLI_rng_get_float(phandle->rng);
+ //rand1 = p_float_to_int_range(item->u.ipack.sa_params[1], phandle->ncharts + 1);
+ /*rand1 = p_float_to_int_range(randf1, phandle->ncharts + 1);*/
+ rand1 = p_float_to_int_range(randf1, cur_nfp + 1);
+ /*printf("-rand1 choosen as: %i\n", rand1);*/
+ if (nfps[rand1]) {
+
+ randf2 = BLI_rng_get_float(phandle->rng);
+ //rand2 = p_float_to_int_range(item->u.ipack.sa_params[2], nfps[rand1]->nverts); /* ToDo: Actual point amount in cfr */
+ //rand2 = p_float_to_int_range(randf2, nfps[rand1]->nverts);
+ r = 0.0f;
+ rand2 = p_float_to_int_range_remainder(randf2, nfps[rand1]->nverts, &r);
+ /*printf("--rand2 choosen as: %i, r as %f\n", rand2, r);*/
+
+ if (nfps[rand1]->final_pos[rand2]) {
+ /* Account for sliding along edges here to cover all possible placements */
+ if(rand2 == (nfps[rand1]->nverts - 1)){
+ delta_edge[0] = nfps[rand1]->final_pos[0]->x - nfps[rand1]->final_pos[rand2]->x;
+ delta_edge[1] = nfps[rand1]->final_pos[0]->y - nfps[rand1]->final_pos[rand2]->y;
+ }
+ else {
+ delta_edge[0] = nfps[rand1]->final_pos[rand2 + 1]->x - nfps[rand1]->final_pos[rand2]->x;
+ delta_edge[1] = nfps[rand1]->final_pos[rand2 + 1]->y - nfps[rand1]->final_pos[rand2]->y;
+ }
+
+ end_pos->x = nfps[rand1]->final_pos[rand2]->x + delta_edge[0] * r;
+ end_pos->y = nfps[rand1]->final_pos[rand2]->y + delta_edge[1] * r;
+
+ found = p_temp_cfr_check(nfps, ifp, end_pos, cur_nfp, rand1);
+ }
+ }
+
+ if (cur_iter >= max_iter) {
+ found = false;
+ break;
+ }
+ }
+#endif
+#ifndef RAND_NFP_POS
+ /* New method, cfr */
+ rand1 = p_float_to_int_range(item->u.ipack.sa_params[2], cfr->nverts);
+
+ if (cfr->final_pos[rand1]) {
+ end_pos[0] = cfr->final_pos[rand1]->x;
+ end_pos[1] = cfr->final_pos[rand1]->y;
+ found = true;
+ }
+ else {
+ printf("Error: cfr->final_pos[%i] doesn't exist!\n", rand1);
+ break;
+ }
+#endif
+ }
+
+ if (found) {
+ if (!init) {
+ printf("--found placement for rand1: %i, rand2: %i, r as %f\n", rand1, rand2, r);
+ }
+
+ /* Place chart */
+ p_place_chart(item, item_inv, end_pos);
+
+ /* ToDo SaphireS: Verify placement? */
+ ch_item->placed = true;
+ if (item->u.ipack.decomposed){
+ for (i = 0; i < item->u.ipack.ntris; i++) {
+ item->u.ipack.tris[i]->placed = true;
+ }
+ }
+ }
+
+ /* delete temporary inversed convex hull */
+ p_convex_hull_delete(item_inv);
+ p_convex_hull_restore_direction(ch_item, margin);
+ if (item->u.ipack.decomposed){
+ for (i = 0; i < item->u.ipack.ntris; i++){
+ PConvexHull *tri = item->u.ipack.tris[i];
+ p_convex_hull_restore_direction(tri, margin);
+ }
+ }
+ printf("-restoring angles/edges done!\n");
+
+ /* CleanUp, pay attention to also delete IFP which is part of nfps */
+#ifndef RAND_NFP_POS
+ MEM_freeN(cfr);
+#endif
+ MEM_freeN(end_pos);
+
+ for (j = 0; j <= num_nfp; j++) {
+ if (nfps[j]) {
+ p_no_fit_polygon_delete(nfps[j]);
+ }
+ }
+ MEM_freeN(nfps);
+ printf("-freeing stuff done!\n");
+ p_flush_uvs(phandle, item); /* ToDo SaphireS: Needs update to work ... */
+
+ return found;
+}
+
+static float p_scale_binary_search(PHandle *phandle, PChart *chart, float val, float range, int depth, float abs_scale, float found, float margin)
+{
+ float range1, val1;
+
+ if (depth--) {
+ p_chart_uv_scale_origin(chart, val);
+ p_convex_hull_update_all(chart->u.ipack.convex_hull, margin);
+
+ abs_scale *= val;
+
+ if (!(p_chart_pack_individual(phandle, chart, margin))) {
+ /*scale down */
+ //printf("-no placement found for scale: %f, trying scaling down\n", val);
+ range1 = range * 0.5f;
+ val1 = 1.0f - range1;
+
+ return p_scale_binary_search(phandle, chart, val1, range1, depth, abs_scale, found, margin);
+ }
+ else {
+ /* scale up */
+ //printf("-placement found for scale: %f, trying scaling up\n", val);
+ range1 = range * 0.5f;
+ val1 = 1.0f + range;
+ found = abs_scale;
+
+ return p_scale_binary_search(phandle, chart, val1, range1, depth, abs_scale, found, margin);
+ }
+ }
+ else {
+ printf("-scale factor found: %f\n", (found / abs_scale));
+ p_chart_uv_scale_origin(chart, 1.0f / (found / abs_scale)); // = abs_scale / found
+ p_convex_hull_update_all(chart->u.ipack.convex_hull, margin);
+
+ return (found / abs_scale);
+ }
+}
+
+static float p_binary_depth_search(PHandle *phandle, PChart *chart, int depth, float margin)
+{
+ float value = 0.5f, abs_scale = chart->u.ipack.last_scale/*1.0f*/, found = 1.0f;
+
+ return p_scale_binary_search(phandle, chart, value, value, depth, abs_scale, found, margin);
+}
+
+static bool p_compute_packing_solution(PHandle *phandle, float margin /* ToDo SaphireS: Simulated Annealing parameters */)
+{
+ PChart *chart;
+ int i, j;
+ int depth = 4;
+
+ /* Place UV islands one by one */
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+ float scale = 1.0f;
+
+ //printf("p_compute_packing_solution: chart[%i] with area %f:\n", i, chart->u.ipack.area);
+
+ if (chart->u.ipack.decomposed) {
+ if (!(chart->u.ipack.tris[0]->placed)) {
+ if (!p_chart_pack_individual(phandle, chart, margin)) {
+ /* binary depth search for scaling down the current chart */
+ scale = p_binary_depth_search(phandle, chart, depth, margin);
+ chart->u.ipack.last_scale *= scale;
+ printf("p_binary_depth_search() done, scale = %f! \n", scale);
+
+ /* ToDo SaphireS: Avoid recomputation, store placement/scale of best solution from binary depth search! */
+ /* scale chart */
+ p_chart_uv_scale_origin(chart, scale);
+ for (j = 0; j < chart->u.ipack.ntris; j++) {
+ PConvexHull *hull = chart->u.ipack.tris[j];
+
+ p_convex_hull_update_all(hull, margin);
+
+ p_chart_pack_individual(phandle, chart, margin);
+ hull->placed = true;
+ }
+ }
+ }
+ }
+ else {
+ if (!(chart->u.ipack.convex_hull->placed)) {
+ if (!p_chart_pack_individual(phandle, chart, margin)) {
+ /* binary depth search for scaling down the current chart */
+ scale = p_binary_depth_search(phandle, chart, depth, margin);
+ chart->u.ipack.last_scale *= scale;
+ printf("p_binary_depth_search() done, scale = %f! \n", scale);
+
+ /* ToDo SaphireS: Avoid recomputation, store placement/scale of best solution from binary depth search! */
+ /* scale chart */
+ p_chart_uv_scale_origin(chart, scale);
+
+ p_convex_hull_update(chart->u.ipack.convex_hull, true);
+
+ p_chart_pack_individual(phandle, chart, margin);
+ chart->u.ipack.convex_hull->placed = true;
+ }
+ }
+ }
+ }
+
+ /* Un-set placed property of charts so next iteration works as expected */
+ /*for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+ chart->u.ipack.convex_hull->placed = false;
+ }*/
+
+ return true;
+}
+
+void param_irregular_pack_begin(ParamHandle *handle, float *w_area, float margin, int rot_step, bool concave)
+{
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart;
+ PEdge *outer, *e;
+ PFace *f;
+ int i, j, nboundaries = 0;
+ unsigned int seed = 31415925;
+ float used_area, init_scale, init_value = 0.6f, randf1, rot;
+
+ param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
+ phandle->state = PHANDLE_STATE_PACK;
+
+ /* Initializations */
+ phandle->rng = BLI_rng_new(seed);
+ used_area = p_face_uv_area_combined(handle);
+ init_scale = init_value / used_area;
+ printf("init_scale: %f\n", init_scale);
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+
+ /* Back up UVs */
+ for (f = chart->faces; f; f = f->nextlink) {
+ p_face_backup_uvs(f);
+ }
+
+ /* Set initial scale of charts */
+ /* ToDo: Do this in p_compute_packing_solution */
+ /*p_chart_uv_scale_origin(chart, init_scale); */
+
+ /* Initial random Simulated Annealing parameters*/
+ randf1 = BLI_rng_get_float(phandle->rng);
+ chart->u.ipack.sa_params[0] = randf1; /* theta */
+ //printf("-init theta for chart[%i]: %f\n", i, chart->u.ipack.sa_params[0]);
+ randf1 = BLI_rng_get_float(phandle->rng);
+ chart->u.ipack.sa_params[1] = randf1; /* m */
+ //printf("-init m for chart[%i]: %f\n", i, chart->u.ipack.sa_params[1]);
+ randf1 = BLI_rng_get_float(phandle->rng);
+ chart->u.ipack.sa_params[2] = randf1; /* f */
+ //printf("-init f for chart[%i]: %f\n", i, chart->u.ipack.sa_params[2]);
+
+ /* Initial rotation */
+ rot = (int)(chart->u.ipack.sa_params[0] * (float)rot_step) * (2 * M_PI / (float)rot_step);
+ //printf("init rot for chart[%i]: %f\n", i, rot);
+ p_chart_uv_rotate_origin(chart, rot);
+
+ /* Get boundaries of chart*/
+ /* Find initial boundary edge */
+
+ nboundaries = 0;
+ p_chart_boundaries(chart, NULL, &outer);
+ if (!outer) {
+ /* ToDo Saphires: BKE_report(..) */
+ printf("Warning: p_chart_boundaries: No boundary edge found for chart %i!\n", i);
+ chart->u.ipack.convex_hull = p_convex_hull_new(chart);
+ chart->u.ipack.convex_hull->placed = true;
+ chart->u.ipack.decomposed = false;
+ break;
+ }
+
+ /* Get number of boundary edges */
+ e = outer;
+ do {
+ nboundaries++;
+ e = p_boundary_edge_next(e);
+ } while (e != outer);
+
+ //printf("number of boundary edges: %i\n", nboundaries);
+ PVert **bounds = (PVert **)MEM_mallocN(sizeof(PVert *) * nboundaries, "PCHullpoints");
+ float(*hullverts)[2] = BLI_array_alloca(hullverts, nboundaries);
+
+ /* Get boundary verts */
+ e = outer;
+ j = 0;
+ do {
+ bounds[j] = e->vert;
+ hullverts[j][0] = e->vert->uv[0];
+ hullverts[j][1] = e->vert->uv[1];
+ /*printf(">>bounds: vert x: %f, y: %f\n", bounds[j]->uv[0], bounds[j]->uv[1]);
+ printf(">-hullverts x: %f, y: %f\n", hullverts[j][0], hullverts[j][1]);*/
+ j++;
+ e = p_boundary_edge_next(e);
+ } while (e != outer);
+
+ /* Start computation of hull(s) for chart ---------------------------*/
+ /* Determine if chart is concave or convex */
+ if (concave && p_is_concave(chart, (const float(*)[2])hullverts, nboundaries)) {
+ //printf("Entered concave execution path\n");
+ /* Decompose concave hull into convex hulls and store within chart */
+ chart->u.ipack.tris = p_decompose_triangulate_chart(chart, (const float(*)[2])hullverts, nboundaries);
+ chart->u.ipack.decomposed = true;
+ chart->u.ipack.convex_hull = p_convex_hull_new(chart);
+ chart->u.ipack.best_pos = MEM_callocN(sizeof(PPointUV), "PPointUV");
+ //printf("--chart decomposed into %i tris\n", chart->u.ipack.ntris);
+
+ /* For each convex hull: */
+ for (j = 0; j < chart->u.ipack.ntris; j++) {
+ PConvexHull *hull = chart->u.ipack.tris[j];
+
+ /* Apply margin */
+ if (!(compare_ff(margin, 0.0f, 0.0001f))) {
+ p_convex_hull_grow(hull, margin);
+ p_convex_hull_update(hull, false);
+ }
+
+ /* Compute horizontal angle for edges of hull (Needed for NFP) */
+ p_convex_hull_compute_horizontal_angles(hull);
+ /* Compute edge lengths */
+ p_convex_hull_compute_edge_components(hull);
+
+ /* ToDo SaphireS: turn last few steps into a reusable function for cleaner code */
+ }
+
+ //printf("Bounds of chart [%i]: minx: %f, maxx: %f, miny: %f,maxy: %f\n", i, chart->u.ipack.convex_hull->min_v[0], chart->u.ipack.convex_hull->max_v[0], chart->u.ipack.convex_hull->min_v[1], chart->u.ipack.convex_hull->max_v[1]);
+ /*chart->u.ipack.convex_hull = NULL;*/ /* ToDo SaphireS: Unifiy tris and convex_hull */
+ }
+ else {
+ //printf("Entered convex execution path\n");
+ /* Compute convex hull for each chart -> CW */
+ chart->u.ipack.convex_hull = p_convex_hull_new(chart);
+ chart->u.ipack.decomposed = false;
+ chart->u.ipack.best_pos = MEM_callocN(sizeof(PPointUV), "PPointUV");
+
+ /* Apply margin here */
+ if (!(compare_ff(margin, 0.0f, 0.0001f))) {
+ p_convex_hull_grow(chart->u.ipack.convex_hull, margin);
+ p_convex_hull_update(chart->u.ipack.convex_hull, false);
+ }
+
+ /* Compute horizontal angle for edges of hull (Needed for NFP) */
+ p_convex_hull_compute_horizontal_angles(chart->u.ipack.convex_hull);
+ /* Compute edge lengths */
+ p_convex_hull_compute_edge_components(chart->u.ipack.convex_hull);
+
+ /* DEBUG */
+ //printf("Bounds of chart [%i]: minx: %f, maxx: %f, miny: %f,maxy: %f\n", i, chart->u.ipack.convex_hull->min_v[0], chart->u.ipack.convex_hull->max_v[0], chart->u.ipack.convex_hull->min_v[1], chart->u.ipack.convex_hull->max_v[1]);
+
+ chart->u.ipack.tris = NULL; /* ToDo SaphireS: Unifiy tris and convex_hull */
+ }
+
+ chart->u.ipack.area = p_chart_uv_area_signed(chart); /* used for sorting */
+
+ MEM_freeN(bounds);
+ }
+
+ /* Sort UV islands by area */
+ qsort(phandle->charts, (size_t)phandle->ncharts, sizeof(PChart *), chart_areasort);
+
+ if (p_compute_packing_solution(phandle, margin)) {
+ printf("Initial packing solution found---------------------------------------------\n");
+ }
+
+ used_area = p_face_uv_area_combined(handle);
+
+ /* ToDo(SaphireS): Account for aspect ratio != 1 */
+ *w_area = 1.0f - used_area;
+}
+
+void param_irregular_pack_iter(ParamHandle *handle, float *w_area, unsigned int seed, int rot_step, float margin)
+{
+ PHandle *phandle = (PHandle *)handle;
+ PChart* chart;
+ float randf, rot, rand_value, rot_rand, place_rand, upscale_fac = 1.5f;
+ int rand_chart, rand_param, i;
+
+ BLI_rng_seed(phandle->rng, seed);
+
+ printf("starting param_irregular_pack_iter-----------------------------\n");
+
+ param_assert(phandle->state == PHANDLE_STATE_PACK);
+
+ /* packing solution for random part, based on last solution */
+ randf = BLI_rng_get_float(phandle->rng);
+ rand_chart = p_float_to_int_range(randf, phandle->ncharts);
+ chart = phandle->charts[rand_chart];
+ chart->u.ipack.convex_hull->placed = false;
+ if (chart->u.ipack.decomposed) {
+ for (i = 0; i < chart->u.ipack.ntris; i++){
+ chart->u.ipack.tris[i]->placed = false;
+ }
+ }
+
+ /* Set initial scale of charts so finding a better solution is possible */
+ p_chart_uv_scale_origin(chart, upscale_fac); /* ToDo SaphireS: Find best upscale_fac value */
+ chart->u.ipack.last_scale = upscale_fac;
+ p_convex_hull_update_all(chart->u.ipack.convex_hull, margin);
+
+ /* Set random SA parameter of chosen chart to new value */
+ randf = BLI_rng_get_float(phandle->rng);
+ rand_param = p_float_to_int_range(randf, 3); /* 0 = theta, 1 = m, 2 = f */
+ rand_value = BLI_rng_get_float(phandle->rng);
+ rand_value -= 0.5f;
+
+ if (rand_param == 0) {
+ rot_rand = fabsf(remainderf(chart->u.ipack.sa_params[0] + rand_value, 1.0f));
+ printf("SA param rot_rand for chart[%i]: %f\n", rand_chart, rot_rand);
+ rot = (int)(rot_rand * (float)rot_step) * (2 * M_PI / (float)rot_step);
+ printf("SA param rot for chart[%i]: %f\n", rand_chart, rot);
+ //p_chart_uv_rotate_origin(chart, rot);
+ p_convex_hull_update_all(chart->u.ipack.convex_hull, margin);
+
+ if (chart->u.ipack.decomposed) {
+ for (i = 0; i < chart->u.ipack.ntris; i++){
+ PConvexHull *tri = chart->u.ipack.tris[i];
+ p_convex_hull_update_all(tri, margin);
+ }
+ }
+ }
+ else {
+ place_rand = fabsf(remainderf(chart->u.ipack.sa_params[2] + rand_value, 1.0f));
+ chart->u.ipack.sa_params[2] = place_rand;
+ printf("SA param place_rand for chart[%i]: %f\n", rand_chart, place_rand);
+ }
+
+ /* Find placement for part */
+ if (p_compute_packing_solution(phandle, margin)) {
+ printf("packing solution found---------------------------------------------\n");
+ }
+
+ float used_area = p_face_uv_area_combined(handle);
+
+ /* ToDo(SaphireS): Account for aspect ratio != 1 */
+ *w_area = 1.0f - used_area;
+
+}
+
+void param_irregular_pack_end(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart;
+ int i, j;
+
+ param_assert(phandle->state == PHANDLE_STATE_PACK);
+ phandle->state = PHANDLE_STATE_CONSTRUCTED;
+
+ /* ToDo (SaphireS) */
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+ MEM_freeN(chart->u.ipack.best_pos);
+
+ if (chart->u.ipack.decomposed){
+ for (j = 0; j < chart->u.ipack.ntris; j++) {
+ p_convex_hull_delete(chart->u.ipack.tris[j]);
+ }
+ MEM_freeN(chart->u.ipack.tris);
+ }
+
+ p_convex_hull_delete(chart->u.ipack.convex_hull);
+ }
+
+ BLI_rng_free(phandle->rng);
+ phandle->rng = NULL;
+}
+
void param_average(ParamHandle *handle)
{
PChart *chart;
@@ -4669,6 +6295,248 @@ void param_scale(ParamHandle *handle, float x, float y)
}
}
+void param_scale_bounds(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart;
+ int i;
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+
+ float tot_width, tot_height, scale;
+ float minv[2], maxv[2], trans[2];
+
+ /* Compute bounds of chart */
+ p_chart_uv_bbox(chart, minv, maxv);
+
+ /* Move center to 0,0 */
+ trans[0] = (minv[0] + maxv[0]) / -2.0f;
+ trans[1] = (minv[1] + maxv[1]) / -2.0f;
+ p_chart_uv_translate(chart, trans);
+
+ /* Compute width/height of bounds */
+ if (signf(minv[0]) != signf(maxv[0]))
+ tot_width = fabsf(minv[0]) + fabsf(maxv[0]);
+ else
+ tot_width = maxv[0] - minv[0];
+
+ if (signf(minv[1]) != signf(maxv[1]))
+ tot_height = fabsf(minv[1]) + fabsf(maxv[1]);
+ else
+ tot_height = maxv[1] - minv[1];
+
+ if (tot_height >= tot_width)
+ scale = phandle->aspy / tot_height;
+ else
+ scale = phandle->aspx / tot_width;
+
+ /* Scale to fit UV area */
+ p_chart_uv_scale(chart, scale);
+
+ /* Move chart to center of UV Space*/
+ trans[0] = phandle->aspx / 2.0f;
+ trans[1] = phandle->aspy / 2.0f;
+ p_chart_uv_translate(chart, trans);
+ }
+}
+
+static void p_verttag_add_adjacent(Heap *heap, PVert *v_a, PVert **v_prev,
+ float *cost, bool use_topology_distance)
+{
+ const int v_a_index = v_a->u.id;
+ PEdge *e, *we, *lastwe = NULL;
+ e = v_a->edge;
+
+ /* rewind to start */
+ lastwe = e;
+ for (we = p_wheel_edge_prev(e); we && (we != e); we = p_wheel_edge_prev(we)) {
+ lastwe = we;
+ }
+
+ we = lastwe;
+ do {
+ PVert *v_b = we->next->vert;
+ if (!(v_b->flag & PVERT_MARKED) && !(we->flag & PEDGE_DIAG )) {
+ /* v_b not visited yet, check it out! */
+ const int v_b_index = v_b->u.id;
+ const float cost_cut = use_topology_distance ? 1.0f : len_v2v2(v_a->uv, v_b->uv);
+ const float cost_new = cost[v_a_index] + cost_cut;
+
+ if (cost[v_b_index] > cost_new) {
+ cost[v_b_index] = cost_new;
+ v_prev[v_b_index] = v_a;
+ BLI_heap_insert(heap, cost_new, v_b);
+ }
+ }
+
+ we = p_wheel_edge_next(we);
+ } while (we && (we != lastwe));
+}
+
+static LinkNode *p_calc_path_vert(PChart *chart, PVert *src, PVert *dst, bool topological_distance)
+{
+ LinkNode *path = NULL;
+ Heap *heap;
+ PVert *vert;
+ PVert **verts_prev;
+ float *cost;
+ int totvert, index;
+
+ /* Clear flags, assign index */
+ for (vert = chart->verts, index = 0; vert; vert = vert->nextlink, index++) {
+ vert->flag &= ~PVERT_MARKED;
+ vert->u.id = index; /* Re-use lscm id field */
+ }
+
+ /* alloc */
+ totvert = chart->nverts;
+ verts_prev = MEM_callocN(sizeof(*verts_prev) * totvert, __func__);
+ cost = MEM_mallocN(sizeof(*cost) * totvert, __func__);
+
+ copy_vn_fl(cost, totvert, 1e20f);
+
+ /* regular dijkstra shortest path */
+ heap = BLI_heap_new();
+ BLI_heap_insert(heap, 0.0f, src);
+ cost[src->u.id] = 0.0f;
+
+ while (!BLI_heap_is_empty(heap)) {
+ vert = BLI_heap_popmin(heap);
+
+ if (vert == dst) {
+ break;
+ }
+
+ if (!(vert->flag & PVERT_MARKED)) {
+ vert->flag |= PVERT_MARKED;
+ p_verttag_add_adjacent(heap, vert, verts_prev, cost, topological_distance);
+ }
+ }
+
+ if (vert == dst) {
+ do {
+ BLI_linklist_prepend(&path, vert);
+ } while (vert = verts_prev[vert->u.id]);
+ }
+
+ MEM_freeN(verts_prev);
+ MEM_freeN(cost);
+ BLI_heap_free(heap, NULL);
+
+ return path;
+}
+
+static void p_vert_select_edges(PVert *v)
+{
+ v->flag |= PVERT_SELECT;
+ PEdge *e = v->edge;
+ e->flag |= PEDGE_SELECT;
+
+ /* rewind to start */
+ PEdge *we, *lastwe = e;
+ for (we = p_wheel_edge_prev(e); we && (we != e); we = p_wheel_edge_prev(we)) {
+ lastwe = we;
+ }
+
+ we = lastwe;
+ do {
+
+ we->flag |= PEDGE_SELECT;
+ PVert *v_e = we->vert;
+ v_e->flag |= PVERT_SELECT;
+ we = p_wheel_edge_next(we);
+
+ } while (we && (we != lastwe));
+}
+
+void param_shortest_path(ParamHandle *handle, bool *p_found, bool topological_distance)
+{
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart, *current_chart = 0;
+ PVert *v, *vert_src = NULL, *vert_dst = NULL;
+ int i;
+ bool success = false;
+
+ if (phandle->ncharts == 0) {
+ *p_found = success;
+ return;
+ }
+
+ /* Get src and dst */
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+
+ for (v = chart->verts; v; v = v->nextlink) {
+
+ if (v->flag & PVERT_SELECT) {
+
+ if (vert_src == NULL) {
+ vert_src = v;
+ current_chart = chart;
+ }
+ else if (vert_dst == NULL) {
+ if (current_chart == chart) {
+ vert_dst = v;
+ }
+ }
+ }
+ }
+ }
+
+ /* Connect src and dst */
+ LinkNode *path = NULL;
+ if (vert_src && vert_dst) {
+
+ path = p_calc_path_vert(current_chart, vert_src, vert_dst, topological_distance);
+
+ if (path) {
+ LinkNode *node = NULL;
+ node = path;
+
+ do {
+ PVert *v1 = node->link;
+ p_vert_select_edges(v1);
+ } while (node = node->next);
+
+ success = true;
+ BLI_linklist_free(path, NULL);
+ }
+ }
+
+ *p_found = success;
+}
+
+void param_select_overlapping(ParamHandle *handle, const bool extend)
+{
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart1, *chart2;
+ int i, j;
+
+ /* deselect charts */
+ if (!extend)
+ {
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart1 = phandle->charts[i];
+ p_chart_select(chart1, false);
+ }
+ }
+
+ /* Check charts for intersections/overlaps */
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart1 = phandle->charts[i];
+
+ for (j = 0; j < phandle->ncharts; j++) {
+ chart2 = phandle->charts[j];
+ if ((i != j) && p_charts_intersect(chart1, chart2)) {
+ /* select charts */
+ p_chart_select(chart1, true);
+ p_chart_select(chart2, true);
+ }
+ }
+ }
+}
+
void param_flush(ParamHandle *handle)
{
PHandle *phandle = (PHandle *)handle;
@@ -4688,6 +6556,26 @@ void param_flush(ParamHandle *handle)
}
}
+/* Use this function if you need to flush position + selection tags */
+void param_flush_sel(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart;
+ int i;
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+
+ if ((phandle->state == PHANDLE_STATE_LSCM) && !chart->u.lscm.context)
+ continue;
+
+ if (phandle->blend == 0.0f)
+ p_flush_uvs_selection(phandle, chart);
+ else
+ p_flush_uvs_blend(phandle, chart, phandle->blend);
+ }
+}
+
void param_flush_restore(ParamHandle *handle)
{
PHandle *phandle = (PHandle *)handle;
@@ -4703,3 +6591,110 @@ void param_flush_restore(ParamHandle *handle)
}
}
+void param_accept_placement_all(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle *)handle;
+ PConvexHull *chull;
+ int i;
+ printf("param_store_packing_solution\n");
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ PChart *chart = phandle->charts[i];
+ chull = chart->u.ipack.convex_hull;
+ /*chart->u.ipack.best_pos->x = chull->h_verts[chull->ref_vert_index]->uv[0];
+ chart->u.ipack.best_pos->y = chull->h_verts[chull->ref_vert_index]->uv[1];*/
+ chart->u.ipack.best_pos->x = chull->verts[chull->ref_vert_index]->x;
+ chart->u.ipack.best_pos->y = chull->verts[chull->ref_vert_index]->y;
+ chart->u.ipack.last_scale = 1.f;
+ }
+}
+
+void param_accept_placement(PChart *chart)
+{
+ PConvexHull *chull = chart->u.ipack.convex_hull;
+ int i;
+ printf("param_store_packing_solution\n");
+
+ /*chart->u.ipack.best_pos->x = chull->h_verts[chull->ref_vert_index]->uv[0];
+ chart->u.ipack.best_pos->y = chull->h_verts[chull->ref_vert_index]->uv[1];*/
+ chart->u.ipack.best_pos->x = chull->verts[chull->ref_vert_index]->x;
+ chart->u.ipack.best_pos->y = chull->verts[chull->ref_vert_index]->y;
+ chart->u.ipack.last_scale = 1.f;
+}
+
+
+void param_restore_placement(ParamHandle *handle, float margin)
+{
+ PHandle *phandle = (PHandle *)handle;
+ PConvexHull *chull;
+ float trans[2], cur_pos[2], scale_fac;
+ int i;
+ printf("param_restore_packing_solution\n");
+
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ PChart *chart = phandle->charts[i];
+ chull = chart->u.ipack.convex_hull;
+
+ if (chart->u.ipack.last_scale != 1.f) {
+ scale_fac = 1.f / chart->u.ipack.last_scale;
+ printf("scale_fac for chart[%i]: %f\n", i, scale_fac);
+
+ p_chart_uv_scale_origin(chart, scale_fac);
+ p_convex_hull_update(chart->u.ipack.convex_hull, true);
+ p_convex_hull_grow(chart->u.ipack.convex_hull, margin);
+ p_convex_hull_update(chart->u.ipack.convex_hull, false);
+ p_convex_hull_compute_horizontal_angles(chart->u.ipack.convex_hull); /* ToDo: Shouldn't be necessary! */
+ p_convex_hull_compute_edge_components(chart->u.ipack.convex_hull);
+ chart->u.ipack.last_scale = 1.f;
+
+ /*cur_pos[0] = chull->h_verts[chull->ref_vert_index]->uv[0];
+ cur_pos[1] = chull->h_verts[chull->ref_vert_index]->uv[1];*/
+ cur_pos[0] = chull->verts[chull->ref_vert_index]->x;
+ cur_pos[1] = chull->verts[chull->ref_vert_index]->y;
+
+ trans[0] = chart->u.ipack.best_pos->x - cur_pos[0];
+ trans[1] = chart->u.ipack.best_pos->y - cur_pos[1];
+
+ p_chart_uv_translate(chart, trans);
+ }
+ }
+}
+
+/* XXX (SaphireS): Remove */
+void param_test(ParamHandle *handle)
+{
+ /* TEST STUFF */
+ printf("param_test() reached!\n");
+
+ float area = p_face_uv_area_combined(handle);
+
+ PHandle *phandle = (PHandle *)handle;
+ PChart *chart;
+ PConvexHull *hull;
+ int i, j;
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+
+ chart->u.ipack.convex_hull = p_convex_hull_new(chart);
+ hull = chart->u.ipack.convex_hull;
+ printf("convex hull for chart %i done!\n", i);
+
+ for (j = 0; j < hull->nverts; j++) {
+ printf("--PVert of convex hull - x: %f, y: %f\n", hull->h_verts[j]->uv[0], hull->h_verts[j]->uv[1]);
+ printf("-+PPointUV of convex hull - x: %f, y: %f\n", hull->verts[j]->x, hull->verts[j]->y);
+ }
+
+ printf("p_convex_hull_grow()\n");
+ p_convex_hull_grow(hull, 0.1f);
+
+ for (j = 0; j < hull->nverts; j++) {
+ printf("--PVert of convex hull - x: %f, y: %f\n", hull->h_verts[j]->uv[0], hull->h_verts[j]->uv[1]);
+ printf("-+PPointUV of convex hull - x: %f, y: %f\n", hull->verts[j]->x, hull->verts[j]->y);
+ }
+
+ p_convex_hull_delete(hull);
+ }
+
+ printf("used uv charts area: %f\n", area);
+}
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.h b/source/blender/editors/uvedit/uvedit_parametrizer.h
index eaea781971d..9764d3551f7 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.h
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.h
@@ -1,3 +1,4 @@
+
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
@@ -63,7 +64,8 @@ void param_face_add(ParamHandle *handle,
float *uv[4],
ParamBool *pin,
ParamBool *select,
- float face_normal[3]);
+ float face_normal[3],
+ int **flag);
void param_edge_set_seam(ParamHandle *handle,
ParamKey *vkeys);
@@ -101,6 +103,15 @@ void param_smooth_area(ParamHandle *handle);
void param_pack(ParamHandle *handle, float margin, bool do_rotate);
+/* Packing 2.0 */
+
+void param_irregular_pack_begin(ParamHandle *handle, float *w_area, float margin, int rot_step, bool concave);
+void param_irregular_pack_iter(ParamHandle *handle, float *w_area, unsigned int seed, int rot_step, float margin);
+void param_irregular_pack_end(ParamHandle *handle);
+void param_accept_placement_all(ParamHandle *handle);
+//void param_accept_placement(PChart *chart);
+void param_restore_placement(ParamHandle *handle, float margin);
+
/* Average area for all charts */
void param_average(ParamHandle *handle);
@@ -109,11 +120,26 @@ void param_average(ParamHandle *handle);
void param_scale(ParamHandle *handle, float x, float y);
+/* Scale to bounds */
+
+void param_scale_bounds(ParamHandle *handle);
+
+/* Select shortest Path */
+
+void param_shortest_path(ParamHandle *handle, bool *p_found, bool topological_distance);
+
+/* Select Overlapping */
+
+void param_select_overlapping(ParamHandle *handle, const bool extend);
+
/* Flushing */
void param_flush(ParamHandle *handle);
+void param_flush_sel(ParamHandle *handle);
void param_flush_restore(ParamHandle *handle);
+/* XXX (SaphireS): Remove */
+void param_test(ParamHandle *handle);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index d8080002818..719b5c78926 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -46,6 +46,7 @@
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_uvproject.h"
#include "BLI_string.h"
@@ -82,6 +83,20 @@
#include "uvedit_intern.h"
#include "uvedit_parametrizer.h"
+static int set_handle_params(bool implicit, bool fill_holes, bool selected, bool correct_aspect, bool all_faces)
+{
+ int hparams = 0;
+
+ /* Set flags fpr handle_params */
+ if (implicit) hparams |= HANDLE_IMPLICIT;
+ if (fill_holes) hparams |= HANDLE_FILL;
+ if (selected) hparams |= HANDLE_SELECTED;
+ if (correct_aspect) hparams |= HANDLE_CORRECT_ASPECT;
+ if (all_faces) hparams |= HANDLE_ALL_FACES;
+
+ return hparams;
+}
+
static void modifier_unwrap_state(Object *obedit, Scene *scene, bool *r_use_subsurf)
{
ModifierData *md;
@@ -235,6 +250,7 @@ static void construct_param_handle_face_add(ParamHandle *handle, Scene *scene,
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 **flag = BLI_array_alloca(flag, efa->len);
int i;
BMIter liter;
@@ -251,15 +267,14 @@ static void construct_param_handle_face_add(ParamHandle *handle, Scene *scene,
co[i] = l->v->co;
uv[i] = luv->uv;
pin[i] = (luv->flag & MLOOPUV_PINNED) != 0;
+ flag[i] = &(luv->flag);
select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
}
- param_face_add(handle, key, i, vkeys, co, uv, pin, select, efa->no);
+ param_face_add(handle, key, i, vkeys, co, uv, pin, select, efa->no, flag);
}
-static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
- const bool implicit, const bool fill, const bool sel,
- const bool correct_aspect)
+static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm, const int handle_params)
{
ParamHandle *handle;
BMFace *efa;
@@ -268,6 +283,12 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
BMIter iter, liter;
int i;
+ const bool implicit = handle_params & HANDLE_IMPLICIT;
+ const bool fill = handle_params & HANDLE_FILL;
+ const bool sel = handle_params & HANDLE_SELECTED;
+ const bool correct_aspect = handle_params & HANDLE_CORRECT_ASPECT;
+ const bool all_faces = handle_params & HANDLE_ALL_FACES;
+
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
handle = param_construct_begin();
@@ -290,7 +311,7 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
continue;
}
- if (implicit) {
+ if (implicit && !all_faces) {
bool is_loopsel = false;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -325,7 +346,7 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
static void texface_from_original_index(BMFace *efa, int index, float **uv, ParamBool *pin, ParamBool *select,
- Scene *scene, const int cd_loop_uv_offset)
+ int *flag, Scene *scene, const int cd_loop_uv_offset)
{
BMLoop *l;
BMIter liter;
@@ -334,6 +355,7 @@ static void texface_from_original_index(BMFace *efa, int index, float **uv, Para
*uv = NULL;
*pin = 0;
*select = 1;
+ *flag = 0;
if (index == ORIGINDEX_NONE)
return;
@@ -344,6 +366,7 @@ static void texface_from_original_index(BMFace *efa, int index, float **uv, Para
*uv = luv->uv;
*pin = (luv->flag & MLOOPUV_PINNED) ? 1 : 0;
*select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ *flag = luv->flag;
break;
}
}
@@ -445,6 +468,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
ParamBool pin[4], select[4];
float *co[4];
float *uv[4];
+ int flag[4];
BMFace *origFace = faceMap[i];
if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
@@ -473,12 +497,12 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
/* 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);
+ texface_from_original_index(origFace, origVertIndices[mloop[0].v], &uv[0], &pin[0], &select[0], &flag[0], scene, cd_loop_uv_offset);
+ texface_from_original_index(origFace, origVertIndices[mloop[1].v], &uv[1], &pin[1], &select[1], &flag[1], scene, cd_loop_uv_offset);
+ texface_from_original_index(origFace, origVertIndices[mloop[2].v], &uv[2], &pin[2], &select[2], &flag[2], scene, cd_loop_uv_offset);
+ texface_from_original_index(origFace, origVertIndices[mloop[3].v], &uv[3], &pin[3], &select[3], &flag[3], scene, cd_loop_uv_offset);
- param_face_add(handle, key, 4, vkeys, co, uv, pin, select, NULL);
+ param_face_add(handle, key, 4, vkeys, co, uv, pin, select, NULL, flag);
}
/* these are calculated from original mesh too */
@@ -527,6 +551,8 @@ static bool minimize_stretch_init(bContext *C, wmOperator *op)
return false;
}
+ int hparams = set_handle_params(implicit, fill_holes, true, true, false);
+
ms = MEM_callocN(sizeof(MinStretch), "MinStretch");
ms->scene = scene;
ms->obedit = obedit;
@@ -534,7 +560,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(scene, obedit, em->bm, implicit, fill_holes, 1, 1);
+ ms->handle = construct_param_handle(scene, obedit, em->bm, hparams);
ms->lasttime = PIL_check_seconds_timer();
param_stretch_begin(ms->handle);
@@ -712,12 +738,48 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively", 0, 100);
}
+/* ******************** Select Shortest Path operator **************** */
+bool ED_uvedit_shortest_path_select(Scene *scene, Object *ob, BMesh *bm, bool topo_dist)
+{
+ ParamHandle *handle;
+ bool path_found = false;
+ int hparams = set_handle_params(true, false, false, true, true);
+ handle = construct_param_handle(scene, ob, bm, hparams);
+ param_shortest_path(handle, &path_found, topo_dist);
+ param_flush_sel(handle);
+ param_delete(handle);
+ return path_found;
+}
+
+/* ******************** Select Overlapping UVs operator **************** */
+void ED_uvedit_overlapping_select(Scene *scene, Object *ob, BMesh *bm, const bool extend)
+{
+ ParamHandle *handle;
+ int hparams = set_handle_params(true, false, false, true, true);
+ handle = construct_param_handle(scene, ob, bm, hparams);
+ param_select_overlapping(handle, extend);
+ param_flush_sel(handle);
+ param_delete(handle);
+}
+
+/* ******************** Scale To Bounds operator **************** */
+void ED_uvedit_scale_to_bounds(Scene *scene, Object *ob, BMesh *bm)
+{
+ ParamHandle *handle;
+ int hparams = set_handle_params(true, false, true, true, false);
+ handle = construct_param_handle(scene, ob, bm, hparams);
+ param_scale_bounds(handle);
+ param_flush(handle);
+ param_delete(handle);
+}
+
/* ******************** Pack Islands operator **************** */
void ED_uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm, bool selected, bool correct_aspect, bool do_rotate)
{
ParamHandle *handle;
- handle = construct_param_handle(scene, ob, bm, true, false, selected, correct_aspect);
+ int hparams = set_handle_params(true, false, selected, correct_aspect, false);
+ handle = construct_param_handle(scene, ob, bm, hparams);
param_pack(handle, scene->toolsettings->uvcalc_margin, do_rotate);
param_flush(handle);
param_delete(handle);
@@ -765,6 +827,344 @@ void UV_OT_pack_islands(wmOperatorType *ot)
RNA_def_float_factor(ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
}
+/* ******************** Pack Islands operator 2.0 **************** */
+
+typedef struct SimulatedAnnealing {
+ RNG *rng;
+ int seed;
+ float theta;
+ float f;
+ float r;
+ float temperature;
+ int rot_steps;
+} SimulatedAnnealing;
+
+typedef struct PackIslands {
+ Scene *scene;
+ Object *obedit;
+ BMEditMesh *em;
+ ParamHandle *handle;
+ double lasttime;
+ int iter_global, iter_local, iter_max;
+ wmTimer *timer;
+ float wasted_area_last, margin;
+ bool use_concave;
+ SimulatedAnnealing *sa;
+} PackIslands;
+
+static bool irregular_pack_islands_init(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ PackIslands *pi;
+ SimulatedAnnealing *simann;
+ unsigned int seed = 31415926;
+ float wasted_area;
+ bool average_scale = RNA_boolean_get(op->ptr, "average_islands_scale");
+
+ /* Keep for now, needed when making packing work with current selection */
+ /*if (!uvedit_have_selection(scene, em, implicit)) {
+ return false;
+ }*/
+
+ int hparams = set_handle_params(true, false, false, false, true);
+
+ pi = MEM_callocN(sizeof(PackIslands), "PackIslands");
+ pi->scene = scene;
+ pi->obedit = obedit;
+ pi->em = em;
+ pi->iter_max = RNA_int_get(op->ptr, "iterations");
+ pi->iter_global = 0;
+ pi->iter_local = 0;
+ pi->margin = RNA_float_get(op->ptr, "margin") / 2.0f; /* Only apply half the margin per chart */
+ pi->use_concave = RNA_boolean_get(op->ptr, "concave");
+ pi->handle = construct_param_handle(scene, obedit, em->bm, hparams);
+ pi->lasttime = PIL_check_seconds_timer();
+
+ simann = MEM_callocN(sizeof(SimulatedAnnealing), "SimulatedAnnealing");
+ simann->rng = BLI_rng_new(seed);
+ simann->seed = seed;
+ simann->theta = 0.0f;
+ simann->f = 0.0f;
+ simann->r = 0.0f;
+ simann->temperature = 1.0f;
+ simann->rot_steps = RNA_int_get(op->ptr, "rotation_steps");
+ pi->sa = simann;
+
+ if (average_scale)
+ param_average(pi->handle);
+
+ param_irregular_pack_begin(pi->handle,
+ &wasted_area,
+ pi->margin,
+ pi->sa->rot_steps,
+ pi->use_concave /* SA */);
+
+ param_accept_placement_all(pi->handle);
+
+ pi->wasted_area_last = wasted_area;
+ printf("wasted area currently: %f\n", wasted_area);
+
+ op->customdata = pi;
+
+ DAG_id_tag_update(pi->obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, pi->obedit->data);
+
+ return true;
+}
+
+static void irregular_pack_islands_iteration(bContext *C, wmOperator *op, bool interactive)
+{
+ PackIslands *pi = op->customdata;
+ ScrArea *sa = CTX_wm_area(C);
+ float wasted_area = 0.0f, dE, r1, r2;
+ float a = 0.95f;
+ /* ToDo Saphires: Find optimal parameter */
+ float k = 0.5f; /* Stefan-Boltzman constant-like parameter */
+ int local_iter_max = 50;
+
+ pi->iter_global++;
+
+ /* Cooling Schedule */
+ if (pi->iter_local >= local_iter_max) {
+ pi->sa->temperature = pi->sa->temperature * a;
+ pi->iter_local = 0;
+ }
+
+
+ /* Find neighboring solution */
+ /*ToDo Saphires: Pass SA parameters */
+ param_irregular_pack_iter(pi->handle,
+ &wasted_area,
+ pi->iter_global,
+ pi->sa->rot_steps,
+ pi->margin /* SA */);
+
+ /* delta Energy */
+ dE = wasted_area - pi->wasted_area_last;
+
+ printf("wasted area currently: %f, wasted area last: %f\n", wasted_area, pi->wasted_area_last);
+
+ if (dE < 0) {
+ /* Current solution is new best solution, keep placement */
+ param_accept_placement_all(pi->handle);
+ pi->wasted_area_last = wasted_area;
+ printf("dE < 0\n");
+ }
+ else {
+ r1 = BLI_rng_get_float(pi->sa->rng);
+
+ r2 = (float)exp(-dE/(k * pi->sa->temperature));
+
+ if (0 /*r1 < r2*/) {
+ /* Current solution is new best solution, keep placement */
+ param_accept_placement_all(pi->handle);
+ pi->wasted_area_last = wasted_area;
+ printf("r1 < r2\n");
+ }
+ else {
+ /* no better solution found, "frozen state solution" */
+ printf("frozen state, revert\n");
+ param_restore_placement(pi->handle, pi->margin);
+ pi->iter_local++;
+ }
+ }
+
+ /* RNA_int_set(op->ptr, "iterations", pi->iter_global); */ /* ToDo SaphireS */
+
+ if (interactive /*&& (PIL_check_seconds_timer() - pi->lasttime > 0.5)*/) {
+ char str[UI_MAX_DRAW_STR];
+
+ param_flush(pi->handle);
+
+ if (sa) {
+ BLI_snprintf(str, sizeof(str),
+ IFACE_("Pack Islands (irregular). Iteration: %i, Wasted UV Area (Best Solution): %f"), pi->iter_global, pi->wasted_area_last);
+ ED_area_headerprint(sa, str);
+ }
+
+ pi->lasttime = PIL_check_seconds_timer();
+
+ DAG_id_tag_update(pi->obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, pi->obedit->data);
+
+ printf("done iteration\n");
+ }
+}
+
+static void irregular_pack_islands_exit(bContext *C, wmOperator *op, bool cancel)
+{
+ PackIslands *pi = op->customdata;
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa)
+ ED_area_headerprint(sa, NULL);
+ if (pi->timer)
+ WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), pi->timer);
+
+ if (cancel) {
+ param_flush_restore(pi->handle); /* Restore original UVs */
+ }
+ else {
+ //param_restore_packing_solution(pi->handle); /* Restore best solution*/
+ param_flush(pi->handle); /* Keep new UVs */
+ }
+
+ param_irregular_pack_end(pi->handle);
+ param_delete(pi->handle);
+
+ BLI_rng_free(pi->sa->rng);
+ MEM_freeN(pi->sa);
+
+ DAG_id_tag_update(pi->obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, pi->obedit->data);
+
+ MEM_freeN(pi);
+ op->customdata = NULL;
+}
+
+static int irregular_pack_islands_exec(bContext *C, wmOperator *op)
+{
+ int i, iterations;
+
+ if (!irregular_pack_islands_init(C, op))
+ return OPERATOR_CANCELLED;
+
+ iterations = RNA_int_get(op->ptr, "iterations");
+ for (i = 0; i < iterations; i++)
+ irregular_pack_islands_iteration(C, op, false);
+ irregular_pack_islands_exit(C, op, false);
+
+ return OPERATOR_FINISHED;
+}
+
+static int irregular_pack_islands_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ PackIslands *pi;
+
+ if (!irregular_pack_islands_init(C, op))
+ return OPERATOR_CANCELLED;
+
+ irregular_pack_islands_iteration(C, op, true);
+
+ pi = op->customdata;
+ WM_event_add_modal_handler(C, op);
+ pi->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int irregular_pack_islands_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ PackIslands *pi = op->customdata;
+
+ switch (event->type) {
+ case ESCKEY:
+ case RIGHTMOUSE:
+ irregular_pack_islands_exit(C, op, true);
+ return OPERATOR_CANCELLED;
+ case RETKEY:
+ case PADENTER:
+ case LEFTMOUSE:
+ irregular_pack_islands_exit(C, op, false);
+ return OPERATOR_FINISHED;
+ case TIMER:
+ if (pi->timer == event->customdata) {
+ double start = PIL_check_seconds_timer();
+
+ do {
+ irregular_pack_islands_iteration(C, op, true);
+ } while (PIL_check_seconds_timer() - start < 0.01);
+ }
+ break;
+ }
+
+ if (pi->iter_max && pi->iter_global >= pi->iter_max) {
+ irregular_pack_islands_exit(C, op, false);
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void irregular_pack_islands_cancel(bContext *C, wmOperator *op)
+{
+ irregular_pack_islands_exit(C, op, true);
+}
+
+void UV_OT_irregular_pack_islands(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Pack Islands (irregular)";
+ ot->idname = "UV_OT_irregular_pack_islands";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
+ ot->description = "New and improved packing taking into account irregular uv shapes";
+
+ /* api callbacks */
+ ot->exec = irregular_pack_islands_exec;
+ ot->invoke = irregular_pack_islands_invoke;
+ ot->modal = irregular_pack_islands_modal;
+ ot->cancel = irregular_pack_islands_cancel;
+ ot->poll = ED_operator_uvedit;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "concave", false, "Use concave boundaries", "Use concave boundaries (slower but better results)");
+ RNA_def_float(ot->srna, "margin", 0.0f, 0.0f, 1.0f, "Margin", "Border Margin/Padding to apply per UV island", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "rotation_steps", 4, 0, 360, "Rotation Steps", "Allowed rotations to try during packing. (2=180°, 4=90°, etc.)", 0, 360);
+ RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively", 0, 10000);
+ RNA_def_boolean(ot->srna, "average_islands_scale", true, "Average Islands Scale", "Average Islands Scale before starting packing");
+}
+
+/* ******************** XXX (SaphireS): DEBUG-TEST operator **************** */
+
+/* XXX (SaphireS): Remove */
+static void ED_uvedit_test_debug(Scene *scene, Object *ob, BMesh *bm, bool selected, bool correct_aspect)
+{
+ ParamHandle *handle;
+ int hparams = set_handle_params(true, false, selected, correct_aspect, true);
+ handle = construct_param_handle(scene, ob, bm, hparams);
+
+ param_test(handle);
+
+ param_flush(handle);
+ param_delete(handle);
+}
+
+/* XXX (SaphireS): Remove */
+static int test_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ /*if (!uvedit_have_selection(scene, em, true)) {
+ return OPERATOR_CANCELLED;
+ }*/
+
+ ED_uvedit_test_debug(scene, obedit, em->bm, false, true);
+
+ DAG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+/* XXX (SaphireS): Remove */
+void UV_OT_test(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "DEBUG - TEST";
+ ot->idname = "UV_OT_test";
+ ot->description = "Debug operator to test stuff";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = test_exec;
+ ot->poll = ED_operator_uvedit;
+}
+
/* ******************** Average Islands Scale operator **************** */
static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
@@ -774,12 +1174,14 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
BMEditMesh *em = BKE_editmesh_from_object(obedit);
ParamHandle *handle;
bool implicit = true;
+
+ int hparams = set_handle_params(implicit, false, true, true, false);
if (!uvedit_have_selection(scene, em, implicit)) {
return OPERATOR_CANCELLED;
}
- handle = construct_param_handle(scene, obedit, em->bm, implicit, 0, 1, 1);
+ handle = construct_param_handle(scene, obedit, em->bm, hparams);
param_average(handle);
param_flush(handle);
param_delete(handle);
@@ -817,6 +1219,8 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
modifier_unwrap_state(obedit, scene, &use_subsurf);
+ int hparams = set_handle_params(false, fillholes, false, true, false);
+
if (!ED_uvedit_test(obedit)) {
return;
}
@@ -824,7 +1228,7 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
if (use_subsurf)
liveHandle = construct_param_handle_subsurfed(scene, obedit, em, fillholes, false, true);
else
- liveHandle = construct_param_handle(scene, obedit, em->bm, false, fillholes, false, true);
+ liveHandle = construct_param_handle(scene, obedit, em->bm, hparams);
param_lscm_begin(liveHandle, PARAM_TRUE, abf);
}
@@ -1146,21 +1550,27 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
const bool fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0;
const bool correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0;
+ const bool pack_islands = (scene->toolsettings->uvcalc_flag & UVCALC_PACKISLANDS) != 0;
bool use_subsurf;
+ int hparams = set_handle_params(false, fill_holes, sel, correct_aspect, false);
+
modifier_unwrap_state(obedit, scene, &use_subsurf);
if (use_subsurf)
handle = construct_param_handle_subsurfed(scene, obedit, em, fill_holes, sel, correct_aspect);
else
- handle = construct_param_handle(scene, obedit, em->bm, false, fill_holes, sel, correct_aspect);
+ handle = construct_param_handle(scene, obedit, em->bm, hparams);
param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
param_lscm_solve(handle);
param_lscm_end(handle);
param_average(handle);
- param_pack(handle, scene->toolsettings->uvcalc_margin, false);
+ if (pack_islands)
+ param_pack(handle, scene->toolsettings->uvcalc_margin, false);
+ else
+ param_scale_bounds(handle);
param_flush(handle);
@@ -1175,6 +1585,7 @@ static int unwrap_exec(bContext *C, wmOperator *op)
int method = RNA_enum_get(op->ptr, "method");
const bool fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
+ const bool pack_islands = RNA_boolean_get(op->ptr, "pack_islands");
const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data");
bool use_subsurf_final;
float obsize[3];
@@ -1189,6 +1600,9 @@ static int unwrap_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ /* Reveal hidden UVs since they're taken into account*/
+ ED_uvedit_reveal(em);
+
mat4_to_size(obsize, obedit->obmat);
if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f))
BKE_report(op->reports, RPT_INFO,
@@ -1215,6 +1629,9 @@ static int unwrap_exec(bContext *C, wmOperator *op)
if (correct_aspect) scene->toolsettings->uvcalc_flag &= ~UVCALC_NO_ASPECT_CORRECT;
else scene->toolsettings->uvcalc_flag |= UVCALC_NO_ASPECT_CORRECT;
+ if (pack_islands) scene->toolsettings->uvcalc_flag |= UVCALC_PACKISLANDS;
+ else scene->toolsettings->uvcalc_flag &= ~UVCALC_PACKISLANDS;
+
if (use_subsurf) scene->toolsettings->uvcalc_flag |= UVCALC_USESUBSURF;
else scene->toolsettings->uvcalc_flag &= ~UVCALC_USESUBSURF;
@@ -1258,6 +1675,8 @@ void UV_OT_unwrap(wmOperatorType *ot)
"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, "pack_islands", 1, "Pack Islands",
+ "Pack UV islands after unwrapping");
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);
@@ -1303,6 +1722,9 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ /* Reveal hidden UVs since they're taken into account*/
+ ED_uvedit_reveal(em);
+
cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
if (RNA_boolean_get(op->ptr, "orthographic")) {
@@ -1405,6 +1827,9 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
+ /* Reveal hidden UVs since they're taken into account*/
+ ED_uvedit_reveal(me->edit_btmesh);
+
ED_mesh_uv_loop_reset(C, me);
DAG_id_tag_update(obedit->data, 0);
@@ -1491,6 +1916,9 @@ static int sphere_project_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ /* Reveal hidden UVs since they're taken into account*/
+ ED_uvedit_reveal(em);
+
cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
uv_map_transform(C, op, center, rotmat);
@@ -1570,6 +1998,9 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ /* Reveal hidden UVs since they're taken into account*/
+ ED_uvedit_reveal(em);
+
cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
uv_map_transform(C, op, center, rotmat);
@@ -1676,6 +2107,9 @@ static int cube_project_exec(bContext *C, wmOperator *op)
if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
return OPERATOR_CANCELLED;
}
+
+ /* Reveal hidden UVs since they're taken into account*/
+ ED_uvedit_reveal(em);
ED_uvedit_unwrap_cube_project(obedit, em->bm, cube_size, true);
uv_map_clip_correct(scene, obedit, em, op);
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 3676066a399..3e878fab66b 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -213,6 +213,7 @@ enum {
MLOOPUV_EDGESEL = (1 << 0),
MLOOPUV_VERTSEL = (1 << 1),
MLOOPUV_PINNED = (1 << 2),
+ MLOOPUV_HIDDEN = (1 << 3)
};
/**
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 3201b75ee1e..76cac158b5f 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -2152,6 +2152,7 @@ typedef enum ImagePaintMode {
#define UVCALC_NO_ASPECT_CORRECT 2 /* would call this UVCALC_ASPECT_CORRECT, except it should be default with old file */
#define UVCALC_TRANSFORM_CORRECT 4 /* adjust UV's while transforming to avoid distortion */
#define UVCALC_USESUBSURF 8 /* Use mesh data after subsurf to compute UVs*/
+#define UVCALC_PACKISLANDS 16 /* Pack Islands after unwrapping*/
/* toolsettings->uv_flag */
#define UV_SYNC_SELECTION 1