diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2006-02-09 00:01:00 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2006-02-09 00:01:00 +0300 |
commit | 3753d817abf1041af435c1ae32b8ff03e945bcde (patch) | |
tree | 312046ecc686c8d0022d984295ee3313b265c16d /source/blender/src/unwrapper.c | |
parent | eb42008067d76906b7b5d2088e86b1a43356ea47 (diff) |
Seam Cutting in Faceselect Mode:
- Mark Border Seam: mark edges on the border of face selection as seam.
- Clear Seam: clears seams in selected faces.
Hotkey: Ctrl+E
- Alt+RMB Click: mark/clear edge as seam
- Alt+Shift+RMB Click: mark/clear seams along the shortest/straightest path
from last marked seam. The cost of the path also includes some measure of
'straightness' next to the typical distance to make things work more
predicatble and edgeloop friendly. Note that this cuts a path from edge to
edge, not vertex to vertex. That gives some nice control over the direction
of the seam.
Also includes:
- Removed old LSCM code.
- Fix updates glitches with DerivedMesh/Subsurf drawing in FaceSelect mode.
Now there's a drawMappedFacesTex instead of drawFacesTex.
- Minimize Stretch menu entry called Limit Stitch.
- Removed the lasttface global, was being set before it was used anyway, so
might as wel return from a function.
- Moved some backbuf sampling code to drawview.c from editmesh, so it can be
used by Faceselect and VPaint.
- Use BLI_heap in parametrizer.c.
Diffstat (limited to 'source/blender/src/unwrapper.c')
-rw-r--r-- | source/blender/src/unwrapper.c | 1239 |
1 files changed, 37 insertions, 1202 deletions
diff --git a/source/blender/src/unwrapper.c b/source/blender/src/unwrapper.c index a3ade13126f..fdf68b61a5a 100644 --- a/source/blender/src/unwrapper.c +++ b/source/blender/src/unwrapper.c @@ -60,49 +60,13 @@ #include "blendef.h" #include "mydevice.h" -#include "ONL_opennl.h" #include "BDR_unwrapper.h" #include "PIL_time.h" #include "parametrizer.h" -/* Implementation Least Squares Conformal Maps parameterization, based on - * chapter 2 of: - * Bruno Levy, Sylvain Petitjean, Nicolas Ray, Jerome Maillot. Least Squares - * Conformal Maps for Automatic Texture Atlas Generation. In Siggraph 2002, - * July 2002. - */ - -/* Data structure defines */ -#define LSCM_SEAM1 1 -#define LSCM_SEAM2 2 -#define LSCM_INDEXED 4 -#define LSCM_PINNED 8 - -/* LscmVert = One UV */ -typedef struct LscmVert { - int v, v1, v2; /* vertex indices */ - int index; /* index in solver */ - short tf_index; /* index in tface (0, 1, 2 or 3) */ - short flag; /* see above LSCM constants */ - TFace *tf; /* original tface */ -} LscmVert; - -/* QuickSort helper function, sort by vertex id */ -static int comp_lscmvert(const void *u1, const void *u2) -{ - LscmVert *v1, *v2; - - v1= *((LscmVert**)u1); - v2= *((LscmVert**)u2); - - if (v1->v > v2->v) return 1; - else if (v1->v < v2->v) return -1; - return 0; -} - -/* Hashed edge table utility */ +/* Set tface seams based on edge data, uses hash table to find seam edges. */ static void hash_add_face(EdgeHash *ehash, MFace *mf) { @@ -116,1149 +80,23 @@ static void hash_add_face(EdgeHash *ehash, MFace *mf) BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL); } -/* divide selected faces in groups, based on seams. note that group numbering - starts at 1 */ -static int make_seam_groups(Mesh *me, int **seamgroups) -{ - int a, b, gid; - TFace *tf, *tface; - MFace *mf, *mface; - int *gf, *gface, *groups; - EdgeHash *ehash; - int doit, mark; - - if(!me || !me->tface) return 0; - - groups= (int*)MEM_callocN(sizeof(int)*me->totface, "SeamGroups"); - - ehash= BLI_edgehash_new(); - - mface= (MFace*)me->mface; - tface= (TFace*)me->tface; - gface= groups; - gid= 0; - for(b=me->totface; b>0; b--, mface++, tface++, gface++) { - if(!(tface->flag & TF_SELECT) || *gface!=0) continue; - - if(gid != 0) - BLI_edgehash_clear(ehash, NULL); - - gid++; - *gface= gid; - mark= 0; - doit= 1; - - - while(doit) { - doit= 0; - - /* select connected: fill array */ - tf= tface; - mf= mface; - gf= gface; - a= b; - while(a--) { - if(tf->flag & TF_HIDE); - else if(tf->flag & TF_SELECT && *gf==gid) { - hash_add_face(ehash, mf); - } - tf++; mf++; gf++; - } - - /* select the faces using array - * consider faces connected when they share one non-seam edge */ - tf= tface; - mf= mface; - gf= gface; - a= b; - while(a--) { - if(tf->flag & TF_HIDE); - else if(tf->flag & TF_SELECT && *gf==0) { - mark= 0; - - if(!(tf->unwrap & TF_SEAM1)) - if(BLI_edgehash_haskey(ehash, mf->v1, mf->v2)) - mark= 1; - if(!(tf->unwrap & TF_SEAM2)) - if(BLI_edgehash_haskey(ehash, mf->v2, mf->v3)) - mark= 1; - if(!(tf->unwrap & TF_SEAM3)) { - if(mf->v4) { - if(BLI_edgehash_haskey(ehash, mf->v3, mf->v4)) - mark= 1; - } - else if(BLI_edgehash_haskey(ehash, mf->v3, mf->v1)) - mark= 1; - } - if(mf->v4 && !(tf->unwrap & TF_SEAM4)) - if(BLI_edgehash_haskey(ehash, mf->v4, mf->v1)) - mark= 1; - - if(mark) { - *gf= gid; - doit= 1; - } - } - tf++; mf++; gf++; - } - } - } - - BLI_edgehash_free(ehash, NULL); - *seamgroups= groups; - - return gid; -} - -static void lscm_rotate_vert(int a, LscmVert **sortvert, int v2, int index) -{ - LscmVert **sv, *v; - int found, b; - - /* starting from edge sortvert->v,v2, rotate around vertex and set - * index until a seam or an already marked tri is encountered */ - found = 1; - - while(found) { - found= 0; - sv=sortvert; - - for(b=a; b>0 && ((*sv)->v == (*sortvert)->v) && !found; b--, sv++) { - v= *sv; - - if(v->flag & LSCM_INDEXED); - else if(v->v1 == v2) { - v2= v->v2; - - if(v->flag & LSCM_SEAM1) break; - - v->index= index; - v->flag |= LSCM_INDEXED; - found= 1; - break; - } - else if(v->v2==v2) { - v2= v->v1; - - if(v->flag & LSCM_SEAM2) break; - - v->index= index; - v->flag |= LSCM_INDEXED; - found= 1; - break; - } - } - } -} - -static int lscm_vertex_set_index(int a, LscmVert **sortvert, int totindex) -{ - LscmVert **sv, *v; - int index, b; - - /* rotate over 'wheel' of faces around vertex, incrementing the index - everytime we meet a seam, or no next connected face is found. - repeat this until we have and id for all verts. - if mesh is non-manifold, non-manifold edges will be cut randomly */ - - index= totindex; - sv= sortvert; - - for(b=a; b>0 && ((*sv)->v == (*sortvert)->v); b--, sv++) { - v= *sv; - - if(v->flag & LSCM_INDEXED) continue; - - v->index= index; - v->flag |= LSCM_INDEXED; - - lscm_rotate_vert(b, sv, v->v1, index); - lscm_rotate_vert(b, sv, v->v2, index); - - index++; - } - - return index; -} - -static int lscm_set_indices(LscmVert **sortvert, int totvert) -{ - LscmVert *v, **sv; - int a, lastvert, totindex; - - totindex= 0; - lastvert= -1; - sv= sortvert; - - for(a=totvert; a>0; a--, sv++) { - v= *sv; - if(v->v != lastvert) { - totindex= lscm_vertex_set_index(a, sv, totindex); - lastvert= v->v; - } - } - - return totindex; -} - -static void lscm_normalize(float *co, float *center, float radius) -{ - /* normalize relative to complete surface */ - VecSubf(co, co, center); - VecMulf(co, (float)1.0/radius); -} - -static void lscm_add_triangle(float *v1, float *v2, float *v3, int vid1, int vid2, int vid3, float *center, float radius) -{ - float x[3], y[3], z[3], sub[3], z1[2], z2[2]; - int id0[2], id1[2], id2[2]; - - /* project 3d triangle - * edge length is lost, as this algorithm is angle based */ - lscm_normalize(v1, center, radius); - lscm_normalize(v2, center, radius); - lscm_normalize(v3, center, radius); - - VecSubf(x, v2, v1); - Normalise(x); - - VecSubf(sub, v3, v1); - Crossf(z, x, sub); - Normalise(z); - - Crossf(y, z, x); - - /* reduce to two 2d vectors */ - VecSubf(sub, v2, v1); - z1[0]= Normalise(sub); - z1[1]= 0; - - VecSubf(sub, v3, v1); - z2[0]= Inpf(sub, x); - z2[1]= Inpf(sub, y); - - /* split id's up for u and v - id = u, id + 1 = v */ - id0[0]= 2*vid1; - id0[1]= 2*vid1 + 1; - id1[0]= 2*vid2; - id1[1]= 2*vid2 + 1; - id2[0]= 2*vid3; - id2[1]= 2*vid3 + 1; - - /* The LSCM Equation: - * ------------------ - * (u,v) are the uv coords we are looking for -> complex number u + i*v - * (x,y) are the above calculated local coords -> complex number x + i*y - * Uk = uk + i*vk - * Zk = xk + i*yk (= zk[0] + i*zk[1] in the code) - * - * That makes the equation: - * (Z1 - Z0)(U2 - U0) = (Z2 - Z0)(U1 - U0) - * - * x0, y0 and y1 were made zero by projecting the triangle: - * (x1 + i*y1)(u2 + i*v2 - u0 - i*v0) = (x2 + i*y2)(u1 + i*v1 - u0 - i*v0) - * - * this gives the following coefficients: - * u0 * ((-x1 + x2) + i*(y2)) - * v0 * ((-y2) + i*(-x1 + x2)) - * u1 * ((-x2) + i*(-y2)) - * v1 * ((y2) + i*(-x2)) - * u2 * (x1) - * v2 * (i*(x1)) - */ - - /* real part */ - nlBegin(NL_ROW); - nlCoefficient(id0[0], -z1[0] + z2[0]); - nlCoefficient(id0[1], -z2[1] ); - nlCoefficient(id1[0], -z2[0] ); - nlCoefficient(id1[1], z2[1] ); - nlCoefficient(id2[0], z1[0] ); - nlEnd(NL_ROW); - - /* imaginary part */ - nlBegin(NL_ROW); - nlCoefficient(id0[0], z2[1] ); - nlCoefficient(id0[1], -z1[0] + z2[0]); - nlCoefficient(id1[0], -z2[1] ); - nlCoefficient(id1[1], -z2[0] ); - nlCoefficient(id2[1], z1[0] ); - nlEnd(NL_ROW); -} - -static float lscm_angle_cos(float *v1, float *v2, float *v3) -{ - float vec1[3], vec2[3]; - - VecSubf(vec1, v2, v1); - VecSubf(vec2, v3, v1); - Normalise(vec1); - Normalise(vec2); - - return vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2]; -} - -static int lscm_build_vertex_data(Mesh *me, int *groups, int gid, LscmVert **lscm_vertices, LscmVert ***sort_vertices) -{ - MVert *mv; - MFace *mf; - TFace *tf; - int *gf, totvert, a; - LscmVert *lscmvert, **sortvert; - LscmVert *v1, *v2, *v3, **sv1, **sv2, **sv3; - float a1, a2; - - /* determine size for malloc */ - totvert= 0; - mv = me->mvert; - mf= me->mface; - tf= me->tface; - gf= groups; - a1 = a2 = 0; - - for(a=me->totface; a>0; a--) { - if(*gf==gid) { - - totvert += 3; - if(mf->v4) totvert +=3; - } - tf++; mf++; gf++; - } - - /* a list per face vertices */ - lscmvert= (LscmVert*)MEM_mallocN(sizeof(LscmVert)*totvert,"LscmVerts"); - /* the above list sorted by vertex id */ - sortvert= (LscmVert**)MEM_mallocN(sizeof(LscmVert*)*totvert, "LscmVSort"); - - /* actually build the list (including virtual triangulation) */ - mf= me->mface; - tf= me->tface; - gf= groups; - - v1= lscmvert; - v2= lscmvert + 1; - v3= lscmvert + 2; - - sv1= sortvert; - sv2= sortvert + 1; - sv3= sortvert + 2; - - /* warning: ugly code :) */ - for(a=me->totface; a>0; a--) { - if(*gf==gid) { - /* determine triangulation direction, to avoid degenerate - triangles (small cos = degenerate). */ - if(mf->v4) { - a1 = lscm_angle_cos((mv+mf->v1)->co, (mv+mf->v2)->co, (mv+mf->v3)->co); - a1 += lscm_angle_cos((mv+mf->v2)->co, (mv+mf->v1)->co, (mv+mf->v3)->co); - a1 += lscm_angle_cos((mv+mf->v3)->co, (mv+mf->v1)->co, (mv+mf->v2)->co); - - a2 = lscm_angle_cos((mv+mf->v1)->co, (mv+mf->v2)->co, (mv+mf->v4)->co); - a2 += lscm_angle_cos((mv+mf->v2)->co, (mv+mf->v1)->co, (mv+mf->v4)->co); - a2 += lscm_angle_cos((mv+mf->v4)->co, (mv+mf->v1)->co, (mv+mf->v2)->co); - } - - a1 = 0.0; a2 = 1.0; - - if(!mf->v4 || a1 > a2) { - v1->v= mf->v1; - v2->v= mf->v2; - v3->v= mf->v3; - - v1->tf_index= 0; - v2->tf_index= 1; - v3->tf_index= 2; - - v1->flag= v2->flag= v3->flag= 0; - - v1->v1= v2->v; - v1->v2= v3->v; - - v2->v1= v1->v; - v2->v2= v3->v; - - v3->v1= v1->v; - v3->v2= v2->v; - - v1->tf= v2->tf= v3->tf= tf; - - *sv1= v1; - *sv2= v2; - *sv3= v3; - - if(tf->unwrap & TF_SEAM1) { - v1->flag |= LSCM_SEAM1; - v2->flag |= LSCM_SEAM1; - } - - if(tf->unwrap & TF_SEAM2) { - v2->flag |= LSCM_SEAM2; - v3->flag |= LSCM_SEAM2; - } - - if(!mf->v4 && tf->unwrap & TF_SEAM3) { - v1->flag |= LSCM_SEAM2; - v3->flag |= LSCM_SEAM1; - } - - v1 += 3; v2 += 3; v3 += 3; - sv1 += 3; sv2 += 3; sv3 += 3; - } - - if(mf->v4 && a1 > a2) { - v1->v= mf->v1; - v2->v= mf->v3; - v3->v= mf->v4; - - v1->tf_index= 0; - v2->tf_index= 2; - v3->tf_index= 3; - - v1->flag= v2->flag= v3->flag= 0; - - v1->v1= v2->v; - v1->v2= v3->v; - - v2->v1= v3->v; - v2->v2= v1->v; - - v3->v1= v1->v; - v3->v2= v2->v; - - v1->tf= v2->tf= v3->tf= tf; - - *sv1= v1; - *sv2= v2; - *sv3= v3; - - if(tf->unwrap & TF_SEAM3) { - v2->flag |= LSCM_SEAM1; - v3->flag |= LSCM_SEAM2; - } - - if(tf->unwrap & TF_SEAM4) { - v1->flag |= LSCM_SEAM2; - v3->flag |= LSCM_SEAM1; - } - - v1 += 3; v2 += 3; v3 += 3; - sv1 += 3; sv2 += 3; sv3 += 3; - } - - if(mf->v4 && a1 <= a2) { - v1->v= mf->v1; - v2->v= mf->v2; - v3->v= mf->v4; - - v1->tf_index= 0; - v2->tf_index= 1; - v3->tf_index= 3; - - v1->flag= v2->flag= v3->flag= 0; - - v1->v1= v2->v; - v1->v2= v3->v; - - v2->v1= v1->v; - v2->v2= v3->v; - - v3->v1= v1->v; - v3->v2= v2->v; - - v1->tf= v2->tf= v3->tf= tf; - - *sv1= v1; - *sv2= v2; - *sv3= v3; - - if(tf->unwrap & TF_SEAM1) { - v1->flag |= LSCM_SEAM1; - v2->flag |= LSCM_SEAM1; - } - - if(tf->unwrap & TF_SEAM4) { - v1->flag |= LSCM_SEAM2; - v3->flag |= LSCM_SEAM1; - } - - v1 += 3; v2 += 3; v3 += 3; - sv1 += 3; sv2 += 3; sv3 += 3; - - /* -- */ - - v1->v= mf->v2; - v2->v= mf->v3; - v3->v= mf->v4; - - v1->tf_index= 1; - v2->tf_index= 2; - v3->tf_index= 3; - - v1->flag= v2->flag= v3->flag= 0; - - v1->v1= v2->v; - v1->v2= v3->v; - - v2->v1= v1->v; - v2->v2= v3->v; - - v3->v1= v1->v; - v3->v2= v2->v; - - v1->tf= v2->tf= v3->tf= tf; - - *sv1= v1; - *sv2= v2; - *sv3= v3; - - if(tf->unwrap & TF_SEAM2) { - v1->flag |= LSCM_SEAM1; - v2->flag |= LSCM_SEAM1; - } - - if(tf->unwrap & TF_SEAM3) { - v2->flag |= LSCM_SEAM2; - v3->flag |= LSCM_SEAM2; - } - - v1 += 3; v2 += 3; v3 += 3; - sv1 += 3; sv2 += 3; sv3 += 3; - } - - } - tf++; mf++; gf++; - } - - /* sort by vertex id */ - qsort(sortvert, totvert, sizeof(LscmVert*), comp_lscmvert); - - *lscm_vertices= lscmvert; - *sort_vertices= sortvert; - return totvert; -} - -static void lscm_min_max_cent_rad(Mesh *me, LscmVert **sortvert, int totvert, float *min, float *max, float *center, float *radius) -{ - MVert *mv= me->mvert; - LscmVert *v, **sv; - int a, lastvert, vertcount; - float *co, sub[3]; - - /* find min, max and center */ - center[0]= center[1]= center[2]= 0.0; - INIT_MINMAX(min, max); - - vertcount= 0; - lastvert= -1; - sv= sortvert; - - for(a=totvert; a>0; a--, sv++) { - v= *sv; - if(v->v != lastvert) { - co= (mv+v->v)->co; - - VecAddf(center, center, (mv+v->v)->co); - DO_MINMAX(co, min, max); - - vertcount++; - lastvert= v->v; - } - } - - VecMulf(center, (float)1.0/(float)vertcount); - - /* find radius */ - VecSubf(sub, center, max); - *radius= Normalise(sub); - - if(*radius < 1e-20) - *radius= 1.0; -} - -static void lscm_projection_axes(float *min, float *max, float *p1, float *p2) -{ - float dx, dy, dz; - - dx= max[0] - min[0]; - dy= max[1] - min[1]; - dz= max[2] - min[2]; - - p1[0]= p1[1]= p1[2]= 0.0; - p2[0]= p2[1]= p2[2]= 0.0; - - if(dx < dy && dx < dz) { - if(dy > dz) p1[1]= p2[2]= 1.0; /* y, z */ - else p1[2]= p2[1]= 1.0; /* z, y */ - } - else if(dy < dx && dy < dz) { - if(dx > dz) p1[0]= p2[2]= 1.0; /* x, z */ - else p1[2]= p2[0]= 1.0; /* z, x */ - } - else { - if(dx > dy) p1[0]= p2[1]= 1.0; /* x, y */ - else p1[1]= p2[0]= 1.0; /* y, x */ - } -} - -static void lscm_set_initial_solution(Mesh *me, LscmVert **sortvert, int totvert, float *p1, float *p2, int *vertex_min, int *vertex_max) -{ - float umin, umax, *uv, *co; - int vmin, vmax, a; - LscmVert **sv, *v; - MVert *mv= me->mvert; - - umin= 1.0e30; - umax= -1.0e30; - - vmin= 0; - vmax= 2; - - sv= sortvert; - - for(a=totvert; a>0; a--, sv++) { - v= *sv; - co= (mv+v->v)->co; - uv= v->tf->uv[v->tf_index]; - - uv[0]= Inpf(co, p1); - uv[1]= Inpf(co, p2); - - if(uv[0] < umin) { - vmin= v->index; - umin= uv[0]; - } - if(uv[0] > umax) { - vmax= v->index; - umax= uv[0]; - } - - nlSetVariable(2*v->index, uv[0]); - nlSetVariable(2*v->index + 1, uv[1]); - } - - *vertex_min= vmin; - *vertex_max= vmax; -} - -static void lscm_set_pinned_solution(Mesh *me, LscmVert **sortvert, int totvert, int *pinned) -{ - float min[2], max[2], *uv, *co; - int a, pin; - LscmVert **sv, *v; - MVert *mv= me->mvert; - - INIT_MINMAX2(min, max); - *pinned= 0; - - sv= sortvert; - - for(a=totvert; a>0; a--, sv++) { - v= *sv; - co= (mv+v->v)->co; - uv= v->tf->uv[v->tf_index]; - - pin = ((v->tf->unwrap & TF_PIN1) && (v->tf_index == 0)) || - ((v->tf->unwrap & TF_PIN2) && (v->tf_index == 1)) || - ((v->tf->unwrap & TF_PIN3) && (v->tf_index == 2)) || - ((v->tf->unwrap & TF_PIN4) && (v->tf_index == 3)); - - nlSetVariable(2*v->index, uv[0]); - nlSetVariable(2*v->index + 1, uv[1]); - - if(pin){ - DO_MINMAX2(uv, min, max); - - *pinned += 1; - - nlLockVariable(2*v->index); - nlLockVariable(2*v->index + 1); - } - } - - if (*pinned){ - /* abuse umax vmax for caculating euclidian distance */ - max[0] -= min[0]; - max[1] -= min[1]; - - /* check for degenerated pinning box */ - if (((max[0]*max[0])+(max[1]*max[1])) < 1e-10) - *pinned = -1; - } -} - - -static void lscm_build_matrix(Mesh *me, LscmVert *lscmvert, int *groups, int gid, float *center, float radius) -{ - MVert *mv= me->mvert; - MFace *mf; - TFace *tf; - int *gf, a, id1, id2, id3; - LscmVert *v; - float co1[3], co2[3], co3[3]; - - nlBegin(NL_MATRIX); - - mf= me->mface; - tf= me->tface; - gf= groups; - v= lscmvert; - - for(a=me->totface; a>0; a--) { - if(*gf==gid) { - VecCopyf(co1, (mv+v->v)->co); - id1= v->index; v++; - VecCopyf(co2, (mv+v->v)->co); - id2= v->index; v++; - VecCopyf(co3, (mv+v->v)->co); - id3= v->index; v++; - lscm_add_triangle(co1, co2, co3, id1, id2, id3, center, radius); - - if(mf->v4) { - VecCopyf(co1, (mv+v->v)->co); - id1= v->index; v++; - VecCopyf(co2, (mv+v->v)->co); - id2= v->index; v++; - VecCopyf(co3, (mv+v->v)->co); - id3= v->index; v++; - lscm_add_triangle(co1, co2, co3, id1, id2, id3, center, radius); - } - } - tf++; mf++; gf++; - } - - nlEnd(NL_MATRIX); -} - -static void lscm_load_solution(Mesh *me, LscmVert *lscmvert, int *groups, int gid) -{ - MFace *mf; - TFace *tf; - int *gf, a, b; - LscmVert *v; - float *uv; - - mf= me->mface; - tf= me->tface; - gf= groups; - v= lscmvert; - - for(a=me->totface; a>0; a--) { - if(*gf==gid) { - - if(mf->v4) b= 6; - else b=3; - - /* index= u, index + 1= v */ - while(b > 0) { - uv= v->tf->uv[v->tf_index]; - - uv[0]= nlGetVariable(2*v->index); - uv[1]= nlGetVariable(2*v->index + 1); - - v++; - b--; - } - } - tf++; mf++; gf++; - } -} - -static int unwrap_lscm_face_group(Mesh *me, int *groups, int gid) -{ - LscmVert *lscmvert, **sortvert; - int totindex, totvert, vmin, vmax,pinned; - float min[3], max[3], center[3], radius, p1[3], p2[3]; - - /* build the data structures */ - totvert= lscm_build_vertex_data(me, groups, gid, &lscmvert, &sortvert); - - /* calculate min, max, center and radius */ - lscm_min_max_cent_rad(me, sortvert, totvert, min, max, center, &radius); - - /* index distinct vertices */ - totindex= lscm_set_indices(sortvert, totvert); - - /* create solver */ - nlNewContext(); - nlSolverParameteri(NL_NB_VARIABLES, 2*totindex); - nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE); - - nlBegin(NL_SYSTEM); - - /* find axes for projecting initial solutions on */ - lscm_projection_axes(min, max, p1, p2); - /* see if pinned data is avail and set on fly */ - lscm_set_pinned_solution(me, sortvert, totvert, &pinned); - - if(pinned < 0); /* really small pinned uv's: won't see difference anyway */ - else { - /* auto pinning */ - if(pinned < 2) - { - /* set initial solution and locate two extrema vertices to pin */ - lscm_set_initial_solution(me,sortvert,totvert,p1,p2,&vmin,&vmax); - - /* pin 2 uv's */ - nlLockVariable(2*vmin); - nlLockVariable(2*vmin + 1); - nlLockVariable(2*vmax); - nlLockVariable(2*vmax + 1); - } - - /* add triangles to the solver */ - lscm_build_matrix(me, lscmvert, groups, gid, center, radius); - - nlEnd(NL_SYSTEM); - - /* LSCM solver magic! */ - nlSolve(NULL, NL_FALSE); - - /* load new uv's: will be projected uv's if solving failed */ - lscm_load_solution(me, lscmvert, groups, gid); - } - - nlDeleteContext(nlGetCurrent()); - MEM_freeN(lscmvert); - MEM_freeN(sortvert); - return (pinned); -} - -static void seam_group_bbox(Mesh *me, int *groups, int gid, float *min, float *max) -{ - MFace *mf; - TFace *tf; - int *gf, a; - - INIT_MINMAX2(min, max); - - mf= me->mface; - tf= me->tface; - gf= groups; - - for(a=me->totface; a>0; a--) { - if((gid!=0 && *gf==gid) || (gid==0 && *gf)) { - - DO_MINMAX2(tf->uv[0], min, max) - DO_MINMAX2(tf->uv[1], min, max) - DO_MINMAX2(tf->uv[2], min, max) - - if(mf->v4) { - DO_MINMAX2(tf->uv[3], min, max) - } - } - tf++; mf++; gf++; - } -} - -static void seam_group_scale(Mesh *me, int *groups, int gid, float scale) -{ - MFace *mf; - TFace *tf; - int *gf, a; - - mf= me->mface; - tf= me->tface; - gf= groups; - - for(a=me->totface; a>0; a--) { - if((gid!=0 && *gf==gid) || (gid==0 && *gf)) { - - Vec2Mulf(tf->uv[0], scale); - Vec2Mulf(tf->uv[1], scale); - Vec2Mulf(tf->uv[2], scale); - if(mf->v4) Vec2Mulf(tf->uv[3], scale); - } - tf++; mf++; gf++; - } -} - -static void seam_group_move(Mesh *me, int *groups, int gid, float add[2]) -{ - MFace *mf; - TFace *tf; - int *gf, a; - - mf= me->mface; - tf= me->tface; - gf= groups; - - for(a=me->totface; a>0; a--) { - if((gid!=0 && *gf==gid) || (gid==0 && *gf)) { - - Vec2Addf(tf->uv[0], tf->uv[0], add); - Vec2Addf(tf->uv[1], tf->uv[1], add); - Vec2Addf(tf->uv[2], tf->uv[2], add); - if(mf->v4) Vec2Addf(tf->uv[3], tf->uv[3], add); - } - tf++; mf++; gf++; - } -} - -/* put group withing (0,0)->(1,1) boundbox */ -static void seam_group_normalize(Mesh *me, int *groups, int gid) -{ - float min[2], max[2], sx, sy, scale, add[2]; - - seam_group_bbox(me, groups, gid, min, max); - - sx= (max[0]-min[0]); - sy= (max[1]-min[1]); - - scale= MAX2(sx, sy); - scale= (1.0/scale); - - add[0]= -min[0]; - add[1]= -min[1]; - - seam_group_move(me, groups, gid, add); - seam_group_scale(me, groups, gid, scale); -} - -/* get scale relative to mesh */ -static float seam_group_relative_scale(Mesh *me, int *groups, int gid) -{ - MVert *mv= me->mvert; - MFace *mf; - TFace *tf; - int *gf, a; - float len_xyz, len_uv; - - len_xyz= 0.0; - len_uv= 0.0; - mf= me->mface; - tf= me->tface; - gf= groups; - - for(a=me->totface; a>0; a--) { - if(*gf==gid) { - - len_uv += Vec2Lenf(tf->uv[0], tf->uv[1]); - len_xyz += VecLenf((mv+mf->v1)->co, (mv+mf->v2)->co); - - len_uv += Vec2Lenf(tf->uv[1], tf->uv[2]); - len_xyz += VecLenf((mv+mf->v2)->co, (mv+mf->v3)->co); - - if(mf->v4) { - - len_uv += Vec2Lenf(tf->uv[2], tf->uv[3]); - len_xyz += VecLenf((mv+mf->v3)->co, (mv+mf->v4)->co); - - len_uv += Vec2Lenf(tf->uv[3], tf->uv[0]); - len_xyz += VecLenf((mv+mf->v4)->co, (mv+mf->v1)->co); - } - else { - len_uv += Vec2Lenf(tf->uv[2], tf->uv[0]); - len_xyz += VecLenf((mv+mf->v3)->co, (mv+mf->v1)->co); - } - } - tf++; mf++; gf++; - } - - return (len_uv/len_xyz); -} - -/* very primitive packing */ -static void pack_seam_groups(Mesh *me, int *groups, int totgroup) -{ - float *groupscale, minscale, scale, add[2], groupw; - float dx, dy, packx, packy, min[2], max[2], rowh; - int a; - - groupscale = (float*)MEM_mallocN(sizeof(float)*totgroup, "SeamGroupScale"); - - minscale= 1e30; - - for(a=0; a<totgroup; a++) { - groupscale[a]= seam_group_relative_scale(me, groups, a+1); - minscale= MIN2(groupscale[a], minscale); - } - - packx= packy= 0.0; - rowh= 0.0; - groupw= 1.0/sqrt(totgroup); - - for(a=0; a<totgroup; a++) { - - /* scale so all groups have the same size relative to the mesh */ - scale = minscale/groupscale[a]; - scale *= groupw; - - seam_group_bbox(me, groups, a+1, min, max); - dx= (max[0]-min[0])*scale; - dy= (max[1]-min[1])*scale; - - /* for padding */ - dx += 0.01; - dy += 0.01; - - add[0]= add[1]= 0.0; - - if(dx > 1.0) { - add[0]= 0.0; - add[1]= packy; - - packy += dy; - packx= 0.0; - rowh= 0.0; - } - else if(dx <= (1.0-packx)) { - add[0]= packx; - add[1]= packy; - - packx += dx; - rowh= MAX2(rowh, dy); - } - else { - packy += rowh; - packx= dx; - rowh= dy; - - add[0]= 0.0; - add[1]= packy; - } - - /* for padding */ - add[0] += 0.005; - add[1] += 0.005; - - seam_group_scale(me, groups, a+1, scale); - seam_group_move(me, groups, a+1, add); - } - - MEM_freeN(groupscale); - - seam_group_normalize(me, groups, 0); - seam_group_scale(me, groups, 0, 0.98); - add[0]= add[1]= 0.01; - seam_group_move(me, groups, 0, add); -} - -void unwrap_lscm(void) -{ - int dopack = 1; - int res; - Mesh *me; - int totgroup, *groups=NULL, a; - - if (G.scene->toolsettings->unwrapper != 2) { - unwrap_lscm_new(); - return; - } - - me= get_mesh(OBACT); - if(me==0 || me->tface==0) return; - - totgroup= make_seam_groups(me, &groups); - - if(totgroup==0) return; - - for(a=totgroup; a>0; a--) { - res= unwrap_lscm_face_group(me, groups, a); - if((res < 3) && (res > -1)) { - seam_group_normalize(me, groups, a); - } - else { - dopack = 0; - } - - } - - if(dopack) pack_seam_groups(me, groups, totgroup); - - MEM_freeN(groups); - - BIF_undo_push("UV lscm unwrap"); - - object_uvs_changed(OBACT); - - allqueue(REDRAWVIEW3D, 0); - allqueue(REDRAWIMAGE, 0); -} - -/* note; to make it quick work, brecht/jens: you can make it nice later! (ton) */ -void unwrap_lscm_live(void) -{ - int dopack = 1; - int res; - Mesh *me; - int totgroup, *groups=NULL, a; - - me= get_mesh(OBACT); - if(me==0 || me->tface==0) return; - - totgroup= make_seam_groups(me, &groups); - - if(totgroup==0) return; - - for(a=totgroup; a>0; a--) { - res= unwrap_lscm_face_group(me, groups, a); - if((res < 3) && (res > -1)) { - seam_group_normalize(me, groups, a); - } - else { - dopack = 0; - } - - } - - if(dopack) pack_seam_groups(me, groups, totgroup); - - MEM_freeN(groups); - -} - -/* Set tface seams based on edge data, uses hash table to find seam edges. */ - -void set_seamtface() -{ - Mesh *me; - EdgeHash *ehash; - int a; - MFace *mf; - TFace *tf; - MEdge *medge; - - me= get_mesh(OBACT); - if(!me || !me->tface || !(G.f & G_FACESELECT)) return; - - ehash= BLI_edgehash_new(); - - for(medge=me->medge, a=me->totedge; a>0; a--, medge++) - if(medge->flag & ME_SEAM) - BLI_edgehash_insert(ehash, medge->v1, medge->v2, NULL); - - mf= me->mface; - tf= me->tface; - for(a=me->totface; a>0; a--, mf++, tf++) { - tf->unwrap &= ~(TF_SEAM1|TF_SEAM2|TF_SEAM3|TF_SEAM4); - - if(!ehash) continue; - - if(BLI_edgehash_haskey(ehash, mf->v1, mf->v2)) tf->unwrap |= TF_SEAM1; - if(BLI_edgehash_haskey(ehash, mf->v2, mf->v3)) tf->unwrap |= TF_SEAM2; - - if(mf->v4) { - if(BLI_edgehash_haskey(ehash, mf->v3, mf->v4)) tf->unwrap |= TF_SEAM3; - if(BLI_edgehash_haskey(ehash, mf->v4, mf->v1)) tf->unwrap |= TF_SEAM4; - } - else if(BLI_edgehash_haskey(ehash, mf->v3, mf->v1)) tf->unwrap |= TF_SEAM3; - } - - BLI_edgehash_free(ehash, NULL); -} - void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index) { TFace *tf; MFace *mf; int a, doit=1, mark=0; char *linkflag; - EdgeHash *ehash; + EdgeHash *ehash, *seamhash; + MEdge *med; ehash= BLI_edgehash_new(); + seamhash = BLI_edgehash_new(); linkflag= MEM_callocN(sizeof(char)*me->totface, "linkflaguv"); + for(med=me->medge, a=0; a < me->totedge; a++, med++) + if(med->flag & ME_SEAM) + BLI_edgehash_insert(seamhash, med->v1, med->v2, NULL); + if (mode==0 || mode==1) { /* only put face under cursor in array */ mf= ((MFace*)me->mface) + index; @@ -1285,27 +123,29 @@ void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index) tf= me->tface; mf= me->mface; for(a=0; a<me->totface; a++, tf++, mf++) { - if(tf->flag & TF_HIDE); - else if(!linkflag[a]) { + if(tf->flag & TF_HIDE) + continue; + + if(!linkflag[a]) { mark= 0; - if(!(tf->unwrap & TF_SEAM1)) + if(!BLI_edgehash_haskey(seamhash, mf->v1, mf->v2)) if(BLI_edgehash_haskey(ehash, mf->v1, mf->v2)) mark= 1; - if(!(tf->unwrap & TF_SEAM2)) + if(!BLI_edgehash_haskey(seamhash, mf->v2, mf->v3)) if(BLI_edgehash_haskey(ehash, mf->v2, mf->v3)) mark= 1; - if(!(tf->unwrap & TF_SEAM3)) { - if(mf->v4) { + if(mf->v4) { + if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v4)) if(BLI_edgehash_haskey(ehash, mf->v3, mf->v4)) mark= 1; - } - else if(BLI_edgehash_haskey(ehash, mf->v3, mf->v1)) - mark= 1; + if(!BLI_edgehash_haskey(seamhash, mf->v4, mf->v1)) + if(BLI_edgehash_haskey(ehash, mf->v4, mf->v1)) + mark= 1; } - if(mf->v4 && !(tf->unwrap & TF_SEAM4)) - if(BLI_edgehash_haskey(ehash, mf->v4, mf->v1)) - mark= 1; + else if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v1)) + if(BLI_edgehash_haskey(ehash, mf->v3, mf->v1)) + mark = 1; if(mark) { linkflag[a]= 1; @@ -1317,6 +157,9 @@ void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index) } + BLI_edgehash_free(ehash, NULL); + BLI_edgehash_free(seamhash, NULL); + if(mode==0 || mode==2) { for(a=0, tf=me->tface; a<me->totface; a++, tf++) if(linkflag[a]) @@ -1341,7 +184,6 @@ void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index) } } - BLI_edgehash_free(ehash, NULL); MEM_freeN(linkflag); BIF_undo_push("Select linked UV face"); @@ -1350,7 +192,7 @@ void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index) /* Parametrizer */ -ParamHandle *construct_param_handle(Mesh *me, short implicit, short fill) +ParamHandle *construct_param_handle(Mesh *me, short implicit, short fill, short sel) { int a; TFace *tf; @@ -1371,7 +213,10 @@ ParamHandle *construct_param_handle(Mesh *me, short implicit, short fill) float *uv[4]; int nverts; - if ((tf->flag & TF_HIDE) || !(tf->flag & TF_SELECT)) + if (tf->flag & TF_HIDE) + continue; + + if (sel && !(tf->flag & TF_SELECT)) continue; if (implicit && !(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4))) @@ -1429,7 +274,7 @@ ParamHandle *construct_param_handle(Mesh *me, short implicit, short fill) return handle; } -void unwrap_lscm_new(void) +void unwrap_lscm(short seamcut) { Mesh *me; ParamHandle *handle; @@ -1439,7 +284,7 @@ void unwrap_lscm_new(void) me= get_mesh(OBACT); if(me==0 || me->tface==0) return; - handle = construct_param_handle(me, 0, fillholes); + handle = construct_param_handle(me, 0, fillholes, seamcut == 0); param_lscm_begin(handle, PARAM_FALSE, abf); param_lscm_solve(handle); @@ -1451,7 +296,8 @@ void unwrap_lscm_new(void) param_delete(handle); - BIF_undo_push("UV unwrap"); + if (!seamcut) + BIF_undo_push("UV unwrap"); object_uvs_changed(OBACT); @@ -1471,7 +317,7 @@ void minimize_stretch_tface_uv(void) me = get_mesh(OBACT); if(me==0 || me->tface==0) return; - handle = construct_param_handle(me, 1, fillholes); + handle = construct_param_handle(me, 1, fillholes, 1); lasttime = PIL_check_seconds_timer(); @@ -1561,7 +407,7 @@ void smooth_area_tface_uv(void) me = get_mesh(OBACT); if(me==0 || me->tface==0) return; - handle = construct_param_handle(me, 1, fillholes); + handle = construct_param_handle(me, 1, fillholes, 1); param_smooth_area(handle); param_flush(handle); param_delete(handle); @@ -1584,24 +430,16 @@ void unwrap_lscm_live_begin(void) short abf = G.scene->toolsettings->unwrapper == 1; short fillholes = G.scene->toolsettings->uvcalc_flag & 1; - if (G.scene->toolsettings->unwrapper == 2) - return; - me= get_mesh(OBACT); if(me==0 || me->tface==0) return; - liveHandle = construct_param_handle(me, 0, fillholes); + liveHandle = construct_param_handle(me, 0, fillholes, 1); param_lscm_begin(liveHandle, PARAM_TRUE, abf); } void unwrap_lscm_live_re_solve(void) { - if (G.scene->toolsettings->unwrapper == 2) { - unwrap_lscm(); - return; - } - if (liveHandle) { param_lscm_solve(liveHandle); param_flush(liveHandle); @@ -1610,9 +448,6 @@ void unwrap_lscm_live_re_solve(void) void unwrap_lscm_live_end(short cancel) { - if (G.scene->toolsettings->unwrapper == 2) - return; - if (liveHandle) { param_lscm_end(liveHandle); if (cancel) |