diff options
author | Aurel Gruber <aurel.gruber@infix.ch> | 2016-11-18 14:54:50 +0300 |
---|---|---|
committer | Aurel Gruber <aurel.gruber@infix.ch> | 2017-02-27 13:24:36 +0300 |
commit | 4aac14f0d2d83e4bf38f6a92335de6c3e73559f9 (patch) | |
tree | 20aef6c2f51e3d6a0a7b1380e1de6e3063a55bd8 /source/blender/editors/uvedit | |
parent | 23fa36889820965033d90e4ecb5855776fc41d65 (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.txt | 3 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_intern.h | 2 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_ops.c | 4 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_parametrizer.c | 357 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_parametrizer.h | 16 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_unwrap_ops.c | 399 |
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 **************/ |