Added LSCM UV Unwrapping:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Tue, 13 Jul 2004 11:48:52 +0000 (11:48 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Tue, 13 Jul 2004 11:48:52 +0000 (11:48 +0000)
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.

31 files changed:
source/blender/blenkernel/BKE_global.h
source/blender/blenkernel/BKE_utildefines.h
source/blender/blenkernel/intern/displist.c
source/blender/blenkernel/intern/subsurf.c
source/blender/blenlib/BLI_arithb.h
source/blender/blenlib/BLI_editVert.h
source/blender/blenlib/intern/arithb.c
source/blender/include/BDR_unwrapper.h [new file with mode: 0644]
source/blender/include/BIF_editmesh.h
source/blender/include/BIF_editsima.h
source/blender/include/BIF_resources.h
source/blender/include/butspace.h
source/blender/makesdna/DNA_mesh_types.h
source/blender/makesdna/DNA_meshdata_types.h
source/blender/makesdna/DNA_userdef_types.h
source/blender/src/Makefile
source/blender/src/SConscript
source/blender/src/buttons_editing.c
source/blender/src/drawimage.c
source/blender/src/drawmesh.c
source/blender/src/drawobject.c
source/blender/src/editface.c
source/blender/src/editmesh.c
source/blender/src/editobject.c
source/blender/src/editsima.c
source/blender/src/header_image.c
source/blender/src/header_view3d.c
source/blender/src/resources.c
source/blender/src/space.c
source/blender/src/toolbox.c
source/blender/src/unwrapper.c [new file with mode: 0644]

index 7586f14c894a40d8a721411a9b3f2fb5d74a18e4..b9c4583484095bae09b9a7e0befb1235c6da37c1 100644 (file)
@@ -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 */
 
index 97cd46aa3fc56a5beab6a7a547a95ed544a4038c..44cef530f484df83a0cd110419dc70deb0fe2026 100644 (file)
@@ -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]; \
index 530442f03a9e58cb7e1d6db9f2eff44d6238812a..1b100d339fba9ab43874480fb2bd2b0ea2e1acea 100644 (file)
@@ -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];
index 6b069782336d1210c1f3c69767b1666f68e2e87c..4a8724272b7bb47b515b4c40f7352251869e91f3 100644 (file)
@@ -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];
                        
index 5941d421d1670cd087783f82fbebc92faf55d679..4df5db5f39ef0bb218b94fe755716cdbe2c81d83 100644 (file)
@@ -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
 }
index 568aa6b65ae5e122e049969d3052a1085efca0b4..3f477036c0b8567b2d624e951d0e89e5a3443e7c 100644 (file)
@@ -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
index ac025b3412721c4536c63a87fa2d5f7ec55b7200..ff057a61e517af46eb7ac187209e8131fa68d7dc 100644 (file)
@@ -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 (file)
index 0000000..72633ba
--- /dev/null
@@ -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 */
+
index 09dcd69dc9f8b8eaaae9eca83a056f01fd6cfd26..de289c88e200c029c0bc3f0e8dd33ec7d8079be6 100644 (file)
@@ -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
 
index e3e803ad5d23387eba0f09f6bf45d3758866c819..c3750bfc018b51a6fee83ff4209748fd119aa2f7 100644 (file)
@@ -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);
 
index 6bce7e4e3f171381f71a70fc1695f6d44bbc4ed4..ededfab748914c9a05e1652f7df0cc81e9602160 100644 (file)
@@ -376,6 +376,8 @@ enum {
        TH_VERTEX_SIZE,
        TH_EDGE,
        TH_EDGE_SELECT,
+       TH_EDGE_SEAM,
+       TH_EDGE_FACESEL,
        TH_FACE,
        TH_FACE_SELECT
 };
index 55fac76e7fbb1de6e3a082b97eab2d0e3967975e..eb9e7455bafcfea71f9e22fa521f4fc0d1f0ee87 100644 (file)
@@ -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
index 674c144923d14713553e42d7c6d0acd329dc18c5..f9cb375572b063f5d8f6abcbf80e22250d3ce04d 100644 (file)
@@ -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
index 04de27f58b06abd01f521a90982132de3b8d5100..f0ac467afb2731ca826c67913eaaa93a7119eadc 100644 (file)
@@ -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
index 97a944db70d88710df51aed9d36f17fc759be8c4..7c2773f0b5b79b9140e28c3ead11f5e007bc9978 100644 (file)
@@ -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;
index bdb5af6b801359c04dff3dadd3e1bfd4795f78d8..210ed7d73206fc0938aad07ecc1d7b994fe3c8fe 100644 (file)
@@ -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
 
index 24471f09b475b93e567d857326666dd230a4a474..2c371369679b3d72bab77e68b930264b1a88752c 100644 (file)
@@ -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'])
index 33021c7d17f6d702f7c1aff0dfe6aa41f0177a00..9167e4ccd7f6316bdcbaea5a2b241cfc5c19828a 100644 (file)
 #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;
 
index 5155fb6e4227e7eb4981d153b2f54b9824416730..5f4042ee962d8c43fb768488b676fe756c7beb82 100644 (file)
@@ -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);
index 0f9f8c3cfaa1dbbca899bee2e2f96200f6593a88..b06ff19170e93ba791b5e01a8d8c9acd0d0618c9 100644 (file)
@@ -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);
        }
index 87f2b1c0014c0f3a14fa716eb0c0a353a51014cd..971e4222f8ecd6ff095fcc6e78d875b37b65c90a 100644 (file)
@@ -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;
 
index f2c6585d51efe37619ff1208bf57b12b34c44db7..5fe27735e1207cf9cee7029a5c810396db4bac42 100644 (file)
@@ -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();
index 20455fe0b6ec2e9c6c53d70c70c58d31da01b4e7..f745bb44740cb62b4dc91b25aa3f3933c7fef1d4 100644 (file)
@@ -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;
+       }
+}
+
index 0a995064bdaad55a128295d5f64f8675fd85b7c1..39cd046b5bdf377df236e5574ca1e9f8ecc3d2f5 100644 (file)
 #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);
        }
index 9e3558be259b368bdf24e3560708412c966d6447..a55de07550472b8d5486ce20638f407394ce1f19 100644 (file)
@@ -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);
+}
+
index b110a3d9a2c1a49f3757017aaae3ff04820aadf0..bcf4fcaa3340826ff66b072375b075c253fe25a3 100644 (file)
@@ -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, "");
index aaf063d28d14ef106b8c7af7afae6d71ec2e1c5c..badbef1b4509592d6679580c6233196b9073311f 100644 (file)
@@ -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;
index 78d01e6b9ea2efa6fb31ed53f8ffdb5bfb8a1dfb..028cec1a5d228b63f9dedd93d71f9a30e21ed449 100644 (file)
@@ -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);
                }
index a35de2087f5f00878aa2565f3b48f5148d63e56c..8683d66e232e3eb0e9d2200e81be534ede2fbade 100644 (file)
 #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');
index c2422434562347643dec7b8a15f181c3c66a5e4b..188499378af5e918a59acc993006cb88d4fb26cc 100644 (file)
@@ -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 (file)
index 0000000..13c31b3
--- /dev/null
@@ -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);
+}
+