diff options
31 files changed, 1876 insertions, 273 deletions
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index 7586f14c894..b9c45834840 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -187,6 +187,8 @@ typedef struct Global { #define G_NOFROZEN (1 << 17) // frozen modules inactive #define G_DRAWEDGES (1 << 18) #define G_DRAWCREASES (1 << 19) +#define G_DRAWSEAMS (1 << 20) +#define G_HIDDENEDGES (1 << 21) /* G.fileflags */ diff --git a/source/blender/blenkernel/BKE_utildefines.h b/source/blender/blenkernel/BKE_utildefines.h index 97cd46aa3fc..44cef530f48 100644 --- a/source/blender/blenkernel/BKE_utildefines.h +++ b/source/blender/blenkernel/BKE_utildefines.h @@ -81,6 +81,8 @@ #define INIT_MINMAX(min, max) (min)[0]= (min)[1]= (min)[2]= 1.0e30; (max)[0]= (max)[1]= (max)[2]= -1.0e30; +#define INIT_MINMAX2(min, max) (min)[0]= (min)[1]= 1.0e30; (max)[0]= (max)[1]= -1.0e30; + #define DO_MINMAX(vec, min, max) if( (min)[0]>(vec)[0] ) (min)[0]= (vec)[0]; \ if( (min)[1]>(vec)[1] ) (min)[1]= (vec)[1]; \ if( (min)[2]>(vec)[2] ) (min)[2]= (vec)[2]; \ diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 530442f03a9..1b100d339fb 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -277,12 +277,17 @@ void displistmesh_to_mesh(DispListMesh *dlm, Mesh *me) } else { me->totface= dlm->totface; me->totvert= dlm->totvert; - + me->mvert= MEM_dupallocN(dlm->mvert); me->mface= mfaces= MEM_mallocN(sizeof(*mfaces)*me->totface, "me->mface"); me->tface= MEM_dupallocN(dlm->tface); me->mcol= MEM_dupallocN(dlm->mcol); - + + if(dlm->medge) { + me->totedge= dlm->totedge; + me->medge= MEM_dupallocN(dlm->medge); + } + for (i=0; i<me->totface; i++) { MFace *mf= &mfaces[i]; MFace *oldmf= &dlm->mface[i]; diff --git a/source/blender/blenkernel/intern/subsurf.c b/source/blender/blenkernel/intern/subsurf.c index 6b069782336..4a8724272b7 100644 --- a/source/blender/blenkernel/intern/subsurf.c +++ b/source/blender/blenkernel/intern/subsurf.c @@ -176,8 +176,9 @@ struct _HyperVert { LinkNode *edges, *faces; }; -/* hyper edge flag */ +/* hyper edge flags */ #define DR_OPTIM 1 +#define HE_SEAM 2 struct _HyperEdge { HyperEdge *next; @@ -200,6 +201,7 @@ struct _HyperFace { unsigned char (*vcol)[4]; float (*uvco)[2]; + short unwrap; /* for getting back tface, matnr, etc */ union { @@ -342,7 +344,7 @@ static HyperMesh *hypermesh_from_mesh(Mesh *me, float *extverts, int subdivLevel MFace *mface= me->mface; MEdge *medge= me->medge; float creasefac= ((float)subdivLevels)/255.0; // in Mesh sharpness is byte - int i, j; + int i, j, flag; hme->orig_me= me; if (me->tface) @@ -362,8 +364,11 @@ static HyperMesh *hypermesh_from_mesh(Mesh *me, float *extverts, int subdivLevel if(medge) { for (i=0; i<me->totedge; i++) { MEdge *med= &medge[i]; + + flag= DR_OPTIM; + if(med->flag & ME_SEAM) flag |= HE_SEAM; - hypermesh_add_edge(hme, vert_tbl[med->v1], vert_tbl[med->v2], DR_OPTIM, + hypermesh_add_edge(hme, vert_tbl[med->v1], vert_tbl[med->v2], flag, creasefac*((float)med->crease) ); } } @@ -395,6 +400,8 @@ static HyperMesh *hypermesh_from_mesh(Mesh *me, float *extverts, int subdivLevel f->vcol= BLI_memarena_alloc(hme->arena, sizeof(*f->vcol)*nverts); for (j=0; j<nverts; j++) *((unsigned int*) f->vcol[j])= tf->col[j]; + + f->unwrap= tf->unwrap; } else if (hme->hasvcol) { MCol *mcol= &me->mcol[i*4]; @@ -418,6 +425,7 @@ static HyperMesh *hypermesh_from_editmesh(EditMesh *em, int subdivLevels) { EditEdge *ee; EditVlak *ef; float creasefac= (float)subdivLevels; + int flag; /* we only add vertices with edges, 'f1' is a free flag */ /* added: check for hide flag in vertices */ @@ -437,8 +445,10 @@ static HyperMesh *hypermesh_from_editmesh(EditMesh *em, int subdivLevels) { ee->v2->prev= (EditVert*) hypermesh_add_vert(hme, ee->v2->co, ee->v2->co); ee->v2->f1= 0; } - - hypermesh_add_edge(hme, (HyperVert*) ee->v1->prev, (HyperVert*) ee->v2->prev, DR_OPTIM, + + flag= DR_OPTIM; + if(ee->seam) flag |= HE_SEAM; + hypermesh_add_edge(hme, (HyperVert*) ee->v1->prev, (HyperVert*) ee->v2->prev, flag, creasefac*ee->crease); } } @@ -743,6 +753,13 @@ static void hypermesh_subdivide(HyperMesh *me, HyperMesh *nme) { Vec2Cpy(nf->uvco[1], uvco_edge[j]); Vec2Cpy(nf->uvco[2], uvco_mid); Vec2Cpy(nf->uvco[3], uvco_edge[last]); + + if(j==0 && (f->unwrap & ((f->nverts==4)?TF_PIN4:TF_PIN3))) + nf->unwrap= TF_PIN1; + else if(j==1 && f->unwrap & TF_PIN1) nf->unwrap= TF_PIN1; + else if(j==2 && f->unwrap & TF_PIN2) nf->unwrap= TF_PIN1; + else if(j==3 && f->unwrap & TF_PIN3) nf->unwrap= TF_PIN1; + else nf->unwrap= 0; } } } @@ -956,8 +973,8 @@ static DispListMesh *hypermesh_to_displistmesh(HyperMesh *hme, short flag) { med->v1= (int) e->v[0]->nmv; med->v2= (int) e->v[1]->nmv; - /* flag only for optimal */ - if(e->flag) med->flag = ME_EDGEDRAW; + if(e->flag & DR_OPTIM) med->flag |= ME_EDGEDRAW; + if(e->flag & HE_SEAM) med->flag |= ME_SEAM; } /* and we add the handles (med is re-used) */ @@ -1036,6 +1053,7 @@ static DispListMesh *hypermesh_to_displistmesh(HyperMesh *hme, short flag) { tf->transp= origtf->transp; tf->mode= origtf->mode; tf->tile= origtf->tile; + tf->unwrap= f->unwrap; } else if (hme->hasvcol) { MCol *mcolbase= &dlm->mcol[i*4]; diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h index 5941d421d16..4df5db5f39e 100644 --- a/source/blender/blenlib/BLI_arithb.h +++ b/source/blender/blenlib/BLI_arithb.h @@ -749,7 +749,22 @@ triatoquat( MinMaxRGB( short c[] ); - + float +Vec2Lenf( + float *v1, + float *v2 +); + void +Vec2Mulf( + float *v1, + float f +); + void +Vec2Addf( + float *v, + float *v1, + float *v2 +); #ifdef __cplusplus } diff --git a/source/blender/blenlib/BLI_editVert.h b/source/blender/blenlib/BLI_editVert.h index 568aa6b65ae..3f477036c0b 100644 --- a/source/blender/blenlib/BLI_editVert.h +++ b/source/blender/blenlib/BLI_editVert.h @@ -58,9 +58,9 @@ typedef struct EditEdge { struct EditEdge *next, *prev; struct EditVert *v1, *v2, *vn; - short f,h; - short f1, dir; - float crease; + short f, f1; + unsigned char h, dir, seam; + float crease; } EditEdge; typedef struct EditVlak diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c index ac025b34127..ff057a61e51 100644 --- a/source/blender/blenlib/intern/arithb.c +++ b/source/blender/blenlib/intern/arithb.c @@ -2181,6 +2181,27 @@ void MinMaxRGB(short c[]) else if(c[2]<0) c[2]=0; } +float Vec2Lenf(float *v1, float *v2) +{ + float x, y; + + x = v1[0]-v2[0]; + y = v1[1]-v2[1]; + return (float)sqrt(x*x+y*y); +} + +void Vec2Mulf(float *v1, float f) +{ + v1[0]*= f; + v1[1]*= f; +} + +void Vec2Addf(float *v, float *v1, float *v2) +{ + v[0]= v1[0]+ v2[0]; + v[1]= v1[1]+ v2[1]; +} + void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b) { int i; diff --git a/source/blender/include/BDR_unwrapper.h b/source/blender/include/BDR_unwrapper.h new file mode 100644 index 00000000000..72633bab9e4 --- /dev/null +++ b/source/blender/include/BDR_unwrapper.h @@ -0,0 +1,40 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BDR_UNWRAPPER_H +#define BDR_UNWRAPPER_H + +void set_seamtface(); /* set TF_SEAM flags in tfaces */ +void unwrap_lscm(); /* unwrap selected tfaces */ + +#endif /* BDR_UNWRAPPER_H */ + diff --git a/source/blender/include/BIF_editmesh.h b/source/blender/include/BIF_editmesh.h index 09dcd69dc9f..de289c88e20 100644 --- a/source/blender/include/BIF_editmesh.h +++ b/source/blender/include/BIF_editmesh.h @@ -165,8 +165,12 @@ void select_more(void); void select_less(void); void selectrandom_mesh(void); +void Edge_Menu(void); + void editmesh_select_by_material(int index); void editmesh_deselect_by_material(int index); +void editmesh_mark_seam(int clear); + #endif diff --git a/source/blender/include/BIF_editsima.h b/source/blender/include/BIF_editsima.h index e3e803ad5d2..c3750bfc018 100644 --- a/source/blender/include/BIF_editsima.h +++ b/source/blender/include/BIF_editsima.h @@ -45,4 +45,5 @@ void stitch_uv_tface(int mode); void unlink_selection(void); void select_linked_tface_uv(void); void toggle_uv_select(int mode); +void pin_tface_uv(int mode); diff --git a/source/blender/include/BIF_resources.h b/source/blender/include/BIF_resources.h index 6bce7e4e3f1..ededfab7489 100644 --- a/source/blender/include/BIF_resources.h +++ b/source/blender/include/BIF_resources.h @@ -376,6 +376,8 @@ enum { TH_VERTEX_SIZE, TH_EDGE, TH_EDGE_SELECT, + TH_EDGE_SEAM, + TH_EDGE_FACESEL, TH_FACE, TH_FACE_SELECT }; diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index 55fac76e7fb..eb9e7455baf 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -524,25 +524,26 @@ enum { #define B_UVAUTOCALCBUTS 3400 enum { B_UVAUTO_REDRAW = 3301, - B_UVAUTO_SPHERE, - B_UVAUTO_CYLINDER, - B_UVAUTO_CYLRADIUS, - B_UVAUTO_WINDOW, - B_UVAUTO_CUBE, - B_UVAUTO_CUBESIZE, - B_UVAUTO_STD1, - B_UVAUTO_STD2, - B_UVAUTO_STD4, - B_UVAUTO_STD8, - B_UVAUTO_BOUNDS1, - B_UVAUTO_BOUNDS2, - B_UVAUTO_BOUNDS4, - B_UVAUTO_BOUNDS8, - B_UVAUTO_TOP, - B_UVAUTO_FACE, - B_UVAUTO_OBJECT, - B_UVAUTO_ALIGNX, - B_UVAUTO_ALIGNY + B_UVAUTO_SPHERE, + B_UVAUTO_CYLINDER, + B_UVAUTO_CYLRADIUS, + B_UVAUTO_WINDOW, + B_UVAUTO_CUBE, + B_UVAUTO_CUBESIZE, + B_UVAUTO_STD1, + B_UVAUTO_STD2, + B_UVAUTO_STD4, + B_UVAUTO_STD8, + B_UVAUTO_BOUNDS1, + B_UVAUTO_BOUNDS2, + B_UVAUTO_BOUNDS4, + B_UVAUTO_BOUNDS8, + B_UVAUTO_TOP, + B_UVAUTO_FACE, + B_UVAUTO_OBJECT, + B_UVAUTO_ALIGNX, + B_UVAUTO_ALIGNY, + B_UVAUTO_LSCM }; #define B_EFFECTSBUTS 3500 diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 674c144923d..f9cb375572b 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -53,7 +53,7 @@ typedef struct TFace { float uv[4][2]; /* when you change this: also do function set_correct_uv in editmesh.c, and there are more locations that use the size of this part */ unsigned int col[4]; char flag, transp; - short mode, tile, pad; + short mode, tile, unwrap; } TFace; typedef struct Mesh { @@ -153,6 +153,16 @@ typedef struct Mesh { #define TF_ALPHA 2 #define TF_SUB 3 +/* tface->unwrap */ +#define TF_SEAM1 1 +#define TF_SEAM2 2 +#define TF_SEAM3 4 +#define TF_SEAM4 8 +#define TF_PIN1 16 +#define TF_PIN2 32 +#define TF_PIN3 64 +#define TF_PIN4 128 + #define MESH_MAX_VERTS 2000000000L #endif diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 04de27f58b0..f0ac467afb2 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -79,7 +79,7 @@ typedef struct MSticky { /* medge->flag (1=SELECT)*/ #define ME_EDGEDRAW 2 - +#define ME_SEAM 4 /* puno = vertexnormal (mface) */ #define ME_FLIPV1 1 diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 97a944db70d..7c2773f0b5b 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -82,6 +82,7 @@ typedef struct ThemeSpace { char active[4], transform[4]; char vertex[4], vertex_select[4]; char edge[4], edge_select[4]; + char edge_seam[4], edge_facesel[4]; char face[4], face_select[4]; char vertex_size, pad; diff --git a/source/blender/src/Makefile b/source/blender/src/Makefile index bdb5af6b801..210ed7d7320 100644 --- a/source/blender/src/Makefile +++ b/source/blender/src/Makefile @@ -85,6 +85,8 @@ CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I$(NAN_DECIMATION)/include CPPFLAGS += -I$(NAN_BSP)/include +CPPFLAGS += -I$(NAN_OPENNL)/include + CPPFLAGS += -I../readstreamglue CPPFLAGS += -I../include diff --git a/source/blender/src/SConscript b/source/blender/src/SConscript index 24471f09b47..2c371369679 100644 --- a/source/blender/src/SConscript +++ b/source/blender/src/SConscript @@ -101,6 +101,7 @@ source_files = ['B.blend.c', 'swapbuffers.c', 'toets.c', 'toolbox.c', + 'unwrapper.c', 'usiblender.c', 'view.c', 'vpaint.c', @@ -128,7 +129,8 @@ src_env.Append (CPPPATH = ['#/intern/guardedalloc', '../readstreamglue', '../img', '../quicktime', - '#/intern/ghost']) + '#/intern/ghost', + '#/intern/opennl/extern']) src_env.Append (CPPPATH = user_options_dict['PYTHON_INCLUDE']) src_env.Append (CPPPATH = user_options_dict['SDL_INCLUDE']) diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 33021c7d17f..9167e4ccd7f 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -137,6 +137,7 @@ #include "BDR_editface.h" #include "BDR_editobject.h" #include "BDR_vpaint.h" +#include "BDR_unwrapper.h" #include "BSE_drawview.h" #include "BSE_editipo.h" @@ -2037,26 +2038,25 @@ static void editing_panel_mesh_tools1(Object *ob, Mesh *me) block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_tools1", UI_EMBOSS, UI_HELV, curarea->win); if(uiNewPanel(curarea, block, "Mesh Tools 1", "Editing", 960, 0, 318, 204)==0) return; - uiDefBut(block, BUT,B_DOCENTRE, "Centre", 1091, 200, 166, 19, 0, 0, 0, 0, 0, "Shifts object data to be centered about object's origin"); uiBlockBeginAlign(block); - uiDefBut(block, BUT,B_HIDE, "Hide", 1091,155,77,24, 0, 0, 0, 0, 0, "Hides selected faces"); - uiDefBut(block, BUT,B_REVEAL, "Reveal", 1171,155,86,24, 0, 0, 0, 0, 0, "Reveals selected faces"); + uiDefBut(block, BUT,B_DOCENTRE, "Centre", 1091, 200, 166, 19, 0, 0, 0, 0, 0, "Shifts object data to be centered about object's origin"); + uiDefBut(block, BUT,B_HIDE, "Hide", 1091, 180, 77, 19, 0, 0, 0, 0, 0, "Hides selected faces"); + uiDefBut(block, BUT,B_REVEAL, "Reveal", 1171, 180, 86, 19, 0, 0, 0, 0, 0, "Reveals selected faces"); + uiDefBut(block, BUT,B_SELSWAP, "Select Swap", 1091, 160, 166, 19, 0, 0, 0, 0, 0, "Selects unselected faces, and deselects selected faces"); uiBlockEndAlign(block); - uiDefBut(block, BUT,B_SELSWAP, "Select Swap", 1091,130,166,24, 0, 0, 0, 0, 0, "Selects unselected faces, and deselects selected faces"); - uiBlockBeginAlign(block); - uiDefButF(block, NUM, REDRAWVIEW3D, "NSize:", 1090, 110, 164, 19, &editbutsize, 0.001, 2.0, 10, 0, "Sets the length to use when displaying face normals"); - uiDefButI(block, TOG|BIT|19, REDRAWVIEW3D, "Draw Creases", 1090,90,164,19, &G.f, 0, 0, 0, 0, "Displays face normals as lines"); - uiDefButI(block, TOG|BIT|6, REDRAWVIEW3D, "Draw Normals", 1090,70,164,19, &G.f, 0, 0, 0, 0, "Displays face normals as lines"); - uiDefButI(block, TOG|BIT|7, REDRAWVIEW3D, "Draw Faces", 1090,50,164,19, &G.f, 0, 0, 0, 0, "Displays all faces as shades"); - uiDefButI(block, TOG|BIT|18, REDRAWVIEW3D, "Draw Edges", 1090,30,164,19, &G.f, 0, 0, 0, 0, "Displays selected edges using hilights"); - uiDefButI(block, TOG|BIT|11, 0, "All edges", 1090,10,164,19, &G.f, 0, 0, 0, 0, "Displays all edges in object mode without optimization"); + uiDefButF(block, NUM, REDRAWVIEW3D, "NSize:", 1090, 131, 166, 19, &editbutsize, 0.001, 2.0, 10, 0, "Sets the length to use when displaying face normals"); + uiDefButI(block, TOG|BIT|6, REDRAWVIEW3D, "Draw Normals", 1090,110,166,19, &G.f, 0, 0, 0, 0, "Displays face normals as lines"); + uiDefButI(block, TOG|BIT|7, REDRAWVIEW3D, "Draw Faces", 1090,88,166,19, &G.f, 0, 0, 0, 0, "Displays all faces as shades"); + uiDefButI(block, TOG|BIT|18, REDRAWVIEW3D, "Draw Edges", 1090,66,166,19, &G.f, 0, 0, 0, 0, "Displays selected edges using hilights"); + uiDefButI(block, TOG|BIT|19, REDRAWVIEW3D, "Draw Creases", 1090,44,166,19, &G.f, 0, 0, 0, 0, "Displays creased edges using hilights"); + uiDefButI(block, TOG|BIT|20, REDRAWVIEW3D, "Draw Seams", 1090,22,166,19, &G.f, 0, 0, 0, 0, "Displays UV unwrapping seams"); + uiDefButI(block, TOG|BIT|11, 0, "All Edges", 1090, 0,166,19, &G.f, 0, 0, 0, 0, "Displays all edges in object mode without optimization"); uiBlockEndAlign(block); } - static void editing_panel_links(Object *ob) { uiBlock *block; @@ -2365,7 +2365,6 @@ static void editing_panel_mesh_paint(void) } - static void editing_panel_mesh_texface(void) { uiBlock *block; @@ -2403,9 +2402,9 @@ static void editing_panel_mesh_texface(void) uiBlockSetCol(block, TH_AUTO); uiBlockBeginAlign(block); - uiDefBut(block, BUT, B_COPY_TF_MODE, "Copy DrawMode", 600,7,117,28, 0, 0, 0, 0, 0, "Copy the drawmode"); - uiDefBut(block, BUT, B_COPY_TF_UV, "Copy UV+tex", 721,7,85,28, 0, 0, 0, 0, 0, "Copy UV information and textures"); - uiDefBut(block, BUT, B_COPY_TF_COL, "Copy VertCol", 809,7,103,28, 0, 0, 0, 0, 0, "Copy vertex colours"); + uiDefBut(block, BUT, B_COPY_TF_MODE, "Copy DrawMode", 600,7,117,28, 0, 0, 0, 0, 0, "Copy the drawmode from active face to selected faces"); + uiDefBut(block, BUT, B_COPY_TF_UV, "Copy UV+tex", 721,7,85,28, 0, 0, 0, 0, 0, "Copy UV information and textures from active face to selected faces"); + uiDefBut(block, BUT, B_COPY_TF_COL, "Copy VertCol", 809,7,103,28, 0, 0, 0, 0, 0, "Copy vertex colours from active face to selected faces"); } } @@ -2429,6 +2428,9 @@ void do_uvautocalculationbuts(unsigned short event) case B_UVAUTO_WINDOW: if(select_area(SPACE_VIEW3D)) calculate_uv_map(event); break; + case B_UVAUTO_LSCM: + unwrap_lscm(); + break; } } @@ -2444,28 +2446,34 @@ static void editing_panel_mesh_uvautocalculation(void) return; uiBlockBeginAlign(block); - uiDefBut(block, BUT, B_UVAUTO_STD1,"Standard 1/1",100,row,200,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping"); - uiDefBut(block, BUT, B_UVAUTO_STD2,"1/2",100,row-butHB,66,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/2"); - uiDefBut(block, BUT, B_UVAUTO_STD4,"1/4",166,row-butHB,67,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/4"); - uiDefBut(block, BUT, B_UVAUTO_STD8,"1/8",234,row-butHB,66,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/8"); + uiDefBut(block, BUT, B_UVAUTO_LSCM,"LSCM Unwrap",100,row,200,butH, 0, 0, 0, 0, 0, "Applies conformal UV mapping, preserving local angles"); uiBlockEndAlign(block); - row-= 2*butHB+butS; + row-= butHB+butS; uiBlockBeginAlign(block); - uiDefBut(block, BUT, B_UVAUTO_BOUNDS1,"Bounds 1/1",100,row,200,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/1"); - uiDefBut(block, BUT, B_UVAUTO_BOUNDS2,"1/2",100,row-butHB,66,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/2"); - uiDefBut(block, BUT, B_UVAUTO_BOUNDS4,"1/4",166,row-butHB,67,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/4"); - uiDefBut(block, BUT, B_UVAUTO_BOUNDS8,"1/8",234,row-butHB,66,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/8"); - uiDefBut(block, BUT, B_UVAUTO_WINDOW,"From Window",100,row-2*butH,200,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping from window"); + uiDefBut(block, BUT, B_UVAUTO_STD1,"Standard",100,row,100,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping"); + uiDefBut(block, BUT, B_UVAUTO_STD2,"/2",200,row,33,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/2"); + uiDefBut(block, BUT, B_UVAUTO_STD4,"/4",233,row,34,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/4"); + uiDefBut(block, BUT, B_UVAUTO_STD8,"/8",267,row,33,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/8"); uiBlockEndAlign(block); - row-= 3*butHB+butS; + row-= butHB+butS; + + uiBlockBeginAlign(block); + uiDefBut(block, BUT, B_UVAUTO_BOUNDS1,"Bounds",100,row,100,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/1"); + uiDefBut(block, BUT, B_UVAUTO_BOUNDS2,"/2",200,row,33,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/2"); + uiDefBut(block, BUT, B_UVAUTO_BOUNDS4,"/4",233,row,34,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/4"); + uiDefBut(block, BUT, B_UVAUTO_BOUNDS8,"/8",267,row,33,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/8"); + uiDefBut(block, BUT, B_UVAUTO_WINDOW,"From Window",100,row-butH,200,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping from window"); + uiBlockEndAlign(block); + row-= 2*butHB+butS; uiBlockBeginAlign(block); - uiDefButS(block,ROW,REDRAWVIEW3D,"No Edges",100,row,200,butH,&facesel_draw_edges, 2.0, 0, 0, 0, "Don't draw edges of deselected faces in 3D view"); - uiDefButS(block,ROW,REDRAWVIEW3D,"Draw Edges",100,row-butH,200,butH,&facesel_draw_edges, 2.0, 1.0, 0, 0, "Draw edges of deselected faces z-buffered in 3D view"); - uiDefButS(block,ROW,REDRAWVIEW3D,"All Edges",100,row-2*butH,200,butH,&facesel_draw_edges, 2.0, 2.0, 0, 0, "Draw all edges of deselected faces in 3D view"); + uiDefButI(block, TOG|BIT|7, REDRAWVIEW3D, "Draw Faces", 100,row,200,butH, &G.f, 0, 0, 0, 0, "Displays all faces as shades"); + uiDefButI(block,TOG|BIT|18,REDRAWVIEW3D,"Draw Edges",100,row-butHB,200,butH,&G.f, 2.0, 0, 0, 0, "Displays edges of visible faces"); + uiDefButI(block,TOG|BIT|21,REDRAWVIEW3D,"Draw Hidden Edges",100,row-2*butHB,200,butH,&G.f, 2.0, 1.0, 0, 0, "Displays edges of hidden faces"); + uiDefButI(block,TOG|BIT|20,REDRAWVIEW3D,"Draw Seams",100,row-3*butHB,200,butH,&G.f, 2.0, 2.0, 0, 0, "Displays UV unwrapping seams"); uiBlockEndAlign(block); - row-= 3*butHB+butS; + row-= 4*butHB+butS; row= 180; diff --git a/source/blender/src/drawimage.c b/source/blender/src/drawimage.c index 5155fb6e422..5f4042ee962 100644 --- a/source/blender/src/drawimage.c +++ b/source/blender/src/drawimage.c @@ -316,9 +316,8 @@ void draw_tfaces(void) Mesh *me; int a; char col1[4], col2[4]; + float pointsize= BIF_GetThemeValuef(TH_VERTEX_SIZE); - glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE)); - if(G.f & G_FACESELECT) { me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0); if(me && me->tface) { @@ -460,16 +459,16 @@ void draw_tfaces(void) setlinestyle(0); } - /* to make sure vertices markers are visible, draw them last */ - /* we draw selected over unselected, so two loops */ - BIF_GetThemeColor3ubv(TH_VERTEX, col1); - glColor4ubv(col1); + /* unselected uv's */ + BIF_ThemeColor(TH_VERTEX); + glPointSize(pointsize); + + bglBegin(GL_POINTS); tface= me->tface; mface= me->mface; a= me->totface; while(a--) { if(mface->v3 && (tface->flag & TF_SELECT) ) { - bglBegin(GL_POINTS); if(tface->flag & TF_SEL1); else bglVertex2fv(tface->uv[0]); if(tface->flag & TF_SEL2); else bglVertex2fv(tface->uv[1]); @@ -477,20 +476,46 @@ void draw_tfaces(void) if(mface->v4) { if(tface->flag & TF_SEL4); else bglVertex2fv(tface->uv[3]); } - bglEnd(); } tface++; mface++; } - /* selected */ - BIF_GetThemeColor3ubv(TH_VERTEX_SELECT, col2); - glColor4ubv(col2); + bglEnd(); + + /* pinned uv's */ + /* give odd pointsizes odd pin pointsizes */ + glPointSize(pointsize*2 + (((int)pointsize % 2)? (-1): 0)); + cpack(0xFF); + + bglBegin(GL_POINTS); + tface= me->tface; + mface= me->mface; + a= me->totface; + while(a--) { + if(mface->v3 && (tface->flag & TF_SELECT) ) { + + if(tface->unwrap & TF_PIN1) bglVertex2fv(tface->uv[0]); + if(tface->unwrap & TF_PIN2) bglVertex2fv(tface->uv[1]); + if(tface->unwrap & TF_PIN3) bglVertex2fv(tface->uv[2]); + if(mface->v4) { + if(tface->unwrap & TF_PIN4) bglVertex2fv(tface->uv[3]); + } + } + tface++; + mface++; + } + bglEnd(); + + /* selected uv's */ + BIF_ThemeColor(TH_VERTEX_SELECT); + glPointSize(pointsize); + + bglBegin(GL_POINTS); tface= me->tface; mface= me->mface; a= me->totface; while(a--) { if(mface->v3 && (tface->flag & TF_SELECT) ) { - bglBegin(GL_POINTS); if(tface->flag & TF_SEL1) bglVertex2fv(tface->uv[0]); if(tface->flag & TF_SEL2) bglVertex2fv(tface->uv[1]); @@ -498,11 +523,11 @@ void draw_tfaces(void) if(mface->v4) { if(tface->flag & TF_SEL4) bglVertex2fv(tface->uv[3]); } - bglEnd(); } tface++; mface++; } + bglEnd(); } } glPointSize(1.0); diff --git a/source/blender/src/drawmesh.c b/source/blender/src/drawmesh.c index 0f9f8c3cfaa..b06ff19170e 100644 --- a/source/blender/src/drawmesh.c +++ b/source/blender/src/drawmesh.c @@ -68,7 +68,9 @@ #include "BKE_object.h" #include "BKE_material.h" +#include "BIF_resources.h" #include "BIF_gl.h" +#include "BIF_glutil.h" #include "BIF_mywindow.h" #include "BIF_resources.h" @@ -83,8 +85,6 @@ //#include "glext.h" /* some local functions */ -static void draw_hide_tfaces(Object *ob, Mesh *me); - #if defined(GL_EXT_texture_object) && (!defined(__sun__) || (!defined(__sun))) && !defined(__APPLE__) /* exception for mesa... not according th opengl specs */ @@ -496,42 +496,6 @@ void spack(unsigned int ucol) glColor3ub(cp[3], cp[2], cp[1]); } -static void draw_hide_tfaces(Object *ob, Mesh *me) -{ - TFace *tface; - MFace *mface; - float *v1, *v2, *v3, *v4; - int a; - - if(me==0 || me->tface==0) return; - - mface= me->mface; - tface= me->tface; - - cpack(0x0); - setlinestyle(1); - for(a=me->totface; a>0; a--, mface++, tface++) { - if(mface->v3==0) continue; - - if( (tface->flag & TF_HIDE)) { - - v1= (me->mvert+mface->v1)->co; - v2= (me->mvert+mface->v2)->co; - v3= (me->mvert+mface->v3)->co; - if(mface->v4) v4= (me->mvert+mface->v4)->co; else v4= 0; - - glBegin(GL_LINE_LOOP); - glVertex3fv( v1 ); - glVertex3fv( v2 ); - glVertex3fv( v3 ); - if(mface->v4) glVertex3fv( v4 ); - glEnd(); - } - } - setlinestyle(0); -} - - void draw_tfaces3D(Object *ob, Mesh *me) { MFace *mface; @@ -540,26 +504,42 @@ void draw_tfaces3D(Object *ob, Mesh *me) float *v1, *v2, *v3, *v4; float *av1= NULL, *av2= NULL, *av3= NULL, *av4= NULL, *extverts= NULL; int a, activeFaceInSelection= 0; - extern short facesel_draw_edges; + extern void bPolygonOffset(short val); if(me==0 || me->tface==0) return; dl= find_displist(&ob->disp, DL_VERTS); if (dl) extverts= dl->verts; - /* shadow view */ - if(facesel_draw_edges>0){ - if(facesel_draw_edges==2) glDisable(GL_DEPTH_TEST); - else glEnable(GL_DEPTH_TEST); - cpack(0x00); + glEnable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + bPolygonOffset(1); + + /* Draw (Hidden) Edges */ + if(G.f & G_DRAWEDGES || G.f & G_HIDDENEDGES){ + BIF_ThemeColor(TH_EDGE_FACESEL); mface= me->mface; tface= me->tface; for(a=me->totface; a>0; a--, mface++, tface++) { - v1= (me->mvert+mface->v1)->co; - v2= (me->mvert+mface->v2)->co; - v3= (me->mvert+mface->v3)->co; - v4= mface->v4?(me->mvert+mface->v4)->co: NULL; + if(mface->v3==0) continue; + if(tface->flag & TF_HIDE) { + if(!(G.f & G_HIDDENEDGES)) continue; + } + else if(!(G.f & G_DRAWEDGES)) continue; + + if(extverts) { + v1= extverts+3*mface->v1; + v2= extverts+3*mface->v2; + v3= extverts+3*mface->v3; + v4= mface->v4?(extverts+3*mface->v4):NULL; + } else { + v1= (me->mvert+mface->v1)->co; + v2= (me->mvert+mface->v2)->co; + v3= (me->mvert+mface->v3)->co; + v4= mface->v4?(me->mvert+mface->v4)->co:NULL; + } + glBegin(GL_LINE_LOOP); glVertex3fv(v1); glVertex3fv(v2); @@ -569,17 +549,101 @@ void draw_tfaces3D(Object *ob, Mesh *me) } } - glDisable(GL_DEPTH_TEST); + if(G.f & G_DRAWSEAMS) { + BIF_ThemeColor(TH_EDGE_SEAM); + glLineWidth(2); + glBegin(GL_LINES); + mface= me->mface; + tface= me->tface; + for(a=me->totface; a>0; a--, mface++, tface++) { + if(mface->v3==0) continue; + if(tface->flag & TF_HIDE) continue; + + if(extverts) { + v1= extverts+3*mface->v1; + v2= extverts+3*mface->v2; + v3= extverts+3*mface->v3; + v4= mface->v4?(extverts+3*mface->v4):NULL; + } else { + v1= (me->mvert+mface->v1)->co; + v2= (me->mvert+mface->v2)->co; + v3= (me->mvert+mface->v3)->co; + v4= mface->v4?(me->mvert+mface->v4)->co:NULL; + } + + if(tface->unwrap & TF_SEAM1) { + glVertex3fv(v1); + glVertex3fv(v2); + } + + if(tface->unwrap & TF_SEAM2) { + glVertex3fv(v2); + glVertex3fv(v3); + } + + if(tface->unwrap & TF_SEAM3) { + glVertex3fv(v3); + if(v4) glVertex3fv(v4); + else glVertex3fv(v1); + } + + if(v4 && tface->unwrap & TF_SEAM4) { + glVertex3fv(v4); + glVertex3fv(v1); + } + } + glEnd(); + + glLineWidth(1); + } + + /* Draw Selected Faces in transparent purple */ + if(G.f & G_DRAWFACES) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + BIF_ThemeColor4(TH_FACE_SELECT); + + mface= me->mface; + tface= me->tface; + for(a=me->totface; a>0; a--, mface++, tface++) { + if(mface->v3==0) continue; + if(tface->flag & TF_HIDE) continue; + + if(tface->flag & TF_SELECT) { + if(extverts) { + v1= extverts+3*mface->v1; + v2= extverts+3*mface->v2; + v3= extverts+3*mface->v3; + v4= mface->v4?(extverts+3*mface->v4):NULL; + } else { + v1= (me->mvert+mface->v1)->co; + v2= (me->mvert+mface->v2)->co; + v3= (me->mvert+mface->v3)->co; + v4= mface->v4?(me->mvert+mface->v4)->co:NULL; + } + + glBegin(v4?GL_QUADS:GL_TRIANGLES); + glVertex3fv( v1 ); + glVertex3fv( v2 ); + glVertex3fv( v3 ); + if(v4) glVertex3fv( v4 ); + glEnd(); + } + } + glDisable(GL_BLEND); + } + + /* Draw Stippled Outline for selected faces */ mface= me->mface; tface= me->tface; - /* SELECT faces */ + bPolygonOffset(1); for(a=me->totface; a>0; a--, mface++, tface++) { if(mface->v3==0) continue; if(tface->flag & TF_HIDE) continue; - if( tface->flag & (TF_ACTIVE|TF_SELECT) ) { - if (extverts) { + if(tface->flag & (TF_ACTIVE|TF_SELECT) ) { + if(extverts) { v1= extverts+3*mface->v1; v2= extverts+3*mface->v2; v3= extverts+3*mface->v3; @@ -619,7 +683,7 @@ void draw_tfaces3D(Object *ob, Mesh *me) } } - /* draw active face on top */ + /* Draw Active Face on top */ /* colors: R=x G=y */ if(av1) { cpack(0xFF); @@ -646,7 +710,10 @@ void draw_tfaces3D(Object *ob, Mesh *me) setlinestyle(0); } - glEnable(GL_DEPTH_TEST); + /* We added 2 offsets, so go back 2, and disable */ + bPolygonOffset(-1); + bPolygonOffset(-1); + bPolygonOffset(0); } static int set_gl_light(Object *ob) @@ -998,16 +1065,13 @@ void draw_tface_mesh(Object *ob, Mesh *me, int dt) glEnd(); } } - + /* switch off textures */ set_tpage(0); } - glShadeModel(GL_FLAT); glDisable(GL_CULL_FACE); - draw_hide_tfaces(ob, me); - if(ob==OBACT && (G.f & G_FACESELECT)) { draw_tfaces3D(ob, me); } diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c index 87f2b1c0014..971e4222f8e 100644 --- a/source/blender/src/drawobject.c +++ b/source/blender/src/drawobject.c @@ -2490,6 +2490,26 @@ static void drawmeshwire(Object *ob) } glEnd(); } + + if(handles==0 && G.f & G_DRAWSEAMS) { + BIF_ThemeColor(TH_EDGE_SEAM); + glLineWidth(2); + + glBegin(GL_LINES); + eed= em->edges.first; + while(eed) { + if(eed->h==0 && eed->seam) { + glVertex3fv(eed->v1->co); + glVertex3fv(eed->v2->co); + } + eed= eed->next; + } + glEnd(); + + cpack(0x0); + glLineWidth(1); + } + if(ob!=G.obedit) return; calc_meshverts(); @@ -3405,7 +3425,7 @@ static int ob_from_decimator(Object *ob) } /* true or false */ -static void bPolygonOffset(short val) +void bPolygonOffset(short val) { static float winmat[16], ofs=0.0; diff --git a/source/blender/src/editface.c b/source/blender/src/editface.c index f2c6585d51e..5fe27735e12 100644 --- a/source/blender/src/editface.c +++ b/source/blender/src/editface.c @@ -96,7 +96,9 @@ #include "BSE_trans_types.h" #endif /* NAN_TPT */ -TFace *lasttface=0; +#include "BDR_unwrapper.h" + +TFace *lasttface=NULL; static void uv_calc_center_vector(float *result, Object *ob, Mesh *me) { @@ -651,7 +653,7 @@ void select_linked_tfaces() Mesh *me; TFace *tface; MFace *mface; - int a, doit=1; + int a, doit=1, mark=0; char *cpmain; me= get_mesh(OBACT); @@ -669,7 +671,7 @@ void select_linked_tfaces() while(a--) { if(tface->flag & TF_HIDE); else if(tface->flag & TF_SELECT) { - if( mface->v3) { + if(mface->v3) { cpmain[mface->v1]= 1; cpmain[mface->v2]= 1; cpmain[mface->v3]= 1; @@ -686,18 +688,30 @@ void select_linked_tfaces() a= me->totface; while(a--) { if(tface->flag & TF_HIDE); - else if((tface->flag & TF_SELECT)==0) { - if( mface->v3) { + else if(mface->v3 && ((tface->flag & TF_SELECT)==0)) { + mark= 0; + + if(!(tface->unwrap & TF_SEAM1)) + if(cpmain[mface->v1] && cpmain[mface->v2]) + mark= 1; + if(!(tface->unwrap & TF_SEAM2)) + if(cpmain[mface->v2] && cpmain[mface->v3]) + mark= 1; + if(!(tface->unwrap & TF_SEAM3)) { if(mface->v4) { - if(cpmain[mface->v4]) { - tface->flag |= TF_SELECT; - doit= 1; - } - } - if( cpmain[mface->v1] || cpmain[mface->v2] || cpmain[mface->v3] ) { - tface->flag |= TF_SELECT; - doit= 1; + if(cpmain[mface->v3] && cpmain[mface->v4]) + mark= 1; } + else if(cpmain[mface->v3] && cpmain[mface->v1]) + mark= 1; + } + if(mface->v4 && !(tface->unwrap & TF_SEAM4)) + if(cpmain[mface->v4] && cpmain[mface->v1]) + mark= 1; + + if(mark) { + tface->flag |= TF_SELECT; + doit= 1; } } tface++; mface++; @@ -708,7 +722,6 @@ void select_linked_tfaces() allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWIMAGE, 0); - } void deselectall_tface() @@ -1024,6 +1037,7 @@ float CalcNormUV(float *a, float *b, float *c) #define UV_STD2_MAPPING 129 #define UV_STD1_MAPPING 128 #define UV_WINDOW_MAPPING 5 +#define UV_LSCM_MAPPING 6 #define UV_CYL_EX 32 #define UV_SPHERE_EX 34 @@ -1043,6 +1057,7 @@ void uv_autocalc_tface() MENUSTRING("Cube", UV_CUBE_MAPPING) "|" MENUSTRING("Cylinder", UV_CYL_MAPPING) "|" MENUSTRING("Sphere", UV_SPHERE_MAPPING) "|" + MENUSTRING("LSCM", UV_LSCM_MAPPING) "|" MENUSTRING("Bounds to 1/8", UV_BOUNDS8_MAPPING) "|" MENUSTRING("Bounds to 1/4", UV_BOUNDS4_MAPPING) "|" MENUSTRING("Bounds to 1/2", UV_BOUNDS2_MAPPING) "|" @@ -1079,6 +1094,8 @@ void uv_autocalc_tface() calculate_uv_map(B_UVAUTO_STD1); break; case UV_WINDOW_MAPPING: calculate_uv_map(B_UVAUTO_WINDOW); break; + case UV_LSCM_MAPPING: + unwrap_lscm(); break; } } @@ -1104,7 +1121,10 @@ void set_faceselect() /* toggle */ if(G.f & G_FACESELECT) { setcursor_space(SPACE_VIEW3D, CURSOR_FACESEL); - if(me) set_lasttface(); + if(me) { + set_lasttface(); + set_seamtface(); /* set TF_SEAM flags in tface */ + } } else if((G.f & (G_WEIGHTPAINT|G_VERTEXPAINT|G_TEXTUREPAINT))==0) { if(me) reveal_tface(); diff --git a/source/blender/src/editmesh.c b/source/blender/src/editmesh.c index 20455fe0b6e..f745bb44740 100644 --- a/source/blender/src/editmesh.c +++ b/source/blender/src/editmesh.c @@ -363,7 +363,7 @@ EditEdge *addedgelist(EditVert *v1, EditVert *v2, EditEdge *example) /* find in hashlist */ eed= findedgelist(v1, v2); - + if(eed==NULL) { eed= (EditEdge *)calloc(sizeof(EditEdge), 1); @@ -372,11 +372,12 @@ EditEdge *addedgelist(EditVert *v1, EditVert *v2, EditEdge *example) BLI_addtail(&em->edges, eed); eed->dir= swap; insert_hashedge(eed); - } - - /* copy crease data, seam flag? */ - if(example) { - eed->crease = example->crease; + /* copy edge data: + rule is to do this with addedgelist call, before addvlaklist */ + if(example) { + eed->crease= example->crease; + eed->seam = example->seam; + } } return eed; @@ -452,15 +453,14 @@ EditVlak *addvlaklist(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, Ed EditMesh *em = G.editMesh; EditVlak *evl; EditEdge *e1, *e2=0, *e3=0, *e4=0; - /* add face to list and do the edges */ - e1= addedgelist(v1, v2, example?example->e1:NULL); - e2= addedgelist(v2, v3, example?example->e2:NULL); - if(v4) e3= addedgelist(v3, v4, example?example->e3:NULL); - else e3= addedgelist(v3, v1, example?example->e3:NULL); - if(v4) e4= addedgelist(v4, v1, example?example->e4:NULL); - + e1= addedgelist(v1, v2, NULL); + e2= addedgelist(v2, v3, NULL); + if(v4) e3= addedgelist(v3, v4, NULL); + else e3= addedgelist(v3, v1, NULL); + if(v4) e4= addedgelist(v4, v1, NULL); + if(v1==v2 || v2==v3 || v1==v3) return NULL; if(e2==0) return NULL; @@ -480,7 +480,7 @@ EditVlak *addvlaklist(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, Ed evl->tf= example->tf; evl->flag= example->flag; } - else { + else { if (G.obedit && G.obedit->actcol) evl->mat_nr= G.obedit->actcol-1; default_uv(evl->tf.uv, 1.0); @@ -488,7 +488,7 @@ EditVlak *addvlaklist(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, Ed /* Initialize colors */ evl->tf.col[0]= evl->tf.col[1]= evl->tf.col[2]= evl->tf.col[3]= vpaint_get_current_col(); } - + BLI_addtail(&em->faces, evl); if(evl->v4) CalcNormFloat4(v1->co, v2->co, v3->co, v4->co, evl->n); @@ -1023,6 +1023,7 @@ void make_editMesh_real(Mesh *me) for(a=0; a<me->totedge; a++, medge++) { eed= addedgelist(evlist[medge->v1], evlist[medge->v2], NULL); eed->crease= ((float)medge->crease)/255.0; + if(medge->flag & ME_SEAM) eed->seam= 1; } } @@ -1341,7 +1342,8 @@ void load_editMesh_real(Mesh *me, int undo) medge->v2= (unsigned int) eed->v2->vn; if(eed->f<2) medge->flag = ME_EDGEDRAW; medge->crease= (char)(255.0*eed->crease); - + if(eed->seam) medge->flag |= ME_SEAM; + medge++; eed= eed->next; } @@ -3686,8 +3688,11 @@ short extrudeflag(short flag,short type) if(eed->dir==1) evl2= addvlaklist(eed->v1, eed->v2, eed->v2->vn, eed->v1->vn, NULL); else evl2= addvlaklist(eed->v2, eed->v1, eed->v1->vn, eed->v2->vn, NULL); if (smooth) evl2->flag |= ME_SMOOTH; - - /* new edges, needs copied from old edge. actually we should find face that has this edge */ + + /* Needs smarter adaption of existing creases. + * If addedgelist is used, make sure seams are set to 0 on these + * new edges, since we do not want to add any seams on extrusion. + */ evl2->e1->crease= eed->crease; evl2->e2->crease= eed->crease; evl2->e3->crease= eed->crease; @@ -3876,7 +3881,6 @@ short removedoublesflag(short flag, float limit) /* return amount */ if(eed->v1->f & 128) eed->v1= eed->v1->vn; if(eed->v2->f & 128) eed->v2= eed->v2->vn; - e1= addedgelist(eed->v1, eed->v2, eed); if(e1) e1->f= 1; @@ -4187,12 +4191,30 @@ static void uv_quart(float *uv, float *uv1) uv[1]= (uv1[1]+uv1[3]+uv1[5]+uv1[7])/4.0; } -static void set_wuv(int tot, EditVlak *evl, int v1, int v2, int v3, int v4) +static void vlak_pin_vertex(EditVlak *evl, EditVert *vertex) +{ + if(evl->v1 == vertex) evl->tf.unwrap |= TF_PIN1; + else if(evl->v2 == vertex) evl->tf.unwrap |= TF_PIN2; + else if(evl->v3 == vertex) evl->tf.unwrap |= TF_PIN3; + else if(evl->v4 && vertex && evl->v4 == vertex) evl->tf.unwrap |= TF_PIN4; +} + +static void set_wuv(int tot, EditVlak *evl, int v1, int v2, int v3, int v4, EditVlak *evlpin) { /* this weird function only to be used for subdivide, the 'w' in the name has no meaning! */ float *uv, uvo[4][2]; unsigned int *col, colo[4], col1, col2; int a, v; + + /* recover pinning */ + if(evlpin){ + evl->tf.unwrap= 0; + if(evlpin->tf.unwrap & TF_PIN1) vlak_pin_vertex(evl, evlpin->v1); + if(evlpin->tf.unwrap & TF_PIN2) vlak_pin_vertex(evl, evlpin->v2); + if(evlpin->tf.unwrap & TF_PIN3) vlak_pin_vertex(evl, evlpin->v3); + if(evlpin->tf.unwrap & TF_PIN4) vlak_pin_vertex(evl, evlpin->v4); + } + /* Numbers corespond to verts (corner points), */ /* edge->vn's (center edges), the Center */ memcpy(uvo, evl->tf.uv, sizeof(uvo)); /* And the quincunx points of a face */ @@ -4311,7 +4333,7 @@ static EditVert *vert_from_number(EditVlak *evl, int nr) return NULL; } -static void addvlak_subdiv(EditVlak *evl, int val1, int val2, int val3, int val4, EditVert *eve) +static void addvlak_subdiv(EditVlak *evl, int val1, int val2, int val3, int val4, EditVert *eve, EditVlak *evlpin) { EditVlak *w; EditVert *v1, *v2, *v3, *v4; @@ -4330,8 +4352,8 @@ static void addvlak_subdiv(EditVlak *evl, int val1, int val2, int val3, int val4 w= addvlaklist(v1, v2, v3, v4, evl); if(w) { - if(evl->v4) set_wuv(4, w, val1, val2, val3, val4); - else set_wuv(3, w, val1, val2, val3, val4); + if(evl->v4) set_wuv(4, w, val1, val2, val3, val4, evlpin); + else set_wuv(3, w, val1, val2, val3, val4, evlpin); } } @@ -4404,7 +4426,7 @@ void subdivideflag(int flag, float rad, int beauty) extern float doublimit; EditVert *eve; EditEdge *eed, *e1, *e2, *e3, *e4, *nexted; - EditVlak *evl; + EditVlak *evl, evlpin; float fac, vec[3], vec1[3], len1, len2, len3, percent; short test; @@ -4534,6 +4556,9 @@ void subdivideflag(int flag, float rad, int beauty) evl= em->faces.last; while(evl) { + + evlpin= *evl; /* make a copy of evl to recover uv pinning later */ + if( vlakselectedOR(evl, flag) ) { e1= evl->e1; e2= evl->e2; @@ -4542,67 +4567,79 @@ void subdivideflag(int flag, float rad, int beauty) test= 0; if(e1 && e1->vn) { - test+= 1; + test+= 1; e1->f= 1; + /* add edges here, to copy correct edge data */ + eed= addedgelist(e1->v1, e1->vn, e1); + eed= addedgelist(e1->vn, e1->v2, e1); } - if(e2 && e2->vn) { - test+= 2; + if(e2 && e2->vn) { + test+= 2; e2->f= 1; + /* add edges here, to copy correct edge data */ + eed= addedgelist(e2->v1, e2->vn, e2); + eed= addedgelist(e2->vn, e2->v2, e2); } - if(e3 && e3->vn) { - test+= 4; + if(e3 && e3->vn) { + test+= 4; e3->f= 1; + /* add edges here, to copy correct edge data */ + eed= addedgelist(e3->v1, e3->vn, e3); + eed= addedgelist(e3->vn, e3->v2, e3); } - if(e4 && e4->vn) { - test+= 8; + if(e4 && e4->vn) { + test+= 8; e4->f= 1; + /* add edges here, to copy correct edge data */ + eed= addedgelist(e4->v1, e4->vn, e4); + eed= addedgelist(e4->vn, e4->v2, e4); } if(test) { if(evl->v4==0) { /* All the permutations of 3 edges*/ - if((test & 3)==3) addvlak_subdiv(evl, 2, 2+4, 1+4, 0, 0); - if((test & 6)==6) addvlak_subdiv(evl, 3, 3+4, 2+4, 0, 0); - if((test & 5)==5) addvlak_subdiv(evl, 1, 1+4, 3+4, 0, 0); + if((test & 3)==3) addvlak_subdiv(evl, 2, 2+4, 1+4, 0, 0, &evlpin); + if((test & 6)==6) addvlak_subdiv(evl, 3, 3+4, 2+4, 0, 0, &evlpin); + if((test & 5)==5) addvlak_subdiv(evl, 1, 1+4, 3+4, 0, 0, &evlpin); if(test==7) { /* four new faces, old face renews */ evl->v1= e1->vn; evl->v2= e2->vn; evl->v3= e3->vn; - set_wuv(3, evl, 1+4, 2+4, 3+4, 0); + set_wuv(3, evl, 1+4, 2+4, 3+4, 0, &evlpin); } else if(test==3) { - addvlak_subdiv(evl, 1+4, 2+4, 3, 0, 0); + addvlak_subdiv(evl, 1+4, 2+4, 3, 0, 0, &evlpin); evl->v2= e1->vn; - set_wuv(3, evl, 1, 1+4, 3, 0); + set_wuv(3, evl, 1, 1+4, 3, 0, &evlpin); } else if(test==6) { - addvlak_subdiv(evl, 2+4, 3+4, 1, 0, 0); + addvlak_subdiv(evl, 2+4, 3+4, 1, 0, 0, &evlpin); evl->v3= e2->vn; - set_wuv(3, evl, 1, 2, 2+4, 0); + set_wuv(3, evl, 1, 2, 2+4, 0, &evlpin); } else if(test==5) { - addvlak_subdiv(evl, 3+4, 1+4, 2, 0, 0); + addvlak_subdiv(evl, 3+4, 1+4, 2, 0, 0, &evlpin); evl->v1= e3->vn; - set_wuv(3, evl, 3+4, 2, 3, 0); + set_wuv(3, evl, 3+4, 2, 3, 0, &evlpin); } else if(test==1) { - addvlak_subdiv(evl, 1+4, 2, 3, 0, 0); + addvlak_subdiv(evl, 1+4, 2, 3, 0, 0, &evlpin); evl->v2= e1->vn; - set_wuv(3, evl, 1, 1+4, 3, 0); + set_wuv(3, evl, 1, 1+4, 3, 0, &evlpin); } else if(test==2) { - addvlak_subdiv(evl, 2+4, 3, 1, 0, 0); + addvlak_subdiv(evl, 2+4, 3, 1, 0, 0, &evlpin); evl->v3= e2->vn; - set_wuv(3, evl, 1, 2, 2+4, 0); + set_wuv(3, evl, 1, 2, 2+4, 0, &evlpin); } else if(test==4) { - addvlak_subdiv(evl, 3+4, 1, 2, 0, 0); + addvlak_subdiv(evl, 3+4, 1, 2, 0, 0, &evlpin); evl->v1= e3->vn; - set_wuv(3, evl, 3+4, 2, 3, 0); + set_wuv(3, evl, 3+4, 2, 3, 0, &evlpin); } - evl->e1= addedgelist(evl->v1, evl->v2, evl->e1); - evl->e2= addedgelist(evl->v2, evl->v3, evl->e2); - evl->e3= addedgelist(evl->v3, evl->v1, evl->e3); - + evl->e1= addedgelist(evl->v1, evl->v2, NULL); + evl->e2= addedgelist(evl->v2, evl->v3, NULL); + evl->e3= addedgelist(evl->v3, evl->v1, NULL); + } else { /* All the permutations of 4 faces */ if(test==15) { @@ -4615,170 +4652,170 @@ void subdivideflag(int flag, float rad, int beauty) eve= addvertlist(vec); eve->f |= flag; - - addvlak_subdiv(evl, 2, 2+4, 9, 1+4, eve); - addvlak_subdiv(evl, 3, 3+4, 9, 2+4, eve); - addvlak_subdiv(evl, 4, 4+4, 9, 3+4, eve); + + addvlak_subdiv(evl, 2, 2+4, 9, 1+4, eve, &evlpin); + addvlak_subdiv(evl, 3, 3+4, 9, 2+4, eve, &evlpin); + addvlak_subdiv(evl, 4, 4+4, 9, 3+4, eve, &evlpin); evl->v2= e1->vn; evl->v3= eve; evl->v4= e4->vn; - set_wuv(4, evl, 1, 1+4, 9, 4+4); + set_wuv(4, evl, 1, 1+4, 9, 4+4, &evlpin); } - else { - if(((test & 3)==3)&&(test!=3)) addvlak_subdiv(evl, 1+4, 2, 2+4, 0, 0); - if(((test & 6)==6)&&(test!=6)) addvlak_subdiv(evl, 2+4, 3, 3+4, 0, 0); - if(((test & 12)==12)&&(test!=12)) addvlak_subdiv(evl, 3+4, 4, 4+4, 0, 0); - if(((test & 9)==9)&&(test!=9)) addvlak_subdiv(evl, 4+4, 1, 1+4, 0, 0); - + else { + if(((test & 3)==3)&&(test!=3)) addvlak_subdiv(evl, 1+4, 2, 2+4, 0, 0, &evlpin); + if(((test & 6)==6)&&(test!=6)) addvlak_subdiv(evl, 2+4, 3, 3+4, 0, 0, &evlpin); + if(((test & 12)==12)&&(test!=12)) addvlak_subdiv(evl, 3+4, 4, 4+4, 0, 0, &evlpin); + if(((test & 9)==9)&&(test!=9)) addvlak_subdiv(evl, 4+4, 1, 1+4, 0, 0, &evlpin); + if(test==1) { /* Edge 1 has new vert */ - addvlak_subdiv(evl, 1+4, 2, 3, 0, 0); - addvlak_subdiv(evl, 1+4, 3, 4, 0, 0); + addvlak_subdiv(evl, 1+4, 2, 3, 0, 0, &evlpin); + addvlak_subdiv(evl, 1+4, 3, 4, 0, 0, &evlpin); evl->v2= e1->vn; evl->v3= evl->v4; evl->v4= 0; - set_wuv(4, evl, 1, 1+4, 4, 0); + set_wuv(4, evl, 1, 1+4, 4, 0, &evlpin); } else if(test==2) { /* Edge 2 has new vert */ - addvlak_subdiv(evl, 2+4, 3, 4, 0, 0); - addvlak_subdiv(evl, 2+4, 4, 1, 0, 0); + addvlak_subdiv(evl, 2+4, 3, 4, 0, 0, &evlpin); + addvlak_subdiv(evl, 2+4, 4, 1, 0, 0, &evlpin); evl->v3= e2->vn; evl->v4= 0; - set_wuv(4, evl, 1, 2, 2+4, 0); + set_wuv(4, evl, 1, 2, 2+4, 0, &evlpin); } else if(test==4) { /* Edge 3 has new vert */ - addvlak_subdiv(evl, 3+4, 4, 1, 0, 0); - addvlak_subdiv(evl, 3+4, 1, 2, 0, 0); + addvlak_subdiv(evl, 3+4, 4, 1, 0, 0, &evlpin); + addvlak_subdiv(evl, 3+4, 1, 2, 0, 0, &evlpin); evl->v1= evl->v2; evl->v2= evl->v3; evl->v3= e3->vn; evl->v4= 0; - set_wuv(4, evl, 2, 3, 3+4, 0); + set_wuv(4, evl, 2, 3, 3+4, 0, &evlpin); } else if(test==8) { /* Edge 4 has new vert */ - addvlak_subdiv(evl, 4+4, 1, 2, 0, 0); - addvlak_subdiv(evl, 4+4, 2, 3, 0, 0); + addvlak_subdiv(evl, 4+4, 1, 2, 0, 0, &evlpin); + addvlak_subdiv(evl, 4+4, 2, 3, 0, 0, &evlpin); evl->v1= evl->v3; evl->v2= evl->v4; evl->v3= e4->vn; evl->v4= 0; - set_wuv(4, evl, 3, 4, 4+4, 0); + set_wuv(4, evl, 3, 4, 4+4, 0, &evlpin); } else if(test==3) { /*edge 1&2 */ - /* make new vert in center of new edge */ + /* make new vert in center of new edge */ vec[0]=(e1->vn->co[0]+e2->vn->co[0])/2; vec[1]=(e1->vn->co[1]+e2->vn->co[1])/2; vec[2]=(e1->vn->co[2]+e2->vn->co[2])/2; eve= addvertlist(vec); eve->f |= flag; /* Add new faces */ - addvlak_subdiv(evl, 4, 10, 2+4, 3, eve); - addvlak_subdiv(evl, 4, 1, 1+4, 10, eve); + addvlak_subdiv(evl, 4, 10, 2+4, 3, eve, &evlpin); + addvlak_subdiv(evl, 4, 1, 1+4, 10, eve, &evlpin); /* orig face becomes small corner */ evl->v1=e1->vn; //evl->v2=evl->v2; evl->v3=e2->vn; evl->v4=eve; - - set_wuv(4, evl, 1+4, 2, 2+4, 10); + + set_wuv(4, evl, 1+4, 2, 2+4, 10, &evlpin); } else if(test==6) { /* 2&3 */ - /* make new vert in center of new edge */ + /* make new vert in center of new edge */ vec[0]=(e2->vn->co[0]+e3->vn->co[0])/2; vec[1]=(e2->vn->co[1]+e3->vn->co[1])/2; vec[2]=(e2->vn->co[2]+e3->vn->co[2])/2; eve= addvertlist(vec); eve->f |= flag; /*New faces*/ - addvlak_subdiv(evl, 1, 11, 3+4, 4, eve); - addvlak_subdiv(evl, 1, 2, 2+4, 11, eve); + addvlak_subdiv(evl, 1, 11, 3+4, 4, eve, &evlpin); + addvlak_subdiv(evl, 1, 2, 2+4, 11, eve, &evlpin); /* orig face becomes small corner */ evl->v1=e2->vn; evl->v2=evl->v3; evl->v3=e3->vn; evl->v4=eve; - - set_wuv(4, evl, 2+4, 3, 3+4, 11); + + set_wuv(4, evl, 2+4, 3, 3+4, 11, &evlpin); } else if(test==12) { /* 3&4 */ - /* make new vert in center of new edge */ + /* make new vert in center of new edge */ vec[0]=(e3->vn->co[0]+e4->vn->co[0])/2; vec[1]=(e3->vn->co[1]+e4->vn->co[1])/2; vec[2]=(e3->vn->co[2]+e4->vn->co[2])/2; eve= addvertlist(vec); eve->f |= flag; /*New Faces*/ - addvlak_subdiv(evl, 2, 12, 4+4, 1, eve); - addvlak_subdiv(evl, 2, 3, 3+4, 12, eve); + addvlak_subdiv(evl, 2, 12, 4+4, 1, eve, &evlpin); + addvlak_subdiv(evl, 2, 3, 3+4, 12, eve, &evlpin); /* orig face becomes small corner */ evl->v1=e3->vn; evl->v2=evl->v4; evl->v3=e4->vn; evl->v4=eve; - - set_wuv(4, evl, 3+4, 4, 4+4, 12); + + set_wuv(4, evl, 3+4, 4, 4+4, 12, &evlpin); } else if(test==9) { /* 4&1 */ - /* make new vert in center of new edge */ + /* make new vert in center of new edge */ vec[0]=(e1->vn->co[0]+e4->vn->co[0])/2; vec[1]=(e1->vn->co[1]+e4->vn->co[1])/2; vec[2]=(e1->vn->co[2]+e4->vn->co[2])/2; eve= addvertlist(vec); eve->f |= flag; /*New Faces*/ - addvlak_subdiv(evl, 3, 13, 1+4, 2, eve); - addvlak_subdiv(evl, 3, 4, 4+4, 13, eve); + addvlak_subdiv(evl, 3, 13, 1+4, 2, eve, &evlpin); + addvlak_subdiv(evl, 3, 4, 4+4,13, eve, &evlpin); /* orig face becomes small corner */ evl->v2=evl->v1; evl->v1=e4->vn; evl->v3=e1->vn; evl->v4=eve; - - set_wuv(4, evl, 4+4, 1, 1+4, 13); + + set_wuv(4, evl, 4+4, 1, 1+4, 13, &evlpin); } else if(test==5) { /* 1&3 */ - addvlak_subdiv(evl, 1+4, 2, 3, 3+4, 0); + addvlak_subdiv(evl, 1+4, 2, 3, 3+4, 0, &evlpin); evl->v2= e1->vn; evl->v3= e3->vn; - set_wuv(4, evl, 1, 1+4, 3+4, 4); + set_wuv(4, evl, 1, 1+4, 3+4, 4, &evlpin); } else if(test==10) { /* 2&4 */ - addvlak_subdiv(evl, 2+4, 3, 4, 4+4, 0); + addvlak_subdiv(evl, 2+4, 3, 4, 4+4, 0, &evlpin); evl->v3= e2->vn; evl->v4= e4->vn; - set_wuv(4, evl, 1, 2, 2+4, 4+4); + set_wuv(4, evl, 1, 2, 2+4, 4+4, &evlpin); }/* Unfortunately, there is no way to avoid tris on 1 or 3 edges*/ else if(test==7) { /*1,2&3 */ - addvlak_subdiv(evl, 1+4, 2+4, 3+4, 0, 0); + addvlak_subdiv(evl, 1+4, 2+4, 3+4, 0, 0, &evlpin); evl->v2= e1->vn; evl->v3= e3->vn; - set_wuv(4, evl, 1, 1+4, 3+4, 4); + set_wuv(4, evl, 1, 1+4, 3+4, 4, &evlpin); } else if(test==14) { /* 2,3&4 */ - addvlak_subdiv(evl, 2+4, 3+4, 4+4, 0, 0); + addvlak_subdiv(evl, 2+4, 3+4, 4+4, 0, 0, &evlpin); evl->v3= e2->vn; evl->v4= e4->vn; - set_wuv(4, evl, 1, 2, 2+4, 4+4); + set_wuv(4, evl, 1, 2, 2+4, 4+4, &evlpin); } else if(test==13) {/* 1,3&4 */ - addvlak_subdiv(evl, 3+4, 4+4, 1+4, 0, 0); + addvlak_subdiv(evl, 3+4, 4+4, 1+4, 0, 0, &evlpin); evl->v4= e3->vn; evl->v1= e1->vn; - set_wuv(4, evl, 1+4, 3, 3, 3+4); + set_wuv(4, evl, 1+4, 3, 3, 3+4, &evlpin); } else if(test==11) { /* 1,2,&4 */ - addvlak_subdiv(evl, 4+4, 1+4, 2+4, 0, 0); + addvlak_subdiv(evl, 4+4, 1+4, 2+4, 0, 0, &evlpin); evl->v1= e4->vn; evl->v2= e2->vn; - set_wuv(4, evl, 4+4, 2+4, 3, 4); + set_wuv(4, evl, 4+4, 2+4, 3, 4, &evlpin); } } - evl->e1= addedgelist(evl->v1, evl->v2, evl->e1); - evl->e2= addedgelist(evl->v2, evl->v3, evl->e2); - if(evl->v4) evl->e3= addedgelist(evl->v3, evl->v4, evl->e3); - else evl->e3= addedgelist(evl->v3, evl->v1, evl->e3); - if(evl->v4) evl->e4= addedgelist(evl->v4, evl->v1, evl->e4); + evl->e1= addedgelist(evl->v1, evl->v2, NULL); + evl->e2= addedgelist(evl->v2, evl->v3, NULL); + if(evl->v4) evl->e3= addedgelist(evl->v3, evl->v4, NULL); + else evl->e3= addedgelist(evl->v3, evl->v1, NULL); + if(evl->v4) evl->e4= addedgelist(evl->v4, evl->v1, NULL); else evl->e4= NULL; } } @@ -8900,6 +8937,7 @@ void bevel_mesh(float bsize, int allfaces) #endif } + /* Needs better adaption of creases? */ addedgelist(evl->e1->v1->vn, evl->e1->v2->vn, evl->e1); addedgelist(evl->e2->v1->vn,evl->e2->v2->vn, evl->e2); addedgelist(evl->e3->v1->vn,evl->e3->v2->vn, evl->e3); @@ -9832,3 +9870,58 @@ void editmesh_deselect_by_material(int index) { } } } + +void editmesh_mark_seam(int clear) +{ + EditMesh *em= G.editMesh; + EditEdge *eed; + Mesh *me= G.obedit->data; + + /* auto-enable seams drawing */ + if(clear==0) { + if(!(G.f & G_DRAWSEAMS)) { + G.f |= G_DRAWSEAMS; + allqueue(REDRAWBUTSEDIT, 0); + } + if(!me->medge) + me->medge= MEM_callocN(sizeof(MEdge), "fake mesh edge"); + } + + if(clear) { + eed= em->edges.first; + while(eed) { + if((eed->h==0) && (eed->v1->f & 1) && (eed->v2->f & 1)) { + eed->seam = 0; + } + eed= eed->next; + } + } + else { + eed= em->edges.first; + while(eed) { + if((eed->h==0) && (eed->v1->f & 1) && (eed->v2->f & 1)) { + eed->seam = 1; + } + eed= eed->next; + } + } + + allqueue(REDRAWVIEW3D, 0); +} + +void Edge_Menu() { + short ret; + + ret= pupmenu("Edge Specials%t|Mark Seam %x1|Clear Seam %x2"); + + switch(ret) + { + case 1: + editmesh_mark_seam(0); + break; + case 2: + editmesh_mark_seam(1); + break; + } +} + diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index 0a995064bda..39cd046b5bd 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -143,6 +143,7 @@ #include "BDR_editobject.h" #include "BDR_drawobject.h" #include "BDR_editcurve.h" +#include "BDR_unwrapper.h" #include "render.h" #include <time.h> @@ -1097,8 +1098,11 @@ void exit_editmode(int freedata) /* freedata==0 at render */ load_editMesh(); /* makes new displist */ if(freedata) free_editMesh(); - - if(G.f & G_FACESELECT) allqueue(REDRAWIMAGE, 0); + + if(G.f & G_FACESELECT) { + set_seamtface(); + allqueue(REDRAWIMAGE, 0); + } build_particle_system(G.obedit); } diff --git a/source/blender/src/editsima.c b/source/blender/src/editsima.c index 9e3558be259..a55de075504 100644 --- a/source/blender/src/editsima.c +++ b/source/blender/src/editsima.c @@ -79,6 +79,7 @@ #include "BSE_trans_types.h" #include "BDR_editobject.h" +#include "BDR_unwrapper.h" #include "blendef.h" #include "mydevice.h" @@ -1682,3 +1683,34 @@ void toggle_uv_select(int mode) allqueue(REDRAWIMAGE, 0); } +void pin_tface_uv(int mode) +{ + Mesh *me; + TFace *tface; + MFace *mface; + int a; + + if( is_uv_tface_editing_allowed()==0 ) return; + me= get_mesh(OBACT); + + mface= me->mface; + tface= me->tface; + for(a=me->totface; a>0; a--, tface++, mface++) { + if(mode ==1){ + if(tface->flag & TF_SEL1) tface->unwrap |= TF_PIN1; + if(tface->flag & TF_SEL2) tface->unwrap |= TF_PIN2; + if(tface->flag & TF_SEL3) tface->unwrap |= TF_PIN3; + if(mface->v4) + if(tface->flag & TF_SEL4) tface->unwrap |= TF_PIN4; + } + else if (mode ==0){ + if(tface->flag & TF_SEL1) tface->unwrap &= ~TF_PIN1; + if(tface->flag & TF_SEL2) tface->unwrap &= ~TF_PIN2; + if(tface->flag & TF_SEL3) tface->unwrap &= ~TF_PIN3; + if(mface->v4) + if(tface->flag & TF_SEL4) tface->unwrap &= ~TF_PIN4; + } + } + scrarea_queue_winredraw(curarea); +} + diff --git a/source/blender/src/header_image.c b/source/blender/src/header_image.c index b110a3d9a2c..bcf4fcaa334 100644 --- a/source/blender/src/header_image.c +++ b/source/blender/src/header_image.c @@ -62,6 +62,7 @@ #include "DNA_userdef_types.h" #include "BDR_drawmesh.h" +#include "BDR_unwrapper.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_main.h" @@ -816,8 +817,6 @@ static uiBlock *image_uvs_transformmenu(void *arg_unused) static void do_image_uvsmenu(void *arg, int event) { - ScrArea *sa; - /* events >=20 are registered bpython scripts */ if (event >= 20) BPY_menu_do_python(PYMENU_UV, event - 20); @@ -847,6 +846,16 @@ static void do_image_uvsmenu(void *arg, int event) if(G.sima->flag & SI_NOPIXELSNAP) G.sima->flag &= ~SI_NOPIXELSNAP; else G.sima->flag |= SI_NOPIXELSNAP; break; + case 8: + pin_tface_uv(1); + break; + case 9: + pin_tface_uv(0); + break; + case 10: + if (okee("LSCM unwrap")) + unwrap_lscm(); + break; } } @@ -873,6 +882,12 @@ static uiBlock *image_uvsmenu(void *arg_unused) uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Unpin|Alt P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pin|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "LSCM Unwrap|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, ""); + + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Limit Stitch...|Shift V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Stitch|V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, ""); uiDefIconTextBlockBut(block, image_uvs_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, ""); diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c index aaf063d28d1..badbef1b450 100644 --- a/source/blender/src/header_view3d.c +++ b/source/blender/src/header_view3d.c @@ -1938,6 +1938,12 @@ void do_view3d_edit_mesh_edgesmenu(void *arg, int event) case 6: bevel_menu(); break; + case 7: /* Mark Seam */ + editmesh_mark_seam(0); + break; + case 8: /* Clear Seam */ + editmesh_mark_seam(1); + break; } allqueue(REDRAWVIEW3D, 0); } @@ -1964,6 +1970,11 @@ static uiBlock *view3d_edit_mesh_edgesmenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Subdivide Fractal|W, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Subdivide Smooth|W, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, ""); + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Mark Seam|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Seam|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, ""); + uiBlockSetDirection(block, UI_RIGHT); uiTextBoundsBlock(block, 60); return block; diff --git a/source/blender/src/resources.c b/source/blender/src/resources.c index 78d01e6b9ea..028cec1a5d2 100644 --- a/source/blender/src/resources.c +++ b/source/blender/src/resources.c @@ -428,6 +428,10 @@ char *BIF_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) cp= ts->edge; break; case TH_EDGE_SELECT: cp= ts->edge_select; break; + case TH_EDGE_SEAM: + cp= ts->edge_seam; break; + case TH_EDGE_FACESEL: + cp= ts->edge_facesel; break; case TH_FACE: cp= ts->face; break; case TH_FACE_SELECT: @@ -502,6 +506,8 @@ void BIF_InitTheme(void) btheme->tv3d.vertex_size= 2; SETCOL(btheme->tv3d.edge, 0x0, 0x0, 0x0, 255); SETCOL(btheme->tv3d.edge_select, 0x90, 0x90, 0x30, 255); + SETCOL(btheme->tv3d.edge_seam, 230, 150, 50, 255); + SETCOL(btheme->tv3d.edge_facesel, 75, 75, 75, 255); SETCOL(btheme->tv3d.face, 0, 50, 150, 30); SETCOL(btheme->tv3d.face_select, 200, 100, 200, 60); @@ -648,6 +654,8 @@ char *BIF_ThemeColorsPup(int spacetype) sprintf(str, "Vertex Selected %%x%d|", TH_VERTEX_SELECT); strcat(cp, str); sprintf(str, "Vertex Size %%x%d|", TH_VERTEX_SIZE); strcat(cp, str); sprintf(str, "Edge Selected %%x%d|", TH_EDGE_SELECT); strcat(cp, str); + sprintf(str, "Edge Seam %%x%d|", TH_EDGE_SEAM); strcat(cp, str); + sprintf(str, "Edge UV Face Select %%x%d|", TH_EDGE_FACESEL); strcat(cp, str); sprintf(str, "Face %%x%d|", TH_FACE); strcat(cp, str); sprintf(str, "Face Selected %%x%d", TH_FACE_SELECT); strcat(cp, str); } diff --git a/source/blender/src/space.c b/source/blender/src/space.c index a35de2087f5..8683d66e232 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -128,6 +128,7 @@ #include "BDR_editface.h" #include "BDR_drawmesh.h" #include "BDR_drawobject.h" +#include "BDR_unwrapper.h" #include "BLO_readfile.h" /* for BLO_blendhandle_close */ @@ -1015,11 +1016,15 @@ void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) extrude_ika(ob, 1); } } - if (G.qual == LR_SHIFTKEY) { - if (G.obedit && G.obedit->type==OB_MESH) { - transform('e'); - } - } + else if (G.qual==LR_CTRLKEY) { + if(G.obedit && G.obedit->type==OB_MESH) + Edge_Menu(); + } + else if (G.qual==LR_SHIFTKEY) { + if (G.obedit && G.obedit->type==OB_MESH) { + transform('e'); + } + } break; case FKEY: if(G.obedit) { @@ -3419,6 +3424,10 @@ void winqreadimagespace(ScrArea *sa, void *spacedata, BWinEvent *evt) else toggle_uv_select('f'); break; + case EKEY : + if (okee("LSCM unwrap")) + unwrap_lscm(); + break; case GKEY: if((G.qual==0)) transform_tface_uv('g'); @@ -3457,6 +3466,12 @@ void winqreadimagespace(ScrArea *sa, void *spacedata, BWinEvent *evt) G.f |= G_PROPORTIONAL; } break; + case PKEY: + if(G.qual==LR_ALTKEY) + pin_tface_uv(0); + else + pin_tface_uv(1); + break; case RKEY: if((G.qual==0)) transform_tface_uv('r'); diff --git a/source/blender/src/toolbox.c b/source/blender/src/toolbox.c index c2422434562..188499378af 100644 --- a/source/blender/src/toolbox.c +++ b/source/blender/src/toolbox.c @@ -1712,6 +1712,9 @@ static TBitem tb_mesh_edit_edge[]= { { 0, "Subdivide|W, 1", 2, NULL}, { 0, "Subdivide Fractal|W, 2", 1, NULL}, { 0, "Subdivide Smooth|W, 3", 0, NULL}, +{ 0, "SEPR", 0, NULL}, +{ 0, "Mark Seam|Ctrl E", 7, NULL}, +{ 0, "Clear Seam|Ctrl E", 8, NULL}, { -1, "", 0, do_view3d_edit_mesh_edgesmenu}}; static TBitem tb_mesh_edit_face[]= { diff --git a/source/blender/src/unwrapper.c b/source/blender/src/unwrapper.c new file mode 100644 index 00000000000..13c31b308e6 --- /dev/null +++ b/source/blender/src/unwrapper.c @@ -0,0 +1,1159 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <stdlib.h> +#include <math.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef WIN32 +#include "BLI_winstuff.h" +#endif +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" + +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_utildefines.h" + +#include "BLI_arithb.h" + +#include "BIF_space.h" + +#include "blendef.h" +#include "mydevice.h" + +#include "ONL_opennl.h" +#include "BDR_unwrapper.h" + +/* Implementation Least Squares Conformal Maps parameterization, based on + * chapter 2 of: + * Bruno Levy, Sylvain Petitjean, Nicolas Ray, Jerome Maillot. Least Squares + * Conformal Maps for Automatic Texture Atlas Generation. In Siggraph 2002, + * July 2002. + */ + +/* Data structure defines */ +#define LSCM_SEAM1 1 +#define LSCM_SEAM2 2 +#define LSCM_INDEXED 4 +#define LSCM_PINNED 8 + +/* LscmVert = One UV */ +typedef struct LscmVert { + int v, v1, v2; /* vertex indices */ + int index; /* index in solver */ + short tf_index; /* index in tface (0, 1, 2 or 3) */ + short flag; /* see above LSCM constants */ + TFace *tf; /* original tface */ +} LscmVert; + +/* QuickSort helper function, sort by vertex id */ +static int comp_lscmvert(const void *u1, const void *u2) +{ + LscmVert *v1, *v2; + + v1= *((LscmVert**)u1); + v2= *((LscmVert**)u2); + + if (v1->v > v2->v) return 1; + else if (v1->v < v2->v) return -1; + return 0; +} + +/* divide selected faces in groups, based on seams. note that group numbering + starts at 1 */ +static int make_seam_groups(Mesh *me, int **seamgroups) +{ + int a, b, gid; + TFace *tf, *tface; + MFace *mf, *mface; + int *gf, *gface, *groups; + char *cpmain; + int doit, mark; + + if(!me || !me->tface) return 0; + + groups= (int*)MEM_callocN(sizeof(int)*me->totface, "SeamGroups"); + cpmain= (char*)MEM_mallocN(me->totvert, "cpmain"); + + mface= (MFace*)me->mface; + tface= (TFace*)me->tface; + gface= groups; + gid= 0; + for(b=me->totface; b>0; b--, mface++, tface++, gface++) { + if(!(tface->flag & TF_SELECT) || *gface!=0) continue; + gid++; + *gface= gid; + mark= 0; + doit= 1; + memset(cpmain, 0, me->totvert); + + while(doit) { + doit= 0; + + /* select connected: fill array */ + tf= tface; + mf= mface; + gf= gface; + a= b; + while(a--) { + if(tf->flag & TF_HIDE); + else if(tf->flag & TF_SELECT && *gf==gid && mf->v3) { + cpmain[mf->v1]= 1; + cpmain[mf->v2]= 1; + cpmain[mf->v3]= 1; + if(mf->v4) cpmain[mf->v4]= 1; + } + tf++; mf++; gf++; + } + + /* select the faces using array + * consider faces connected when they share one non-seam edge */ + tf= tface; + mf= mface; + gf= gface; + a= b; + while(a--) { + if(tf->flag & TF_HIDE); + else if(tf->flag & TF_SELECT && mf->v3 && *gf==0) { + mark= 0; + + if(!(tf->unwrap & TF_SEAM1)) + if(cpmain[mf->v1] && cpmain[mf->v2]) + mark= 1; + if(!(tf->unwrap & TF_SEAM2)) + if(cpmain[mf->v2] && cpmain[mf->v3]) + mark= 1; + if(!(tf->unwrap & TF_SEAM3)) { + if(mf->v4) { + if(cpmain[mf->v3] && cpmain[mf->v4]) + mark= 1; + } + else if(cpmain[mf->v3] && cpmain[mf->v1]) + mark= 1; + } + if(mf->v4 && !(tf->unwrap & TF_SEAM4)) + if(cpmain[mf->v4] && cpmain[mf->v1]) + mark= 1; + + if(mark) { + *gf= gid; + doit= 1; + } + } + tf++; mf++; gf++; + } + } + } + *seamgroups= groups; + + MEM_freeN(cpmain); + return gid; +} + +static void lscm_rotate_vert(int a, LscmVert **sortvert, int v2, int index) +{ + LscmVert **sv, *v; + int found, b; + + /* starting from edge sortvert->v,v2, rotate around vertex and set + * index until a seam or an already marked tri is encountered */ + found = 1; + + while(found) { + found= 0; + sv=sortvert; + + for(b=a; b>0 && ((*sv)->v == (*sortvert)->v) && !found; b--, sv++) { + v= *sv; + + if(v->flag & LSCM_INDEXED); + else if(v->v1 == v2) { + v2= v->v2; + + if(v->flag & LSCM_SEAM1) break; + + v->index= index; + v->flag |= LSCM_INDEXED; + found= 1; + break; + } + else if(v->v2==v2) { + v2= v->v1; + + if(v->flag & LSCM_SEAM2) break; + + v->index= index; + v->flag |= LSCM_INDEXED; + found= 1; + break; + } + } + } +} + +static int lscm_vertex_set_index(int a, LscmVert **sortvert, int totindex) +{ + LscmVert **sv, *v; + int index, b; + + /* rotate over 'wheel' of faces around vertex, incrementing the index + everytime we meet a seam, or no next connected face is found. + repeat this until we have and id for all verts. + if mesh is non-manifold, non-manifold edges will be cut randomly */ + + index= totindex; + sv= sortvert; + + for(b=a; b>0 && ((*sv)->v == (*sortvert)->v); b--, sv++) { + v= *sv; + + if(v->flag & LSCM_INDEXED) continue; + + v->index= index; + v->flag |= LSCM_INDEXED; + + lscm_rotate_vert(b, sv, v->v1, index); + lscm_rotate_vert(b, sv, v->v2, index); + + index++; + } + + return index; +} + +static int lscm_set_indices(LscmVert **sortvert, int totvert) +{ + LscmVert *v, **sv; + int a, lastvert, totindex; + + totindex= 0; + lastvert= -1; + sv= sortvert; + + for(a=totvert; a>0; a--, sv++) { + v= *sv; + if(v->v != lastvert) { + totindex= lscm_vertex_set_index(a, sv, totindex); + lastvert= v->v; + } + } + + return totindex; +} + +static void lscm_normalize(float *co, float *center, float radius) +{ + /* normalize relative to complete surface */ + VecSubf(co, co, center); + VecMulf(co, (float)1.0/radius); +} + +static void lscm_add_triangle(float *v1, float *v2, float *v3, int vid1, int vid2, int vid3, float *center, float radius) +{ + float x[3], y[3], z[3], sub[3], z1[2], z2[2]; + int id0[2], id1[2], id2[2]; + + /* project 3d triangle + * edge length is lost, as this algorithm is angle based */ + lscm_normalize(v1, center, radius); + lscm_normalize(v2, center, radius); + lscm_normalize(v3, center, radius); + + VecSubf(x, v2, v1); + Normalise(x); + + VecSubf(sub, v3, v1); + Crossf(z, x, sub); + Normalise(z); + + Crossf(y, z, x); + + /* reduce to two 2d vectors */ + VecSubf(sub, v2, v1); + z1[0]= Normalise(sub); + z1[1]= 0; + + VecSubf(sub, v3, v1); + z2[0]= Inpf(sub, x); + z2[1]= Inpf(sub, y); + + /* split id's up for u and v + id = u, id + 1 = v */ + id0[0]= 2*vid1; + id0[1]= 2*vid1 + 1; + id1[0]= 2*vid2; + id1[1]= 2*vid2 + 1; + id2[0]= 2*vid3; + id2[1]= 2*vid3 + 1; + + /* The LSCM Equation: + * ------------------ + * (u,v) are the uv coords we are looking for -> complex number u + i*v + * (x,y) are the above calculated local coords -> complex number x + i*y + * Uk = uk + i*vk + * Zk = xk + i*yk (= zk[0] + i*zk[1] in the code) + * + * That makes the equation: + * (Z1 - Z0)(U2 - U0) = (Z2 - Z0)(U1 - U0) + * + * x0, y0 and y1 were made zero by projecting the triangle: + * (x1 + i*y1)(u2 + i*v2 - u0 - i*v0) = (x2 + i*y2)(u1 + i*v1 - u0 - i*v0) + * + * this gives the following coefficients: + * u0 * ((-x1 + x2) + i*(y2)) + * v0 * ((-y2) + i*(-x1 + x2)) + * u1 * ((-x2) + i*(-y2)) + * v1 * ((y2) + i*(-x2)) + * u2 * (x1) + * v2 * (i*(x1)) + */ + + /* real part */ + nlBegin(NL_ROW); + nlCoefficient(id0[0], -z1[0] + z2[0]); + nlCoefficient(id0[1], -z2[1] ); + nlCoefficient(id1[0], -z2[0] ); + nlCoefficient(id1[1], z2[1] ); + nlCoefficient(id2[0], z1[0] ); + nlEnd(NL_ROW); + + /* imaginary part */ + nlBegin(NL_ROW); + nlCoefficient(id0[0], z2[1] ); + nlCoefficient(id0[1], -z1[0] + z2[0]); + nlCoefficient(id1[0], -z2[1] ); + nlCoefficient(id1[1], -z2[0] ); + nlCoefficient(id2[1], z1[0] ); + nlEnd(NL_ROW); +} + +static int lscm_build_vertex_data(Mesh *me, int *groups, int gid, LscmVert **lscm_vertices, LscmVert ***sort_vertices) +{ + MFace *mf; + TFace *tf; + int *gf, totvert, a; + LscmVert *lscmvert, **sortvert; + LscmVert *v1, *v2, *v3, **sv1, **sv2, **sv3; + + /* determine size for malloc */ + totvert= 0; + mf= me->mface; + tf= me->tface; + gf= groups; + + for(a=me->totface; a>0; a--) { + if(*gf==gid) { + + totvert += 3; + if(mf->v4) totvert +=3; + } + tf++; mf++; gf++; + } + + /* a list per face vertices */ + lscmvert= (LscmVert*)MEM_mallocN(sizeof(LscmVert)*totvert,"LscmVerts"); + /* the above list sorted by vertex id */ + sortvert= (LscmVert**)MEM_mallocN(sizeof(LscmVert*)*totvert, "LscmVSort"); + + /* actually build the list (including virtual triangulation) */ + mf= me->mface; + tf= me->tface; + gf= groups; + + v1= lscmvert; + v2= lscmvert + 1; + v3= lscmvert + 2; + + sv1= sortvert; + sv2= sortvert + 1; + sv3= sortvert + 2; + + /* warning: ugly code :) */ + for(a=me->totface; a>0; a--) { + if(*gf==gid) { + v1->v= mf->v1; + v2->v= mf->v2; + v3->v= mf->v3; + + v1->tf_index= 0; + v2->tf_index= 1; + v3->tf_index= 2; + + v1->flag= v2->flag= v3->flag= 0; + + v1->v1= mf->v2; + v1->v2= mf->v3; + + v2->v1= mf->v1; + v2->v2= mf->v3; + + v3->v1= mf->v1; + v3->v2= mf->v2; + + v1->tf= v2->tf= v3->tf= tf; + + *sv1= v1; + *sv2= v2; + *sv3= v3; + + if(tf->unwrap & TF_SEAM1) { + v1->flag |= LSCM_SEAM1; + v2->flag |= LSCM_SEAM1; + } + + if(tf->unwrap & TF_SEAM2) { + v2->flag |= LSCM_SEAM2; + v3->flag |= LSCM_SEAM2; + } + + if(!mf->v4 && tf->unwrap & TF_SEAM3) { + v1->flag |= LSCM_SEAM2; + v3->flag |= LSCM_SEAM1; + } + + v1 += 3; v2 += 3; v3 += 3; + sv1 += 3; sv2 += 3; sv3 += 3; + + if(mf->v4) { + v1->v= mf->v1; + v2->v= mf->v3; + v3->v= mf->v4; + + v1->tf_index= 0; + v2->tf_index= 2; + v3->tf_index= 3; + + v1->flag= v2->flag= v3->flag= 0; + + v1->v1= mf->v3; + v1->v2= mf->v4; + + v2->v1= mf->v4; + v2->v2= mf->v1; + + v3->v1= mf->v1; + v3->v2= mf->v3; + + v1->tf= v2->tf= v3->tf= tf; + + *sv1= v1; + *sv2= v2; + *sv3= v3; + + if(tf->unwrap & TF_SEAM3) { + v2->flag |= LSCM_SEAM1; + v3->flag |= LSCM_SEAM2; + } + + if(tf->unwrap & TF_SEAM4) { + v1->flag |= LSCM_SEAM2; + v3->flag |= LSCM_SEAM1; + } + + v1 += 3; v2 += 3; v3 += 3; + sv1 += 3; sv2 += 3; sv3 += 3; + } + } + tf++; mf++; gf++; + } + + /* sort by vertex id */ + qsort(sortvert, totvert, sizeof(LscmVert*), comp_lscmvert); + + *lscm_vertices= lscmvert; + *sort_vertices= sortvert; + return totvert; +} + +static void lscm_min_max_cent_rad(Mesh *me, LscmVert **sortvert, int totvert, float *min, float *max, float *center, float *radius) +{ + MVert *mv= me->mvert; + LscmVert *v, **sv; + int a, lastvert, vertcount; + float *co, sub[3]; + + /* find min, max and center */ + center[0]= center[1]= center[2]= 0.0; + INIT_MINMAX(min, max); + + vertcount= 0; + lastvert= -1; + sv= sortvert; + + for(a=totvert; a>0; a--, sv++) { + v= *sv; + if(v->v != lastvert) { + co= (mv+v->v)->co; + + VecAddf(center, center, (mv+v->v)->co); + DO_MINMAX(co, min, max); + + vertcount++; + lastvert= v->v; + } + } + + VecMulf(center, (float)1.0/(float)vertcount); + + /* find radius */ + VecSubf(sub, center, max); + *radius= Normalise(sub); + + if(*radius < 1e-20) + *radius= 1.0; +} + +static void lscm_projection_axes(float *min, float *max, float *p1, float *p2) +{ + float dx, dy, dz; + + dx= max[0] - min[0]; + dy= max[1] - min[1]; + dz= max[2] - min[2]; + + p1[0]= p1[1]= p1[2]= 0.0; + p2[0]= p2[1]= p2[2]= 0.0; + + if(dx < dy && dx < dz) { + if(dy > dz) p1[1]= p2[2]= 1.0; /* y, z */ + else p1[2]= p2[1]= 1.0; /* z, y */ + } + else if(dy < dx && dy < dz) { + if(dx > dz) p1[0]= p2[2]= 1.0; /* x, z */ + else p1[2]= p2[0]= 1.0; /* z, x */ + } + else if(dz < dx && dz < dy) { + if(dx > dy) p1[0]= p2[1]= 1.0; /* x, y */ + else p1[1]= p2[0]= 1.0; /* y, x */ + } +} + +static void lscm_set_initial_solution(Mesh *me, LscmVert **sortvert, int totvert, float *p1, float *p2, int *vertex_min, int *vertex_max) +{ + float umin, umax, *uv, *co; + int vmin, vmax, a; + LscmVert **sv, *v; + MVert *mv= me->mvert; + + umin= 1.0e30; + umax= -1.0e30; + + vmin= 0; + vmax= 2; + + sv= sortvert; + + for(a=totvert; a>0; a--, sv++) { + v= *sv; + co= (mv+v->v)->co; + uv= v->tf->uv[v->tf_index]; + + uv[0]= Inpf(co, p1); + uv[1]= Inpf(co, p2); + + if(uv[0] < umin) { + vmin= v->index; + umin= uv[0]; + } + if(uv[0] > umax) { + vmax= v->index; + umax= uv[0]; + } + + nlSetVariable(2*v->index, uv[0]); + nlSetVariable(2*v->index + 1, uv[1]); + } + + *vertex_min= vmin; + *vertex_max= vmax; +} + +static void lscm_set_pinned_solution(Mesh *me, LscmVert **sortvert, int totvert, int *pinned) +{ + float min[2], max[2], *uv, *co; + int a, pin; + LscmVert **sv, *v; + MVert *mv= me->mvert; + + INIT_MINMAX2(min, max); + *pinned= 0; + + sv= sortvert; + + for(a=totvert; a>0; a--, sv++) { + v= *sv; + co= (mv+v->v)->co; + uv= v->tf->uv[v->tf_index]; + + pin = ((v->tf->unwrap & TF_PIN1) && (v->tf_index == 0)) || + ((v->tf->unwrap & TF_PIN2) && (v->tf_index == 1)) || + ((v->tf->unwrap & TF_PIN3) && (v->tf_index == 2)) || + ((v->tf->unwrap & TF_PIN4) && (v->tf_index == 3)); + + nlSetVariable(2*v->index, uv[0]); + nlSetVariable(2*v->index + 1, uv[1]); + + if(pin){ + DO_MINMAX2(uv, min, max); + + *pinned += 1; + + nlLockVariable(2*v->index); + nlLockVariable(2*v->index + 1); + } + } + + if (*pinned){ + /* abuse umax vmax for caculating euclidian distance */ + max[0] -= min[0]; + max[1] -= min[1]; + + /* check for degenerated pinning box */ + if (((max[0]*max[0])+(max[1]*max[1])) < 1e-10) + *pinned = -1; + } +} + + +static void lscm_build_matrix(Mesh *me, LscmVert *lscmvert, int *groups, int gid, float *center, float radius) +{ + MVert *mv= me->mvert; + MFace *mf; + TFace *tf; + int *gf, a, id1, id2, id3; + LscmVert *v; + float co1[3], co2[3], co3[3]; + + nlBegin(NL_MATRIX); + + mf= me->mface; + tf= me->tface; + gf= groups; + v= lscmvert; + + for(a=me->totface; a>0; a--) { + if(*gf==gid) { + VecCopyf(co1, (mv+v->v)->co); + id1= v->index; v++; + VecCopyf(co2, (mv+v->v)->co); + id2= v->index; v++; + VecCopyf(co3, (mv+v->v)->co); + id3= v->index; v++; + lscm_add_triangle(co1, co2, co3, id1, id2, id3, center, radius); + + if(mf->v4) { + VecCopyf(co1, (mv+v->v)->co); + id1= v->index; v++; + VecCopyf(co2, (mv+v->v)->co); + id2= v->index; v++; + VecCopyf(co3, (mv+v->v)->co); + id3= v->index; v++; + lscm_add_triangle(co1, co2, co3, id1, id2, id3, center, radius); + } + } + tf++; mf++; gf++; + } + + nlEnd(NL_MATRIX); +} + +static void lscm_load_solution(Mesh *me, LscmVert *lscmvert, int *groups, int gid) +{ + MFace *mf; + TFace *tf; + int *gf, a, b; + LscmVert *v; + float *uv; + + mf= me->mface; + tf= me->tface; + gf= groups; + v= lscmvert; + + for(a=me->totface; a>0; a--) { + if(*gf==gid) { + + if(mf->v4) b= 6; + else b=3; + + /* index= u, index + 1= v */ + while(b > 0) { + uv= v->tf->uv[v->tf_index]; + + uv[0]= nlGetVariable(2*v->index); + uv[1]= nlGetVariable(2*v->index + 1); + + v++; + b--; + } + } + tf++; mf++; gf++; + } +} + +static int unwrap_lscm_face_group(Mesh *me, int *groups, int gid) +{ + LscmVert *lscmvert, **sortvert; + int totindex, totvert, vmin, vmax,pinned; + float min[3], max[3], center[3], radius, p1[3], p2[3]; + + /* build the data structures */ + totvert= lscm_build_vertex_data(me, groups, gid, &lscmvert, &sortvert); + + /* calculate min, max, center and radius */ + lscm_min_max_cent_rad(me, sortvert, totvert, min, max, center, &radius); + + /* index distinct vertices */ + totindex= lscm_set_indices(sortvert, totvert); + + /* create solver */ + nlNewContext(); + nlSolverParameteri(NL_NB_VARIABLES, 2*totindex); + nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE); + + nlBegin(NL_SYSTEM); + + /* find axes for projecting initial solutions on */ + lscm_projection_axes(min, max, p1, p2); + /* see if pinned data is avail and set on fly */ + lscm_set_pinned_solution(me, sortvert, totvert, &pinned); + + if(pinned < 0); /* really small pinned uv's: won't see difference anyway */ + else { + /* auto pinning */ + if(pinned < 2) + { + /* set initial solution and locate two extrema vertices to pin */ + lscm_set_initial_solution(me,sortvert,totvert,p1,p2,&vmin,&vmax); + + /* pin 2 uv's */ + nlLockVariable(2*vmin); + nlLockVariable(2*vmin + 1); + nlLockVariable(2*vmax); + nlLockVariable(2*vmax + 1); + } + + /* add triangles to the solver */ + lscm_build_matrix(me, lscmvert, groups, gid, center, radius); + + nlEnd(NL_SYSTEM); + + /* LSCM solver magic! */ + nlSolve(); + + /* load new uv's: will be projected uv's if solving failed */ + lscm_load_solution(me, lscmvert, groups, gid); + } + + nlDeleteContext(nlGetCurrent()); + MEM_freeN(lscmvert); + MEM_freeN(sortvert); + return (pinned); +} + +static void seam_group_bbox(Mesh *me, int *groups, int gid, float *min, float *max) +{ + MFace *mf; + TFace *tf; + int *gf, a; + + INIT_MINMAX2(min, max); + + mf= me->mface; + tf= me->tface; + gf= groups; + + for(a=me->totface; a>0; a--) { + if((gid!=0 && *gf==gid) || (gid==0 && *gf)) { + + DO_MINMAX2(tf->uv[0], min, max) + DO_MINMAX2(tf->uv[1], min, max) + DO_MINMAX2(tf->uv[2], min, max) + + if(mf->v4) { + DO_MINMAX2(tf->uv[3], min, max) + } + } + tf++; mf++; gf++; + } +} + +static void seam_group_scale(Mesh *me, int *groups, int gid, float scale) +{ + MFace *mf; + TFace *tf; + int *gf, a; + + mf= me->mface; + tf= me->tface; + gf= groups; + + for(a=me->totface; a>0; a--) { + if((gid!=0 && *gf==gid) || (gid==0 && *gf)) { + + Vec2Mulf(tf->uv[0], scale); + Vec2Mulf(tf->uv[1], scale); + Vec2Mulf(tf->uv[2], scale); + if(mf->v4) Vec2Mulf(tf->uv[3], scale); + } + tf++; mf++; gf++; + } +} + +static void seam_group_move(Mesh *me, int *groups, int gid, float add[2]) +{ + MFace *mf; + TFace *tf; + int *gf, a; + + mf= me->mface; + tf= me->tface; + gf= groups; + + for(a=me->totface; a>0; a--) { + if((gid!=0 && *gf==gid) || (gid==0 && *gf)) { + + Vec2Addf(tf->uv[0], tf->uv[0], add); + Vec2Addf(tf->uv[1], tf->uv[1], add); + Vec2Addf(tf->uv[2], tf->uv[2], add); + if(mf->v4) Vec2Addf(tf->uv[3], tf->uv[3], add); + } + tf++; mf++; gf++; + } +} + +/* put group withing (0,0)->(1,1) boundbox */ +static void seam_group_normalize(Mesh *me, int *groups, int gid) +{ + float min[2], max[2], sx, sy, scale, add[2]; + + seam_group_bbox(me, groups, gid, min, max); + + sx= (max[0]-min[0]); + sy= (max[1]-min[1]); + + scale= MAX2(sx, sy); + scale= (1.0/scale); + + add[0]= -min[0]; + add[1]= -min[1]; + + seam_group_move(me, groups, gid, add); + seam_group_scale(me, groups, gid, scale); +} + +/* get scale relative to mesh */ +static float seam_group_relative_scale(Mesh *me, int *groups, int gid) +{ + MVert *mv= me->mvert; + MFace *mf; + TFace *tf; + int *gf, a; + float len_xyz, len_uv; + + len_xyz= 0.0; + len_uv= 0.0; + mf= me->mface; + tf= me->tface; + gf= groups; + + for(a=me->totface; a>0; a--) { + if(*gf==gid) { + + len_uv += Vec2Lenf(tf->uv[0], tf->uv[1]); + len_xyz += VecLenf((mv+mf->v1)->co, (mv+mf->v2)->co); + + len_uv += Vec2Lenf(tf->uv[1], tf->uv[2]); + len_xyz += VecLenf((mv+mf->v2)->co, (mv+mf->v3)->co); + + if(mf->v4) { + + len_uv += Vec2Lenf(tf->uv[2], tf->uv[3]); + len_xyz += VecLenf((mv+mf->v3)->co, (mv+mf->v4)->co); + + len_uv += Vec2Lenf(tf->uv[3], tf->uv[0]); + len_xyz += VecLenf((mv+mf->v4)->co, (mv+mf->v1)->co); + } + else { + len_uv += Vec2Lenf(tf->uv[2], tf->uv[0]); + len_xyz += VecLenf((mv+mf->v3)->co, (mv+mf->v1)->co); + } + } + tf++; mf++; gf++; + } + + return (len_uv/len_xyz); +} + +/* very primitive packing */ +static void pack_seam_groups(Mesh *me, int *groups, int totgroup) +{ + float *groupscale, minscale, scale, add[2], groupw; + float dx, dy, packx, packy, min[2], max[2], rowh; + int a; + + groupscale = (float*)MEM_mallocN(sizeof(float)*totgroup, "SeamGroupScale"); + + minscale= 1e30; + + for(a=0; a<totgroup; a++) { + groupscale[a]= seam_group_relative_scale(me, groups, a+1); + minscale= MIN2(groupscale[a], minscale); + } + + packx= packy= 0.0; + rowh= 0.0; + groupw= 1.0/sqrt(totgroup); + + for(a=0; a<totgroup; a++) { + + /* scale so all groups have the same size relative to the mesh */ + scale = minscale/groupscale[a]; + scale *= groupw; + + seam_group_bbox(me, groups, a+1, min, max); + dx= (max[0]-min[0])*scale; + dy= (max[1]-min[1])*scale; + + /* for padding */ + dx += 0.05; + dy += 0.05; + + add[0]= add[1]= 0.0; + + if(dx > 1.0) { + add[0]= 0.0; + add[1]= packy; + + packy += dy; + packx= 0.0; + rowh= 0.0; + } + else if(dx <= (1.0-packx)) { + add[0]= packx; + add[1]= packy; + + packx += dx; + rowh= MAX2(rowh, dy); + } + else { + packy += rowh; + packx= dx; + rowh= dy; + + add[0]= 0.0; + add[1]= packy; + } + + /* for padding */ + add[0] += 0.025; + add[1] += 0.025; + + seam_group_scale(me, groups, a+1, scale); + seam_group_move(me, groups, a+1, add); + } + + MEM_freeN(groupscale); + + seam_group_normalize(me, groups, 0); + seam_group_scale(me, groups, 0, 0.9); + add[0]= add[1]= 0.05; + seam_group_move(me, groups, 0, add); +} + +void unwrap_lscm(void) +{ + int dopack = 1; + int res; + Mesh *me; + int totgroup, *groups=NULL, a; + + me= get_mesh(OBACT); + if(me==0 || me->tface==0) return; + + totgroup= make_seam_groups(me, &groups); + + if(totgroup==0) return; + + for(a=totgroup; a>0; a--) { + res= unwrap_lscm_face_group(me, groups, a); + if((res < 3) && (res > -1)) { + seam_group_normalize(me, groups, a); + } + else { + dopack = 0; + } + + } + + if(dopack) pack_seam_groups(me, groups, totgroup); + + MEM_freeN(groups); + + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWIMAGE, 0); +} + +/* Set tface seams based on edge data, uses hash table to find seam edges. */ + +#define SEDHASH(a, b) ((a)*256 + (b)) +#define SEDHASHSIZE 65536 +#define SEDHMAX 256 + +typedef struct SeamHashEdge { + MEdge *e; + struct SeamHashEdge *next; +} SeamHashEdge; + +/* Hash table with edges, to find edges based on v1, v2 */ +static SeamHashEdge *make_seam_hash_edge_table(Mesh *me) +{ + SeamHashEdge *htable, *first, *he; + MEdge *medge; + unsigned int a, hv1, hv2; + + if(me->medge==NULL) + return NULL; + + htable= MEM_callocN(SEDHASHSIZE*sizeof(SeamHashEdge), "lscmedgehashtable"); + + medge= me->medge; + for(a=me->totedge; a>0; a--, medge++) { + if(!(medge->flag & ME_SEAM)) continue; + + hv1= medge->v1 % SEDHMAX; + hv2= medge->v2 % SEDHMAX; + if(hv1 > hv2) + SWAP(unsigned int, hv1, hv2); + + first = htable + SEDHASH(hv1, hv2); + + if(first->e == NULL) { + first->e = medge; + } + else { + he= (SeamHashEdge*)malloc(sizeof(SeamHashEdge)); + he->e= medge; + he->next= first->next; + first->next= he; + } + } + + return htable; +} + +static int edge_is_seam(SeamHashEdge *htable, unsigned int v1, unsigned int v2) +{ + SeamHashEdge *he; + unsigned int hv1, hv2; + + hv1 = v1 % SEDHMAX; + hv2 = v2 % SEDHMAX; + + if(hv1 > hv2) + SWAP(unsigned int, hv1, hv2); + + he= htable + SEDHASH(hv1, hv2); + + while(he) { + if(he->e) { + if(he->e->v1==v1 && he->e->v2==v2) return 1; + else if(he->e->v1==v2 && he->e->v2==v1) return 1; + } + he= he->next; + } + + return 0; +} + +static void free_seam_hash_edge_table(SeamHashEdge *htable) +{ + SeamHashEdge *first, *he, *hen; + int a; + + if(htable) { + first= htable; + for(a=SEDHASHSIZE; a>0; a--, first++) { + he= first->next; + while(he) { + hen= he->next; + free(he); + he= hen; + } + } + MEM_freeN(htable); + htable= NULL; + } +} + +void set_seamtface() +{ + Mesh *me; + SeamHashEdge *htable; + int a; + MFace *mf; + TFace *tf; + + me= get_mesh(OBACT); + if(!me || !me->tface || !(G.f & G_FACESELECT)) return; + + htable= make_seam_hash_edge_table(me); + + mf= me->mface; + tf= me->tface; + for(a=me->totface; a>0; a--, mf++, tf++) { + if(mf->v3==0) continue; + tf->unwrap &= ~(TF_SEAM1|TF_SEAM2|TF_SEAM3|TF_SEAM4); + + if(!htable) continue; + + if(edge_is_seam(htable, mf->v1, mf->v2)) tf->unwrap |= TF_SEAM1; + if(edge_is_seam(htable, mf->v2, mf->v3)) tf->unwrap |= TF_SEAM2; + + if(mf->v4) { + if(edge_is_seam(htable, mf->v3, mf->v4)) tf->unwrap |= TF_SEAM3; + if(edge_is_seam(htable, mf->v4, mf->v1)) tf->unwrap |= TF_SEAM4; + } + else if(edge_is_seam(htable, mf->v3, mf->v1)) tf->unwrap |= TF_SEAM3; + } + + free_seam_hash_edge_table(htable); +} + |