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:
authorAurel Gruber <aurel.gruber@infix.ch>2016-11-18 14:54:50 +0300
committerAurel Gruber <aurel.gruber@infix.ch>2017-02-27 13:24:36 +0300
commit4aac14f0d2d83e4bf38f6a92335de6c3e73559f9 (patch)
tree20aef6c2f51e3d6a0a7b1380e1de6e3063a55bd8 /source/blender/editors/uvedit
parent23fa36889820965033d90e4ecb5855776fc41d65 (diff)
Category: UV Unwrapping SLIM Algorithm Integration
integrating SLIM including data gathering and transfer from Blender to SLIM This commit is huge, because I copied over the code from a different repository. Not commit-by-commit. The Algorithm can be invoked either by choosing SLIM from the dropdown in the unwrapping settings or by hitting ctrl. + m in the uv editor for relaxation. Tried adding it to the menu the same way as minimizing stretch is there but failed.
Diffstat (limited to 'source/blender/editors/uvedit')
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt3
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h2
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c357
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.h16
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c399
6 files changed, 775 insertions, 6 deletions
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index 543ef0e0663..a7e2da05083 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -31,6 +31,8 @@ set(INC
../../../../intern/guardedalloc
../../../../intern/eigen
../../../../intern/glew-mx
+
+ ../../../../intern/SLIM/src
)
set(INC_SYS
@@ -56,3 +58,4 @@ endif()
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_uvedit "${SRC}" "${INC}" "${INC_SYS}")
+target_link_libraries(bf_editor_uvedit bf_intern_slim)
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index e028c08091c..e8dbb337cf4 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -75,6 +75,8 @@ void UV_OT_cube_project(struct wmOperatorType *ot);
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);
+// AUREL SLIM interactive parameterization
+void UV_OT_minimize_stretch_slim(struct wmOperatorType *ot);
void UV_OT_pack_islands(struct wmOperatorType *ot);
void UV_OT_reset(struct wmOperatorType *ot);
void UV_OT_sphere_project(struct wmOperatorType *ot);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 193b006cf0d..6cdce37ab03 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -4265,6 +4265,8 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_cylinder_project);
WM_operatortype_append(UV_OT_project_from_view);
WM_operatortype_append(UV_OT_minimize_stretch);
+ // AUREL SLIM Interactive Parameterization
+ WM_operatortype_append(UV_OT_minimize_stretch_slim);
WM_operatortype_append(UV_OT_pack_islands);
WM_operatortype_append(UV_OT_reset);
WM_operatortype_append(UV_OT_sphere_project);
@@ -4341,6 +4343,8 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf)
/* unwrap */
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);
+ // AUREL SLIM Interactive Parameterization
+ WM_keymap_add_item(keymap, "UV_OT_minimize_stretch_slim", MKEY, 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_average_islands_scale", AKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index bdfff123aa4..759af69fd33 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -35,6 +35,9 @@
#include "BLI_boxpack2d.h"
#include "BLI_convexhull2d.h"
+#include "BKE_editmesh.h"
+#include "bmesh.h"
+
#include "uvedit_parametrizer.h"
#include <math.h>
@@ -113,6 +116,8 @@ typedef struct PVert {
float uv[2];
unsigned char flag;
+ bool on_boundary_flag;
+ int slimId;
} PVert;
typedef struct PEdge {
@@ -199,6 +204,9 @@ typedef struct PChart {
float rescale, area;
float size[2] /* , trans[2] */;
} pack;
+ struct PChartSLIM {
+ bool pins_exist;
+ } slim;
} u;
unsigned char flag;
@@ -4703,3 +4711,352 @@ void param_flush_restore(ParamHandle *handle)
}
}
+/* AUREL THESIS
+ In the following are all functions necessary to transfer data from the native part to SLIM.
+ */
+void allocate_memory_for_pointerarrays(matrix_transfer *mt, PHandle *phandle);
+void allocate_memory_for_matrices(const int chartNr, const PHandle *phandle, const matrix_transfer *mt);
+void create_weight_matrix(const int chartNr, const PHandle *phandle, matrix_transfer *mt, float *tempW, MDeformVert *dvert, int defgrp_index, BMEditMesh *em);
+void transfer_vertices(const int chartNr, const PHandle *phandle, matrix_transfer *mt, float *tempW);
+void transfer_edges(const int chartNr, const PHandle *phandle, const matrix_transfer *mt);
+void transfer_boundary_vertices(const int chartNr, const PHandle *phandle, const matrix_transfer *mt, float *tempW);
+void transfer_faces(const int chartNr, const PHandle *phandle, const matrix_transfer *mt);
+
+/* AUREL THESIS: Conversion Function to build matrix for SLIM Parametrization */
+void convert_blender_slim(ParamHandle *handle, matrix_transfer *mt, bool selectionOnly, MDeformVert *dvert, int defgrp_index, BMEditMesh *em)
+{
+ PHandle *phandle = (PHandle *)handle;
+
+ // allocate memory for the arrays that hold the pointers to the matrices for each chart
+ // there are #charts pointers of each kind
+ allocate_memory_for_pointerarrays(mt, phandle);
+
+ int chartNr;
+
+ /*Allocate memory for matrices of Vertices,Faces etc. for each chart*/
+ for (chartNr = 0; chartNr<phandle->ncharts; chartNr++) {
+ allocate_memory_for_matrices(chartNr, phandle, mt);
+ }
+
+ /*For each chart, fill up matrices*/
+
+ //printf("number of charts: %d \n", mt->nCharts);
+ for (chartNr = 0; chartNr < phandle->ncharts; chartNr++) {
+ mt->nPinnedVertices[chartNr] = 0;
+ mt->nBoundaryVertices[chartNr] = 0;
+
+ float *tempW = MEM_mallocN(mt->nVerts[chartNr] * sizeof(*tempW), " Weight-per-face Vector, ordered by BM_ITER_MESH_INDEX");
+
+ create_weight_matrix(chartNr, phandle, mt, tempW, dvert, defgrp_index, em);
+ transfer_boundary_vertices(chartNr, phandle, mt, tempW);
+ transfer_vertices(chartNr, phandle, mt, tempW);
+ transfer_edges(chartNr, phandle, mt);
+ transfer_faces(chartNr, phandle, mt);
+
+ mt->PPmatrices[chartNr] = MEM_reallocN_id(mt->PPmatrices[chartNr], mt->nPinnedVertices[chartNr] * 2 * sizeof(**mt->PPmatrices), "Pinned-Vertex-position Matrix");
+ mt->Pmatrices[chartNr] = MEM_reallocN_id(mt->Pmatrices[chartNr], mt->nPinnedVertices[chartNr] * sizeof(**mt->Pmatrices), " Pinned-Vertex Matrix");
+ mt->Bvectors[chartNr] = MEM_reallocN_id(mt->Bvectors[chartNr], mt->nBoundaryVertices[chartNr] * sizeof(**mt->Bvectors), " boundary-Vertex Matrix");
+ mt->Ematrices[chartNr] = MEM_reallocN_id(mt->Ematrices[chartNr], (mt->nEdges[chartNr] + mt->nBoundaryVertices[chartNr]) * 2 * sizeof(**mt->Ematrices), " boundarys-Vertex Matrix");
+ }
+
+};
+
+/* AUREL THESIS
+ Allocate pointer arrays for each matrix-group. Meaning as many pointers per array as there are charts.
+ */
+void allocate_memory_for_pointerarrays(matrix_transfer *mt, PHandle *phandle){
+ mt->nCharts = phandle->ncharts;
+ mt->nVerts = MEM_mallocN(mt->nCharts * sizeof(*mt->nVerts), "Array of number of vertices per Chart");
+ mt->nFaces = MEM_mallocN(mt->nCharts * sizeof(*mt->nFaces), "Array of number of Faces per Chart");
+ mt->nEdges = MEM_mallocN(mt->nCharts * sizeof(*mt->nEdges), "Array of number of Edges per Chart");
+ mt->nPinnedVertices = MEM_mallocN(mt->nCharts * sizeof(*mt->nPinnedVertices), "Array of number of Faces per Chart");
+ mt->nBoundaryVertices = MEM_mallocN(mt->nCharts * sizeof(*mt->nBoundaryVertices), "Array of number of Faces per Chart");
+
+ mt->Vmatrices = MEM_mallocN(mt->nCharts * sizeof(*mt->Vmatrices), "Array of pointers to Vertex matrices");
+ mt->UVmatrices = MEM_mallocN(mt->nCharts * sizeof(*mt->UVmatrices), "Array of pointers to UV matrices");
+ mt->PPmatrices = MEM_mallocN(mt->nCharts * sizeof(*mt->PPmatrices), "Array of pointers to Pinned-Vertex-Position matrices");
+
+ mt->Fmatrices = MEM_mallocN(mt->nCharts * sizeof(*mt->Fmatrices), "Array of pointers to Face matrices");
+ mt->Pmatrices = MEM_mallocN(mt->nCharts * sizeof(*mt->Pmatrices), "Array of pointers to Pinned-Vertex matrices");
+ mt->Bvectors = MEM_mallocN(mt->nCharts * sizeof(*mt->Bvectors), "Array of pointers to boundary-Vertex vectors");
+ mt->Ematrices = MEM_mallocN(mt->nCharts * sizeof(*mt->Ematrices), "Array of pointers to Edge matrices");
+
+ mt->ELvectors = MEM_mallocN(mt->nCharts * sizeof(*mt->ELvectors), "Array of pointers to Edge-Length vectors");
+ mt->Wvectors = MEM_mallocN(mt->nCharts * sizeof(*mt->Wvectors), "Array of pointers to weight-per-face vectors");
+}
+
+/* AUREL THESIS
+ For one chart, allocate memory. If no accurate estimate (e.g. for number of pinned vertices) overestimate and
+ correct later.
+ */
+void allocate_memory_for_matrices(const int chartNr, const PHandle *phandle, const matrix_transfer *mt){
+
+ mt->nVerts[chartNr] = phandle->charts[chartNr]->nverts;
+ mt->nFaces[chartNr] = phandle->charts[chartNr]->nfaces;
+ mt->nEdges[chartNr] = phandle->charts[chartNr]->nedges;
+
+ mt->Vmatrices[chartNr] = MEM_mallocN(mt->nVerts[chartNr] * 3 * sizeof(**mt->Vmatrices), "Vertex Matrix");
+ mt->UVmatrices[chartNr] = MEM_mallocN(mt->nVerts[chartNr] * 2 * sizeof(**mt->UVmatrices), "UV Matrix");
+ mt->PPmatrices[chartNr] = MEM_mallocN(mt->nVerts[chartNr] * 2 * sizeof(**mt->PPmatrices), "Pinned-Vertex-position Matrix");
+
+ mt->Fmatrices[chartNr] = MEM_mallocN(mt->nFaces[chartNr] * 3 * sizeof(**mt->Fmatrices), "Face Matrix");
+ mt->Pmatrices[chartNr] = MEM_mallocN(mt->nVerts[chartNr] * sizeof(**mt->Pmatrices), " Pinned-Vertex Matrix");
+ mt->Bvectors[chartNr] = MEM_mallocN(mt->nVerts[chartNr] * sizeof(**mt->Bvectors), " Boundary-Vertex Vector");
+ mt->Wvectors[chartNr] = MEM_mallocN(mt->nVerts[chartNr] * sizeof(**mt->Wvectors), " Weight-per-face Vector");
+
+ mt->Ematrices[chartNr] = MEM_mallocN(mt->nEdges[chartNr] * 2 * 2 * sizeof(**mt->Ematrices), " Edge matrix");
+ mt->ELvectors[chartNr] = MEM_mallocN(mt->nEdges[chartNr] * 2 * sizeof(**mt->ELvectors), " Edge-Length Vector");
+}
+
+/* AUREL THESIS
+ Get weights from the weight map for weighted parametrisation.
+ */
+void create_weight_matrix(const int chartNr, const PHandle *phandle, matrix_transfer *mt, float *tempW, MDeformVert *dvert, int defgrp_index, BMEditMesh *em){
+
+ BMIter iter;
+ BMVert *vert;
+ int i;
+ double weight;
+
+ /*
+ BM_ITER_MESH_INDEX(vert, &iter, em->bm, BM_VERTS_OF_MESH, i){
+ weight = defvert_find_weight(dvert + i, defgrp_index);
+ tempW[i] = weight;
+ //printf("tempW[%d] = %f \n",i, weight);
+ }*/
+
+}
+
+/* AUREL THESIS Transfer edges and edge lengths */
+void transfer_edges(const int chartNr, const PHandle *phandle, const matrix_transfer *mt){
+
+ PChart *chart = phandle->charts[chartNr];
+
+ int *E = mt->Ematrices[chartNr];
+ double *EL = mt->ELvectors[chartNr];
+
+ int vid = 0;
+ int eid = 0;
+
+ PEdge *e, *e1;
+ PEdge *outer;
+ p_chart_boundaries(chart, NULL, &outer);
+ PEdge *be = outer;
+
+
+ do{
+ E[eid] = be->vert->slimId;
+ EL[eid] = p_edge_length(be);
+
+ be = p_boundary_edge_next(be);
+ E[eid + mt->nEdges[chartNr] + mt->nBoundaryVertices[chartNr]] = be->vert->slimId;
+ eid++;
+
+ } while (be != outer);
+
+ for (e = chart->edges; e; e = e->nextlink){
+ e1 = e->next;
+ //printf(" %i %i \n", e->vert->slimId, e1->vert->slimId);
+ E[eid] = e->vert->slimId;
+ EL[eid] = p_edge_length(e);
+
+ E[eid + mt->nEdges[chartNr] + mt->nBoundaryVertices[chartNr]] = e1->vert->slimId;
+ eid++;
+ }
+}
+
+/* AUREL THESIS Transfer vertices and pinned information */
+void transfer_vertices(const int chartNr, const PHandle *phandle, matrix_transfer *mt, float *tempW){
+
+ /*AUREL GRUBER: Attempt to get weight paint colors end*/
+
+ PChart *chart = phandle->charts[chartNr];
+ PVert *v;
+
+ double *V, *UV, *PP;
+ float *W;
+ int *P;
+ float weight;
+
+ int r = mt->nVerts[chartNr];
+ V = mt->Vmatrices[chartNr];
+ UV = mt->UVmatrices[chartNr];
+ P = mt->Pmatrices[chartNr];
+ PP = mt->PPmatrices[chartNr];
+ W = mt->Wvectors[chartNr];
+
+ int pVid = 0;
+ int vid = mt->nBoundaryVertices[chartNr];
+ //For every vertex, fill up V matrix and P matrix (pinned vertices)
+ for (v = chart->verts; v; v = v->nextlink){
+
+ if (!v->on_boundary_flag){
+ //weight = tempW[v->slimId];
+ //printf("weights as used internal verts: %f id, x,y,z: %d, %f, %f, %f \n", weight, v->slimId, v->co[0], v->co[1], v->co[2]);
+ v->slimId = vid;
+ W[v->slimId] = 0;
+ vid++;
+ }
+
+
+
+ V[v->slimId] = v->co[0];
+ //printf(" %f ", V[vid]);
+ V[r + v->slimId] = v->co[1];
+ //printf("%f ", V[r + vid]);
+ V[2 * r + v->slimId] = v->co[2];
+ //printf("%f \n", V[2*r + vid]);
+
+
+ UV[v->slimId] = v->uv[0];
+ UV[r + v->slimId] = v->uv[1];
+
+
+ if (v->flag & PVERT_PIN){
+
+ mt->pinned_vertices = true;
+
+ //printf("vid: %d, v->uv[0]: %f \n", v->slimId, v->uv[0]);
+ //printf("vid: %d, v->uv[1]: %f \n", v->slimId, v->uv[1]);
+
+ mt->nPinnedVertices[chartNr] += 1;
+ P[pVid] = v->slimId;
+ PP[2 * pVid] = (double)v->uv[0];
+ PP[2 * pVid + 1] = (double)v->uv[1];
+ pVid += 1;
+ }
+ }
+
+
+}
+
+/* AUREL THESIS Transfer boundary vertices */
+void transfer_boundary_vertices(const int chartNr, const PHandle *phandle, const matrix_transfer *mt, float *tempW){
+
+ PChart *chart = phandle->charts[chartNr];
+ PVert *v;
+
+ int *B = mt->Bvectors[chartNr];
+ float *W = mt->Wvectors[chartNr];
+ int vid;
+ float weight;
+
+ //For every vertex, set slim_flag to 0
+ for (v = chart->verts; v; v = v->nextlink){
+ v->on_boundary_flag = false;
+ }
+
+ //find vertices on boundary and save into vector B
+ PEdge *outer;
+ vid = 0;
+ p_chart_boundaries(chart, NULL, &outer);
+ PEdge *be = outer;
+ do{
+ weight = 0; //tempW[be->vert->slimId];
+
+ mt->nBoundaryVertices[chartNr] += 1;
+ be->vert->slimId = vid;
+ be->vert->on_boundary_flag = true;
+ B[vid] = vid;
+ W[vid] = weight;
+
+ vid += 1;
+ be = p_boundary_edge_next(be);
+
+ } while (be != outer);
+}
+
+/* AUREL THESIS Transfer faces */
+void transfer_faces(const int chartNr, const PHandle *phandle, const matrix_transfer *mt){
+ PChart *chart = phandle->charts[chartNr];
+
+ PFace *f;
+
+ PEdge *e;
+ PEdge *e1;
+ PEdge *e2;
+
+ int fid = 0;
+ for (f = chart->faces; f; f = f->nextlink) {
+ e = f->edge;
+ e1 = e->next;
+ e2 = e1->next;
+
+ int r = mt->nFaces[chartNr];
+ int *F;
+
+ F = mt->Fmatrices[chartNr];
+
+ F[fid] = e->vert->slimId;
+ //printf(" %i ", F[fid]);
+ F[r + fid] = e1->vert->slimId;
+ //printf(" %i ", F[r + fid]);
+ F[2 * r + fid] = e2->vert->slimId;
+ //printf(" %i ", F[2*r + fid]);
+ fid++;
+ }
+};
+
+/* AUREL THESIS
+ Set UV on each vertex after SLIM parametrization, for each chart.
+ */
+void set_uv_param_slim(ParamHandle *handle, matrix_transfer *mt){
+ PHandle *phandle = (PHandle*) handle;
+ int vid;
+ PVert *v;
+
+ for (int chartNr = 0; chartNr<mt->nCharts; chartNr++) {
+
+ double *UV = mt->UVmatrices[chartNr];
+
+ for (v = phandle->charts[chartNr]->verts; v; v = v->nextlink){
+ vid = v->slimId;
+ v->uv[0] = UV[vid*2];
+ //printf("uv[%d][0] = %f \n", vid, UV[vid*2]);
+ v->uv[1] = UV[vid*2 + 1];
+ //printf("uv[%d][1] = %f \n", vid, UV[vid*2 + 1]);
+ }
+
+ }
+
+};
+
+void find_bounding_vertices(PVert **minx, PVert **maxx, PVert **miny, PVert **maxy, PVert *vert)
+{
+ if ((*minx)->uv[0] > vert->uv[0]) *minx = vert;
+ if ((*miny)->uv[1] > vert->uv[1]) *miny = vert;
+
+ if ((*maxx)->uv[0] < vert->uv[0]) *maxx = vert;
+ if ((*maxy)->uv[0] < vert->uv[0]) *maxy = vert;
+
+}
+
+
+double norm(PVert *min, PVert *max){
+ double x = max->uv[0] - min->uv[0];
+ double y = max->uv[1] - min->uv[1];
+ return sqrt(x*x + y*y);
+}
+
+/* AUREL THESIS
+ Examines if any pins are present or not.
+ */
+bool mark_pins(ParamHandle *paramHandle){
+ bool noPins = true;
+ PHandle *handle = (PHandle *)paramHandle;
+
+ for (int chartNr = 0; chartNr < handle->ncharts; chartNr++) {
+ PChart *chart = handle->charts[chartNr];
+
+ int nPins = 0;
+ PVert *v;
+ for (v = chart->verts; v; v = v->nextlink) {
+ if (v->flag & PVERT_PIN) {
+ nPins++;
+ noPins = false;
+ }
+ }
+ chart->u.slim.pins_exist = (nPins > 0);
+ }
+ return noPins;
+}
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.h b/source/blender/editors/uvedit/uvedit_parametrizer.h
index eaea781971d..1ca9e8b6df8 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.h
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.h
@@ -30,9 +30,19 @@
#ifdef __cplusplus
extern "C" {
#endif
-
+
+
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_deform.h"
+
+
#include "BLI_sys_types.h" // for intptr_t support
+#include "matrix_transfer.h" // for SLIM
+
+
typedef void ParamHandle; /* handle to a set of charts */
typedef intptr_t ParamKey; /* (hash) key for identifying verts and faces */
typedef enum ParamBool {
@@ -114,6 +124,10 @@ void param_scale(ParamHandle *handle, float x, float y);
void param_flush(ParamHandle *handle);
void param_flush_restore(ParamHandle *handle);
+/* AUREL THESIS */
+void convert_blender_slim(ParamHandle *handle, matrix_transfer *mt, bool selectionOnly,MDeformVert *dvert, int defgrp_index, BMEditMesh *em);
+void set_uv_param_slim(ParamHandle *handle, matrix_transfer *mt);
+bool mark_pins(ParamHandle *paramHandle);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index d8080002818..7162d51ddcc 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -82,6 +82,12 @@
#include "uvedit_intern.h"
#include "uvedit_parametrizer.h"
+#include "matrix_transfer.h"
+#include "slim_parametrizer.h"
+
+#define max(x, y) (((x) > (y)) ? (x) : (y))
+#define min(x, y) (((x) < (y)) ? (x) : (y))
+
static void modifier_unwrap_state(Object *obedit, Scene *scene, bool *r_use_subsurf)
{
ModifierData *md;
@@ -712,6 +718,274 @@ 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);
}
+
+/* AUREL THESIS
+ ******************** Minimize Stretch SLIM operator **************** */
+
+/* AUREL THESIS
+ Holds all necessary state for one session of interactive parametrisation.
+ */
+typedef struct {
+ matrix_transfer *mt;
+ ParamHandle *handle;
+ Object *obedit;
+
+ wmTimer *timer;
+ void** slimPtrs;
+ float blend;
+ bool firstIteration;
+ bool fixBorder;
+
+ bool noPins;
+} MinStretchSlim;
+
+void setup_weights();
+void setup_slim(Scene * scene, ParamHandle *handle, matrix_transfer *mt, MDeformVert *dvert, int defgrp_index, BMEditMesh *em);
+void free_matrix_transfer(matrix_transfer *mt);
+
+/* AUREL THESIS
+ Initialises SLIM and transfars data matrices
+ */
+static bool minimize_stretch_SLIM_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);
+
+ const bool fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
+
+
+ /* AUREL THESIS setup to get weight paint colors*/
+ Mesh *me = obedit->data;
+ DerivedMesh *dm = mesh_create_derived(me, NULL);
+ char *name = "slim";
+ int defgrp_index = defgroup_name_index(obedit, name);
+ MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ setup_weights(obedit, em);
+
+ ParamHandle *handle = construct_param_handle(scene, obedit, em->bm, false, true, 1, 1);
+
+
+ MinStretchSlim *mss = MEM_callocN(sizeof(MinStretchSlim), "Data for minimizing stretch with SLIM");
+ mss->mt = MEM_callocN(sizeof(matrix_transfer), "Matrix Transfer to SLIM");
+ mss->handle = handle;
+ mss->obedit = obedit;
+ mss->firstIteration = true;
+ mss->fixBorder = true;
+ //fills in mt
+
+
+ setup_slim(scene, handle, mss->mt, dvert, defgrp_index, em);
+
+ mss->slimPtrs = MEM_callocN(mss->mt->nCharts * sizeof(void*), "pointers to Slim-objects");
+
+ for (int chartNr = 0; chartNr < mss->mt->nCharts; chartNr++){
+ mss->slimPtrs[chartNr] = setup_slim_C(mss->mt, chartNr, mss->fixBorder, true);
+ }
+
+ op->customdata = mss;
+ return true;
+}
+
+/* AUREL THESIS
+ After initialisation, these iterations are executed, until applied or canceled by the user.
+ */
+static void minimize_stretch_SLIM_iteration(bContext *C, wmOperator *op, bool interactive)
+{
+ // AUREL THESIS In first iteration, check if pins are present
+ MinStretchSlim *mss = op->customdata;
+ if (mss->firstIteration){
+ mss->firstIteration = false;
+ if (!(mss->fixBorder)){
+ mss->noPins = mark_pins(mss->handle);
+ }
+ }
+
+ // AUREL THESIS Do one iteration and tranfer UVs
+ for (int chartNr = 0; chartNr < mss->mt->nCharts; chartNr++){
+ void *slimPtr = mss->slimPtrs[chartNr];
+ param_slim_single_iteration_C(slimPtr);
+ transfer_uvs_blended_C(mss->mt, slimPtr, chartNr, mss->blend);
+ }
+
+ // AUREL THESIS Assign new UVs back to each vertex
+ set_uv_param_slim(mss->handle, mss->mt);
+ if (!(mss->fixBorder)){
+ if (mss->noPins){
+ param_pack(mss->handle, 0, false);
+ }
+ }
+ param_flush(mss->handle);
+
+
+ DAG_id_tag_update(mss->obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, mss->obedit->data);
+}
+
+/* AUREL THESIS
+ Exit interactive parametrisation. Clean up memory.
+ */
+static void minimize_stretch_SLIM_exit(bContext *C, wmOperator *op, bool cancel)
+{
+ MinStretchSlim *mss = op->customdata;
+ /*
+ if (!mss->fixBorder){
+ remove_pins(mss->handle);
+ }*/
+
+ if (cancel){
+ mss->blend = 1.0f;
+ }
+
+ for (int chartNr = 0; chartNr < mss->mt->nCharts; chartNr++){
+ void *slimPtr = mss->slimPtrs[chartNr];
+ transfer_uvs_blended_C(mss->mt, slimPtr, chartNr, mss->blend);
+ }
+
+ set_uv_param_slim(mss->handle, mss->mt);
+
+ if (!(mss->fixBorder)){
+ if (mss->noPins){
+ param_pack(mss->handle, 0, false);
+ }
+ }
+
+ param_flush(mss->handle);
+ param_delete(mss->handle);
+
+ free_matrix_transfer(mss->mt);
+ MEM_freeN(mss->slimPtrs);
+ MEM_freeN(mss);
+ op->customdata = NULL;
+}
+
+/* AUREL THESIS
+ NON-interactive version of interactive parametrisation. Every modal operator of blender has this mode.
+ In this case, it's obviously never used, since the "normal" non-interactive unwrapping method is to be preferred.
+ */
+static int minimize_stretch_SLIM_exec(bContext *C, wmOperator *op)
+{
+ int n_iterations = 1;
+
+ if (!minimize_stretch_SLIM_init(C, op))
+ return OPERATOR_CANCELLED;
+
+ MinStretchSlim *mss = op->customdata;
+
+ param_slim(mss->mt, n_iterations, true, true);
+
+ minimize_stretch_SLIM_exit(C, op, false);
+
+ return OPERATOR_FINISHED;
+}
+
+/* AUREL THESIS
+ Entry point to interactive parametrisation. Already executes one iteration, allowing faster feedback.
+ */
+static int minimize_stretch_SLIM_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ MinStretchSlim *mss;
+
+ if (!minimize_stretch_SLIM_init(C, op))
+ return OPERATOR_CANCELLED;
+
+ minimize_stretch_SLIM_iteration(C, op, true);
+
+ mss = op->customdata;
+ WM_event_add_modal_handler(C, op);
+ mss->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* AUREL THESIS
+ The control structure of the modal operator. a next iteration is either started due to a timer or
+ user input.
+ */
+static int minimize_stretch_SLIM_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ MinStretchSlim *mss = op->customdata;
+
+ switch (event->type) {
+ case ESCKEY:
+ case RIGHTMOUSE:
+ minimize_stretch_SLIM_exit(C, op, true);
+ return OPERATOR_CANCELLED;
+ case RETKEY:
+ case PADENTER:
+ case LEFTMOUSE:
+ minimize_stretch_SLIM_exit(C, op, false);
+ return OPERATOR_FINISHED;
+ case PADPLUSKEY:
+ case WHEELUPMOUSE:
+ if (event->val == KM_PRESS) {
+ if (mss->blend < 1.0f) {
+ mss->blend += min(0.1f, 1 - (mss->blend));
+ minimize_stretch_SLIM_iteration(C, op, true);
+ }
+ }
+ break;
+ case PADMINUS:
+ case WHEELDOWNMOUSE:
+ if (event->val == KM_PRESS) {
+ if (mss->blend > 0.0f) {
+ mss->blend -= min(0.1f, mss->blend);
+ minimize_stretch_SLIM_iteration(C, op, true);
+ }
+ }
+ break;
+ case TIMER:
+ if (mss->timer == event->customdata) {
+ double start = PIL_check_seconds_timer();
+
+ do {
+ minimize_stretch_SLIM_iteration(C, op, true);
+ } while (PIL_check_seconds_timer() - start < 0.01);
+ }
+ break;
+ }
+
+ /*if (ms->iterations && ms->i >= ms->iterations) {
+ minimize_stretch_exit(C, op, false);
+ return OPERATOR_FINISHED;
+ }*/
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* AUREL THESIS
+ Cancels the interactive parametrisation and discards the obtained map.
+ */
+static void minimize_stretch_SLIM_cancel(bContext *C, wmOperator *op)
+{
+ minimize_stretch_SLIM_exit(C, op, true);
+}
+
+/* AUREL THESIS
+ Registration of the operator and integration into UI (can be executed with ctrl. + M)
+ */
+void UV_OT_minimize_stretch_slim(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Minimize Stretch SLIM";
+ ot->idname = "UV_OT_minimize_stretch_slim";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
+ ot->description = "Reduce UV stretching by applying the SLIM algorithm";
+
+ /* api callbacks */
+ ot->exec = minimize_stretch_SLIM_exec;
+ ot->invoke = minimize_stretch_SLIM_invoke;
+ ot->modal = minimize_stretch_SLIM_modal;
+ ot->cancel = minimize_stretch_SLIM_cancel;
+ ot->poll = ED_operator_uvedit;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "fill_holes_slim", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry");
+ RNA_def_float_factor(ot->srna, "blend_slim", 0.0f, 0.0f, 1.0f, "Blend", "Blend factor between stretch minimized and original", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "iterations_slim", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively", 0, 100);
+}
+
/* ******************** Pack Islands operator **************** */
void ED_uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm, bool selected, bool correct_aspect, bool do_rotate)
@@ -1141,7 +1415,20 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOper
/* assumes UV Map is checked, doesn't run update funcs */
void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
{
+
BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ /* AUREL THESIS setup to get weight paint colors for weighted parametrisation*/
+ Mesh *me = obedit->data;
+ DerivedMesh *dm = mesh_create_derived(me, NULL);
+ char *name = "slim";
+ int defgrp_index = defgroup_name_index(obedit, name);
+ MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+
+ setup_weights(obedit, em);
+
+ /* END AUREL THESIS*/
+
ParamHandle *handle;
const bool fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0;
@@ -1155,24 +1442,109 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
else
handle = construct_param_handle(scene, obedit, em->bm, false, fill_holes, sel, correct_aspect);
- param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
- param_lscm_solve(handle);
- param_lscm_end(handle);
+ bool transform_islands = true;
- param_average(handle);
- param_pack(handle, scene->toolsettings->uvcalc_margin, false);
+ /* AUREL THESIS - SLIM parametrization */
+
+ if (scene->toolsettings->unwrapper == 2){ //SLIM method chosen
+ int n_iterations = scene->toolsettings->slim_n_iterations;
+ bool skip_initialization = scene->toolsettings->slim_skip_initialization;
+ bool fixed_boundary = scene->toolsettings->slim_fixed_boundary;
+ bool pack_islands = scene->toolsettings->slim_pack_islands;
+
+ matrix_transfer *mt = MEM_mallocN(sizeof(matrix_transfer), "Matrix Transfer to SLIM");
+
+ /* AUREL THESIS
+ transfer of data matrices, initialisation of SLIM, actual parametrisation and finally
+ reassignment of new UVs to vertices.
+ */
+ setup_slim(scene, handle, mt, dvert, defgrp_index, em);
+ param_slim(mt, n_iterations, fixed_boundary, skip_initialization);
+ set_uv_param_slim(handle, mt);
+
+ //if any vertices are pinned, don't pack (i.e. reposition/-scale) UV charts
+ if (mt->pinned_vertices || !pack_islands){
+ transform_islands = false;
+ }
+
+ //cleanup
+ free_matrix_transfer(mt);
+
+ }else{ // AUREL THESIS use traditional parametrisation methods
+ param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
+ param_lscm_solve(handle);
+ param_lscm_end(handle);
+ }
+
+ if (transform_islands){
+ param_average(handle);
+ param_pack(handle, scene->toolsettings->uvcalc_margin, false);
+ }
param_flush(handle);
param_delete(handle);
}
+
+void setup_weights(Object *obedit, BMEditMesh *em){
+
+ // AUREL THESIS iterate over bm edit mesh and set indices for weight retrieval,
+ // This allows for later matching of vertices to weights.
+ BMVert *vert;
+ BMIter iter;
+ int i;
+ BM_ITER_MESH_INDEX(vert, &iter, em->bm, BM_VERTS_OF_MESH, i){
+ vert->id = i;
+ }
+}
+
+/* AUREL THESIS
+ Transfers necessary data from native part to SLIM.
+ */
+void setup_slim(Scene * scene, ParamHandle *handle, matrix_transfer *mt, MDeformVert *dvert, int defgrp_index, BMEditMesh *em){
+ mt->pinned_vertices = false;
+ convert_blender_slim(handle, mt, false, dvert, defgrp_index, em);
+}
+
+/* AUREL THESIS
+ Cleanup memory.
+ */
+void free_matrix_transfer(matrix_transfer *mt){
+
+ //Cleanup
+
+ for (int chartNr = 0; chartNr<mt->nCharts; chartNr++) {
+
+ MEM_freeN(mt->Vmatrices[chartNr]);
+ MEM_freeN(mt->UVmatrices[chartNr]);
+ MEM_freeN(mt->Fmatrices[chartNr]);
+
+ }
+
+ MEM_freeN(mt->nVerts);
+ MEM_freeN(mt->nFaces);
+ MEM_freeN(mt->nPinnedVertices);
+ MEM_freeN(mt->Vmatrices);
+ MEM_freeN(mt->UVmatrices);
+ MEM_freeN(mt->Fmatrices);
+ MEM_freeN(mt->Pmatrices);
+ MEM_freeN(mt->PPmatrices);
+ MEM_freeN(mt);
+}
+
static int unwrap_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);
int method = RNA_enum_get(op->ptr, "method");
+
+ int n_slim_iterations = RNA_int_get(op->ptr, "slim_iterations");
+ bool slim_pack_islands = RNA_int_get(op->ptr, "slim_pack_islands");
+ bool slim_skip_initialization = RNA_int_get(op->ptr, "slim_skip_initialization");
+ bool slim_fixed_boundary = RNA_int_get(op->ptr, "slim_fixed_boundary");
+
const bool fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data");
@@ -1203,6 +1575,13 @@ static int unwrap_exec(bContext *C, wmOperator *op)
else
RNA_enum_set(op->ptr, "method", scene->toolsettings->unwrapper);
+ /* get number of iterations and methood in global phase for SLIM unwraping*/
+ scene->toolsettings->slim_n_iterations = n_slim_iterations;
+ scene->toolsettings->slim_fixed_boundary = slim_fixed_boundary;
+ scene->toolsettings->slim_pack_islands = slim_pack_islands;
+ scene->toolsettings->slim_skip_initialization = slim_skip_initialization;
+
+
/* remember packing marging */
if (RNA_struct_property_is_set(op->ptr, "margin"))
scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
@@ -1238,6 +1617,7 @@ void UV_OT_unwrap(wmOperatorType *ot)
static EnumPropertyItem method_items[] = {
{0, "ANGLE_BASED", 0, "Angle Based", ""},
{1, "CONFORMAL", 0, "Conformal", ""},
+ {2, "SLIM", 0, "SLIM", "" },
{0, NULL, 0, NULL, NULL}
};
@@ -1261,6 +1641,15 @@ void UV_OT_unwrap(wmOperatorType *ot)
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);
+
+ RNA_def_int(ot->srna, "slim_iterations", 1, 0, 10000, "SLIM Iterations",
+ "Number of Iterations if the SLIM algorithm is used.", 1, 30);
+ RNA_def_boolean(ot->srna, "slim_skip_initialization", 0, "SLIM Skip Initialization",
+ "Use existing map as initialization for SLIM (May not contain flips!).");
+ RNA_def_boolean(ot->srna, "slim_fixed_boundary", 0, "SLIM Fix Boundary",
+ "When using SLIM and skipping initialization, this pins the boundary vertices to stay in place.");
+ RNA_def_boolean(ot->srna, "slim_pack_islands", 1, "SLIM Pack Islands",
+ "When using SLIM, this skips the packing of islands afterwards.");
}
/**************** Project From View operator **************/