2
* $Id: unwrapper.c,v 1.9 2005/04/23 01:36:08 blendix Exp $
4
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* as published by the Free Software Foundation; either version 2
9
* of the License, or (at your option) any later version. The Blender
10
* Foundation also sells licenses for use in proprietary software under
11
* the Blender License. See http://www.blender.org/BL/ for information
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software Foundation,
21
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24
* All rights reserved.
26
* The Original Code is: all of this file.
28
* Contributor(s): none yet.
30
* ***** END GPL/BL DUAL LICENSE BLOCK *****
41
#include "MEM_guardedalloc.h"
43
#include "DNA_mesh_types.h"
44
#include "DNA_meshdata_types.h"
45
#include "DNA_scene_types.h"
47
#include "BKE_global.h"
49
#include "BKE_utildefines.h"
51
#include "BLI_arithb.h"
53
#include "BIF_space.h"
58
#include "ONL_opennl.h"
59
#include "BDR_unwrapper.h"
61
/* Implementation Least Squares Conformal Maps parameterization, based on
63
* Bruno Levy, Sylvain Petitjean, Nicolas Ray, Jerome Maillot. Least Squares
64
* Conformal Maps for Automatic Texture Atlas Generation. In Siggraph 2002,
68
/* Data structure defines */
71
#define LSCM_INDEXED 4
74
/* LscmVert = One UV */
75
typedef struct LscmVert {
76
int v, v1, v2; /* vertex indices */
77
int index; /* index in solver */
78
short tf_index; /* index in tface (0, 1, 2 or 3) */
79
short flag; /* see above LSCM constants */
80
TFace *tf; /* original tface */
83
/* QuickSort helper function, sort by vertex id */
84
static int comp_lscmvert(const void *u1, const void *u2)
88
v1= *((LscmVert**)u1);
89
v2= *((LscmVert**)u2);
91
if (v1->v > v2->v) return 1;
92
else if (v1->v < v2->v) return -1;
96
/* Hashed edge table utility */
98
#define EDHASH(a, b) ((a)*256 + (b))
99
#define EDHASHSIZE 65536
102
typedef struct HashEdge {
104
struct HashEdge *next;
107
static HashEdge *get_hashedge(HashEdge *table, unsigned int v1, unsigned int v2)
109
unsigned int hv1, hv2;
114
SWAP(unsigned int, hv1, hv2);
116
return (table + EDHASH(hv1, hv2));
119
static int has_hashedge(HashEdge *he, unsigned int v1, unsigned int v2)
122
if(he->v1 || he->v2) {
123
if(he->v1==v1 && he->v2==v2) return 1;
124
else if(he->v1==v2 && he->v2==v1) return 1;
132
static void add_hashedge(HashEdge *first, unsigned int v1, unsigned int v2)
134
if(first->v1 == 0 && first->v2 == 0) {
139
HashEdge *he= (HashEdge*)MEM_mallocN(sizeof(HashEdge), "mini");
142
he->next= first->next;
147
static int edge_in_hash(HashEdge *htable, unsigned int v1, unsigned int v2)
149
return has_hashedge(get_hashedge(htable, v1, v2), v1, v2);
152
static void hash_add_edge(HashEdge *htable, unsigned int v1, unsigned int v2)
154
HashEdge *he = get_hashedge(htable, v1, v2);
156
if (!has_hashedge(he, v1, v2))
157
add_hashedge(he, v1, v2);
160
static void hash_add_face(HashEdge *htable, MFace *mface)
162
hash_add_edge(htable, mface->v1, mface->v2);
163
hash_add_edge(htable, mface->v2, mface->v3);
165
hash_add_edge(htable, mface->v3, mface->v4);
166
hash_add_edge(htable, mface->v4, mface->v1);
169
hash_add_edge(htable, mface->v3, mface->v1);
172
static HashEdge *make_hash_edge_table(Mesh *me, short fill)
174
HashEdge *htable, *he;
178
if(fill && (me->medge==NULL))
181
htable= MEM_callocN(EDHASHSIZE*sizeof(HashEdge), "lscmedgehashtable");
185
for(a=me->totedge; a>0; a--, medge++) {
186
if(medge->flag & ME_SEAM) {
187
he= get_hashedge(htable, medge->v1, medge->v2);
188
add_hashedge(he, medge->v1, medge->v2);
196
static void clear_hash_edge_table(HashEdge *htable)
198
HashEdge *first, *he, *hen;
203
for(a=EDHASHSIZE; a>0; a--, first++) {
210
first->v1 = first->v2 = 0;
216
static void free_hash_edge_table(HashEdge *htable)
219
clear_hash_edge_table(htable);
224
/* divide selected faces in groups, based on seams. note that group numbering
226
static int make_seam_groups(Mesh *me, int **seamgroups)
231
int *gf, *gface, *groups;
235
if(!me || !me->tface) return 0;
237
groups= (int*)MEM_callocN(sizeof(int)*me->totface, "SeamGroups");
239
htable= make_hash_edge_table(me, 0);
241
mface= (MFace*)me->mface;
242
tface= (TFace*)me->tface;
245
for(b=me->totface; b>0; b--, mface++, tface++, gface++) {
246
if(!(tface->flag & TF_SELECT) || *gface!=0) continue;
249
clear_hash_edge_table(htable);
260
/* select connected: fill array */
266
if(tf->flag & TF_HIDE);
267
else if(tf->flag & TF_SELECT && *gf==gid && mf->v3) {
268
hash_add_face(htable, mf);
273
/* select the faces using array
274
* consider faces connected when they share one non-seam edge */
280
if(tf->flag & TF_HIDE);
281
else if(tf->flag & TF_SELECT && mf->v3 && *gf==0) {
284
if(!(tf->unwrap & TF_SEAM1))
285
if(edge_in_hash(htable, mf->v1, mf->v2))
287
if(!(tf->unwrap & TF_SEAM2))
288
if(edge_in_hash(htable, mf->v2, mf->v3))
290
if(!(tf->unwrap & TF_SEAM3)) {
292
if(edge_in_hash(htable, mf->v3, mf->v4))
295
else if(edge_in_hash(htable, mf->v3, mf->v1))
298
if(mf->v4 && !(tf->unwrap & TF_SEAM4))
299
if(edge_in_hash(htable, mf->v4, mf->v1))
312
free_hash_edge_table(htable);
318
static void lscm_rotate_vert(int a, LscmVert **sortvert, int v2, int index)
323
/* starting from edge sortvert->v,v2, rotate around vertex and set
324
* index until a seam or an already marked tri is encountered */
331
for(b=a; b>0 && ((*sv)->v == (*sortvert)->v) && !found; b--, sv++) {
334
if(v->flag & LSCM_INDEXED);
335
else if(v->v1 == v2) {
338
if(v->flag & LSCM_SEAM1) break;
341
v->flag |= LSCM_INDEXED;
348
if(v->flag & LSCM_SEAM2) break;
351
v->flag |= LSCM_INDEXED;
359
static int lscm_vertex_set_index(int a, LscmVert **sortvert, int totindex)
364
/* rotate over 'wheel' of faces around vertex, incrementing the index
365
everytime we meet a seam, or no next connected face is found.
366
repeat this until we have and id for all verts.
367
if mesh is non-manifold, non-manifold edges will be cut randomly */
372
for(b=a; b>0 && ((*sv)->v == (*sortvert)->v); b--, sv++) {
375
if(v->flag & LSCM_INDEXED) continue;
378
v->flag |= LSCM_INDEXED;
380
lscm_rotate_vert(b, sv, v->v1, index);
381
lscm_rotate_vert(b, sv, v->v2, index);
389
static int lscm_set_indices(LscmVert **sortvert, int totvert)
392
int a, lastvert, totindex;
398
for(a=totvert; a>0; a--, sv++) {
400
if(v->v != lastvert) {
401
totindex= lscm_vertex_set_index(a, sv, totindex);
409
static void lscm_normalize(float *co, float *center, float radius)
411
/* normalize relative to complete surface */
412
VecSubf(co, co, center);
413
VecMulf(co, (float)1.0/radius);
416
static void lscm_add_triangle(float *v1, float *v2, float *v3, int vid1, int vid2, int vid3, float *center, float radius)
418
float x[3], y[3], z[3], sub[3], z1[2], z2[2];
419
int id0[2], id1[2], id2[2];
421
/* project 3d triangle
422
* edge length is lost, as this algorithm is angle based */
423
lscm_normalize(v1, center, radius);
424
lscm_normalize(v2, center, radius);
425
lscm_normalize(v3, center, radius);
430
VecSubf(sub, v3, v1);
436
/* reduce to two 2d vectors */
437
VecSubf(sub, v2, v1);
438
z1[0]= Normalise(sub);
441
VecSubf(sub, v3, v1);
445
/* split id's up for u and v
446
id = u, id + 1 = v */
454
/* The LSCM Equation:
456
* (u,v) are the uv coords we are looking for -> complex number u + i*v
457
* (x,y) are the above calculated local coords -> complex number x + i*y
459
* Zk = xk + i*yk (= zk[0] + i*zk[1] in the code)
461
* That makes the equation:
462
* (Z1 - Z0)(U2 - U0) = (Z2 - Z0)(U1 - U0)
464
* x0, y0 and y1 were made zero by projecting the triangle:
465
* (x1 + i*y1)(u2 + i*v2 - u0 - i*v0) = (x2 + i*y2)(u1 + i*v1 - u0 - i*v0)
467
* this gives the following coefficients:
468
* u0 * ((-x1 + x2) + i*(y2))
469
* v0 * ((-y2) + i*(-x1 + x2))
470
* u1 * ((-x2) + i*(-y2))
471
* v1 * ((y2) + i*(-x2))
478
nlCoefficient(id0[0], -z1[0] + z2[0]);
479
nlCoefficient(id0[1], -z2[1] );
480
nlCoefficient(id1[0], -z2[0] );
481
nlCoefficient(id1[1], z2[1] );
482
nlCoefficient(id2[0], z1[0] );
487
nlCoefficient(id0[0], z2[1] );
488
nlCoefficient(id0[1], -z1[0] + z2[0]);
489
nlCoefficient(id1[0], -z2[1] );
490
nlCoefficient(id1[1], -z2[0] );
491
nlCoefficient(id2[1], z1[0] );
495
static float lscm_angle_cos(float *v1, float *v2, float *v3)
497
float vec1[3], vec2[3];
499
VecSubf(vec1, v2, v1);
500
VecSubf(vec2, v3, v1);
504
return vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2];
507
static int lscm_build_vertex_data(Mesh *me, int *groups, int gid, LscmVert **lscm_vertices, LscmVert ***sort_vertices)
513
LscmVert *lscmvert, **sortvert;
514
LscmVert *v1, *v2, *v3, **sv1, **sv2, **sv3;
517
/* determine size for malloc */
525
for(a=me->totface; a>0; a--) {
529
if(mf->v4) totvert +=3;
534
/* a list per face vertices */
535
lscmvert= (LscmVert*)MEM_mallocN(sizeof(LscmVert)*totvert,"LscmVerts");
536
/* the above list sorted by vertex id */
537
sortvert= (LscmVert**)MEM_mallocN(sizeof(LscmVert*)*totvert, "LscmVSort");
539
/* actually build the list (including virtual triangulation) */
552
/* warning: ugly code :) */
553
for(a=me->totface; a>0; a--) {
555
/* determine triangulation direction, to avoid degenerate
556
triangles (small cos = degenerate). */
558
a1 = lscm_angle_cos((mv+mf->v1)->co, (mv+mf->v2)->co, (mv+mf->v3)->co);
559
a1 += lscm_angle_cos((mv+mf->v2)->co, (mv+mf->v1)->co, (mv+mf->v3)->co);
560
a1 += lscm_angle_cos((mv+mf->v3)->co, (mv+mf->v1)->co, (mv+mf->v2)->co);
562
a2 = lscm_angle_cos((mv+mf->v1)->co, (mv+mf->v2)->co, (mv+mf->v4)->co);
563
a2 += lscm_angle_cos((mv+mf->v2)->co, (mv+mf->v1)->co, (mv+mf->v4)->co);
564
a2 += lscm_angle_cos((mv+mf->v4)->co, (mv+mf->v1)->co, (mv+mf->v2)->co);
569
if(!mf->v4 || a1 > a2) {
578
v1->flag= v2->flag= v3->flag= 0;
589
v1->tf= v2->tf= v3->tf= tf;
595
if(tf->unwrap & TF_SEAM1) {
596
v1->flag |= LSCM_SEAM1;
597
v2->flag |= LSCM_SEAM1;
600
if(tf->unwrap & TF_SEAM2) {
601
v2->flag |= LSCM_SEAM2;
602
v3->flag |= LSCM_SEAM2;
605
if(!mf->v4 && tf->unwrap & TF_SEAM3) {
606
v1->flag |= LSCM_SEAM2;
607
v3->flag |= LSCM_SEAM1;
610
v1 += 3; v2 += 3; v3 += 3;
611
sv1 += 3; sv2 += 3; sv3 += 3;
614
if(mf->v4 && a1 > a2) {
623
v1->flag= v2->flag= v3->flag= 0;
634
v1->tf= v2->tf= v3->tf= tf;
640
if(tf->unwrap & TF_SEAM3) {
641
v2->flag |= LSCM_SEAM1;
642
v3->flag |= LSCM_SEAM2;
645
if(tf->unwrap & TF_SEAM4) {
646
v1->flag |= LSCM_SEAM2;
647
v3->flag |= LSCM_SEAM1;
650
v1 += 3; v2 += 3; v3 += 3;
651
sv1 += 3; sv2 += 3; sv3 += 3;
654
if(mf->v4 && a1 <= a2) {
663
v1->flag= v2->flag= v3->flag= 0;
674
v1->tf= v2->tf= v3->tf= tf;
680
if(tf->unwrap & TF_SEAM1) {
681
v1->flag |= LSCM_SEAM1;
682
v2->flag |= LSCM_SEAM1;
685
if(tf->unwrap & TF_SEAM4) {
686
v1->flag |= LSCM_SEAM2;
687
v3->flag |= LSCM_SEAM1;
690
v1 += 3; v2 += 3; v3 += 3;
691
sv1 += 3; sv2 += 3; sv3 += 3;
703
v1->flag= v2->flag= v3->flag= 0;
714
v1->tf= v2->tf= v3->tf= tf;
720
if(tf->unwrap & TF_SEAM2) {
721
v1->flag |= LSCM_SEAM1;
722
v2->flag |= LSCM_SEAM1;
725
if(tf->unwrap & TF_SEAM3) {
726
v2->flag |= LSCM_SEAM2;
727
v3->flag |= LSCM_SEAM2;
730
v1 += 3; v2 += 3; v3 += 3;
731
sv1 += 3; sv2 += 3; sv3 += 3;
738
/* sort by vertex id */
739
qsort(sortvert, totvert, sizeof(LscmVert*), comp_lscmvert);
741
*lscm_vertices= lscmvert;
742
*sort_vertices= sortvert;
746
static void lscm_min_max_cent_rad(Mesh *me, LscmVert **sortvert, int totvert, float *min, float *max, float *center, float *radius)
748
MVert *mv= me->mvert;
750
int a, lastvert, vertcount;
753
/* find min, max and center */
754
center[0]= center[1]= center[2]= 0.0;
755
INIT_MINMAX(min, max);
761
for(a=totvert; a>0; a--, sv++) {
763
if(v->v != lastvert) {
766
VecAddf(center, center, (mv+v->v)->co);
767
DO_MINMAX(co, min, max);
774
VecMulf(center, (float)1.0/(float)vertcount);
777
VecSubf(sub, center, max);
778
*radius= Normalise(sub);
784
static void lscm_projection_axes(float *min, float *max, float *p1, float *p2)
792
p1[0]= p1[1]= p1[2]= 0.0;
793
p2[0]= p2[1]= p2[2]= 0.0;
795
if(dx < dy && dx < dz) {
796
if(dy > dz) p1[1]= p2[2]= 1.0; /* y, z */
797
else p1[2]= p2[1]= 1.0; /* z, y */
799
else if(dy < dx && dy < dz) {
800
if(dx > dz) p1[0]= p2[2]= 1.0; /* x, z */
801
else p1[2]= p2[0]= 1.0; /* z, x */
804
if(dx > dy) p1[0]= p2[1]= 1.0; /* x, y */
805
else p1[1]= p2[0]= 1.0; /* y, x */
809
static void lscm_set_initial_solution(Mesh *me, LscmVert **sortvert, int totvert, float *p1, float *p2, int *vertex_min, int *vertex_max)
811
float umin, umax, *uv, *co;
814
MVert *mv= me->mvert;
824
for(a=totvert; a>0; a--, sv++) {
827
uv= v->tf->uv[v->tf_index];
841
nlSetVariable(2*v->index, uv[0]);
842
nlSetVariable(2*v->index + 1, uv[1]);
849
static void lscm_set_pinned_solution(Mesh *me, LscmVert **sortvert, int totvert, int *pinned)
851
float min[2], max[2], *uv, *co;
854
MVert *mv= me->mvert;
856
INIT_MINMAX2(min, max);
861
for(a=totvert; a>0; a--, sv++) {
864
uv= v->tf->uv[v->tf_index];
866
pin = ((v->tf->unwrap & TF_PIN1) && (v->tf_index == 0)) ||
867
((v->tf->unwrap & TF_PIN2) && (v->tf_index == 1)) ||
868
((v->tf->unwrap & TF_PIN3) && (v->tf_index == 2)) ||
869
((v->tf->unwrap & TF_PIN4) && (v->tf_index == 3));
871
nlSetVariable(2*v->index, uv[0]);
872
nlSetVariable(2*v->index + 1, uv[1]);
875
DO_MINMAX2(uv, min, max);
879
nlLockVariable(2*v->index);
880
nlLockVariable(2*v->index + 1);
885
/* abuse umax vmax for caculating euclidian distance */
889
/* check for degenerated pinning box */
890
if (((max[0]*max[0])+(max[1]*max[1])) < 1e-10)
896
static void lscm_build_matrix(Mesh *me, LscmVert *lscmvert, int *groups, int gid, float *center, float radius)
898
MVert *mv= me->mvert;
901
int *gf, a, id1, id2, id3;
903
float co1[3], co2[3], co3[3];
912
for(a=me->totface; a>0; a--) {
914
VecCopyf(co1, (mv+v->v)->co);
916
VecCopyf(co2, (mv+v->v)->co);
918
VecCopyf(co3, (mv+v->v)->co);
920
lscm_add_triangle(co1, co2, co3, id1, id2, id3, center, radius);
923
VecCopyf(co1, (mv+v->v)->co);
925
VecCopyf(co2, (mv+v->v)->co);
927
VecCopyf(co3, (mv+v->v)->co);
929
lscm_add_triangle(co1, co2, co3, id1, id2, id3, center, radius);
938
static void lscm_load_solution(Mesh *me, LscmVert *lscmvert, int *groups, int gid)
951
for(a=me->totface; a>0; a--) {
957
/* index= u, index + 1= v */
959
uv= v->tf->uv[v->tf_index];
961
uv[0]= nlGetVariable(2*v->index);
962
uv[1]= nlGetVariable(2*v->index + 1);
972
static int unwrap_lscm_face_group(Mesh *me, int *groups, int gid)
974
LscmVert *lscmvert, **sortvert;
975
int totindex, totvert, vmin, vmax,pinned;
976
float min[3], max[3], center[3], radius, p1[3], p2[3];
978
/* build the data structures */
979
totvert= lscm_build_vertex_data(me, groups, gid, &lscmvert, &sortvert);
981
/* calculate min, max, center and radius */
982
lscm_min_max_cent_rad(me, sortvert, totvert, min, max, center, &radius);
984
/* index distinct vertices */
985
totindex= lscm_set_indices(sortvert, totvert);
989
nlSolverParameteri(NL_NB_VARIABLES, 2*totindex);
990
nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
994
/* find axes for projecting initial solutions on */
995
lscm_projection_axes(min, max, p1, p2);
996
/* see if pinned data is avail and set on fly */
997
lscm_set_pinned_solution(me, sortvert, totvert, &pinned);
999
if(pinned < 0); /* really small pinned uv's: won't see difference anyway */
1004
/* set initial solution and locate two extrema vertices to pin */
1005
lscm_set_initial_solution(me,sortvert,totvert,p1,p2,&vmin,&vmax);
1008
nlLockVariable(2*vmin);
1009
nlLockVariable(2*vmin + 1);
1010
nlLockVariable(2*vmax);
1011
nlLockVariable(2*vmax + 1);
1014
/* add triangles to the solver */
1015
lscm_build_matrix(me, lscmvert, groups, gid, center, radius);
1019
/* LSCM solver magic! */
1022
/* load new uv's: will be projected uv's if solving failed */
1023
lscm_load_solution(me, lscmvert, groups, gid);
1026
nlDeleteContext(nlGetCurrent());
1027
MEM_freeN(lscmvert);
1028
MEM_freeN(sortvert);
1032
static void seam_group_bbox(Mesh *me, int *groups, int gid, float *min, float *max)
1038
INIT_MINMAX2(min, max);
1044
for(a=me->totface; a>0; a--) {
1045
if((gid!=0 && *gf==gid) || (gid==0 && *gf)) {
1047
DO_MINMAX2(tf->uv[0], min, max)
1048
DO_MINMAX2(tf->uv[1], min, max)
1049
DO_MINMAX2(tf->uv[2], min, max)
1052
DO_MINMAX2(tf->uv[3], min, max)
1059
static void seam_group_scale(Mesh *me, int *groups, int gid, float scale)
1069
for(a=me->totface; a>0; a--) {
1070
if((gid!=0 && *gf==gid) || (gid==0 && *gf)) {
1072
Vec2Mulf(tf->uv[0], scale);
1073
Vec2Mulf(tf->uv[1], scale);
1074
Vec2Mulf(tf->uv[2], scale);
1075
if(mf->v4) Vec2Mulf(tf->uv[3], scale);
1081
static void seam_group_move(Mesh *me, int *groups, int gid, float add[2])
1091
for(a=me->totface; a>0; a--) {
1092
if((gid!=0 && *gf==gid) || (gid==0 && *gf)) {
1094
Vec2Addf(tf->uv[0], tf->uv[0], add);
1095
Vec2Addf(tf->uv[1], tf->uv[1], add);
1096
Vec2Addf(tf->uv[2], tf->uv[2], add);
1097
if(mf->v4) Vec2Addf(tf->uv[3], tf->uv[3], add);
1103
/* put group withing (0,0)->(1,1) boundbox */
1104
static void seam_group_normalize(Mesh *me, int *groups, int gid)
1106
float min[2], max[2], sx, sy, scale, add[2];
1108
seam_group_bbox(me, groups, gid, min, max);
1110
sx= (max[0]-min[0]);
1111
sy= (max[1]-min[1]);
1113
scale= MAX2(sx, sy);
1119
seam_group_move(me, groups, gid, add);
1120
seam_group_scale(me, groups, gid, scale);
1123
/* get scale relative to mesh */
1124
static float seam_group_relative_scale(Mesh *me, int *groups, int gid)
1126
MVert *mv= me->mvert;
1130
float len_xyz, len_uv;
1138
for(a=me->totface; a>0; a--) {
1141
len_uv += Vec2Lenf(tf->uv[0], tf->uv[1]);
1142
len_xyz += VecLenf((mv+mf->v1)->co, (mv+mf->v2)->co);
1144
len_uv += Vec2Lenf(tf->uv[1], tf->uv[2]);
1145
len_xyz += VecLenf((mv+mf->v2)->co, (mv+mf->v3)->co);
1149
len_uv += Vec2Lenf(tf->uv[2], tf->uv[3]);
1150
len_xyz += VecLenf((mv+mf->v3)->co, (mv+mf->v4)->co);
1152
len_uv += Vec2Lenf(tf->uv[3], tf->uv[0]);
1153
len_xyz += VecLenf((mv+mf->v4)->co, (mv+mf->v1)->co);
1156
len_uv += Vec2Lenf(tf->uv[2], tf->uv[0]);
1157
len_xyz += VecLenf((mv+mf->v3)->co, (mv+mf->v1)->co);
1163
return (len_uv/len_xyz);
1166
/* very primitive packing */
1167
static void pack_seam_groups(Mesh *me, int *groups, int totgroup)
1169
float *groupscale, minscale, scale, add[2], groupw;
1170
float dx, dy, packx, packy, min[2], max[2], rowh;
1173
groupscale = (float*)MEM_mallocN(sizeof(float)*totgroup, "SeamGroupScale");
1177
for(a=0; a<totgroup; a++) {
1178
groupscale[a]= seam_group_relative_scale(me, groups, a+1);
1179
minscale= MIN2(groupscale[a], minscale);
1184
groupw= 1.0/sqrt(totgroup);
1186
for(a=0; a<totgroup; a++) {
1188
/* scale so all groups have the same size relative to the mesh */
1189
scale = minscale/groupscale[a];
1192
seam_group_bbox(me, groups, a+1, min, max);
1193
dx= (max[0]-min[0])*scale;
1194
dy= (max[1]-min[1])*scale;
1200
add[0]= add[1]= 0.0;
1210
else if(dx <= (1.0-packx)) {
1215
rowh= MAX2(rowh, dy);
1230
seam_group_scale(me, groups, a+1, scale);
1231
seam_group_move(me, groups, a+1, add);
1234
MEM_freeN(groupscale);
1236
seam_group_normalize(me, groups, 0);
1237
seam_group_scale(me, groups, 0, 0.98);
1238
add[0]= add[1]= 0.01;
1239
seam_group_move(me, groups, 0, add);
1242
void unwrap_lscm(void)
1247
int totgroup, *groups=NULL, a;
1249
me= get_mesh(OBACT);
1250
if(me==0 || me->tface==0) return;
1252
totgroup= make_seam_groups(me, &groups);
1254
if(totgroup==0) return;
1256
for(a=totgroup; a>0; a--) {
1257
res= unwrap_lscm_face_group(me, groups, a);
1258
if((res < 3) && (res > -1)) {
1259
seam_group_normalize(me, groups, a);
1267
if(dopack) pack_seam_groups(me, groups, totgroup);
1271
BIF_undo_push("UV lscm unwrap");
1273
allqueue(REDRAWVIEW3D, 0);
1274
allqueue(REDRAWIMAGE, 0);
1279
/* Set tface seams based on edge data, uses hash table to find seam edges. */
1281
void set_seamtface()
1289
me= get_mesh(OBACT);
1290
if(!me || !me->tface || !(G.f & G_FACESELECT)) return;
1292
htable= make_hash_edge_table(me, 1);
1296
for(a=me->totface; a>0; a--, mf++, tf++) {
1297
if(mf->v3==0) continue;
1298
tf->unwrap &= ~(TF_SEAM1|TF_SEAM2|TF_SEAM3|TF_SEAM4);
1300
if(!htable) continue;
1302
if(edge_in_hash(htable, mf->v1, mf->v2)) tf->unwrap |= TF_SEAM1;
1303
if(edge_in_hash(htable, mf->v2, mf->v3)) tf->unwrap |= TF_SEAM2;
1306
if(edge_in_hash(htable, mf->v3, mf->v4)) tf->unwrap |= TF_SEAM3;
1307
if(edge_in_hash(htable, mf->v4, mf->v1)) tf->unwrap |= TF_SEAM4;
1309
else if(edge_in_hash(htable, mf->v3, mf->v1)) tf->unwrap |= TF_SEAM3;
1312
free_hash_edge_table(htable);
1315
void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index)
1319
int a, doit=1, mark=0;
1323
htable= make_hash_edge_table(me, 0);
1324
linkflag= MEM_callocN(sizeof(char)*me->totface, "linkflaguv");
1326
if (mode==0 || mode==1) {
1327
/* only put face under cursor in array */
1328
mf= ((MFace*)me->mface) + index;
1329
hash_add_face(htable, mf);
1333
/* fill array by selection */
1336
for(a=0; a<me->totface; a++, tf++, mf++) {
1337
if(tf->flag & TF_HIDE);
1338
else if(tf->flag & TF_SELECT) {
1339
hash_add_face(htable, mf);
1348
/* expand selection */
1351
for(a=0; a<me->totface; a++, tf++, mf++) {
1352
if(tf->flag & TF_HIDE);
1353
else if(mf->v3 && !linkflag[a]) {
1356
if(!(tf->unwrap & TF_SEAM1))
1357
if(edge_in_hash(htable, mf->v1, mf->v2))
1359
if(!(tf->unwrap & TF_SEAM2))
1360
if(edge_in_hash(htable, mf->v2, mf->v3))
1362
if(!(tf->unwrap & TF_SEAM3)) {
1364
if(edge_in_hash(htable, mf->v3, mf->v4))
1367
else if(edge_in_hash(htable, mf->v3, mf->v1))
1370
if(mf->v4 && !(tf->unwrap & TF_SEAM4))
1371
if(edge_in_hash(htable, mf->v4, mf->v1))
1376
hash_add_face(htable, mf);
1384
if(mode==0 || mode==2) {
1385
for(a=0, tf=me->tface; a<me->totface; a++, tf++)
1387
tf->flag |= TF_SELECT;
1389
tf->flag &= ~TF_SELECT;
1392
for(a=0, tf=me->tface; a<me->totface; a++, tf++)
1393
if(linkflag[a] && (tf->flag & TF_SELECT))
1396
if (a<me->totface) {
1397
for(a=0, tf=me->tface; a<me->totface; a++, tf++)
1399
tf->flag &= ~TF_SELECT;
1402
for(a=0, tf=me->tface; a<me->totface; a++, tf++)
1404
tf->flag |= TF_SELECT;
1408
free_hash_edge_table(htable);
1409
MEM_freeN(linkflag);
1411
BIF_undo_push("Select linked UV face");
1412
allqueue(REDRAWVIEW3D, 0);
1413
allqueue(REDRAWIMAGE, 0);