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:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2004-07-13 15:48:52 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2004-07-13 15:48:52 +0400
commite0773281220c5af56585b0e07ccdbfc6ee485b4f (patch)
tree4b06de628461f5822cb31c59eb6c6768ae06cc6f /source/blender
parent4f1c674ee02e07a6986a54a312d7fb9e2547e950 (diff)
Added LSCM UV Unwrapping:
http://www.loria.fr/~levy/Galleries/LSCM/index.html http://www.loria.fr/~levy/Papers/2002/s2002_lscm.pdf 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. Seams: Stored as a flag (ME_SEAM) in the new MEdge struct, these seams define where a mesh will be cut when executing LSCM unwrapping. Seams can be marked and cleared in Edit Mode. Ctrl+EKEY will pop up a menu allowing to Clear or Mark the selected edges as seams. Select Linked in Face Select Mode now only selects linked faces if no seams separate them. So if seams are defined, this will now select the 'face group' defined by the seams. Hotkey is still LKEY. LSCM Unwrap: unwrap UV's by calculating a conformal mapping (preserving local angles). Based on seams, the selected faces will be 'cut'. If multiple 'face groups' are selected, they will be unwrapped separately and packed in the image rectangle in the UV Editor. Packing uses a simple and fast algorithm, only designed to avoid having overlapping faces. LSCM can be found in the Unwrap menu (UKEY), and the UV Calculation panel. Pinning: UV's can be pinned in the UV Editor. When LSCM Unwrap is then executed, these UV's will stay in place, allowing to tweak the solution. PKEY and ALT+PKEY will respectively pin and unpin selected UV's. Face Select Mode Drawing Changes: - Draw Seams option to enable disable drawing of seams - Draw Faces option to enable drawing of selected faces in transparent purple - Draw Hidden Edges option to enable drawing of edges of hidden faces - Draw Edges option to enable drawing of edges of visible faces The colors for these seams, faces and edges are themeable.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_global.h2
-rw-r--r--source/blender/blenkernel/BKE_utildefines.h2
-rw-r--r--source/blender/blenkernel/intern/displist.c9
-rw-r--r--source/blender/blenkernel/intern/subsurf.c32
-rw-r--r--source/blender/blenlib/BLI_arithb.h17
-rw-r--r--source/blender/blenlib/BLI_editVert.h6
-rw-r--r--source/blender/blenlib/intern/arithb.c21
-rw-r--r--source/blender/include/BDR_unwrapper.h40
-rw-r--r--source/blender/include/BIF_editmesh.h4
-rw-r--r--source/blender/include/BIF_editsima.h1
-rw-r--r--source/blender/include/BIF_resources.h2
-rw-r--r--source/blender/include/butspace.h39
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h12
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h2
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h1
-rw-r--r--source/blender/src/Makefile2
-rw-r--r--source/blender/src/SConscript4
-rw-r--r--source/blender/src/buttons_editing.c70
-rw-r--r--source/blender/src/drawimage.c51
-rw-r--r--source/blender/src/drawmesh.c180
-rw-r--r--source/blender/src/drawobject.c22
-rw-r--r--source/blender/src/editface.c50
-rw-r--r--source/blender/src/editmesh.c315
-rw-r--r--source/blender/src/editobject.c8
-rw-r--r--source/blender/src/editsima.c32
-rw-r--r--source/blender/src/header_image.c19
-rw-r--r--source/blender/src/header_view3d.c11
-rw-r--r--source/blender/src/resources.c8
-rw-r--r--source/blender/src/space.c25
-rw-r--r--source/blender/src/toolbox.c3
-rw-r--r--source/blender/src/unwrapper.c1159
31 files changed, 1876 insertions, 273 deletions
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 7586f14c894..b9c45834840 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -187,6 +187,8 @@ typedef struct Global {
#define G_NOFROZEN (1 << 17) // frozen modules inactive
#define G_DRAWEDGES (1 << 18)
#define G_DRAWCREASES (1 << 19)
+#define G_DRAWSEAMS (1 << 20)
+#define G_HIDDENEDGES (1 << 21)
/* G.fileflags */
diff --git a/source/blender/blenkernel/BKE_utildefines.h b/source/blender/blenkernel/BKE_utildefines.h
index 97cd46aa3fc..44cef530f48 100644
--- a/source/blender/blenkernel/BKE_utildefines.h
+++ b/source/blender/blenkernel/BKE_utildefines.h
@@ -81,6 +81,8 @@
#define INIT_MINMAX(min, max) (min)[0]= (min)[1]= (min)[2]= 1.0e30; (max)[0]= (max)[1]= (max)[2]= -1.0e30;
+#define INIT_MINMAX2(min, max) (min)[0]= (min)[1]= 1.0e30; (max)[0]= (max)[1]= -1.0e30;
+
#define DO_MINMAX(vec, min, max) if( (min)[0]>(vec)[0] ) (min)[0]= (vec)[0]; \
if( (min)[1]>(vec)[1] ) (min)[1]= (vec)[1]; \
if( (min)[2]>(vec)[2] ) (min)[2]= (vec)[2]; \
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index 530442f03a9..1b100d339fb 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -277,12 +277,17 @@ void displistmesh_to_mesh(DispListMesh *dlm, Mesh *me)
} else {
me->totface= dlm->totface;
me->totvert= dlm->totvert;
-
+
me->mvert= MEM_dupallocN(dlm->mvert);
me->mface= mfaces= MEM_mallocN(sizeof(*mfaces)*me->totface, "me->mface");
me->tface= MEM_dupallocN(dlm->tface);
me->mcol= MEM_dupallocN(dlm->mcol);
-
+
+ if(dlm->medge) {
+ me->totedge= dlm->totedge;
+ me->medge= MEM_dupallocN(dlm->medge);
+ }
+
for (i=0; i<me->totface; i++) {
MFace *mf= &mfaces[i];
MFace *oldmf= &dlm->mface[i];
diff --git a/source/blender/blenkernel/intern/subsurf.c b/source/blender/blenkernel/intern/subsurf.c
index 6b069782336..4a8724272b7 100644
--- a/source/blender/blenkernel/intern/subsurf.c
+++ b/source/blender/blenkernel/intern/subsurf.c
@@ -176,8 +176,9 @@ struct _HyperVert {
LinkNode *edges, *faces;
};
-/* hyper edge flag */
+/* hyper edge flags */
#define DR_OPTIM 1
+#define HE_SEAM 2
struct _HyperEdge {
HyperEdge *next;
@@ -200,6 +201,7 @@ struct _HyperFace {
unsigned char (*vcol)[4];
float (*uvco)[2];
+ short unwrap;
/* for getting back tface, matnr, etc */
union {
@@ -342,7 +344,7 @@ static HyperMesh *hypermesh_from_mesh(Mesh *me, float *extverts, int subdivLevel
MFace *mface= me->mface;
MEdge *medge= me->medge;
float creasefac= ((float)subdivLevels)/255.0; // in Mesh sharpness is byte
- int i, j;
+ int i, j, flag;
hme->orig_me= me;
if (me->tface)
@@ -362,8 +364,11 @@ static HyperMesh *hypermesh_from_mesh(Mesh *me, float *extverts, int subdivLevel
if(medge) {
for (i=0; i<me->totedge; i++) {
MEdge *med= &medge[i];
+
+ flag= DR_OPTIM;
+ if(med->flag & ME_SEAM) flag |= HE_SEAM;
- hypermesh_add_edge(hme, vert_tbl[med->v1], vert_tbl[med->v2], DR_OPTIM,
+ hypermesh_add_edge(hme, vert_tbl[med->v1], vert_tbl[med->v2], flag,
creasefac*((float)med->crease) );
}
}
@@ -395,6 +400,8 @@ static HyperMesh *hypermesh_from_mesh(Mesh *me, float *extverts, int subdivLevel
f->vcol= BLI_memarena_alloc(hme->arena, sizeof(*f->vcol)*nverts);
for (j=0; j<nverts; j++)
*((unsigned int*) f->vcol[j])= tf->col[j];
+
+ f->unwrap= tf->unwrap;
} else if (hme->hasvcol) {
MCol *mcol= &me->mcol[i*4];
@@ -418,6 +425,7 @@ static HyperMesh *hypermesh_from_editmesh(EditMesh *em, int subdivLevels) {
EditEdge *ee;
EditVlak *ef;
float creasefac= (float)subdivLevels;
+ int flag;
/* we only add vertices with edges, 'f1' is a free flag */
/* added: check for hide flag in vertices */
@@ -437,8 +445,10 @@ static HyperMesh *hypermesh_from_editmesh(EditMesh *em, int subdivLevels) {
ee->v2->prev= (EditVert*) hypermesh_add_vert(hme, ee->v2->co, ee->v2->co);
ee->v2->f1= 0;
}
-
- hypermesh_add_edge(hme, (HyperVert*) ee->v1->prev, (HyperVert*) ee->v2->prev, DR_OPTIM,
+
+ flag= DR_OPTIM;
+ if(ee->seam) flag |= HE_SEAM;
+ hypermesh_add_edge(hme, (HyperVert*) ee->v1->prev, (HyperVert*) ee->v2->prev, flag,
creasefac*ee->crease);
}
}
@@ -743,6 +753,13 @@ static void hypermesh_subdivide(HyperMesh *me, HyperMesh *nme) {
Vec2Cpy(nf->uvco[1], uvco_edge[j]);
Vec2Cpy(nf->uvco[2], uvco_mid);
Vec2Cpy(nf->uvco[3], uvco_edge[last]);
+
+ if(j==0 && (f->unwrap & ((f->nverts==4)?TF_PIN4:TF_PIN3)))
+ nf->unwrap= TF_PIN1;
+ else if(j==1 && f->unwrap & TF_PIN1) nf->unwrap= TF_PIN1;
+ else if(j==2 && f->unwrap & TF_PIN2) nf->unwrap= TF_PIN1;
+ else if(j==3 && f->unwrap & TF_PIN3) nf->unwrap= TF_PIN1;
+ else nf->unwrap= 0;
}
}
}
@@ -956,8 +973,8 @@ static DispListMesh *hypermesh_to_displistmesh(HyperMesh *hme, short flag) {
med->v1= (int) e->v[0]->nmv;
med->v2= (int) e->v[1]->nmv;
- /* flag only for optimal */
- if(e->flag) med->flag = ME_EDGEDRAW;
+ if(e->flag & DR_OPTIM) med->flag |= ME_EDGEDRAW;
+ if(e->flag & HE_SEAM) med->flag |= ME_SEAM;
}
/* and we add the handles (med is re-used) */
@@ -1036,6 +1053,7 @@ static DispListMesh *hypermesh_to_displistmesh(HyperMesh *hme, short flag) {
tf->transp= origtf->transp;
tf->mode= origtf->mode;
tf->tile= origtf->tile;
+ tf->unwrap= f->unwrap;
} else if (hme->hasvcol) {
MCol *mcolbase= &dlm->mcol[i*4];
diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h
index 5941d421d16..4df5db5f39e 100644
--- a/source/blender/blenlib/BLI_arithb.h
+++ b/source/blender/blenlib/BLI_arithb.h
@@ -749,7 +749,22 @@ triatoquat(
MinMaxRGB(
short c[]
);
-
+ float
+Vec2Lenf(
+ float *v1,
+ float *v2
+);
+ void
+Vec2Mulf(
+ float *v1,
+ float f
+);
+ void
+Vec2Addf(
+ float *v,
+ float *v1,
+ float *v2
+);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_editVert.h b/source/blender/blenlib/BLI_editVert.h
index 568aa6b65ae..3f477036c0b 100644
--- a/source/blender/blenlib/BLI_editVert.h
+++ b/source/blender/blenlib/BLI_editVert.h
@@ -58,9 +58,9 @@ typedef struct EditEdge
{
struct EditEdge *next, *prev;
struct EditVert *v1, *v2, *vn;
- short f,h;
- short f1, dir;
- float crease;
+ short f, f1;
+ unsigned char h, dir, seam;
+ float crease;
} EditEdge;
typedef struct EditVlak
diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c
index ac025b34127..ff057a61e51 100644
--- a/source/blender/blenlib/intern/arithb.c
+++ b/source/blender/blenlib/intern/arithb.c
@@ -2181,6 +2181,27 @@ void MinMaxRGB(short c[])
else if(c[2]<0) c[2]=0;
}
+float Vec2Lenf(float *v1, float *v2)
+{
+ float x, y;
+
+ x = v1[0]-v2[0];
+ y = v1[1]-v2[1];
+ return (float)sqrt(x*x+y*y);
+}
+
+void Vec2Mulf(float *v1, float f)
+{
+ v1[0]*= f;
+ v1[1]*= f;
+}
+
+void Vec2Addf(float *v, float *v1, float *v2)
+{
+ v[0]= v1[0]+ v2[0];
+ v[1]= v1[1]+ v2[1];
+}
+
void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b)
{
int i;
diff --git a/source/blender/include/BDR_unwrapper.h b/source/blender/include/BDR_unwrapper.h
new file mode 100644
index 00000000000..72633bab9e4
--- /dev/null
+++ b/source/blender/include/BDR_unwrapper.h
@@ -0,0 +1,40 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_UNWRAPPER_H
+#define BDR_UNWRAPPER_H
+
+void set_seamtface(); /* set TF_SEAM flags in tfaces */
+void unwrap_lscm(); /* unwrap selected tfaces */
+
+#endif /* BDR_UNWRAPPER_H */
+
diff --git a/source/blender/include/BIF_editmesh.h b/source/blender/include/BIF_editmesh.h
index 09dcd69dc9f..de289c88e20 100644
--- a/source/blender/include/BIF_editmesh.h
+++ b/source/blender/include/BIF_editmesh.h
@@ -165,8 +165,12 @@ void select_more(void);
void select_less(void);
void selectrandom_mesh(void);
+void Edge_Menu(void);
+
void editmesh_select_by_material(int index);
void editmesh_deselect_by_material(int index);
+void editmesh_mark_seam(int clear);
+
#endif
diff --git a/source/blender/include/BIF_editsima.h b/source/blender/include/BIF_editsima.h
index e3e803ad5d2..c3750bfc018 100644
--- a/source/blender/include/BIF_editsima.h
+++ b/source/blender/include/BIF_editsima.h
@@ -45,4 +45,5 @@ void stitch_uv_tface(int mode);
void unlink_selection(void);
void select_linked_tface_uv(void);
void toggle_uv_select(int mode);
+void pin_tface_uv(int mode);
diff --git a/source/blender/include/BIF_resources.h b/source/blender/include/BIF_resources.h
index 6bce7e4e3f1..ededfab7489 100644
--- a/source/blender/include/BIF_resources.h
+++ b/source/blender/include/BIF_resources.h
@@ -376,6 +376,8 @@ enum {
TH_VERTEX_SIZE,
TH_EDGE,
TH_EDGE_SELECT,
+ TH_EDGE_SEAM,
+ TH_EDGE_FACESEL,
TH_FACE,
TH_FACE_SELECT
};
diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h
index 55fac76e7fb..eb9e7455baf 100644
--- a/source/blender/include/butspace.h
+++ b/source/blender/include/butspace.h
@@ -524,25 +524,26 @@ enum {
#define B_UVAUTOCALCBUTS 3400
enum {
B_UVAUTO_REDRAW = 3301,
- B_UVAUTO_SPHERE,
- B_UVAUTO_CYLINDER,
- B_UVAUTO_CYLRADIUS,
- B_UVAUTO_WINDOW,
- B_UVAUTO_CUBE,
- B_UVAUTO_CUBESIZE,
- B_UVAUTO_STD1,
- B_UVAUTO_STD2,
- B_UVAUTO_STD4,
- B_UVAUTO_STD8,
- B_UVAUTO_BOUNDS1,
- B_UVAUTO_BOUNDS2,
- B_UVAUTO_BOUNDS4,
- B_UVAUTO_BOUNDS8,
- B_UVAUTO_TOP,
- B_UVAUTO_FACE,
- B_UVAUTO_OBJECT,
- B_UVAUTO_ALIGNX,
- B_UVAUTO_ALIGNY
+ B_UVAUTO_SPHERE,
+ B_UVAUTO_CYLINDER,
+ B_UVAUTO_CYLRADIUS,
+ B_UVAUTO_WINDOW,
+ B_UVAUTO_CUBE,
+ B_UVAUTO_CUBESIZE,
+ B_UVAUTO_STD1,
+ B_UVAUTO_STD2,
+ B_UVAUTO_STD4,
+ B_UVAUTO_STD8,
+ B_UVAUTO_BOUNDS1,
+ B_UVAUTO_BOUNDS2,
+ B_UVAUTO_BOUNDS4,
+ B_UVAUTO_BOUNDS8,
+ B_UVAUTO_TOP,
+ B_UVAUTO_FACE,
+ B_UVAUTO_OBJECT,
+ B_UVAUTO_ALIGNX,
+ B_UVAUTO_ALIGNY,
+ B_UVAUTO_LSCM
};
#define B_EFFECTSBUTS 3500
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 674c144923d..f9cb375572b 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -53,7 +53,7 @@ typedef struct TFace {
float uv[4][2]; /* when you change this: also do function set_correct_uv in editmesh.c, and there are more locations that use the size of this part */
unsigned int col[4];
char flag, transp;
- short mode, tile, pad;
+ short mode, tile, unwrap;
} TFace;
typedef struct Mesh {
@@ -153,6 +153,16 @@ typedef struct Mesh {
#define TF_ALPHA 2
#define TF_SUB 3
+/* tface->unwrap */
+#define TF_SEAM1 1
+#define TF_SEAM2 2
+#define TF_SEAM3 4
+#define TF_SEAM4 8
+#define TF_PIN1 16
+#define TF_PIN2 32
+#define TF_PIN3 64
+#define TF_PIN4 128
+
#define MESH_MAX_VERTS 2000000000L
#endif
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 04de27f58b0..f0ac467afb2 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -79,7 +79,7 @@ typedef struct MSticky {
/* medge->flag (1=SELECT)*/
#define ME_EDGEDRAW 2
-
+#define ME_SEAM 4
/* puno = vertexnormal (mface) */
#define ME_FLIPV1 1
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 97a944db70d..7c2773f0b5b 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -82,6 +82,7 @@ typedef struct ThemeSpace {
char active[4], transform[4];
char vertex[4], vertex_select[4];
char edge[4], edge_select[4];
+ char edge_seam[4], edge_facesel[4];
char face[4], face_select[4];
char vertex_size, pad;
diff --git a/source/blender/src/Makefile b/source/blender/src/Makefile
index bdb5af6b801..210ed7d7320 100644
--- a/source/blender/src/Makefile
+++ b/source/blender/src/Makefile
@@ -85,6 +85,8 @@ CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
CPPFLAGS += -I$(NAN_DECIMATION)/include
CPPFLAGS += -I$(NAN_BSP)/include
+CPPFLAGS += -I$(NAN_OPENNL)/include
+
CPPFLAGS += -I../readstreamglue
CPPFLAGS += -I../include
diff --git a/source/blender/src/SConscript b/source/blender/src/SConscript
index 24471f09b47..2c371369679 100644
--- a/source/blender/src/SConscript
+++ b/source/blender/src/SConscript
@@ -101,6 +101,7 @@ source_files = ['B.blend.c',
'swapbuffers.c',
'toets.c',
'toolbox.c',
+ 'unwrapper.c',
'usiblender.c',
'view.c',
'vpaint.c',
@@ -128,7 +129,8 @@ src_env.Append (CPPPATH = ['#/intern/guardedalloc',
'../readstreamglue',
'../img',
'../quicktime',
- '#/intern/ghost'])
+ '#/intern/ghost',
+ '#/intern/opennl/extern'])
src_env.Append (CPPPATH = user_options_dict['PYTHON_INCLUDE'])
src_env.Append (CPPPATH = user_options_dict['SDL_INCLUDE'])
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
index 33021c7d17f..9167e4ccd7f 100644
--- a/source/blender/src/buttons_editing.c
+++ b/source/blender/src/buttons_editing.c
@@ -137,6 +137,7 @@
#include "BDR_editface.h"
#include "BDR_editobject.h"
#include "BDR_vpaint.h"
+#include "BDR_unwrapper.h"
#include "BSE_drawview.h"
#include "BSE_editipo.h"
@@ -2037,26 +2038,25 @@ static void editing_panel_mesh_tools1(Object *ob, Mesh *me)
block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_tools1", UI_EMBOSS, UI_HELV, curarea->win);
if(uiNewPanel(curarea, block, "Mesh Tools 1", "Editing", 960, 0, 318, 204)==0) return;
- uiDefBut(block, BUT,B_DOCENTRE, "Centre", 1091, 200, 166, 19, 0, 0, 0, 0, 0, "Shifts object data to be centered about object's origin");
uiBlockBeginAlign(block);
- uiDefBut(block, BUT,B_HIDE, "Hide", 1091,155,77,24, 0, 0, 0, 0, 0, "Hides selected faces");
- uiDefBut(block, BUT,B_REVEAL, "Reveal", 1171,155,86,24, 0, 0, 0, 0, 0, "Reveals selected faces");
+ uiDefBut(block, BUT,B_DOCENTRE, "Centre", 1091, 200, 166, 19, 0, 0, 0, 0, 0, "Shifts object data to be centered about object's origin");
+ uiDefBut(block, BUT,B_HIDE, "Hide", 1091, 180, 77, 19, 0, 0, 0, 0, 0, "Hides selected faces");
+ uiDefBut(block, BUT,B_REVEAL, "Reveal", 1171, 180, 86, 19, 0, 0, 0, 0, 0, "Reveals selected faces");
+ uiDefBut(block, BUT,B_SELSWAP, "Select Swap", 1091, 160, 166, 19, 0, 0, 0, 0, 0, "Selects unselected faces, and deselects selected faces");
uiBlockEndAlign(block);
- uiDefBut(block, BUT,B_SELSWAP, "Select Swap", 1091,130,166,24, 0, 0, 0, 0, 0, "Selects unselected faces, and deselects selected faces");
-
uiBlockBeginAlign(block);
- uiDefButF(block, NUM, REDRAWVIEW3D, "NSize:", 1090, 110, 164, 19, &editbutsize, 0.001, 2.0, 10, 0, "Sets the length to use when displaying face normals");
- uiDefButI(block, TOG|BIT|19, REDRAWVIEW3D, "Draw Creases", 1090,90,164,19, &G.f, 0, 0, 0, 0, "Displays face normals as lines");
- uiDefButI(block, TOG|BIT|6, REDRAWVIEW3D, "Draw Normals", 1090,70,164,19, &G.f, 0, 0, 0, 0, "Displays face normals as lines");
- uiDefButI(block, TOG|BIT|7, REDRAWVIEW3D, "Draw Faces", 1090,50,164,19, &G.f, 0, 0, 0, 0, "Displays all faces as shades");
- uiDefButI(block, TOG|BIT|18, REDRAWVIEW3D, "Draw Edges", 1090,30,164,19, &G.f, 0, 0, 0, 0, "Displays selected edges using hilights");
- uiDefButI(block, TOG|BIT|11, 0, "All edges", 1090,10,164,19, &G.f, 0, 0, 0, 0, "Displays all edges in object mode without optimization");
+ uiDefButF(block, NUM, REDRAWVIEW3D, "NSize:", 1090, 131, 166, 19, &editbutsize, 0.001, 2.0, 10, 0, "Sets the length to use when displaying face normals");
+ uiDefButI(block, TOG|BIT|6, REDRAWVIEW3D, "Draw Normals", 1090,110,166,19, &G.f, 0, 0, 0, 0, "Displays face normals as lines");
+ uiDefButI(block, TOG|BIT|7, REDRAWVIEW3D, "Draw Faces", 1090,88,166,19, &G.f, 0, 0, 0, 0, "Displays all faces as shades");
+ uiDefButI(block, TOG|BIT|18, REDRAWVIEW3D, "Draw Edges", 1090,66,166,19, &G.f, 0, 0, 0, 0, "Displays selected edges using hilights");
+ uiDefButI(block, TOG|BIT|19, REDRAWVIEW3D, "Draw Creases", 1090,44,166,19, &G.f, 0, 0, 0, 0, "Displays creased edges using hilights");
+ uiDefButI(block, TOG|BIT|20, REDRAWVIEW3D, "Draw Seams", 1090,22,166,19, &G.f, 0, 0, 0, 0, "Displays UV unwrapping seams");
+ uiDefButI(block, TOG|BIT|11, 0, "All Edges", 1090, 0,166,19, &G.f, 0, 0, 0, 0, "Displays all edges in object mode without optimization");
uiBlockEndAlign(block);
}
-
static void editing_panel_links(Object *ob)
{
uiBlock *block;
@@ -2365,7 +2365,6 @@ static void editing_panel_mesh_paint(void)
}
-
static void editing_panel_mesh_texface(void)
{
uiBlock *block;
@@ -2403,9 +2402,9 @@ static void editing_panel_mesh_texface(void)
uiBlockSetCol(block, TH_AUTO);
uiBlockBeginAlign(block);
- uiDefBut(block, BUT, B_COPY_TF_MODE, "Copy DrawMode", 600,7,117,28, 0, 0, 0, 0, 0, "Copy the drawmode");
- uiDefBut(block, BUT, B_COPY_TF_UV, "Copy UV+tex", 721,7,85,28, 0, 0, 0, 0, 0, "Copy UV information and textures");
- uiDefBut(block, BUT, B_COPY_TF_COL, "Copy VertCol", 809,7,103,28, 0, 0, 0, 0, 0, "Copy vertex colours");
+ uiDefBut(block, BUT, B_COPY_TF_MODE, "Copy DrawMode", 600,7,117,28, 0, 0, 0, 0, 0, "Copy the drawmode from active face to selected faces");
+ uiDefBut(block, BUT, B_COPY_TF_UV, "Copy UV+tex", 721,7,85,28, 0, 0, 0, 0, 0, "Copy UV information and textures from active face to selected faces");
+ uiDefBut(block, BUT, B_COPY_TF_COL, "Copy VertCol", 809,7,103,28, 0, 0, 0, 0, 0, "Copy vertex colours from active face to selected faces");
}
}
@@ -2429,6 +2428,9 @@ void do_uvautocalculationbuts(unsigned short event)
case B_UVAUTO_WINDOW:
if(select_area(SPACE_VIEW3D)) calculate_uv_map(event);
break;
+ case B_UVAUTO_LSCM:
+ unwrap_lscm();
+ break;
}
}
@@ -2444,28 +2446,34 @@ static void editing_panel_mesh_uvautocalculation(void)
return;
uiBlockBeginAlign(block);
- uiDefBut(block, BUT, B_UVAUTO_STD1,"Standard 1/1",100,row,200,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping");
- uiDefBut(block, BUT, B_UVAUTO_STD2,"1/2",100,row-butHB,66,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/2");
- uiDefBut(block, BUT, B_UVAUTO_STD4,"1/4",166,row-butHB,67,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/4");
- uiDefBut(block, BUT, B_UVAUTO_STD8,"1/8",234,row-butHB,66,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/8");
+ uiDefBut(block, BUT, B_UVAUTO_LSCM,"LSCM Unwrap",100,row,200,butH, 0, 0, 0, 0, 0, "Applies conformal UV mapping, preserving local angles");
uiBlockEndAlign(block);
- row-= 2*butHB+butS;
+ row-= butHB+butS;
uiBlockBeginAlign(block);
- uiDefBut(block, BUT, B_UVAUTO_BOUNDS1,"Bounds 1/1",100,row,200,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/1");
- uiDefBut(block, BUT, B_UVAUTO_BOUNDS2,"1/2",100,row-butHB,66,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/2");
- uiDefBut(block, BUT, B_UVAUTO_BOUNDS4,"1/4",166,row-butHB,67,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/4");
- uiDefBut(block, BUT, B_UVAUTO_BOUNDS8,"1/8",234,row-butHB,66,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/8");
- uiDefBut(block, BUT, B_UVAUTO_WINDOW,"From Window",100,row-2*butH,200,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping from window");
+ uiDefBut(block, BUT, B_UVAUTO_STD1,"Standard",100,row,100,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping");
+ uiDefBut(block, BUT, B_UVAUTO_STD2,"/2",200,row,33,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/2");
+ uiDefBut(block, BUT, B_UVAUTO_STD4,"/4",233,row,34,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/4");
+ uiDefBut(block, BUT, B_UVAUTO_STD8,"/8",267,row,33,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/8");
uiBlockEndAlign(block);
- row-= 3*butHB+butS;
+ row-= butHB+butS;
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT, B_UVAUTO_BOUNDS1,"Bounds",100,row,100,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/1");
+ uiDefBut(block, BUT, B_UVAUTO_BOUNDS2,"/2",200,row,33,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/2");
+ uiDefBut(block, BUT, B_UVAUTO_BOUNDS4,"/4",233,row,34,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/4");
+ uiDefBut(block, BUT, B_UVAUTO_BOUNDS8,"/8",267,row,33,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/8");
+ uiDefBut(block, BUT, B_UVAUTO_WINDOW,"From Window",100,row-butH,200,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping from window");
+ uiBlockEndAlign(block);
+ row-= 2*butHB+butS;
uiBlockBeginAlign(block);
- uiDefButS(block,ROW,REDRAWVIEW3D,"No Edges",100,row,200,butH,&facesel_draw_edges, 2.0, 0, 0, 0, "Don't draw edges of deselected faces in 3D view");
- uiDefButS(block,ROW,REDRAWVIEW3D,"Draw Edges",100,row-butH,200,butH,&facesel_draw_edges, 2.0, 1.0, 0, 0, "Draw edges of deselected faces z-buffered in 3D view");
- uiDefButS(block,ROW,REDRAWVIEW3D,"All Edges",100,row-2*butH,200,butH,&facesel_draw_edges, 2.0, 2.0, 0, 0, "Draw all edges of deselected faces in 3D view");
+ uiDefButI(block, TOG|BIT|7, REDRAWVIEW3D, "Draw Faces", 100,row,200,butH, &G.f, 0, 0, 0, 0, "Displays all faces as shades");
+ uiDefButI(block,TOG|BIT|18,REDRAWVIEW3D,"Draw Edges",100,row-butHB,200,butH,&G.f, 2.0, 0, 0, 0, "Displays edges of visible faces");
+ uiDefButI(block,TOG|BIT|21,REDRAWVIEW3D,"Draw Hidden Edges",100,row-2*butHB,200,butH,&G.f, 2.0, 1.0, 0, 0, "Displays edges of hidden faces");
+ uiDefButI(block,TOG|BIT|20,REDRAWVIEW3D,"Draw Seams",100,row-3*butHB,200,butH,&G.f, 2.0, 2.0, 0, 0, "Displays UV unwrapping seams");
uiBlockEndAlign(block);
- row-= 3*butHB+butS;
+ row-= 4*butHB+butS;
row= 180;
diff --git a/source/blender/src/drawimage.c b/source/blender/src/drawimage.c
index 5155fb6e422..5f4042ee962 100644
--- a/source/blender/src/drawimage.c
+++ b/source/blender/src/drawimage.c
@@ -316,9 +316,8 @@ void draw_tfaces(void)
Mesh *me;
int a;
char col1[4], col2[4];
+ float pointsize= BIF_GetThemeValuef(TH_VERTEX_SIZE);
- glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
-
if(G.f & G_FACESELECT) {
me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
if(me && me->tface) {
@@ -460,16 +459,16 @@ void draw_tfaces(void)
setlinestyle(0);
}
- /* to make sure vertices markers are visible, draw them last */
- /* we draw selected over unselected, so two loops */
- BIF_GetThemeColor3ubv(TH_VERTEX, col1);
- glColor4ubv(col1);
+ /* unselected uv's */
+ BIF_ThemeColor(TH_VERTEX);
+ glPointSize(pointsize);
+
+ bglBegin(GL_POINTS);
tface= me->tface;
mface= me->mface;
a= me->totface;
while(a--) {
if(mface->v3 && (tface->flag & TF_SELECT) ) {
- bglBegin(GL_POINTS);
if(tface->flag & TF_SEL1); else bglVertex2fv(tface->uv[0]);
if(tface->flag & TF_SEL2); else bglVertex2fv(tface->uv[1]);
@@ -477,20 +476,46 @@ void draw_tfaces(void)
if(mface->v4) {
if(tface->flag & TF_SEL4); else bglVertex2fv(tface->uv[3]);
}
- bglEnd();
}
tface++;
mface++;
}
- /* selected */
- BIF_GetThemeColor3ubv(TH_VERTEX_SELECT, col2);
- glColor4ubv(col2);
+ bglEnd();
+
+ /* pinned uv's */
+ /* give odd pointsizes odd pin pointsizes */
+ glPointSize(pointsize*2 + (((int)pointsize % 2)? (-1): 0));
+ cpack(0xFF);
+
+ bglBegin(GL_POINTS);
+ tface= me->tface;
+ mface= me->mface;
+ a= me->totface;
+ while(a--) {
+ if(mface->v3 && (tface->flag & TF_SELECT) ) {
+
+ if(tface->unwrap & TF_PIN1) bglVertex2fv(tface->uv[0]);
+ if(tface->unwrap & TF_PIN2) bglVertex2fv(tface->uv[1]);
+ if(tface->unwrap & TF_PIN3) bglVertex2fv(tface->uv[2]);
+ if(mface->v4) {
+ if(tface->unwrap & TF_PIN4) bglVertex2fv(tface->uv[3]);
+ }
+ }
+ tface++;
+ mface++;
+ }
+ bglEnd();
+
+ /* selected uv's */
+ BIF_ThemeColor(TH_VERTEX_SELECT);
+ glPointSize(pointsize);
+
+ bglBegin(GL_POINTS);
tface= me->tface;
mface= me->mface;
a= me->totface;
while(a--) {
if(mface->v3 && (tface->flag & TF_SELECT) ) {
- bglBegin(GL_POINTS);
if(tface->flag & TF_SEL1) bglVertex2fv(tface->uv[0]);
if(tface->flag & TF_SEL2) bglVertex2fv(tface->uv[1]);
@@ -498,11 +523,11 @@ void draw_tfaces(void)
if(mface->v4) {
if(tface->flag & TF_SEL4) bglVertex2fv(tface->uv[3]);
}
- bglEnd();
}
tface++;
mface++;
}
+ bglEnd();
}
}
glPointSize(1.0);
diff --git a/source/blender/src/drawmesh.c b/source/blender/src/drawmesh.c
index 0f9f8c3cfaa..b06ff19170e 100644
--- a/source/blender/src/drawmesh.c
+++ b/source/blender/src/drawmesh.c
@@ -68,7 +68,9 @@
#include "BKE_object.h"
#include "BKE_material.h"
+#include "BIF_resources.h"
#include "BIF_gl.h"
+#include "BIF_glutil.h"
#include "BIF_mywindow.h"
#include "BIF_resources.h"
@@ -83,8 +85,6 @@
//#include "glext.h"
/* some local functions */
-static void draw_hide_tfaces(Object *ob, Mesh *me);
-
#if defined(GL_EXT_texture_object) && (!defined(__sun__) || (!defined(__sun))) && !defined(__APPLE__)
/* exception for mesa... not according th opengl specs */
@@ -496,42 +496,6 @@ void spack(unsigned int ucol)
glColor3ub(cp[3], cp[2], cp[1]);
}
-static void draw_hide_tfaces(Object *ob, Mesh *me)
-{
- TFace *tface;
- MFace *mface;
- float *v1, *v2, *v3, *v4;
- int a;
-
- if(me==0 || me->tface==0) return;
-
- mface= me->mface;
- tface= me->tface;
-
- cpack(0x0);
- setlinestyle(1);
- for(a=me->totface; a>0; a--, mface++, tface++) {
- if(mface->v3==0) continue;
-
- if( (tface->flag & TF_HIDE)) {
-
- v1= (me->mvert+mface->v1)->co;
- v2= (me->mvert+mface->v2)->co;
- v3= (me->mvert+mface->v3)->co;
- if(mface->v4) v4= (me->mvert+mface->v4)->co; else v4= 0;
-
- glBegin(GL_LINE_LOOP);
- glVertex3fv( v1 );
- glVertex3fv( v2 );
- glVertex3fv( v3 );
- if(mface->v4) glVertex3fv( v4 );
- glEnd();
- }
- }
- setlinestyle(0);
-}
-
-
void draw_tfaces3D(Object *ob, Mesh *me)
{
MFace *mface;
@@ -540,26 +504,42 @@ void draw_tfaces3D(Object *ob, Mesh *me)
float *v1, *v2, *v3, *v4;
float *av1= NULL, *av2= NULL, *av3= NULL, *av4= NULL, *extverts= NULL;
int a, activeFaceInSelection= 0;
- extern short facesel_draw_edges;
+ extern void bPolygonOffset(short val);
if(me==0 || me->tface==0) return;
dl= find_displist(&ob->disp, DL_VERTS);
if (dl) extverts= dl->verts;
- /* shadow view */
- if(facesel_draw_edges>0){
- if(facesel_draw_edges==2) glDisable(GL_DEPTH_TEST);
- else glEnable(GL_DEPTH_TEST);
- cpack(0x00);
+ glEnable(GL_DEPTH_TEST);
+ glDisable(GL_LIGHTING);
+ bPolygonOffset(1);
+
+ /* Draw (Hidden) Edges */
+ if(G.f & G_DRAWEDGES || G.f & G_HIDDENEDGES){
+ BIF_ThemeColor(TH_EDGE_FACESEL);
mface= me->mface;
tface= me->tface;
for(a=me->totface; a>0; a--, mface++, tface++) {
- v1= (me->mvert+mface->v1)->co;
- v2= (me->mvert+mface->v2)->co;
- v3= (me->mvert+mface->v3)->co;
- v4= mface->v4?(me->mvert+mface->v4)->co: NULL;
+ if(mface->v3==0) continue;
+ if(tface->flag & TF_HIDE) {
+ if(!(G.f & G_HIDDENEDGES)) continue;
+ }
+ else if(!(G.f & G_DRAWEDGES)) continue;
+
+ if(extverts) {
+ v1= extverts+3*mface->v1;
+ v2= extverts+3*mface->v2;
+ v3= extverts+3*mface->v3;
+ v4= mface->v4?(extverts+3*mface->v4):NULL;
+ } else {
+ v1= (me->mvert+mface->v1)->co;
+ v2= (me->mvert+mface->v2)->co;
+ v3= (me->mvert+mface->v3)->co;
+ v4= mface->v4?(me->mvert+mface->v4)->co:NULL;
+ }
+
glBegin(GL_LINE_LOOP);
glVertex3fv(v1);
glVertex3fv(v2);
@@ -569,17 +549,101 @@ void draw_tfaces3D(Object *ob, Mesh *me)
}
}
- glDisable(GL_DEPTH_TEST);
+ if(G.f & G_DRAWSEAMS) {
+ BIF_ThemeColor(TH_EDGE_SEAM);
+ glLineWidth(2);
+ glBegin(GL_LINES);
+ mface= me->mface;
+ tface= me->tface;
+ for(a=me->totface; a>0; a--, mface++, tface++) {
+ if(mface->v3==0) continue;
+ if(tface->flag & TF_HIDE) continue;
+
+ if(extverts) {
+ v1= extverts+3*mface->v1;
+ v2= extverts+3*mface->v2;
+ v3= extverts+3*mface->v3;
+ v4= mface->v4?(extverts+3*mface->v4):NULL;
+ } else {
+ v1= (me->mvert+mface->v1)->co;
+ v2= (me->mvert+mface->v2)->co;
+ v3= (me->mvert+mface->v3)->co;
+ v4= mface->v4?(me->mvert+mface->v4)->co:NULL;
+ }
+
+ if(tface->unwrap & TF_SEAM1) {
+ glVertex3fv(v1);
+ glVertex3fv(v2);
+ }
+
+ if(tface->unwrap & TF_SEAM2) {
+ glVertex3fv(v2);
+ glVertex3fv(v3);
+ }
+
+ if(tface->unwrap & TF_SEAM3) {
+ glVertex3fv(v3);
+ if(v4) glVertex3fv(v4);
+ else glVertex3fv(v1);
+ }
+
+ if(v4 && tface->unwrap & TF_SEAM4) {
+ glVertex3fv(v4);
+ glVertex3fv(v1);
+ }
+ }
+ glEnd();
+
+ glLineWidth(1);
+ }
+
+ /* Draw Selected Faces in transparent purple */
+ if(G.f & G_DRAWFACES) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ BIF_ThemeColor4(TH_FACE_SELECT);
+
+ mface= me->mface;
+ tface= me->tface;
+ for(a=me->totface; a>0; a--, mface++, tface++) {
+ if(mface->v3==0) continue;
+ if(tface->flag & TF_HIDE) continue;
+
+ if(tface->flag & TF_SELECT) {
+ if(extverts) {
+ v1= extverts+3*mface->v1;
+ v2= extverts+3*mface->v2;
+ v3= extverts+3*mface->v3;
+ v4= mface->v4?(extverts+3*mface->v4):NULL;
+ } else {
+ v1= (me->mvert+mface->v1)->co;
+ v2= (me->mvert+mface->v2)->co;
+ v3= (me->mvert+mface->v3)->co;
+ v4= mface->v4?(me->mvert+mface->v4)->co:NULL;
+ }
+
+ glBegin(v4?GL_QUADS:GL_TRIANGLES);
+ glVertex3fv( v1 );
+ glVertex3fv( v2 );
+ glVertex3fv( v3 );
+ if(v4) glVertex3fv( v4 );
+ glEnd();
+ }
+ }
+ glDisable(GL_BLEND);
+ }
+
+ /* Draw Stippled Outline for selected faces */
mface= me->mface;
tface= me->tface;
- /* SELECT faces */
+ bPolygonOffset(1);
for(a=me->totface; a>0; a--, mface++, tface++) {
if(mface->v3==0) continue;
if(tface->flag & TF_HIDE) continue;
- if( tface->flag & (TF_ACTIVE|TF_SELECT) ) {
- if (extverts) {
+ if(tface->flag & (TF_ACTIVE|TF_SELECT) ) {
+ if(extverts) {
v1= extverts+3*mface->v1;
v2= extverts+3*mface->v2;
v3= extverts+3*mface->v3;
@@ -619,7 +683,7 @@ void draw_tfaces3D(Object *ob, Mesh *me)
}
}
- /* draw active face on top */
+ /* Draw Active Face on top */
/* colors: R=x G=y */
if(av1) {
cpack(0xFF);
@@ -646,7 +710,10 @@ void draw_tfaces3D(Object *ob, Mesh *me)
setlinestyle(0);
}
- glEnable(GL_DEPTH_TEST);
+ /* We added 2 offsets, so go back 2, and disable */
+ bPolygonOffset(-1);
+ bPolygonOffset(-1);
+ bPolygonOffset(0);
}
static int set_gl_light(Object *ob)
@@ -998,16 +1065,13 @@ void draw_tface_mesh(Object *ob, Mesh *me, int dt)
glEnd();
}
}
-
+
/* switch off textures */
set_tpage(0);
}
-
glShadeModel(GL_FLAT);
glDisable(GL_CULL_FACE);
- draw_hide_tfaces(ob, me);
-
if(ob==OBACT && (G.f & G_FACESELECT)) {
draw_tfaces3D(ob, me);
}
diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c
index 87f2b1c0014..971e4222f8e 100644
--- a/source/blender/src/drawobject.c
+++ b/source/blender/src/drawobject.c
@@ -2490,6 +2490,26 @@ static void drawmeshwire(Object *ob)
}
glEnd();
}
+
+ if(handles==0 && G.f & G_DRAWSEAMS) {
+ BIF_ThemeColor(TH_EDGE_SEAM);
+ glLineWidth(2);
+
+ glBegin(GL_LINES);
+ eed= em->edges.first;
+ while(eed) {
+ if(eed->h==0 && eed->seam) {
+ glVertex3fv(eed->v1->co);
+ glVertex3fv(eed->v2->co);
+ }
+ eed= eed->next;
+ }
+ glEnd();
+
+ cpack(0x0);
+ glLineWidth(1);
+ }
+
if(ob!=G.obedit) return;
calc_meshverts();
@@ -3405,7 +3425,7 @@ static int ob_from_decimator(Object *ob)
}
/* true or false */
-static void bPolygonOffset(short val)
+void bPolygonOffset(short val)
{
static float winmat[16], ofs=0.0;
diff --git a/source/blender/src/editface.c b/source/blender/src/editface.c
index f2c6585d51e..5fe27735e12 100644
--- a/source/blender/src/editface.c
+++ b/source/blender/src/editface.c
@@ -96,7 +96,9 @@
#include "BSE_trans_types.h"
#endif /* NAN_TPT */
-TFace *lasttface=0;
+#include "BDR_unwrapper.h"
+
+TFace *lasttface=NULL;
static void uv_calc_center_vector(float *result, Object *ob, Mesh *me)
{
@@ -651,7 +653,7 @@ void select_linked_tfaces()
Mesh *me;
TFace *tface;
MFace *mface;
- int a, doit=1;
+ int a, doit=1, mark=0;
char *cpmain;
me= get_mesh(OBACT);
@@ -669,7 +671,7 @@ void select_linked_tfaces()
while(a--) {
if(tface->flag & TF_HIDE);
else if(tface->flag & TF_SELECT) {
- if( mface->v3) {
+ if(mface->v3) {
cpmain[mface->v1]= 1;
cpmain[mface->v2]= 1;
cpmain[mface->v3]= 1;
@@ -686,18 +688,30 @@ void select_linked_tfaces()
a= me->totface;
while(a--) {
if(tface->flag & TF_HIDE);
- else if((tface->flag & TF_SELECT)==0) {
- if( mface->v3) {
+ else if(mface->v3 && ((tface->flag & TF_SELECT)==0)) {
+ mark= 0;
+
+ if(!(tface->unwrap & TF_SEAM1))
+ if(cpmain[mface->v1] && cpmain[mface->v2])
+ mark= 1;
+ if(!(tface->unwrap & TF_SEAM2))
+ if(cpmain[mface->v2] && cpmain[mface->v3])
+ mark= 1;
+ if(!(tface->unwrap & TF_SEAM3)) {
if(mface->v4) {
- if(cpmain[mface->v4]) {
- tface->flag |= TF_SELECT;
- doit= 1;
- }
- }
- if( cpmain[mface->v1] || cpmain[mface->v2] || cpmain[mface->v3] ) {
- tface->flag |= TF_SELECT;
- doit= 1;
+ if(cpmain[mface->v3] && cpmain[mface->v4])
+ mark= 1;
}
+ else if(cpmain[mface->v3] && cpmain[mface->v1])
+ mark= 1;
+ }
+ if(mface->v4 && !(tface->unwrap & TF_SEAM4))
+ if(cpmain[mface->v4] && cpmain[mface->v1])
+ mark= 1;
+
+ if(mark) {
+ tface->flag |= TF_SELECT;
+ doit= 1;
}
}
tface++; mface++;
@@ -708,7 +722,6 @@ void select_linked_tfaces()
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWIMAGE, 0);
-
}
void deselectall_tface()
@@ -1024,6 +1037,7 @@ float CalcNormUV(float *a, float *b, float *c)
#define UV_STD2_MAPPING 129
#define UV_STD1_MAPPING 128
#define UV_WINDOW_MAPPING 5
+#define UV_LSCM_MAPPING 6
#define UV_CYL_EX 32
#define UV_SPHERE_EX 34
@@ -1043,6 +1057,7 @@ void uv_autocalc_tface()
MENUSTRING("Cube", UV_CUBE_MAPPING) "|"
MENUSTRING("Cylinder", UV_CYL_MAPPING) "|"
MENUSTRING("Sphere", UV_SPHERE_MAPPING) "|"
+ MENUSTRING("LSCM", UV_LSCM_MAPPING) "|"
MENUSTRING("Bounds to 1/8", UV_BOUNDS8_MAPPING) "|"
MENUSTRING("Bounds to 1/4", UV_BOUNDS4_MAPPING) "|"
MENUSTRING("Bounds to 1/2", UV_BOUNDS2_MAPPING) "|"
@@ -1079,6 +1094,8 @@ void uv_autocalc_tface()
calculate_uv_map(B_UVAUTO_STD1); break;
case UV_WINDOW_MAPPING:
calculate_uv_map(B_UVAUTO_WINDOW); break;
+ case UV_LSCM_MAPPING:
+ unwrap_lscm(); break;
}
}
@@ -1104,7 +1121,10 @@ void set_faceselect() /* toggle */
if(G.f & G_FACESELECT) {
setcursor_space(SPACE_VIEW3D, CURSOR_FACESEL);
- if(me) set_lasttface();
+ if(me) {
+ set_lasttface();
+ set_seamtface(); /* set TF_SEAM flags in tface */
+ }
}
else if((G.f & (G_WEIGHTPAINT|G_VERTEXPAINT|G_TEXTUREPAINT))==0) {
if(me) reveal_tface();
diff --git a/source/blender/src/editmesh.c b/source/blender/src/editmesh.c
index 20455fe0b6e..f745bb44740 100644
--- a/source/blender/src/editmesh.c
+++ b/source/blender/src/editmesh.c
@@ -363,7 +363,7 @@ EditEdge *addedgelist(EditVert *v1, EditVert *v2, EditEdge *example)
/* find in hashlist */
eed= findedgelist(v1, v2);
-
+
if(eed==NULL) {
eed= (EditEdge *)calloc(sizeof(EditEdge), 1);
@@ -372,11 +372,12 @@ EditEdge *addedgelist(EditVert *v1, EditVert *v2, EditEdge *example)
BLI_addtail(&em->edges, eed);
eed->dir= swap;
insert_hashedge(eed);
- }
-
- /* copy crease data, seam flag? */
- if(example) {
- eed->crease = example->crease;
+ /* copy edge data:
+ rule is to do this with addedgelist call, before addvlaklist */
+ if(example) {
+ eed->crease= example->crease;
+ eed->seam = example->seam;
+ }
}
return eed;
@@ -452,15 +453,14 @@ EditVlak *addvlaklist(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, Ed
EditMesh *em = G.editMesh;
EditVlak *evl;
EditEdge *e1, *e2=0, *e3=0, *e4=0;
-
/* add face to list and do the edges */
- e1= addedgelist(v1, v2, example?example->e1:NULL);
- e2= addedgelist(v2, v3, example?example->e2:NULL);
- if(v4) e3= addedgelist(v3, v4, example?example->e3:NULL);
- else e3= addedgelist(v3, v1, example?example->e3:NULL);
- if(v4) e4= addedgelist(v4, v1, example?example->e4:NULL);
-
+ e1= addedgelist(v1, v2, NULL);
+ e2= addedgelist(v2, v3, NULL);
+ if(v4) e3= addedgelist(v3, v4, NULL);
+ else e3= addedgelist(v3, v1, NULL);
+ if(v4) e4= addedgelist(v4, v1, NULL);
+
if(v1==v2 || v2==v3 || v1==v3) return NULL;
if(e2==0) return NULL;
@@ -480,7 +480,7 @@ EditVlak *addvlaklist(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, Ed
evl->tf= example->tf;
evl->flag= example->flag;
}
- else {
+ else {
if (G.obedit && G.obedit->actcol)
evl->mat_nr= G.obedit->actcol-1;
default_uv(evl->tf.uv, 1.0);
@@ -488,7 +488,7 @@ EditVlak *addvlaklist(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, Ed
/* Initialize colors */
evl->tf.col[0]= evl->tf.col[1]= evl->tf.col[2]= evl->tf.col[3]= vpaint_get_current_col();
}
-
+
BLI_addtail(&em->faces, evl);
if(evl->v4) CalcNormFloat4(v1->co, v2->co, v3->co, v4->co, evl->n);
@@ -1023,6 +1023,7 @@ void make_editMesh_real(Mesh *me)
for(a=0; a<me->totedge; a++, medge++) {
eed= addedgelist(evlist[medge->v1], evlist[medge->v2], NULL);
eed->crease= ((float)medge->crease)/255.0;
+ if(medge->flag & ME_SEAM) eed->seam= 1;
}
}
@@ -1341,7 +1342,8 @@ void load_editMesh_real(Mesh *me, int undo)
medge->v2= (unsigned int) eed->v2->vn;
if(eed->f<2) medge->flag = ME_EDGEDRAW;
medge->crease= (char)(255.0*eed->crease);
-
+ if(eed->seam) medge->flag |= ME_SEAM;
+
medge++;
eed= eed->next;
}
@@ -3686,8 +3688,11 @@ short extrudeflag(short flag,short type)
if(eed->dir==1) evl2= addvlaklist(eed->v1, eed->v2, eed->v2->vn, eed->v1->vn, NULL);
else evl2= addvlaklist(eed->v2, eed->v1, eed->v1->vn, eed->v2->vn, NULL);
if (smooth) evl2->flag |= ME_SMOOTH;
-
- /* new edges, needs copied from old edge. actually we should find face that has this edge */
+
+ /* Needs smarter adaption of existing creases.
+ * If addedgelist is used, make sure seams are set to 0 on these
+ * new edges, since we do not want to add any seams on extrusion.
+ */
evl2->e1->crease= eed->crease;
evl2->e2->crease= eed->crease;
evl2->e3->crease= eed->crease;
@@ -3876,7 +3881,6 @@ short removedoublesflag(short flag, float limit) /* return amount */
if(eed->v1->f & 128) eed->v1= eed->v1->vn;
if(eed->v2->f & 128) eed->v2= eed->v2->vn;
-
e1= addedgelist(eed->v1, eed->v2, eed);
if(e1) e1->f= 1;
@@ -4187,12 +4191,30 @@ static void uv_quart(float *uv, float *uv1)
uv[1]= (uv1[1]+uv1[3]+uv1[5]+uv1[7])/4.0;
}
-static void set_wuv(int tot, EditVlak *evl, int v1, int v2, int v3, int v4)
+static void vlak_pin_vertex(EditVlak *evl, EditVert *vertex)
+{
+ if(evl->v1 == vertex) evl->tf.unwrap |= TF_PIN1;
+ else if(evl->v2 == vertex) evl->tf.unwrap |= TF_PIN2;
+ else if(evl->v3 == vertex) evl->tf.unwrap |= TF_PIN3;
+ else if(evl->v4 && vertex && evl->v4 == vertex) evl->tf.unwrap |= TF_PIN4;
+}
+
+static void set_wuv(int tot, EditVlak *evl, int v1, int v2, int v3, int v4, EditVlak *evlpin)
{
/* this weird function only to be used for subdivide, the 'w' in the name has no meaning! */
float *uv, uvo[4][2];
unsigned int *col, colo[4], col1, col2;
int a, v;
+
+ /* recover pinning */
+ if(evlpin){
+ evl->tf.unwrap= 0;
+ if(evlpin->tf.unwrap & TF_PIN1) vlak_pin_vertex(evl, evlpin->v1);
+ if(evlpin->tf.unwrap & TF_PIN2) vlak_pin_vertex(evl, evlpin->v2);
+ if(evlpin->tf.unwrap & TF_PIN3) vlak_pin_vertex(evl, evlpin->v3);
+ if(evlpin->tf.unwrap & TF_PIN4) vlak_pin_vertex(evl, evlpin->v4);
+ }
+
/* Numbers corespond to verts (corner points), */
/* edge->vn's (center edges), the Center */
memcpy(uvo, evl->tf.uv, sizeof(uvo)); /* And the quincunx points of a face */
@@ -4311,7 +4333,7 @@ static EditVert *vert_from_number(EditVlak *evl, int nr)
return NULL;
}
-static void addvlak_subdiv(EditVlak *evl, int val1, int val2, int val3, int val4, EditVert *eve)
+static void addvlak_subdiv(EditVlak *evl, int val1, int val2, int val3, int val4, EditVert *eve, EditVlak *evlpin)
{
EditVlak *w;
EditVert *v1, *v2, *v3, *v4;
@@ -4330,8 +4352,8 @@ static void addvlak_subdiv(EditVlak *evl, int val1, int val2, int val3, int val4
w= addvlaklist(v1, v2, v3, v4, evl);
if(w) {
- if(evl->v4) set_wuv(4, w, val1, val2, val3, val4);
- else set_wuv(3, w, val1, val2, val3, val4);
+ if(evl->v4) set_wuv(4, w, val1, val2, val3, val4, evlpin);
+ else set_wuv(3, w, val1, val2, val3, val4, evlpin);
}
}
@@ -4404,7 +4426,7 @@ void subdivideflag(int flag, float rad, int beauty)
extern float doublimit;
EditVert *eve;
EditEdge *eed, *e1, *e2, *e3, *e4, *nexted;
- EditVlak *evl;
+ EditVlak *evl, evlpin;
float fac, vec[3], vec1[3], len1, len2, len3, percent;
short test;
@@ -4534,6 +4556,9 @@ void subdivideflag(int flag, float rad, int beauty)
evl= em->faces.last;
while(evl) {
+
+ evlpin= *evl; /* make a copy of evl to recover uv pinning later */
+
if( vlakselectedOR(evl, flag) ) {
e1= evl->e1;
e2= evl->e2;
@@ -4542,67 +4567,79 @@ void subdivideflag(int flag, float rad, int beauty)
test= 0;
if(e1 && e1->vn) {
- test+= 1;
+ test+= 1;
e1->f= 1;
+ /* add edges here, to copy correct edge data */
+ eed= addedgelist(e1->v1, e1->vn, e1);
+ eed= addedgelist(e1->vn, e1->v2, e1);
}
- if(e2 && e2->vn) {
- test+= 2;
+ if(e2 && e2->vn) {
+ test+= 2;
e2->f= 1;
+ /* add edges here, to copy correct edge data */
+ eed= addedgelist(e2->v1, e2->vn, e2);
+ eed= addedgelist(e2->vn, e2->v2, e2);
}
- if(e3 && e3->vn) {
- test+= 4;
+ if(e3 && e3->vn) {
+ test+= 4;
e3->f= 1;
+ /* add edges here, to copy correct edge data */
+ eed= addedgelist(e3->v1, e3->vn, e3);
+ eed= addedgelist(e3->vn, e3->v2, e3);
}
- if(e4 && e4->vn) {
- test+= 8;
+ if(e4 && e4->vn) {
+ test+= 8;
e4->f= 1;
+ /* add edges here, to copy correct edge data */
+ eed= addedgelist(e4->v1, e4->vn, e4);
+ eed= addedgelist(e4->vn, e4->v2, e4);
}
if(test) {
if(evl->v4==0) { /* All the permutations of 3 edges*/
- if((test & 3)==3) addvlak_subdiv(evl, 2, 2+4, 1+4, 0, 0);
- if((test & 6)==6) addvlak_subdiv(evl, 3, 3+4, 2+4, 0, 0);
- if((test & 5)==5) addvlak_subdiv(evl, 1, 1+4, 3+4, 0, 0);
+ if((test & 3)==3) addvlak_subdiv(evl, 2, 2+4, 1+4, 0, 0, &evlpin);
+ if((test & 6)==6) addvlak_subdiv(evl, 3, 3+4, 2+4, 0, 0, &evlpin);
+ if((test & 5)==5) addvlak_subdiv(evl, 1, 1+4, 3+4, 0, 0, &evlpin);
if(test==7) { /* four new faces, old face renews */
evl->v1= e1->vn;
evl->v2= e2->vn;
evl->v3= e3->vn;
- set_wuv(3, evl, 1+4, 2+4, 3+4, 0);
+ set_wuv(3, evl, 1+4, 2+4, 3+4, 0, &evlpin);
}
else if(test==3) {
- addvlak_subdiv(evl, 1+4, 2+4, 3, 0, 0);
+ addvlak_subdiv(evl, 1+4, 2+4, 3, 0, 0, &evlpin);
evl->v2= e1->vn;
- set_wuv(3, evl, 1, 1+4, 3, 0);
+ set_wuv(3, evl, 1, 1+4, 3, 0, &evlpin);
}
else if(test==6) {
- addvlak_subdiv(evl, 2+4, 3+4, 1, 0, 0);
+ addvlak_subdiv(evl, 2+4, 3+4, 1, 0, 0, &evlpin);
evl->v3= e2->vn;
- set_wuv(3, evl, 1, 2, 2+4, 0);
+ set_wuv(3, evl, 1, 2, 2+4, 0, &evlpin);
}
else if(test==5) {
- addvlak_subdiv(evl, 3+4, 1+4, 2, 0, 0);
+ addvlak_subdiv(evl, 3+4, 1+4, 2, 0, 0, &evlpin);
evl->v1= e3->vn;
- set_wuv(3, evl, 3+4, 2, 3, 0);
+ set_wuv(3, evl, 3+4, 2, 3, 0, &evlpin);
}
else if(test==1) {
- addvlak_subdiv(evl, 1+4, 2, 3, 0, 0);
+ addvlak_subdiv(evl, 1+4, 2, 3, 0, 0, &evlpin);
evl->v2= e1->vn;
- set_wuv(3, evl, 1, 1+4, 3, 0);
+ set_wuv(3, evl, 1, 1+4, 3, 0, &evlpin);
}
else if(test==2) {
- addvlak_subdiv(evl, 2+4, 3, 1, 0, 0);
+ addvlak_subdiv(evl, 2+4, 3, 1, 0, 0, &evlpin);
evl->v3= e2->vn;
- set_wuv(3, evl, 1, 2, 2+4, 0);
+ set_wuv(3, evl, 1, 2, 2+4, 0, &evlpin);
}
else if(test==4) {
- addvlak_subdiv(evl, 3+4, 1, 2, 0, 0);
+ addvlak_subdiv(evl, 3+4, 1, 2, 0, 0, &evlpin);
evl->v1= e3->vn;
- set_wuv(3, evl, 3+4, 2, 3, 0);
+ set_wuv(3, evl, 3+4, 2, 3, 0, &evlpin);
}
- evl->e1= addedgelist(evl->v1, evl->v2, evl->e1);
- evl->e2= addedgelist(evl->v2, evl->v3, evl->e2);
- evl->e3= addedgelist(evl->v3, evl->v1, evl->e3);
-
+ evl->e1= addedgelist(evl->v1, evl->v2, NULL);
+ evl->e2= addedgelist(evl->v2, evl->v3, NULL);
+ evl->e3= addedgelist(evl->v3, evl->v1, NULL);
+
}
else { /* All the permutations of 4 faces */
if(test==15) {
@@ -4615,170 +4652,170 @@ void subdivideflag(int flag, float rad, int beauty)
eve= addvertlist(vec);
eve->f |= flag;
-
- addvlak_subdiv(evl, 2, 2+4, 9, 1+4, eve);
- addvlak_subdiv(evl, 3, 3+4, 9, 2+4, eve);
- addvlak_subdiv(evl, 4, 4+4, 9, 3+4, eve);
+
+ addvlak_subdiv(evl, 2, 2+4, 9, 1+4, eve, &evlpin);
+ addvlak_subdiv(evl, 3, 3+4, 9, 2+4, eve, &evlpin);
+ addvlak_subdiv(evl, 4, 4+4, 9, 3+4, eve, &evlpin);
evl->v2= e1->vn;
evl->v3= eve;
evl->v4= e4->vn;
- set_wuv(4, evl, 1, 1+4, 9, 4+4);
+ set_wuv(4, evl, 1, 1+4, 9, 4+4, &evlpin);
}
- else {
- if(((test & 3)==3)&&(test!=3)) addvlak_subdiv(evl, 1+4, 2, 2+4, 0, 0);
- if(((test & 6)==6)&&(test!=6)) addvlak_subdiv(evl, 2+4, 3, 3+4, 0, 0);
- if(((test & 12)==12)&&(test!=12)) addvlak_subdiv(evl, 3+4, 4, 4+4, 0, 0);
- if(((test & 9)==9)&&(test!=9)) addvlak_subdiv(evl, 4+4, 1, 1+4, 0, 0);
-
+ else {
+ if(((test & 3)==3)&&(test!=3)) addvlak_subdiv(evl, 1+4, 2, 2+4, 0, 0, &evlpin);
+ if(((test & 6)==6)&&(test!=6)) addvlak_subdiv(evl, 2+4, 3, 3+4, 0, 0, &evlpin);
+ if(((test & 12)==12)&&(test!=12)) addvlak_subdiv(evl, 3+4, 4, 4+4, 0, 0, &evlpin);
+ if(((test & 9)==9)&&(test!=9)) addvlak_subdiv(evl, 4+4, 1, 1+4, 0, 0, &evlpin);
+
if(test==1) { /* Edge 1 has new vert */
- addvlak_subdiv(evl, 1+4, 2, 3, 0, 0);
- addvlak_subdiv(evl, 1+4, 3, 4, 0, 0);
+ addvlak_subdiv(evl, 1+4, 2, 3, 0, 0, &evlpin);
+ addvlak_subdiv(evl, 1+4, 3, 4, 0, 0, &evlpin);
evl->v2= e1->vn;
evl->v3= evl->v4;
evl->v4= 0;
- set_wuv(4, evl, 1, 1+4, 4, 0);
+ set_wuv(4, evl, 1, 1+4, 4, 0, &evlpin);
}
else if(test==2) { /* Edge 2 has new vert */
- addvlak_subdiv(evl, 2+4, 3, 4, 0, 0);
- addvlak_subdiv(evl, 2+4, 4, 1, 0, 0);
+ addvlak_subdiv(evl, 2+4, 3, 4, 0, 0, &evlpin);
+ addvlak_subdiv(evl, 2+4, 4, 1, 0, 0, &evlpin);
evl->v3= e2->vn;
evl->v4= 0;
- set_wuv(4, evl, 1, 2, 2+4, 0);
+ set_wuv(4, evl, 1, 2, 2+4, 0, &evlpin);
}
else if(test==4) { /* Edge 3 has new vert */
- addvlak_subdiv(evl, 3+4, 4, 1, 0, 0);
- addvlak_subdiv(evl, 3+4, 1, 2, 0, 0);
+ addvlak_subdiv(evl, 3+4, 4, 1, 0, 0, &evlpin);
+ addvlak_subdiv(evl, 3+4, 1, 2, 0, 0, &evlpin);
evl->v1= evl->v2;
evl->v2= evl->v3;
evl->v3= e3->vn;
evl->v4= 0;
- set_wuv(4, evl, 2, 3, 3+4, 0);
+ set_wuv(4, evl, 2, 3, 3+4, 0, &evlpin);
}
else if(test==8) { /* Edge 4 has new vert */
- addvlak_subdiv(evl, 4+4, 1, 2, 0, 0);
- addvlak_subdiv(evl, 4+4, 2, 3, 0, 0);
+ addvlak_subdiv(evl, 4+4, 1, 2, 0, 0, &evlpin);
+ addvlak_subdiv(evl, 4+4, 2, 3, 0, 0, &evlpin);
evl->v1= evl->v3;
evl->v2= evl->v4;
evl->v3= e4->vn;
evl->v4= 0;
- set_wuv(4, evl, 3, 4, 4+4, 0);
+ set_wuv(4, evl, 3, 4, 4+4, 0, &evlpin);
}
else if(test==3) { /*edge 1&2 */
- /* make new vert in center of new edge */
+ /* make new vert in center of new edge */
vec[0]=(e1->vn->co[0]+e2->vn->co[0])/2;
vec[1]=(e1->vn->co[1]+e2->vn->co[1])/2;
vec[2]=(e1->vn->co[2]+e2->vn->co[2])/2;
eve= addvertlist(vec);
eve->f |= flag;
/* Add new faces */
- addvlak_subdiv(evl, 4, 10, 2+4, 3, eve);
- addvlak_subdiv(evl, 4, 1, 1+4, 10, eve);
+ addvlak_subdiv(evl, 4, 10, 2+4, 3, eve, &evlpin);
+ addvlak_subdiv(evl, 4, 1, 1+4, 10, eve, &evlpin);
/* orig face becomes small corner */
evl->v1=e1->vn;
//evl->v2=evl->v2;
evl->v3=e2->vn;
evl->v4=eve;
-
- set_wuv(4, evl, 1+4, 2, 2+4, 10);
+
+ set_wuv(4, evl, 1+4, 2, 2+4, 10, &evlpin);
}
else if(test==6) { /* 2&3 */
- /* make new vert in center of new edge */
+ /* make new vert in center of new edge */
vec[0]=(e2->vn->co[0]+e3->vn->co[0])/2;
vec[1]=(e2->vn->co[1]+e3->vn->co[1])/2;
vec[2]=(e2->vn->co[2]+e3->vn->co[2])/2;
eve= addvertlist(vec);
eve->f |= flag;
/*New faces*/
- addvlak_subdiv(evl, 1, 11, 3+4, 4, eve);
- addvlak_subdiv(evl, 1, 2, 2+4, 11, eve);
+ addvlak_subdiv(evl, 1, 11, 3+4, 4, eve, &evlpin);
+ addvlak_subdiv(evl, 1, 2, 2+4, 11, eve, &evlpin);
/* orig face becomes small corner */
evl->v1=e2->vn;
evl->v2=evl->v3;
evl->v3=e3->vn;
evl->v4=eve;
-
- set_wuv(4, evl, 2+4, 3, 3+4, 11);
+
+ set_wuv(4, evl, 2+4, 3, 3+4, 11, &evlpin);
}
else if(test==12) { /* 3&4 */
- /* make new vert in center of new edge */
+ /* make new vert in center of new edge */
vec[0]=(e3->vn->co[0]+e4->vn->co[0])/2;
vec[1]=(e3->vn->co[1]+e4->vn->co[1])/2;
vec[2]=(e3->vn->co[2]+e4->vn->co[2])/2;
eve= addvertlist(vec);
eve->f |= flag;
/*New Faces*/
- addvlak_subdiv(evl, 2, 12, 4+4, 1, eve);
- addvlak_subdiv(evl, 2, 3, 3+4, 12, eve);
+ addvlak_subdiv(evl, 2, 12, 4+4, 1, eve, &evlpin);
+ addvlak_subdiv(evl, 2, 3, 3+4, 12, eve, &evlpin);
/* orig face becomes small corner */
evl->v1=e3->vn;
evl->v2=evl->v4;
evl->v3=e4->vn;
evl->v4=eve;
-
- set_wuv(4, evl, 3+4, 4, 4+4, 12);
+
+ set_wuv(4, evl, 3+4, 4, 4+4, 12, &evlpin);
}
else if(test==9) { /* 4&1 */
- /* make new vert in center of new edge */
+ /* make new vert in center of new edge */
vec[0]=(e1->vn->co[0]+e4->vn->co[0])/2;
vec[1]=(e1->vn->co[1]+e4->vn->co[1])/2;
vec[2]=(e1->vn->co[2]+e4->vn->co[2])/2;
eve= addvertlist(vec);
eve->f |= flag;
/*New Faces*/
- addvlak_subdiv(evl, 3, 13, 1+4, 2, eve);
- addvlak_subdiv(evl, 3, 4, 4+4, 13, eve);
+ addvlak_subdiv(evl, 3, 13, 1+4, 2, eve, &evlpin);
+ addvlak_subdiv(evl, 3, 4, 4+4,13, eve, &evlpin);
/* orig face becomes small corner */
evl->v2=evl->v1;
evl->v1=e4->vn;
evl->v3=e1->vn;
evl->v4=eve;
-
- set_wuv(4, evl, 4+4, 1, 1+4, 13);
+
+ set_wuv(4, evl, 4+4, 1, 1+4, 13, &evlpin);
}
else if(test==5) { /* 1&3 */
- addvlak_subdiv(evl, 1+4, 2, 3, 3+4, 0);
+ addvlak_subdiv(evl, 1+4, 2, 3, 3+4, 0, &evlpin);
evl->v2= e1->vn;
evl->v3= e3->vn;
- set_wuv(4, evl, 1, 1+4, 3+4, 4);
+ set_wuv(4, evl, 1, 1+4, 3+4, 4, &evlpin);
}
else if(test==10) { /* 2&4 */
- addvlak_subdiv(evl, 2+4, 3, 4, 4+4, 0);
+ addvlak_subdiv(evl, 2+4, 3, 4, 4+4, 0, &evlpin);
evl->v3= e2->vn;
evl->v4= e4->vn;
- set_wuv(4, evl, 1, 2, 2+4, 4+4);
+ set_wuv(4, evl, 1, 2, 2+4, 4+4, &evlpin);
}/* Unfortunately, there is no way to avoid tris on 1 or 3 edges*/
else if(test==7) { /*1,2&3 */
- addvlak_subdiv(evl, 1+4, 2+4, 3+4, 0, 0);
+ addvlak_subdiv(evl, 1+4, 2+4, 3+4, 0, 0, &evlpin);
evl->v2= e1->vn;
evl->v3= e3->vn;
- set_wuv(4, evl, 1, 1+4, 3+4, 4);
+ set_wuv(4, evl, 1, 1+4, 3+4, 4, &evlpin);
}
else if(test==14) { /* 2,3&4 */
- addvlak_subdiv(evl, 2+4, 3+4, 4+4, 0, 0);
+ addvlak_subdiv(evl, 2+4, 3+4, 4+4, 0, 0, &evlpin);
evl->v3= e2->vn;
evl->v4= e4->vn;
- set_wuv(4, evl, 1, 2, 2+4, 4+4);
+ set_wuv(4, evl, 1, 2, 2+4, 4+4, &evlpin);
}
else if(test==13) {/* 1,3&4 */
- addvlak_subdiv(evl, 3+4, 4+4, 1+4, 0, 0);
+ addvlak_subdiv(evl, 3+4, 4+4, 1+4, 0, 0, &evlpin);
evl->v4= e3->vn;
evl->v1= e1->vn;
- set_wuv(4, evl, 1+4, 3, 3, 3+4);
+ set_wuv(4, evl, 1+4, 3, 3, 3+4, &evlpin);
}
else if(test==11) { /* 1,2,&4 */
- addvlak_subdiv(evl, 4+4, 1+4, 2+4, 0, 0);
+ addvlak_subdiv(evl, 4+4, 1+4, 2+4, 0, 0, &evlpin);
evl->v1= e4->vn;
evl->v2= e2->vn;
- set_wuv(4, evl, 4+4, 2+4, 3, 4);
+ set_wuv(4, evl, 4+4, 2+4, 3, 4, &evlpin);
}
}
- evl->e1= addedgelist(evl->v1, evl->v2, evl->e1);
- evl->e2= addedgelist(evl->v2, evl->v3, evl->e2);
- if(evl->v4) evl->e3= addedgelist(evl->v3, evl->v4, evl->e3);
- else evl->e3= addedgelist(evl->v3, evl->v1, evl->e3);
- if(evl->v4) evl->e4= addedgelist(evl->v4, evl->v1, evl->e4);
+ evl->e1= addedgelist(evl->v1, evl->v2, NULL);
+ evl->e2= addedgelist(evl->v2, evl->v3, NULL);
+ if(evl->v4) evl->e3= addedgelist(evl->v3, evl->v4, NULL);
+ else evl->e3= addedgelist(evl->v3, evl->v1, NULL);
+ if(evl->v4) evl->e4= addedgelist(evl->v4, evl->v1, NULL);
else evl->e4= NULL;
}
}
@@ -8900,6 +8937,7 @@ void bevel_mesh(float bsize, int allfaces)
#endif
}
+ /* Needs better adaption of creases? */
addedgelist(evl->e1->v1->vn, evl->e1->v2->vn, evl->e1);
addedgelist(evl->e2->v1->vn,evl->e2->v2->vn, evl->e2);
addedgelist(evl->e3->v1->vn,evl->e3->v2->vn, evl->e3);
@@ -9832,3 +9870,58 @@ void editmesh_deselect_by_material(int index) {
}
}
}
+
+void editmesh_mark_seam(int clear)
+{
+ EditMesh *em= G.editMesh;
+ EditEdge *eed;
+ Mesh *me= G.obedit->data;
+
+ /* auto-enable seams drawing */
+ if(clear==0) {
+ if(!(G.f & G_DRAWSEAMS)) {
+ G.f |= G_DRAWSEAMS;
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ if(!me->medge)
+ me->medge= MEM_callocN(sizeof(MEdge), "fake mesh edge");
+ }
+
+ if(clear) {
+ eed= em->edges.first;
+ while(eed) {
+ if((eed->h==0) && (eed->v1->f & 1) && (eed->v2->f & 1)) {
+ eed->seam = 0;
+ }
+ eed= eed->next;
+ }
+ }
+ else {
+ eed= em->edges.first;
+ while(eed) {
+ if((eed->h==0) && (eed->v1->f & 1) && (eed->v2->f & 1)) {
+ eed->seam = 1;
+ }
+ eed= eed->next;
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void Edge_Menu() {
+ short ret;
+
+ ret= pupmenu("Edge Specials%t|Mark Seam %x1|Clear Seam %x2");
+
+ switch(ret)
+ {
+ case 1:
+ editmesh_mark_seam(0);
+ break;
+ case 2:
+ editmesh_mark_seam(1);
+ break;
+ }
+}
+
diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c
index 0a995064bda..39cd046b5bd 100644
--- a/source/blender/src/editobject.c
+++ b/source/blender/src/editobject.c
@@ -143,6 +143,7 @@
#include "BDR_editobject.h"
#include "BDR_drawobject.h"
#include "BDR_editcurve.h"
+#include "BDR_unwrapper.h"
#include "render.h"
#include <time.h>
@@ -1097,8 +1098,11 @@ void exit_editmode(int freedata) /* freedata==0 at render */
load_editMesh(); /* makes new displist */
if(freedata) free_editMesh();
-
- if(G.f & G_FACESELECT) allqueue(REDRAWIMAGE, 0);
+
+ if(G.f & G_FACESELECT) {
+ set_seamtface();
+ allqueue(REDRAWIMAGE, 0);
+ }
build_particle_system(G.obedit);
}
diff --git a/source/blender/src/editsima.c b/source/blender/src/editsima.c
index 9e3558be259..a55de075504 100644
--- a/source/blender/src/editsima.c
+++ b/source/blender/src/editsima.c
@@ -79,6 +79,7 @@
#include "BSE_trans_types.h"
#include "BDR_editobject.h"
+#include "BDR_unwrapper.h"
#include "blendef.h"
#include "mydevice.h"
@@ -1682,3 +1683,34 @@ void toggle_uv_select(int mode)
allqueue(REDRAWIMAGE, 0);
}
+void pin_tface_uv(int mode)
+{
+ Mesh *me;
+ TFace *tface;
+ MFace *mface;
+ int a;
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+ me= get_mesh(OBACT);
+
+ mface= me->mface;
+ tface= me->tface;
+ for(a=me->totface; a>0; a--, tface++, mface++) {
+ if(mode ==1){
+ if(tface->flag & TF_SEL1) tface->unwrap |= TF_PIN1;
+ if(tface->flag & TF_SEL2) tface->unwrap |= TF_PIN2;
+ if(tface->flag & TF_SEL3) tface->unwrap |= TF_PIN3;
+ if(mface->v4)
+ if(tface->flag & TF_SEL4) tface->unwrap |= TF_PIN4;
+ }
+ else if (mode ==0){
+ if(tface->flag & TF_SEL1) tface->unwrap &= ~TF_PIN1;
+ if(tface->flag & TF_SEL2) tface->unwrap &= ~TF_PIN2;
+ if(tface->flag & TF_SEL3) tface->unwrap &= ~TF_PIN3;
+ if(mface->v4)
+ if(tface->flag & TF_SEL4) tface->unwrap &= ~TF_PIN4;
+ }
+ }
+ scrarea_queue_winredraw(curarea);
+}
+
diff --git a/source/blender/src/header_image.c b/source/blender/src/header_image.c
index b110a3d9a2c..bcf4fcaa334 100644
--- a/source/blender/src/header_image.c
+++ b/source/blender/src/header_image.c
@@ -62,6 +62,7 @@
#include "DNA_userdef_types.h"
#include "BDR_drawmesh.h"
+#include "BDR_unwrapper.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
@@ -816,8 +817,6 @@ static uiBlock *image_uvs_transformmenu(void *arg_unused)
static void do_image_uvsmenu(void *arg, int event)
{
- ScrArea *sa;
-
/* events >=20 are registered bpython scripts */
if (event >= 20) BPY_menu_do_python(PYMENU_UV, event - 20);
@@ -847,6 +846,16 @@ static void do_image_uvsmenu(void *arg, int event)
if(G.sima->flag & SI_NOPIXELSNAP) G.sima->flag &= ~SI_NOPIXELSNAP;
else G.sima->flag |= SI_NOPIXELSNAP;
break;
+ case 8:
+ pin_tface_uv(1);
+ break;
+ case 9:
+ pin_tface_uv(0);
+ break;
+ case 10:
+ if (okee("LSCM unwrap"))
+ unwrap_lscm();
+ break;
}
}
@@ -873,6 +882,12 @@ static uiBlock *image_uvsmenu(void *arg_unused)
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Unpin|Alt P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pin|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "LSCM Unwrap|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Limit Stitch...|Shift V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Stitch|V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
uiDefIconTextBlockBut(block, image_uvs_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c
index aaf063d28d1..badbef1b450 100644
--- a/source/blender/src/header_view3d.c
+++ b/source/blender/src/header_view3d.c
@@ -1938,6 +1938,12 @@ void do_view3d_edit_mesh_edgesmenu(void *arg, int event)
case 6:
bevel_menu();
break;
+ case 7: /* Mark Seam */
+ editmesh_mark_seam(0);
+ break;
+ case 8: /* Clear Seam */
+ editmesh_mark_seam(1);
+ break;
}
allqueue(REDRAWVIEW3D, 0);
}
@@ -1964,6 +1970,11 @@ static uiBlock *view3d_edit_mesh_edgesmenu(void *arg_unused)
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Subdivide Fractal|W, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Subdivide Smooth|W, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Mark Seam|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Seam|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+
uiBlockSetDirection(block, UI_RIGHT);
uiTextBoundsBlock(block, 60);
return block;
diff --git a/source/blender/src/resources.c b/source/blender/src/resources.c
index 78d01e6b9ea..028cec1a5d2 100644
--- a/source/blender/src/resources.c
+++ b/source/blender/src/resources.c
@@ -428,6 +428,10 @@ char *BIF_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
cp= ts->edge; break;
case TH_EDGE_SELECT:
cp= ts->edge_select; break;
+ case TH_EDGE_SEAM:
+ cp= ts->edge_seam; break;
+ case TH_EDGE_FACESEL:
+ cp= ts->edge_facesel; break;
case TH_FACE:
cp= ts->face; break;
case TH_FACE_SELECT:
@@ -502,6 +506,8 @@ void BIF_InitTheme(void)
btheme->tv3d.vertex_size= 2;
SETCOL(btheme->tv3d.edge, 0x0, 0x0, 0x0, 255);
SETCOL(btheme->tv3d.edge_select, 0x90, 0x90, 0x30, 255);
+ SETCOL(btheme->tv3d.edge_seam, 230, 150, 50, 255);
+ SETCOL(btheme->tv3d.edge_facesel, 75, 75, 75, 255);
SETCOL(btheme->tv3d.face, 0, 50, 150, 30);
SETCOL(btheme->tv3d.face_select, 200, 100, 200, 60);
@@ -648,6 +654,8 @@ char *BIF_ThemeColorsPup(int spacetype)
sprintf(str, "Vertex Selected %%x%d|", TH_VERTEX_SELECT); strcat(cp, str);
sprintf(str, "Vertex Size %%x%d|", TH_VERTEX_SIZE); strcat(cp, str);
sprintf(str, "Edge Selected %%x%d|", TH_EDGE_SELECT); strcat(cp, str);
+ sprintf(str, "Edge Seam %%x%d|", TH_EDGE_SEAM); strcat(cp, str);
+ sprintf(str, "Edge UV Face Select %%x%d|", TH_EDGE_FACESEL); strcat(cp, str);
sprintf(str, "Face %%x%d|", TH_FACE); strcat(cp, str);
sprintf(str, "Face Selected %%x%d", TH_FACE_SELECT); strcat(cp, str);
}
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index a35de2087f5..8683d66e232 100644
--- a/source/blender/src/space.c
+++ b/source/blender/src/space.c
@@ -128,6 +128,7 @@
#include "BDR_editface.h"
#include "BDR_drawmesh.h"
#include "BDR_drawobject.h"
+#include "BDR_unwrapper.h"
#include "BLO_readfile.h" /* for BLO_blendhandle_close */
@@ -1015,11 +1016,15 @@ void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
extrude_ika(ob, 1);
}
}
- if (G.qual == LR_SHIFTKEY) {
- if (G.obedit && G.obedit->type==OB_MESH) {
- transform('e');
- }
- }
+ else if (G.qual==LR_CTRLKEY) {
+ if(G.obedit && G.obedit->type==OB_MESH)
+ Edge_Menu();
+ }
+ else if (G.qual==LR_SHIFTKEY) {
+ if (G.obedit && G.obedit->type==OB_MESH) {
+ transform('e');
+ }
+ }
break;
case FKEY:
if(G.obedit) {
@@ -3419,6 +3424,10 @@ void winqreadimagespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
else
toggle_uv_select('f');
break;
+ case EKEY :
+ if (okee("LSCM unwrap"))
+ unwrap_lscm();
+ break;
case GKEY:
if((G.qual==0))
transform_tface_uv('g');
@@ -3457,6 +3466,12 @@ void winqreadimagespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
G.f |= G_PROPORTIONAL;
}
break;
+ case PKEY:
+ if(G.qual==LR_ALTKEY)
+ pin_tface_uv(0);
+ else
+ pin_tface_uv(1);
+ break;
case RKEY:
if((G.qual==0))
transform_tface_uv('r');
diff --git a/source/blender/src/toolbox.c b/source/blender/src/toolbox.c
index c2422434562..188499378af 100644
--- a/source/blender/src/toolbox.c
+++ b/source/blender/src/toolbox.c
@@ -1712,6 +1712,9 @@ static TBitem tb_mesh_edit_edge[]= {
{ 0, "Subdivide|W, 1", 2, NULL},
{ 0, "Subdivide Fractal|W, 2", 1, NULL},
{ 0, "Subdivide Smooth|W, 3", 0, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Mark Seam|Ctrl E", 7, NULL},
+{ 0, "Clear Seam|Ctrl E", 8, NULL},
{ -1, "", 0, do_view3d_edit_mesh_edgesmenu}};
static TBitem tb_mesh_edit_face[]= {
diff --git a/source/blender/src/unwrapper.c b/source/blender/src/unwrapper.c
new file mode 100644
index 00000000000..13c31b308e6
--- /dev/null
+++ b/source/blender/src/unwrapper.c
@@ -0,0 +1,1159 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+
+#include "BIF_space.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+#include "ONL_opennl.h"
+#include "BDR_unwrapper.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;
+}
+
+/* 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;
+ char *cpmain;
+ int doit, mark;
+
+ if(!me || !me->tface) return 0;
+
+ groups= (int*)MEM_callocN(sizeof(int)*me->totface, "SeamGroups");
+ cpmain= (char*)MEM_mallocN(me->totvert, "cpmain");
+
+ 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;
+ gid++;
+ *gface= gid;
+ mark= 0;
+ doit= 1;
+ memset(cpmain, 0, me->totvert);
+
+ 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 && mf->v3) {
+ cpmain[mf->v1]= 1;
+ cpmain[mf->v2]= 1;
+ cpmain[mf->v3]= 1;
+ if(mf->v4) cpmain[mf->v4]= 1;
+ }
+ 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 && mf->v3 && *gf==0) {
+ mark= 0;
+
+ if(!(tf->unwrap & TF_SEAM1))
+ if(cpmain[mf->v1] && cpmain[mf->v2])
+ mark= 1;
+ if(!(tf->unwrap & TF_SEAM2))
+ if(cpmain[mf->v2] && cpmain[mf->v3])
+ mark= 1;
+ if(!(tf->unwrap & TF_SEAM3)) {
+ if(mf->v4) {
+ if(cpmain[mf->v3] && cpmain[mf->v4])
+ mark= 1;
+ }
+ else if(cpmain[mf->v3] && cpmain[mf->v1])
+ mark= 1;
+ }
+ if(mf->v4 && !(tf->unwrap & TF_SEAM4))
+ if(cpmain[mf->v4] && cpmain[mf->v1])
+ mark= 1;
+
+ if(mark) {
+ *gf= gid;
+ doit= 1;
+ }
+ }
+ tf++; mf++; gf++;
+ }
+ }
+ }
+ *seamgroups= groups;
+
+ MEM_freeN(cpmain);
+ 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 int lscm_build_vertex_data(Mesh *me, int *groups, int gid, LscmVert **lscm_vertices, LscmVert ***sort_vertices)
+{
+ MFace *mf;
+ TFace *tf;
+ int *gf, totvert, a;
+ LscmVert *lscmvert, **sortvert;
+ LscmVert *v1, *v2, *v3, **sv1, **sv2, **sv3;
+
+ /* determine size for malloc */
+ totvert= 0;
+ mf= me->mface;
+ tf= me->tface;
+ gf= groups;
+
+ 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) {
+ 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= mf->v2;
+ v1->v2= mf->v3;
+
+ v2->v1= mf->v1;
+ v2->v2= mf->v3;
+
+ v3->v1= mf->v1;
+ v3->v2= mf->v2;
+
+ 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) {
+ 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= mf->v3;
+ v1->v2= mf->v4;
+
+ v2->v1= mf->v4;
+ v2->v2= mf->v1;
+
+ v3->v1= mf->v1;
+ v3->v2= mf->v3;
+
+ 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;
+ }
+ }
+ 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(dz < dx && dz < dy) {
+ 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();
+
+ /* 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.05;
+ dy += 0.05;
+
+ 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.025;
+ add[1] += 0.025;
+
+ 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.9);
+ add[0]= add[1]= 0.05;
+ seam_group_move(me, groups, 0, add);
+}
+
+void unwrap_lscm(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);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+}
+
+/* Set tface seams based on edge data, uses hash table to find seam edges. */
+
+#define SEDHASH(a, b) ((a)*256 + (b))
+#define SEDHASHSIZE 65536
+#define SEDHMAX 256
+
+typedef struct SeamHashEdge {
+ MEdge *e;
+ struct SeamHashEdge *next;
+} SeamHashEdge;
+
+/* Hash table with edges, to find edges based on v1, v2 */
+static SeamHashEdge *make_seam_hash_edge_table(Mesh *me)
+{
+ SeamHashEdge *htable, *first, *he;
+ MEdge *medge;
+ unsigned int a, hv1, hv2;
+
+ if(me->medge==NULL)
+ return NULL;
+
+ htable= MEM_callocN(SEDHASHSIZE*sizeof(SeamHashEdge), "lscmedgehashtable");
+
+ medge= me->medge;
+ for(a=me->totedge; a>0; a--, medge++) {
+ if(!(medge->flag & ME_SEAM)) continue;
+
+ hv1= medge->v1 % SEDHMAX;
+ hv2= medge->v2 % SEDHMAX;
+ if(hv1 > hv2)
+ SWAP(unsigned int, hv1, hv2);
+
+ first = htable + SEDHASH(hv1, hv2);
+
+ if(first->e == NULL) {
+ first->e = medge;
+ }
+ else {
+ he= (SeamHashEdge*)malloc(sizeof(SeamHashEdge));
+ he->e= medge;
+ he->next= first->next;
+ first->next= he;
+ }
+ }
+
+ return htable;
+}
+
+static int edge_is_seam(SeamHashEdge *htable, unsigned int v1, unsigned int v2)
+{
+ SeamHashEdge *he;
+ unsigned int hv1, hv2;
+
+ hv1 = v1 % SEDHMAX;
+ hv2 = v2 % SEDHMAX;
+
+ if(hv1 > hv2)
+ SWAP(unsigned int, hv1, hv2);
+
+ he= htable + SEDHASH(hv1, hv2);
+
+ while(he) {
+ if(he->e) {
+ if(he->e->v1==v1 && he->e->v2==v2) return 1;
+ else if(he->e->v1==v2 && he->e->v2==v1) return 1;
+ }
+ he= he->next;
+ }
+
+ return 0;
+}
+
+static void free_seam_hash_edge_table(SeamHashEdge *htable)
+{
+ SeamHashEdge *first, *he, *hen;
+ int a;
+
+ if(htable) {
+ first= htable;
+ for(a=SEDHASHSIZE; a>0; a--, first++) {
+ he= first->next;
+ while(he) {
+ hen= he->next;
+ free(he);
+ he= hen;
+ }
+ }
+ MEM_freeN(htable);
+ htable= NULL;
+ }
+}
+
+void set_seamtface()
+{
+ Mesh *me;
+ SeamHashEdge *htable;
+ int a;
+ MFace *mf;
+ TFace *tf;
+
+ me= get_mesh(OBACT);
+ if(!me || !me->tface || !(G.f & G_FACESELECT)) return;
+
+ htable= make_seam_hash_edge_table(me);
+
+ mf= me->mface;
+ tf= me->tface;
+ for(a=me->totface; a>0; a--, mf++, tf++) {
+ if(mf->v3==0) continue;
+ tf->unwrap &= ~(TF_SEAM1|TF_SEAM2|TF_SEAM3|TF_SEAM4);
+
+ if(!htable) continue;
+
+ if(edge_is_seam(htable, mf->v1, mf->v2)) tf->unwrap |= TF_SEAM1;
+ if(edge_is_seam(htable, mf->v2, mf->v3)) tf->unwrap |= TF_SEAM2;
+
+ if(mf->v4) {
+ if(edge_is_seam(htable, mf->v3, mf->v4)) tf->unwrap |= TF_SEAM3;
+ if(edge_is_seam(htable, mf->v4, mf->v1)) tf->unwrap |= TF_SEAM4;
+ }
+ else if(edge_is_seam(htable, mf->v3, mf->v1)) tf->unwrap |= TF_SEAM3;
+ }
+
+ free_seam_hash_edge_table(htable);
+}
+