diff options
Diffstat (limited to 'source/blender/src/editmesh.c')
-rw-r--r-- | source/blender/src/editmesh.c | 6387 |
1 files changed, 6387 insertions, 0 deletions
diff --git a/source/blender/src/editmesh.c b/source/blender/src/editmesh.c new file mode 100644 index 00000000000..7597e0b8cd3 --- /dev/null +++ b/source/blender/src/editmesh.c @@ -0,0 +1,6387 @@ +/** + * $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 <stdlib.h> +#include <string.h> +#include <math.h> + +#ifdef WIN32 +#include "BLI_winstuff.h" +#endif +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_editVert.h" +#include "BLI_rand.h" + +#include "MTC_matrixops.h" + +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_key_types.h" +#include "DNA_scene_types.h" +#include "DNA_view3d_types.h" +#include "DNA_material_types.h" +#include "DNA_texture_types.h" + +#include "BKE_utildefines.h" +#include "BKE_key.h" +#include "BKE_object.h" +#include "BKE_texture.h" +#include "BKE_displist.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_mesh.h" + +#include "BIF_gl.h" +#include "BIF_graphics.h" +#include "BIF_editkey.h" +#include "BIF_space.h" +#include "BIF_toolbox.h" +#include "BIF_screen.h" +#include "BIF_interface.h" +#include "BIF_editmesh.h" +#include "BIF_mywindow.h" + +#include "BSE_view.h" +#include "BSE_edit.h" +#include "BSE_trans_types.h" + +#include "BDR_drawobject.h" +#include "BDR_editobject.h" +#include "BDR_editface.h" +#include "BDR_vpaint.h" + +#include "mydevice.h" +#include "blendef.h" +#include "interface.h" /* MAART: for NUM and FLO types */ +#include "nla.h" /* For __NLA : Important - Do not remove! */ +#include "render.h" + +/****/ + +static void free_editverts(ListBase *edve); +static float convex(float *v1, float *v2, float *v3, float *v4); + +/****/ + + +/* extern ListBase fillvertbase, filledgebase; */ /* scanfill.c, in + the lib... already in BLI_blenlib.h */ + +/* voor debug: +#define free(a) freeN(a) +#define malloc(a) mallocN(a, "malloc") +#define calloc(a, b) callocN((a)*(b), "calloc") +#define freelist(a) freelistN(a) +*/ + +extern short editbutflag; + +static float icovert[12][3] = { + {0,0,-200}, + {144.72, -105.144,-89.443}, + {-55.277, -170.128,-89.443}, + {-178.885,0,-89.443}, + {-55.277,170.128,-89.443}, + {144.72,105.144,-89.443}, + {55.277,-170.128,89.443}, + {-144.72,-105.144,89.443}, + {-144.72,105.144,89.443}, + {55.277,170.128,89.443}, + {178.885,0,89.443}, + {0,0,200} +}; +static short icovlak[20][3] = { + {1,0,2}, + {1,0,5}, + {2,0,3}, + {3,0,4}, + {4,0,5}, + {1,5,10}, + {2,1,6}, + {3,2,7}, + {4,3,8}, + {5,4,9}, + {10,1,6}, + {6,2,7}, + {7,3,8}, + {8,4,9}, + {9,5,10}, + {6,10,11}, + {7,6,11}, + {8,7,11}, + {9,8,11}, + {10,9,11} +}; + +/* DEFINES */ +#define UVCOPY(t, s) memcpy(t, s, 2 * sizeof(float)); + +#define TEST_EDITMESH if(G.obedit==0) return; \ + if( (G.vd->lay & G.obedit->lay)==0 ) return; + +#define FACE_MARKCLEAR(f) (f->f1 = 1) + +/* ***************** HASH ********************* */ + +/* HASH struct voor snel opzoeken edges */ +struct HashEdge { + struct EditEdge *eed; + struct HashEdge *next; +}; + +struct HashEdge *hashedgetab=0; + +/********* qsort routines *********/ + + +struct xvertsort { + float x; + EditVert *v1; +}; + +/* Functions */ +static int vergxco(const void *v1, const void *v2) +{ + const struct xvertsort *x1=v1, *x2=v2; + + if( x1->x > x2->x ) return 1; + else if( x1->x < x2->x) return -1; + return 0; +} + +struct vlaksort { + long x; + struct EditVlak *evl; +}; + + +static int vergvlak(const void *v1, const void *v2) +{ + const struct vlaksort *x1=v1, *x2=v2; + + if( x1->x > x2->x ) return 1; + else if( x1->x < x2->x) return -1; + return 0; +} + + +/* ************ ADD / REMOVE / FIND ****************** */ + +#define EDHASH(a, b) ( (a)*256 + (b) ) +#define EDHASHSIZE 65536 + +#if 0 +static void check_hashedge(void) +{ + int i, i2, doubedge=0; + struct HashEdge *he, *he2; + + for (i=0; i<64; i++) { + he= hashedgetab+i; + + while (he && he->eed) { + for (i2=i+1; i2<64; i2++) { + he2= hashedgetab+i2; + + while (he2) { + if (he->eed == he2->eed) doubedge++; + + he2= he2->next; + } + } + + he= he->next; + } + } + + if (doubedge) printf("%d double edges!\n", doubedge); +} +#endif + +EditVert *addvertlist(float *vec) +{ + EditVert *eve; + static unsigned char hashnr= 0; + + eve= calloc(sizeof(EditVert),1); + BLI_addtail(&G.edve, eve); + + if(vec) VECCOPY(eve->co, vec); + + eve->hash= hashnr++; + + return eve; +} + +EditEdge *findedgelist(EditVert *v1, EditVert *v2) +{ + EditVert *v3; + struct HashEdge *he; + + if(hashedgetab==0) { + hashedgetab= MEM_callocN(EDHASHSIZE*sizeof(struct HashEdge), "hashedgetab"); + } + + /* swap ? */ + if( (long)v1 > (long)v2) { + v3= v2; + v2= v1; + v1= v3; + } + + /* eerst even op de flip-plek kijken */ + +/* he= hashedgetab + EDHASH(v2->hash, v1->hash); */ +/* if(he->eed && he->eed->v1==v1 && he->eed->v2==v2) return he->eed; */ + + + he= hashedgetab + EDHASH(v1->hash, v2->hash); + + while(he) { + + if(he->eed && he->eed->v1==v1 && he->eed->v2==v2) return he->eed; + + he= he->next; + } + return 0; +} + +static void insert_hashedge(EditEdge *eed) +{ + /* er van uitgaande dat eed nog niet in lijst zit, en eerst een find is gedaan */ + + struct HashEdge *first, *he; + + /* eerst even op de flip-plek kijken */ +/* he= hashedgetab + EDHASH(eed->v2->hash, eed->v1->hash); */ + +/* if(he->eed==0) { */ +/* he->eed= eed; */ +/* return; */ +/* } */ + + first= hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash); + + if( first->eed==0 ) { + first->eed= eed; + } + else { + he= (struct HashEdge *)malloc(sizeof(struct HashEdge)); + he->eed= eed; + he->next= first->next; + first->next= he; + } +} + +static void remove_hashedge(EditEdge *eed) +{ + /* er van uitgaande dat eed in lijst zit */ + + struct HashEdge *first, *he, *prev=NULL; + + + /* eerst even op de flip-plek kijken */ +/* first= hashedgetab + EDHASH(eed->v2->hash, eed->v1->hash); */ + +/* if(first->eed==eed) { */ + /* uit lijst verwijderen */ + +/* if(first->next) { */ +/* he= first->next; */ +/* first->eed= he->eed; */ +/* first->next= he->next; */ +/* free(he); */ +/* } */ +/* else first->eed= 0; */ + +/* return; */ +/* } */ + + + he=first= hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash); + + while(he) { + if(he->eed == eed) { + /* uit lijst verwijderen */ + if(he==first) { + if(first->next) { + he= first->next; + first->eed= he->eed; + first->next= he->next; + free(he); + } + else he->eed= 0; + } + else { + prev->next= he->next; + free(he); + } + return; + } + prev= he; + he= he->next; + } +} + +void free_hashedgetab(void) +{ + struct HashEdge *he, *first, *hen; + int a; +/* int test[30], nr, toted=0; */ + + /* for(a=0; a<30; a++) test[a]=0; */ + + if(hashedgetab) { + + first= hashedgetab; + for(a=0; a<EDHASHSIZE; a++, first++) { + he= first->next; + /* nr= 0; */ + /* if(first->eed) toted++; */ + /* if(first->eed) nr++; */ + while(he) { + hen= he->next; + free(he); + he= hen; + /* nr++; */ + } + /* if(nr>29) nr= 29; */ + /* test[nr]++; */ + } + MEM_freeN(hashedgetab); + hashedgetab= 0; + + /* printf("toted %d\n", toted); */ + /* toted= 0; */ + /* for(a=0; a<30; a++) { */ + /* printf("tab %d %d\n", a, test[a]); */ + /* } */ + } +} + +EditEdge *addedgelist(EditVert *v1, EditVert *v2) +{ + EditVert *v3; + EditEdge *eed; + int swap= 0; + + /* swap ? */ + if(v1>v2) { + v3= v2; + v2= v1; + v1= v3; + swap= 1; + } + + if(v1==v2) return 0; + if(v1==0 || v2==0) return 0; + + /* opzoeken in hashlijst */ + eed= findedgelist(v1, v2); + + if(eed==0) { + + eed= (EditEdge *)calloc(sizeof(EditEdge), 1); + eed->v1= v1; + eed->v2= v2; + BLI_addtail(&G.eded, eed); + eed->dir= swap; + insert_hashedge(eed); + } + return eed; +} + + +void remedge(EditEdge *eed) +{ + + BLI_remlink(&G.eded, eed); + + remove_hashedge(eed); +} + +static void freevlak(EditVlak *evl) +{ + free(evl); +} + +static void freevlaklist(ListBase *lb) +{ + EditVlak *evl, *next; + + evl= lb->first; + while(evl) { + next= evl->next; + freevlak(evl); + evl= next; + } + lb->first= lb->last= 0; +} + +EditVlak *addvlaklist(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, EditVlak *example) +{ + EditVlak *evl; + EditEdge *e1, *e2=0, *e3=0, *e4=0; + + + /* voeg vlak toe aan lijst en doe meteen de edges */ + e1= addedgelist(v1, v2); + if(v3) e2= addedgelist(v2, v3); + if(v4) e3= addedgelist(v3, v4); else e3= addedgelist(v3, v1); + if(v4) e4= addedgelist(v4, v1); + + if(v1==v2 || v2==v3 || v1==v3) return 0; + if(e2==0) return 0; + + evl= (EditVlak *)calloc(sizeof(EditVlak), 1); + evl->v1= v1; + evl->v2= v2; + evl->v3= v3; + evl->v4= v4; + + evl->e1= e1; + evl->e2= e2; + evl->e3= e3; + evl->e4= e4; + + if(example) { + evl->mat_nr= example->mat_nr; + evl->tface= example->tface; + evl->flag= example->flag; + memcpy(evl->col, example->col, sizeof(example->col)); + memcpy(evl->uv, example->uv, sizeof(example->uv)); + } + else { + if (G.obedit && G.obedit->actcol) + evl->mat_nr= G.obedit->actcol-1; + default_uv(evl->uv, 1.0); + + /* Initialize colors */ + evl->col[0]= evl->col[1]= evl->col[2]= evl->col[3]= vpaint_get_current_col(); + } + + BLI_addtail(&G.edvl, evl); + + if(evl->v4) CalcNormFloat4(v1->co, v2->co, v3->co, v4->co, evl->n); + else CalcNormFloat(v1->co, v2->co, v3->co, evl->n); + + return evl; +} + +static int comparevlak(EditVlak *vl1, EditVlak *vl2) +{ + EditVert *v1, *v2, *v3, *v4; + + if(vl1->v4 && vl2->v4) { + v1= vl2->v1; + v2= vl2->v2; + v3= vl2->v3; + v4= vl2->v4; + + if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1 || vl1->v4==v1) { + if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2 || vl1->v4==v2) { + if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3 || vl1->v4==v3) { + if(vl1->v1==v4 || vl1->v2==v4 || vl1->v3==v4 || vl1->v4==v4) { + return 1; + } + } + } + } + } + else if(vl1->v4==0 && vl2->v4==0) { + v1= vl2->v1; + v2= vl2->v2; + v3= vl2->v3; + + if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1) { + if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2) { + if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3) { + return 1; + } + } + } + } + + return 0; +} + + +#if 0 +static int dubbelvlak(EditVlak *evltest) +{ + + EditVlak *evl; + + evl= G.edvl.first; + while(evl) { + if(evl!=evltest) { + if(comparevlak(evltest, evl)) return 1; + } + evl= evl->next; + } + return 0; +} +#endif + +static int exist_vlak(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4) +{ + EditVlak *evl, evltest; + + evltest.v1= v1; + evltest.v2= v2; + evltest.v3= v3; + evltest.v4= v4; + + evl= G.edvl.first; + while(evl) { + if(comparevlak(&evltest, evl)) return 1; + evl= evl->next; + } + return 0; +} + + +static int vlakselectedOR(EditVlak *evl, int flag) +{ + + if(evl->v1->f & flag) return 1; + if(evl->v2->f & flag) return 1; + if(evl->v3->f & flag) return 1; + if(evl->v4 && (evl->v4->f & 1)) return 1; + return 0; +} + +int vlakselectedAND(EditVlak *evl, int flag) +{ + if(evl->v1->f & flag) { + if(evl->v2->f & flag) { + if(evl->v3->f & flag) { + if(evl->v4) { + if(evl->v4->f & flag) return 1; + } + else return 1; + } + } + } + return 0; +} + +void recalc_editnormals(void) +{ + EditVlak *evl; + + evl= G.edvl.first; + while(evl) { + if(evl->v4) CalcNormFloat4(evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co, evl->n); + else CalcNormFloat(evl->v1->co, evl->v2->co, evl->v3->co, evl->n); + evl= evl->next; + } +} + +static void flipvlak(EditVlak *evl) +{ + if(evl->v4) { + SWAP(EditVert *, evl->v2, evl->v4); + SWAP(EditEdge *, evl->e1, evl->e4); + SWAP(EditEdge *, evl->e2, evl->e3); + SWAP(unsigned int, evl->col[1], evl->col[3]); + if(evl->tface) { + SWAP(float, evl->uv[1][0], evl->uv[3][0]); + SWAP(float, evl->uv[1][1], evl->uv[3][1]); + } + } + else { + SWAP(EditVert *, evl->v2, evl->v3); + SWAP(EditEdge *, evl->e1, evl->e3); + SWAP(unsigned int, evl->col[1], evl->col[2]); + evl->e2->dir= 1-evl->e2->dir; + if(evl->tface) { + SWAP(float, evl->uv[1][0], evl->uv[2][0]); + SWAP(float, evl->uv[1][1], evl->uv[2][1]); + } + } + if(evl->v4) CalcNormFloat4(evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co, evl->n); + else CalcNormFloat(evl->v1->co, evl->v2->co, evl->v3->co, evl->n); +} + + +void flip_editnormals(void) +{ + EditVlak *evl; + + evl= G.edvl.first; + while(evl) { + if( vlakselectedAND(evl, 1) ) { + flipvlak(evl); + } + evl= evl->next; + } +} + +/* ************************ IN & OUT ***************************** */ + +static void edge_normal_compare(EditEdge *eed, EditVlak *evl1) +{ + EditVlak *evl2; + float cent1[3], cent2[3]; + float inp; + + evl2= (EditVlak *)eed->vn; + if(evl1==evl2) return; + + inp= evl1->n[0]*evl2->n[0] + evl1->n[1]*evl2->n[1] + evl1->n[2]*evl2->n[2]; + if(inp<0.999 && inp >-0.999) eed->f= 1; + + if(evl1->v4) CalcCent4f(cent1, evl1->v1->co, evl1->v2->co, evl1->v3->co, evl1->v4->co); + else CalcCent3f(cent1, evl1->v1->co, evl1->v2->co, evl1->v3->co); + if(evl2->v4) CalcCent4f(cent2, evl2->v1->co, evl2->v2->co, evl2->v3->co, evl2->v4->co); + else CalcCent3f(cent2, evl2->v1->co, evl2->v2->co, evl2->v3->co); + + VecSubf(cent1, cent2, cent1); + Normalise(cent1); + inp= cent1[0]*evl1->n[0] + cent1[1]*evl1->n[1] + cent1[2]*evl1->n[2]; + + if(inp < -0.001 ) eed->f1= 1; +} + +static void edge_drawflags(void) +{ + EditVert *eve; + EditEdge *eed, *e1, *e2, *e3, *e4; + EditVlak *evl; + + /* - tel aantal keren in vlakken gebruikt: 0 en 1 is tekenen + * - edges meer dan 1 keer: in *vn zit pointer naar (eerste) vlak + * - loop alle vlakken af, is normaal te afwijkend: tekenen (flag wordt 1) + */ + + recalc_editnormals(); + + /* init */ + eve= G.edve.first; + while(eve) { + eve->f1= 1; /* wordt bij test op nul gezet */ + eve= eve->next; + } + eed= G.eded.first; + while(eed) { + eed->f= eed->f1= 0; + eed->vn= 0; + eed= eed->next; + } + + evl= G.edvl.first; + while(evl) { + e1= evl->e1; + e2= evl->e2; + e3= evl->e3; + e4= evl->e4; + if(e1->f<3) e1->f+= 1; + if(e2->f<3) e2->f+= 1; + if(e3->f<3) e3->f+= 1; + if(e4 && e4->f<3) e4->f+= 1; + + if(e1->vn==0) e1->vn= (EditVert *)evl; + if(e2->vn==0) e2->vn= (EditVert *)evl; + if(e3->vn==0) e3->vn= (EditVert *)evl; + if(e4 && e4->vn==0) e4->vn= (EditVert *)evl; + + evl= evl->next; + } + + if(G.f & G_ALLEDGES) { + evl= G.edvl.first; + while(evl) { + if(evl->e1->f>=2) evl->e1->f= 1; + if(evl->e2->f>=2) evl->e2->f= 1; + if(evl->e3->f>=2) evl->e3->f= 1; + if(evl->e4 && evl->e4->f>=2) evl->e4->f= 1; + + evl= evl->next; + } + } + else { + + /* single-edges afvangen voor cylinder flag */ + + eed= G.eded.first; + while(eed) { + if(eed->f==1) eed->f1= 1; + eed= eed->next; + } + + /* alle vlakken, alle edges met flag==2: vergelijk normaal */ + evl= G.edvl.first; + while(evl) { + if(evl->e1->f==2) edge_normal_compare(evl->e1, evl); + if(evl->e2->f==2) edge_normal_compare(evl->e2, evl); + if(evl->e3->f==2) edge_normal_compare(evl->e3, evl); + if(evl->e4 && evl->e4->f==2) edge_normal_compare(evl->e4, evl); + + evl= evl->next; + } + + /* sphere collision flag */ + + eed= G.eded.first; + while(eed) { + if(eed->f1!=1) { + eed->v1->f1= eed->v2->f1= 0; + } + eed= eed->next; + } + + } +} + +static int contrpuntnorm(float *n, float *puno) +{ + float inp; + + inp= n[0]*puno[0]+n[1]*puno[1]+n[2]*puno[2]; + + /* angles 90 degrees: dont flip */ + if(inp> -0.000001) return 0; + + return 1; +} + +void vertexnormals(int testflip) +{ + Mesh *me; + EditVert *eve; + EditVlak *evl; + float n1[3], n2[3], n3[3], n4[3], co[4], fac1, fac2, fac3, fac4, *temp; + float *f1, *f2, *f3, *f4, xn, yn, zn; + float opp, len; + + if(G.obedit && G.obedit->type==OB_MESH) { + me= G.obedit->data; + if((me->flag & ME_TWOSIDED)==0) testflip= 0; + } + + if(G.totvert==0) return; + + if(G.totface==0) { + /* namaak puno's voor halopuno! */ + eve= G.edve.first; + while(eve) { + VECCOPY(eve->no, eve->co); + Normalise( (float *)eve->no); + eve= eve->next; + } + return; + } + + /* clear normals */ + eve= G.edve.first; + while(eve) { + eve->no[0]= eve->no[1]= eve->no[2]= 0.0; + eve= eve->next; + } + + /* berekenen cos hoeken en oppervlakte en optellen bij puno */ + evl= G.edvl.first; + while(evl) { + VecSubf(n1, evl->v2->co, evl->v1->co); + VecSubf(n2, evl->v3->co, evl->v2->co); + Normalise(n1); + Normalise(n2); + + if(evl->v4==0) { + VecSubf(n3, evl->v1->co, evl->v3->co); + Normalise(n3); + + /* opp= AreaT3Dfl(evl->v1->co, evl->v2->co, evl->v3->co); */ + /* if(opp!=0.0) opp=1.0/opp; */ + /* opp= sqrt(opp); */ + /* for smooth subdivide...*/ + opp= 1.0; + co[0]= opp*saacos(-n3[0]*n1[0]-n3[1]*n1[1]-n3[2]*n1[2]); + co[1]= opp*saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]); + co[2]= opp*saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]); + + } + else { + VecSubf(n3, evl->v4->co, evl->v3->co); + VecSubf(n4, evl->v1->co, evl->v4->co); + Normalise(n3); + Normalise(n4); + + /* opp= AreaQ3Dfl(evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co); */ + /* if(opp!=0.0) opp=1.0/opp; */ + /* opp= sqrt(opp); */ + /* for smooth subdivide...*/ + opp= 1.0; + co[0]= opp*saacos(-n4[0]*n1[0]-n4[1]*n1[1]-n4[2]*n1[2]); + co[1]= opp*saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]); + co[2]= opp*saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]); + co[3]= opp*saacos(-n3[0]*n4[0]-n3[1]*n4[1]-n3[2]*n4[2]); + } + + temp= evl->v1->no; + if(testflip && contrpuntnorm(evl->n, temp) ) co[0]= -co[0]; + temp[0]+= co[0]*evl->n[0]; + temp[1]+= co[0]*evl->n[1]; + temp[2]+= co[0]*evl->n[2]; + + temp= evl->v2->no; + if(testflip && contrpuntnorm(evl->n, temp) ) co[1]= -co[1]; + temp[0]+= co[1]*evl->n[0]; + temp[1]+= co[1]*evl->n[1]; + temp[2]+= co[1]*evl->n[2]; + + temp= evl->v3->no; + if(testflip && contrpuntnorm(evl->n, temp) ) co[2]= -co[2]; + temp[0]+= co[2]*evl->n[0]; + temp[1]+= co[2]*evl->n[1]; + temp[2]+= co[2]*evl->n[2]; + + if(evl->v4) { + temp= evl->v4->no; + if(testflip && contrpuntnorm(evl->n, temp) ) co[3]= -co[3]; + temp[0]+= co[3]*evl->n[0]; + temp[1]+= co[3]*evl->n[1]; + temp[2]+= co[3]*evl->n[2]; + } + + evl= evl->next; + } + + /* normaliseren puntnormalen */ + eve= G.edve.first; + while(eve) { + len= Normalise(eve->no); + if(len==0.0) { + VECCOPY(eve->no, eve->co); + Normalise( eve->no); + } + eve= eve->next; + } + + /* puntnormaal omklap-vlaggen voor bij shade */ + evl= G.edvl.first; + while(evl) { + evl->f=0; + + if(testflip) { + f1= evl->v1->no; + f2= evl->v2->no; + f3= evl->v3->no; + + fac1= evl->n[0]*f1[0] + evl->n[1]*f1[1] + evl->n[2]*f1[2]; + if(fac1<0.0) { + evl->f = ME_FLIPV1; + } + fac2= evl->n[0]*f2[0] + evl->n[1]*f2[1] + evl->n[2]*f2[2]; + if(fac2<0.0) { + evl->f += ME_FLIPV2; + } + fac3= evl->n[0]*f3[0] + evl->n[1]*f3[1] + evl->n[2]*f3[2]; + if(fac3<0.0) { + evl->f += ME_FLIPV3; + } + if(evl->v4) { + f4= evl->v4->no; + fac4= evl->n[0]*f4[0] + evl->n[1]*f4[1] + evl->n[2]*f4[2]; + if(fac4<0.0) { + evl->f += ME_FLIPV4; + } + } + } + /* proj voor cubemap! */ + xn= fabs(evl->n[0]); + yn= fabs(evl->n[1]); + zn= fabs(evl->n[2]); + + if(zn>xn && zn>yn) evl->f += ME_PROJXY; + else if(yn>xn && yn>zn) evl->f += ME_PROJXZ; + else evl->f += ME_PROJYZ; + + evl= evl->next; + } +} + +void free_editMesh(void) +{ + +// if(G.edve.first) BLI_freelist(&G.edve); + if(G.edve.first) free_editverts(&G.edve); + if(G.eded.first) BLI_freelist(&G.eded); + if(G.edvl.first) freevlaklist(&G.edvl); + free_hashedgetab(); + G.totvert= G.totface= 0; +} + +static void free_editverts(ListBase *edve) { +#ifdef __NLA + EditVert *eve; +#endif + + if (!edve) + return; + + if (!edve->first) + return; + +#ifdef __NLA + for (eve= edve->first; eve; eve=eve->next){ + if (eve->dw) + MEM_freeN (eve->dw); + } +#endif + + BLI_freelist (edve); + +} + +static void free_editvert (EditVert *eve) +{ +#ifdef __NLA + if (eve->dw) + MEM_freeN (eve->dw); +#endif + free (eve); +} + +void make_editMesh(void) +{ + Mesh *me; + MFace *mface; + TFace *tface; + MVert *mvert; + KeyBlock *actkey=0; + EditVert *eve, **evlist, *eve1, *eve2, *eve3, *eve4; + EditVlak *evl; + int tot, a; + + if(G.obedit==0) return; + + /* ivm reload */ + free_editMesh(); + + me= get_mesh(G.obedit); + G.totvert= tot= me->totvert; + + if(tot==0) { + countall(); + return; + } + + waitcursor(1); + + /* keys? */ + if(me->key) { + actkey= me->key->block.first; + while(actkey) { + if(actkey->flag & SELECT) break; + actkey= actkey->next; + } + } + + if(actkey) { + key_to_mesh(actkey, me); + tot= actkey->totelem; + } + + /* editverts aanmaken */ + mvert= me->mvert; + + evlist= (EditVert **)MEM_mallocN(tot*sizeof(void *),"evlist"); + for(a=0; a<tot; a++, mvert++) { + eve= addvertlist(mvert->co); + evlist[a]= eve; + eve->no[0]= mvert->no[0]/32767.0; + eve->no[1]= mvert->no[1]/32767.0; + eve->no[2]= mvert->no[2]/32767.0; +#ifdef __NLA + + /* OLD VERSION */ + /* + eve->totweight = mvert->totweight; + if (mvert->dw){ + eve->dw = BLI_callocN (sizeof(MDeformWeight) * mvert->totweight, "deformWeight"); + memcpy (eve->dw, mvert->dw, sizeof(MDeformWeight) * mvert->totweight); + } + */ + + /* NEW VERSION */ + if (me->dvert){ + eve->totweight = me->dvert[a].totweight; + if (me->dvert[a].dw){ + eve->dw = MEM_callocN (sizeof(MDeformWeight) * me->dvert[a].totweight, "deformWeight"); + memcpy (eve->dw, me->dvert[a].dw, sizeof(MDeformWeight) * me->dvert[a].totweight); + } + } + +#endif + } + + if(actkey && actkey->totelem!=me->totvert); + else { + unsigned int *mcol; + + /* edges en vlakken maken */ + mface= me->mface; + tface= me->tface; + mcol= (unsigned int *)me->mcol; + + for(a=0; a<me->totface; a++, mface++) { + eve1= evlist[mface->v1]; + eve2= evlist[mface->v2]; + if(mface->v3) eve3= evlist[mface->v3]; else eve3= 0; + if(mface->v4) eve4= evlist[mface->v4]; else eve4= 0; + + evl= addvlaklist(eve1, eve2, eve3, eve4, NULL); + + if(evl) { + if(mcol) memcpy(evl->col, mcol, 4*sizeof(int)); + + if(me->tface) { + memcpy(evl->col, tface->col, sizeof(tface->col)); + memcpy(evl->uv, tface->uv, sizeof(tface->uv)); + + if( tface->flag & TF_SELECT) { + if(G.f & G_FACESELECT) { + eve1->f |= 1; + eve2->f |= 1; + if(eve3) eve3->f |= 1; + if(eve4) eve4->f |= 1; + } + } + } + + evl->mat_nr= mface->mat_nr; + evl->flag= mface->flag; + evl->tface= tface; + } + + if(me->tface) tface++; + if(mcol) mcol+=4; + } + } + MEM_freeN(evlist); + + countall(); + + if (mesh_uses_displist(me)) + makeDispList(G.obedit); + + waitcursor(0); +} + +/** Rotates MFace and UVFace vertices in case the last + * vertex index is = 0. + * This function is a hack and may only be called in the + * conversion from EditMesh to Mesh data. + * This function is similar to test_index_mface in + * blenkernel/intern/mesh.c. + * To not clutter the blenkernel code with more bad level + * calls/structures, this function resides here. + */ + + +static void fix_faceindices(MFace *mface, EditVlak *evl, int nr) +{ + int a; + float tmpuv[2]; + unsigned int tmpcol; + +/* +mface = ((MFace *) me->mface) + index; + tface = ((TFace *) me->tface) + index; + +*/ + + /* first test if the face is legal */ + + if(mface->v3 && mface->v3==mface->v4) { + mface->v4= 0; + nr--; + } + if(mface->v2 && mface->v2==mface->v3) { + mface->v3= mface->v4; + mface->v4= 0; + nr--; + } + if(mface->v1==mface->v2) { + mface->v2= mface->v3; + mface->v3= mface->v4; + mface->v4= 0; + nr--; + } + + /* voorkom dat een nul op de verkeerde plek staat */ + if(nr==2) { + if(mface->v2==0) SWAP(int, mface->v1, mface->v2); + } + else if(nr==3) { + if(mface->v3==0) { + SWAP(int, mface->v1, mface->v2); + SWAP(int, mface->v2, mface->v3); + /* rotate face UV coordinates, too */ + UVCOPY(tmpuv, evl->uv[0]); + UVCOPY(evl->uv[0], evl->uv[1]); + UVCOPY(evl->uv[1], evl->uv[2]); + UVCOPY(evl->uv[2], tmpuv); + /* same with vertex colours */ + tmpcol = evl->col[0]; + evl->col[0] = evl->col[1]; + evl->col[1] = evl->col[2]; + evl->col[2] = tmpcol; + + + a= mface->edcode; + mface->edcode= 0; + if(a & ME_V1V2) mface->edcode |= ME_V3V1; + if(a & ME_V2V3) mface->edcode |= ME_V1V2; + if(a & ME_V3V1) mface->edcode |= ME_V2V3; + + a= mface->puno; + mface->puno &= ~15; + if(a & ME_FLIPV1) mface->puno |= ME_FLIPV2; + if(a & ME_FLIPV2) mface->puno |= ME_FLIPV3; + if(a & ME_FLIPV3) mface->puno |= ME_FLIPV1; + } + } + else if(nr==4) { + if(mface->v3==0 || mface->v4==0) { + SWAP(int, mface->v1, mface->v3); + SWAP(int, mface->v2, mface->v4); + /* swap UV coordinates */ + UVCOPY(tmpuv, evl->uv[0]); + UVCOPY(evl->uv[0], evl->uv[2]); + UVCOPY(evl->uv[2], tmpuv); + UVCOPY(tmpuv, evl->uv[1]); + UVCOPY(evl->uv[1], evl->uv[3]); + UVCOPY(evl->uv[3], tmpuv); + /* swap vertex colours */ + tmpcol = evl->col[0]; + evl->col[0] = evl->col[2]; + evl->col[2] = tmpcol; + tmpcol = evl->col[1]; + evl->col[1] = evl->col[3]; + evl->col[3] = tmpcol; + + a= mface->edcode; + mface->edcode= 0; + if(a & ME_V1V2) mface->edcode |= ME_V3V4; + if(a & ME_V2V3) mface->edcode |= ME_V2V3; + if(a & ME_V3V4) mface->edcode |= ME_V1V2; + if(a & ME_V4V1) mface->edcode |= ME_V4V1; + + a= mface->puno; + mface->puno &= ~15; + if(a & ME_FLIPV1) mface->puno |= ME_FLIPV3; + if(a & ME_FLIPV2) mface->puno |= ME_FLIPV4; + if(a & ME_FLIPV3) mface->puno |= ME_FLIPV1; + if(a & ME_FLIPV4) mface->puno |= ME_FLIPV2; + } + } + +} + + + +/* load from EditMode to Mesh */ + +void load_editMesh(void) +{ + Mesh *me; + MFace *mface; + MVert *mvert; + MSticky *ms; + KeyBlock *actkey=0; + EditVert *eve; + EditVlak *evl; + EditEdge *eed; + float *fp, nor[3]; + int i, a, ototvert; +#ifdef __NLA + MDeformVert *dvert; + int usedDvert = 0; +#endif + + waitcursor(1); + countall(); + + me= get_mesh(G.obedit); + + ototvert= me->totvert; + + /* zijn er keys? */ + if(me->key) { + actkey= me->key->block.first; + while(actkey) { + if(actkey->flag & SELECT) break; + actkey= actkey->next; + } + } + + + if(actkey && me->key->refkey!=actkey) { + /* aktieve key && niet de refkey: alleen vertices */ + + if(G.totvert) { + if(actkey->data) MEM_freeN(actkey->data); + + fp=actkey->data= MEM_callocN(me->key->elemsize*G.totvert, "actkey->data"); + actkey->totelem= G.totvert; + + eve= G.edve.first; + while(eve) { + VECCOPY(fp, eve->co); + fp+= 3; + eve= eve->next; + } + } + } + else if(me->key && actkey==0) { + /* er zijn keys, alleen veranderingen in mverts schrijven */ + /* als aantal vertices verschillen, beetje onvoorspelbaar */ + + eve= G.edve.first; + mvert= me->mvert; + for(a=0; a<me->totvert; a++, mvert++) { + VECCOPY(mvert->co, eve->co); + eve= eve->next; + if(eve==0) break; + } + } + else { + /* als er keys zijn: de refkey, anders gewoon de me */ + + /* deze telt ook of edges niet in vlakken zitten: */ + /* eed->f==0 niet in vlak, f==1 is tekenen */ + /* eed->f1 : flag voor dynaface (cylindertest) */ + /* eve->f1 : flag voor dynaface (sphere test) */ + edge_drawflags(); + + /* LET OP: op evl->f de punoflag */ + vertexnormals( (me->flag & ME_NOPUNOFLIP)==0 ); + + eed= G.eded.first; + while(eed) { + if(eed->f==0) G.totface++; + eed= eed->next; + } + + /* nieuw Face blok */ + if(G.totface==0) mface= 0; + else mface= MEM_callocN(G.totface*sizeof(MFace), "loadeditMesh1"); + /* nieuw Vertex blok */ + if(G.totvert==0) mvert= 0; + else mvert= MEM_callocN(G.totvert*sizeof(MVert), "loadeditMesh2"); + +#ifdef __NLA + if (G.totvert==0) dvert=0; + else dvert = MEM_callocN(G.totvert*sizeof(MDeformVert), "loadeditMesh3"); + + if (me->dvert) free_dverts(me->dvert, me->totvert); + me->dvert=dvert; +#endif + if(me->mvert) MEM_freeN(me->mvert); + me->mvert= mvert; + + if(me->mface) MEM_freeN(me->mface); + me->mface= mface; + me->totvert= G.totvert; + me->totface= G.totface; + + /* de vertices, gebruik ->vn als teller */ + eve= G.edve.first; + a=0; + + + + while(eve) { + VECCOPY(mvert->co, eve->co); + mvert->mat_nr= 255; /* waarvoor ook al weer, haloos? */ + + /* puno */ + VECCOPY(nor, eve->no); + VecMulf(nor, 32767.0); + VECCOPY(mvert->no, nor); +#ifdef __NLA +/* OLD VERSION */ +/* mvert->totweight = eve->totweight; + if (eve->dw){ + int cv; + mvert->dw = BLI_callocN (sizeof(MDeformWeight)*eve->totweight, "deformWeight"); + memcpy (mvert->dw, eve->dw, sizeof(MDeformWeight)*eve->totweight); + } +*/ + /* NEW VERSION */ + if (dvert){ + dvert->totweight=eve->totweight; + if (eve->dw){ + dvert->dw = MEM_callocN (sizeof(MDeformWeight)*eve->totweight, "deformWeight"); + memcpy (dvert->dw, eve->dw, sizeof(MDeformWeight)*eve->totweight); + usedDvert++; + } + } +#endif + + eve->vn= (EditVert *)(long)(a++); /* teller */ + + mvert->flag= 0; + if(eve->f1==1) mvert->flag |= ME_SPHERETEST; + + eve= eve->next; + mvert++; +#ifdef __NLA + dvert++; +#endif + } + +#ifdef __NLA + /* If we didn't actually need the dverts, get rid of them */ + if (!usedDvert){ + free_dverts(me->dvert, G.totvert); + me->dvert=NULL; + } +#endif + + /* de vlakken */ + evl= G.edvl.first; + i = 0; + while(evl) { + mface= &((MFace *) me->mface)[i]; + + mface->v1= (unsigned int) evl->v1->vn; + mface->v2= (unsigned int) evl->v2->vn; + mface->v3= (unsigned int) evl->v3->vn; + if(evl->v4) mface->v4= (unsigned int) evl->v4->vn; + + mface->mat_nr= evl->mat_nr; + mface->puno= evl->f; + mface->flag= evl->flag; + + /* mat_nr in vertex */ + if(me->totcol>1) { + mvert= me->mvert+mface->v1; + if(mvert->mat_nr == 255) mvert->mat_nr= mface->mat_nr; + mvert= me->mvert+mface->v2; + if(mvert->mat_nr == 255) mvert->mat_nr= mface->mat_nr; + mvert= me->mvert+mface->v3; + if(mvert->mat_nr == 255) mvert->mat_nr= mface->mat_nr; + if(mface->v4) { + mvert= me->mvert+mface->v4; + if(mvert->mat_nr == 255) mvert->mat_nr= mface->mat_nr; + } + } + + /* dyna cilinder flag minder kritisch testen: 'dubbel' in vlakken laten zitten. + * gaat anders fout bij scherpe hoeken (inpspeed voor een wel, ander niet!) + * Mogelijk oplossen door volgorde aan te passen: sphere-cyl-face. Kost te veel? + */ + + /* letop: evl->e1->f==0 is losse edge */ + + if(evl->e1->f==1) { + mface->edcode |= ME_V1V2; + evl->e1->f= 2; + } + if(evl->e2->f==1) { + mface->edcode |= ME_V2V3; + evl->e2->f= 2; + } + if(evl->e3->f==1) { + if(evl->v4) { + mface->edcode |= ME_V3V4; + } + else { + mface->edcode |= ME_V3V1; + } + evl->e3->f= 2; + } + if(evl->e4 && evl->e4->f==1) { + mface->edcode |= ME_V4V1; + evl->e4->f= 2; + } + + /* geen index '0' op plek 3 of 4 */ + if(evl->v4) fix_faceindices(mface, evl, 4); + else fix_faceindices(mface, evl, 3); + + i++; + evl= evl->next; + } + + /* losse edges als vlak toevoegen */ + eed= G.eded.first; + while(eed) { + if( eed->f==0 ) { + mface= &((MFace *) me->mface)[i]; + mface->v1= (unsigned int) eed->v1->vn; + mface->v2= (unsigned int) eed->v2->vn; + test_index_mface(mface, 2); + mface->edcode= ME_V1V2; + i++; + } + eed= eed->next; + } + + tex_space_mesh(me); + if(actkey) mesh_to_key(me, actkey); + + /* texmesh: ahv ->tface alles opnieuw maken */ + if(me->tface && me->totface) { + TFace *tfn, *tf; + + tf=tfn= MEM_callocN(sizeof(TFace)*me->totface, "tface"); + evl= G.edvl.first; + while(evl) { + + if(evl->tface) *tf= *(evl->tface); + else default_tface(tf); + + memcpy(tf->col, evl->col, sizeof(tf->col)); + memcpy(tf->uv, evl->uv, sizeof(tf->uv)); + + if(G.f & G_FACESELECT) { + if( vlakselectedAND(evl, 1) ) tf->flag |= TF_SELECT; + else tf->flag &= ~TF_SELECT; + } + + /* sometimes editmode doesn't free (before render) */ + evl->tface= tf; + + tf++; + evl= evl->next; + } + + MEM_freeN(me->tface); + me->tface= tfn; + } + else if(me->tface) { + /* freeN(me->tface); */ + /* me->tface= 0; */ + } + + /* mcol: ahv indexnrs opnieuw maken */ + if(me->mcol && me->totface) { + unsigned int *mcn, *mc; + + mc=mcn= MEM_mallocN(4*sizeof(int)*me->totface, "mcol"); + evl= G.edvl.first; + while(evl) { + + memcpy(mc, evl->col, 4*sizeof(int)); + + mc+=4; + evl= evl->next; + } + + MEM_freeN(me->mcol); + me->mcol= (MCol *)mcn; + } + else if(me->mcol) { + MEM_freeN(me->mcol); + me->mcol= 0; + } + } + + if(actkey) do_spec_key(me->key); + + /* voor zekerheid: ->vn pointers wissen */ + eve= G.edve.first; + while(eve) { + eve->vn= 0; + eve= eve->next; + } + + /* displisten van alle users, ook deze */ + freedisplist(&me->disp); + freedisplist(&G.obedit->disp); + + /* sticky */ + if(me->msticky) { + if (ototvert<me->totvert) { + ms= MEM_callocN(me->totvert*sizeof(MSticky), "msticky"); + memcpy(ms, me->msticky, ototvert*sizeof(MSticky)); + MEM_freeN(me->msticky); + me->msticky= ms; + error("Sticky was too small"); + } + } + waitcursor(0); +} + + +void remake_editMesh(void) +{ + + if(okee("Reload Original data")==0) return; + + make_editMesh(); + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + +/* ********************* TOOLS ********************* */ + + + +void make_sticky(void) +{ + Object *ob; + Base *base; + MVert *mvert; + Mesh *me; + MSticky *ms; + float ho[4], mat[4][4]; + int a; + + if(G.scene->camera==0) return; + + if(G.obedit) { + error("Unable to perform function in EditMode"); + return; + } + base= FIRSTBASE; + while(base) { + if TESTBASELIB(base) { + if(base->object->type==OB_MESH) { + ob= base->object; + + me= ob->data; + mvert= me->mvert; + if(me->msticky) MEM_freeN(me->msticky); + me->msticky= MEM_mallocN(me->totvert*sizeof(MSticky), "sticky"); + + /* stukje roteerscene */ + R.r= G.scene->r; + R.r.xsch= (R.r.size*R.r.xsch)/100; + R.r.ysch= (R.r.size*R.r.ysch)/100; + + R.afmx= R.r.xsch/2; + R.afmy= R.r.ysch/2; + + R.ycor= ( (float)R.r.yasp)/( (float)R.r.xasp); + + R.rectx= R.r.xsch; + R.recty= R.r.ysch; + R.xstart= -R.afmx; + R.ystart= -R.afmy; + R.xend= R.xstart+R.rectx-1; + R.yend= R.ystart+R.recty-1; + + where_is_object(G.scene->camera); + Mat4CpyMat4(R.viewinv, G.scene->camera->obmat); + Mat4Ortho(R.viewinv); + Mat4Invert(R.viewmat, R.viewinv); + + RE_setwindowclip(1, -1); + + where_is_object(ob); + Mat4MulMat4(mat, ob->obmat, R.viewmat); + + ms= me->msticky; + for(a=0; a<me->totvert; a++, ms++, mvert++) { + VECCOPY(ho, mvert->co); + Mat4MulVecfl(mat, ho); + RE_projectverto(ho, ho); + ms->co[0]= ho[0]/ho[3]; + ms->co[1]= ho[1]/ho[3]; + } + } + } + base= base->next; + } + allqueue(REDRAWBUTSEDIT, 0); +} + +void fasterdraw(void) +{ + Base *base; + Mesh *me; + MFace *mface; + int toggle, a; + + if(G.obedit) return; + + /* vlaggen resetten */ + me= G.main->mesh.first; + while(me) { + me->flag &= ~ME_ISDONE; + me= me->id.next; + } + + base= FIRSTBASE; + while(base) { + if( TESTBASELIB(base) && (base->object->type==OB_MESH)) { + me= base->object->data; + if(me->id.lib==0 && (me->flag & ME_ISDONE)==0) { + me->flag |= ME_ISDONE; + mface= me->mface; + toggle= 0; + for(a=0; a<me->totface; a++) { + if( (mface->edcode & ME_V1V2) && ( (toggle++) & 1) ) { + mface->edcode-= ME_V1V2; + } + if( (mface->edcode & ME_V2V3) && ( (toggle++) & 1)) { + mface->edcode-= ME_V2V3; + } + if( (mface->edcode & ME_V3V1) && ( (toggle++) & 1)) { + mface->edcode-= ME_V3V1; + } + if( (mface->edcode & ME_V4V1) && ( (toggle++) & 1)) { + mface->edcode-= ME_V4V1; + } + if( (mface->edcode & ME_V3V4) && ( (toggle++) & 1)) { + mface->edcode-= ME_V3V4; + } + mface++; + } + } + } + base= base->next; + } + + /* belangrijk?: vlaggen weer resetten */ + me= G.main->mesh.first; + while(me) { + me->flag &= ~ME_ISDONE; + me= me->id.next; + } + + allqueue(REDRAWVIEW3D, 0); +} + +void slowerdraw(void) /* reset fasterdraw */ +{ + Base *base; + Mesh *me; + MFace *mface; + int a; + + if(G.obedit) return; + + base= FIRSTBASE; + while(base) { + if( TESTBASELIB(base) && (base->object->type==OB_MESH)) { + me= base->object->data; + if(me->id.lib==0) { + + mface= me->mface; + + for(a=0; a<me->totface; a++) { + + mface->edcode |= ME_V1V2|ME_V2V3; + mface++; + } + } + } + base= base->next; + } + + allqueue(REDRAWVIEW3D, 0); +} + + +void convert_to_triface(int all) +{ + EditVlak *evl, *evln, *next; + + evl= G.edvl.first; + while(evl) { + next= evl->next; + if(evl->v4) { + if(all || vlakselectedAND(evl, 1) ) { + + evln= addvlaklist(evl->v1, evl->v2, evl->v3, 0, evl); + evln= addvlaklist(evl->v1, evl->v3, evl->v4, 0, evl); + + if(evl->tface) { + evln->uv[1][0]= evln->uv[2][0]; + evln->uv[1][1]= evln->uv[2][1]; + evln->uv[2][0]= evln->uv[3][0]; + evln->uv[2][1]= evln->uv[3][1]; + } + + evln->col[1]= evln->col[2]; + evln->col[2]= evln->col[3]; + + BLI_remlink(&G.edvl, evl); + freevlak(evl); + } + } + evl= next; + } + +} + + +void deselectall_mesh(void) /* toggle */ +{ + EditVert *eve; + int a; + + if(G.obedit->lay & G.vd->lay) { + a= 0; + eve= G.edve.first; + while(eve) { + if(eve->f & 1) { + a= 1; + break; + } + eve= eve->next; + } + eve= G.edve.first; + while(eve) { + if(eve->h==0) { + if(a) eve->f&= -2; + else eve->f|= 1; + } + eve= eve->next; + } + tekenvertices_ext(a==0); + } + countall(); +} + + +void righthandfaces(int select) /* maakt vlakken rechtsdraaiend */ +{ + EditEdge *eed, *ed1, *ed2, *ed3, *ed4; + EditVlak *evl, *startvl; + float maxx, nor[3], cent[3]; + int totsel, found, foundone, direct, turn; + + /* op basis selectconnected om losse objecten te onderscheiden */ + + /* tel per edge hoeveel vlakken het heeft */ + + /* vind het meest linkse, voorste, bovenste vlak */ + + /* zet normaal naar buiten en de eerste richtings vlaggen in de edges */ + + /* loop object af en zet richtingen / richtingsvlaggen: alleen bij edges van 1 of 2 vlakken */ + /* dit is in feit de select connected */ + + /* indien nog (selected) vlakken niet gedaan: opnieuw vind de meest linkse ... */ + + waitcursor(1); + + eed= G.eded.first; + while(eed) { + eed->f= 0; + eed->f1= 0; + eed= eed->next; + } + + /* vlakken en edges tellen */ + totsel= 0; + evl= G.edvl.first; + while(evl) { + if(select==0 || vlakselectedAND(evl, 1) ) { + evl->f= 1; + totsel++; + evl->e1->f1++; + evl->e2->f1++; + evl->e3->f1++; + if(evl->v4) evl->e4->f1++; + } + else evl->f= 0; + + evl= evl->next; + } + + while(totsel>0) { + /* van buiten naar binnen */ + + evl= G.edvl.first; + startvl= 0; + maxx= -1.0e10; + + while(evl) { + if(evl->f) { + CalcCent3f(cent, evl->v1->co, evl->v2->co, evl->v3->co); + cent[0]= fabs(cent[0])+fabs(cent[1])+fabs(cent[2]); + + if(cent[0]>maxx) { + maxx= cent[0]; + startvl= evl; + } + } + evl= evl->next; + } + + /* eerste vlak goedzetten: normaal berekenen */ + CalcNormFloat(startvl->v1->co, startvl->v2->co, startvl->v3->co, nor); + CalcCent3f(cent, startvl->v1->co, startvl->v2->co, startvl->v3->co); + + /* eerste normaal staat zus of zo */ + if(select) { + if(select==2) { + if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] > 0.0) flipvlak(startvl); + } + else { + if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipvlak(startvl); + } + } + else if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipvlak(startvl); + + + eed= startvl->e1; + if(eed->v1==startvl->v1) eed->f= 1; + else eed->f= 2; + + eed= startvl->e2; + if(eed->v1==startvl->v2) eed->f= 1; + else eed->f= 2; + + eed= startvl->e3; + if(eed->v1==startvl->v3) eed->f= 1; + else eed->f= 2; + + eed= startvl->e4; + if(eed) { + if(eed->v1==startvl->v4) eed->f= 1; + else eed->f= 2; + } + + startvl->f= 0; + totsel--; + + /* de normalen testen */ + found= 1; + direct= 1; + while(found) { + found= 0; + if(direct) evl= G.edvl.first; + else evl= G.edvl.last; + while(evl) { + if(evl->f) { + turn= 0; + foundone= 0; + + ed1= evl->e1; + ed2= evl->e2; + ed3= evl->e3; + ed4= evl->e4; + + if(ed1->f) { + if(ed1->v1==evl->v1 && ed1->f==1) turn= 1; + if(ed1->v2==evl->v1 && ed1->f==2) turn= 1; + foundone= 1; + } + else if(ed2->f) { + if(ed2->v1==evl->v2 && ed2->f==1) turn= 1; + if(ed2->v2==evl->v2 && ed2->f==2) turn= 1; + foundone= 1; + } + else if(ed3->f) { + if(ed3->v1==evl->v3 && ed3->f==1) turn= 1; + if(ed3->v2==evl->v3 && ed3->f==2) turn= 1; + foundone= 1; + } + else if(ed4 && ed4->f) { + if(ed4->v1==evl->v4 && ed4->f==1) turn= 1; + if(ed4->v2==evl->v4 && ed4->f==2) turn= 1; + foundone= 1; + } + + if(foundone) { + found= 1; + totsel--; + evl->f= 0; + + if(turn) { + if(ed1->v1==evl->v1) ed1->f= 2; + else ed1->f= 1; + if(ed2->v1==evl->v2) ed2->f= 2; + else ed2->f= 1; + if(ed3->v1==evl->v3) ed3->f= 2; + else ed3->f= 1; + if(ed4) { + if(ed4->v1==evl->v4) ed4->f= 2; + else ed4->f= 1; + } + + flipvlak(evl); + + } + else { + if(ed1->v1== evl->v1) ed1->f= 1; + else ed1->f= 2; + if(ed2->v1==evl->v2) ed2->f= 1; + else ed2->f= 2; + if(ed3->v1==evl->v3) ed3->f= 1; + else ed3->f= 2; + if(ed4) { + if(ed4->v1==evl->v4) ed4->f= 1; + else ed4->f= 2; + } + } + } + } + if(direct) evl= evl->next; + else evl= evl->prev; + } + direct= 1-direct; + } + } + + recalc_editnormals(); + + makeDispList(G.obedit); + + waitcursor(0); +} + +static EditVert *findnearestvert(short sel) +{ + /* als sel==1 krijgen vertices met flag==1 een nadeel */ + EditVert *eve,*act=0; + static EditVert *acto=0; + short dist=100,temp,mval[2]; + + if(G.edve.first==0) return 0; + + /* projektie doen */ + calc_meshverts_ext(); /* drawobject.c */ + + /* er wordt geteld van acto->next tot last en van first tot acto */ + /* bestaat acto ? */ + eve= G.edve.first; + while(eve) { + if(eve==acto) break; + eve= eve->next; + } + if(eve==0) acto= G.edve.first; + + if(acto==0) return 0; + + /* is er een aangegeven vertex? deel 1 */ + getmouseco_areawin(mval); + eve= acto->next; + while(eve) { + if(eve->h==0) { + temp= abs(mval[0]- eve->xs)+ abs(mval[1]- eve->ys); + if( (eve->f & 1)==sel ) temp+=5; + if(temp<dist) { + act= eve; + dist= temp; + if(dist<4) break; + } + } + eve= eve->next; + } + /* is er een aangegeven vertex? deel 2 */ + if(dist>3) { + eve= G.edve.first; + while(eve) { + if(eve->h==0) { + temp= abs(mval[0]- eve->xs)+ abs(mval[1]- eve->ys); + if( (eve->f & 1)==sel ) temp+=5; + if(temp<dist) { + act= eve; + if(temp<4) break; + dist= temp; + } + if(eve== acto) break; + } + eve= eve->next; + } + } + + acto= act; + return act; +} + +static void tekenvertices_special(int mode, EditVert *act) +{ + /* voor speciale gevallen: + * mode 0: deselect geselecteerde, teken ze, behalve act + * mode 1: teken alleen act + */ + ScrArea *tempsa, *sa; + View3D *vd; + EditVert *eve; + float mat[4][4]; + int doit=0; + + /* eerst testen of er wel special vertices zijn */ + + eve= (EditVert *)G.edve.first; + while(eve) { + eve->f1= 0; + if(eve->h==0) { + if(mode==0) { + if(eve!=act && eve->f & 1) { + doit= 1; + eve->f1= 1; + eve->f -= 1; + } + } + else if(mode==1) { + if(eve==act) eve->f1= 1; + doit= 1; + } + } + eve= eve->next; + } + if(doit==0) return; + + if(G.f & (G_FACESELECT+G_DRAWFACES)) { + scrarea_queue_winredraw(curarea); + return; + } + + if(G.zbuf) glDisable(GL_DEPTH_TEST); + + glDrawBuffer(GL_FRONT); + + /* alle views aflopen */ + tempsa= curarea; + sa= G.curscreen->areabase.first; + while(sa) { + if(sa->spacetype==SPACE_VIEW3D) { + vd= sa->spacedata.first; + if(G.obedit->lay & vd->lay) { + areawinset(sa->win); + mymultmatrix(G.obedit->obmat); + + MTC_Mat4SwapMat4(G.vd->persmat, mat); + mygetsingmatrix(G.vd->persmat); + + tekenvertices(0); + tekenvertices(1); + + MTC_Mat4SwapMat4(G.vd->persmat, mat); + + sa->win_swap= WIN_FRONT_OK; + + myloadmatrix(G.vd->viewmat); + } + } + sa= sa->next; + } + if(curarea!=tempsa) areawinset(tempsa->win); + + glDrawBuffer(GL_BACK); + if(G.zbuf) glEnable(GL_DEPTH_TEST); +} + +void mouse_mesh(void) +{ + EditVert *act=0; + + act= findnearestvert(1); + if(act) { + + if((G.qual & LR_SHIFTKEY)==0) { + tekenvertices_special(0, act); + } + if( (act->f & 1)==0) act->f+= 1; + else if(G.qual & LR_SHIFTKEY) act->f-= 1; + + tekenvertices_special(1, act); + countall(); + } + + rightmouse_transform(); +} + +static void selectconnectedAll(void) +{ + EditVert *v1,*v2; + EditEdge *eed; + short flag=1,toggle=0; + + if(G.eded.first==0) return; + + while(flag==1) { + flag= 0; + toggle++; + if(toggle & 1) eed= G.eded.first; + else eed= G.eded.last; + while(eed) { + v1= eed->v1; + v2= eed->v2; + if(eed->h==0) { + if(v1->f & 1) { + if( (v2->f & 1)==0 ) { + v2->f |= 1; + flag= 1; + } + } + else if(v2->f & 1) { + if( (v1->f & 1)==0 ) { + v1->f |= 1; + flag= 1; + } + } + } + if(toggle & 1) eed= eed->next; + else eed= eed->prev; + } + } + countall(); + + tekenvertices_ext(1); + +} + + +void selectconnected_mesh(void) +{ + EditVert *eve,*v1,*v2,*act= 0; + EditEdge *eed; + short flag=1,sel,toggle=0; + + if(G.eded.first==0) return; + + if(G.qual & LR_CTRLKEY) { + selectconnectedAll(); + return; + } + + sel= 3; + if(G.qual & LR_SHIFTKEY) sel=2; + + act= findnearestvert(sel-2); + if(act==0) { + error(" Nothing indicated "); + return; + } + + /* testflaggen wissen */ + eve= G.edve.first; + while(eve) { + eve->f&= ~2; + eve= eve->next; + } + act->f= (act->f & ~3) | sel; + + while(flag==1) { + flag= 0; + toggle++; + if(toggle & 1) eed= G.eded.first; + else eed= G.eded.last; + while(eed) { + v1= eed->v1; + v2= eed->v2; + if(eed->h==0) { + if(v1->f & 2) { + if( (v2->f & 2)==0 ) { + v2->f= (v2->f & ~3) | sel; + flag= 1; + } + } + else if(v2->f & 2) { + if( (v1->f & 2)==0 ) { + v1->f= (v1->f & ~3) | sel; + flag= 1; + } + } + } + if(toggle & 1) eed= eed->next; + else eed= eed->prev; + } + } + countall(); + + tekenvertices_ext( sel==3 ); +} + + +short extrudeflag(short flag,short type) +{ + /* als type=1 worden oude extrudevlakken verwijderd (ivm spin etc) */ + /* alle verts met (flag & 'flag') extrude */ + /* van oude wordt flag 'flag' gewist, van nieuwe gezet */ + + EditVert *eve, *v1, *v2, *v3, *v4, *nextve; + EditEdge *eed, *e1, *e2, *e3, *e4, *nexted; + EditVlak *evl, *nextvl; + short sel=0, deloud= 0; + + if(G.obedit==0 || get_mesh(G.obedit)==0) return 0; + + /* de vert flag f1 wissen, hiermee test op losse geselecteerde vert */ + eve= G.edve.first; + while(eve) { + if(eve->f & flag) eve->f1= 1; + else eve->f1= 0; + eve= eve->next; + } + /* de edges tellerflag wissen, als selected op 1 zetten */ + eed= G.eded.first; + while(eed) { + if( (eed->v1->f & flag) && (eed->v2->f & flag) ) { + eed->f= 1; + eed->v1->f1= 0; + eed->v2->f1= 0; + } + else eed->f= 0; + + eed->f1= 1; /* aangeven is 'oude' edge (er worden in deze routine nieuwe gemaakt */ + + eed= eed->next; + } + + + /* in alle vlak sel een dupl.flag zetten en bijhorende edgeflags ophogen */ + + evl= G.edvl.first; + while(evl) { + evl->f= 0; + + if(vlakselectedAND(evl, flag)) { + e1= evl->e1; + e2= evl->e2; + e3= evl->e3; + e4= evl->e4; + + if(e1->f < 3) e1->f++; + if(e2->f < 3) e2->f++; + if(e3->f < 3) e3->f++; + if(e4 && e4->f < 3) e4->f++; + evl->f= 1; + } + else if(vlakselectedOR(evl, flag)) { + e1= evl->e1; + e2= evl->e2; + e3= evl->e3; + e4= evl->e4; + + if( (e1->v1->f & flag) && (e1->v2->f & flag) ) e1->f1= 2; + if( (e2->v1->f & flag) && (e2->v2->f & flag) ) e2->f1= 2; + if( (e3->v1->f & flag) && (e3->v2->f & flag) ) e3->f1= 2; + if( e4 && (e4->v1->f & flag) && (e4->v2->f & flag) ) e4->f1= 2; + } + + evl= evl->next; + } + + /* set direction of edges */ + evl= G.edvl.first; + while(evl) { + if(evl->f== 0) { + if(evl->e1->f==2) { + if(evl->e1->v1 == evl->v1) evl->e1->dir= 0; + else evl->e1->dir= 1; + } + if(evl->e2->f==2) { + if(evl->e2->v1 == evl->v2) evl->e2->dir= 0; + else evl->e2->dir= 1; + } + if(evl->e3->f==2) { + if(evl->e3->v1 == evl->v3) evl->e3->dir= 0; + else evl->e3->dir= 1; + } + if(evl->e4 && evl->e4->f==2) { + if(evl->e4->v1 == evl->v4) evl->e4->dir= 0; + else evl->e4->dir= 1; + } + } + evl= evl->next; + } + + + /* de stand van zaken nu: + eve->f1==1: losse selected vertex + + eed->f==0 : edge niet selected, geen extrude + eed->f==1 : edge selected, komt niet in vlak voor, extrude + eed->f==2 : edge selected, komt 1 keer in vlak voor, extrude + eed->f==3 : edge selected, komt in meer vlakken voor, geen extrude + + eed->f1==0: nieuwe edge + eed->f1==1: edge selected, komt in selected vlak voor, als f==3: remove + eed->f1==2: edge selected, komt in NIET selected vlak voor + + + evl->f==1 : vlak dupliceren + */ + + /* alle geselecteerde vertices kopieeren, */ + /* de pointer naar nieuwe vert in oude struct schrijven op eve->vn */ + eve= G.edve.last; + while(eve) { + eve->f&= ~128; /* wissen voor test later op losse verts */ + if(eve->f & flag) { + sel= 1; + v1= addvertlist(0); + + VECCOPY(v1->co, eve->co); + v1->f= eve->f; + eve->f-= flag; + eve->vn= v1; + } + else eve->vn= 0; + eve= eve->prev; + } + + if(sel==0) return 0; + + /* alle edges met eed->f==1 of eed->f==2 worden vlakken */ + /* als deloud==1 worden edges eed->f>2 verwijderd */ + eed= G.eded.last; + while(eed) { + nexted= eed->prev; + if( eed->f<3) { + eed->v1->f|=128; /* =geen losse vert! */ + eed->v2->f|=128; + } + if( (eed->f==1 || eed->f==2) ) { + if(eed->f1==2) deloud=1; + + /* that dir thing does work somewhat... */ + + if(eed->dir==1) addvlaklist(eed->v1, eed->v2, eed->v2->vn, eed->v1->vn, NULL); + else addvlaklist(eed->v2, eed->v1, eed->v1->vn, eed->v2->vn, NULL); + } + + eed= nexted; + } + if(deloud) { + eed= G.eded.first; + while(eed) { + nexted= eed->next; + if(eed->f==3 && eed->f1==1) { + remedge(eed); + free(eed); + } + eed= nexted; + } + } + /* de vlakken dupliceren, eventueel oude verwijderen */ + evl= G.edvl.first; + while(evl) { + nextvl= evl->next; + if(evl->f & 1) { + + v1= evl->v1->vn; + v2= evl->v2->vn; + v3= evl->v3->vn; + if(evl->v4) v4= evl->v4->vn; else v4= 0; + + addvlaklist(v1, v2, v3, v4, evl); + + if(deloud) { + BLI_remlink(&G.edvl, evl); + freevlak(evl); + } + + } + evl= nextvl; + } + /* alle verts met eve->vn!=0 + als eve->f1==1: edge maken + als flag!=128 :als deloud==1: verwijderen + */ + eve= G.edve.last; + while(eve) { + nextve= eve->prev; + if(eve->vn) { + if(eve->f1==1) addedgelist(eve,eve->vn); + else if( (eve->f & 128)==0) { + if(deloud) { + BLI_remlink(&G.edve,eve); +// free(eve); + free_editvert(eve); + eve= NULL; + } + } + } + if(eve) eve->f&= ~128; + + eve= nextve; + } + + /* debug temp: testen op consistente: + evl= G.edvl.first; + while(evl) { + e1= findedgelist(evl->v1, evl->v2); + e2= findedgelist(evl->v2, evl->v3); + e3= findedgelist(evl->v3, evl->v1); + if(e1==0 || e2==0 || e3==0) { + error("edge not in edgelist"); + break; + } + evl= evl->next; + } + */ + + return 1; +} + +void rotateflag(short flag, float *cent, float rotmat[][3]) +{ + /* alle verts met (flag & 'flag') rotate */ + + EditVert *eve; + + eve= G.edve.first; + while(eve) { + if(eve->f & flag) { + eve->co[0]-=cent[0]; + eve->co[1]-=cent[1]; + eve->co[2]-=cent[2]; + Mat3MulVecfl(rotmat,eve->co); + eve->co[0]+=cent[0]; + eve->co[1]+=cent[1]; + eve->co[2]+=cent[2]; + } + eve= eve->next; + } +} + +void translateflag(short flag, float *vec) +{ + /* alle verts met (flag & 'flag') translate */ + + EditVert *eve; + + eve= G.edve.first; + while(eve) { + if(eve->f & flag) { + eve->co[0]+=vec[0]; + eve->co[1]+=vec[1]; + eve->co[2]+=vec[2]; + } + eve= eve->next; + } +} + +short removedoublesflag(short flag, float limit) /* return aantal */ +{ + /* alle verts met (flag & 'flag') worden getest */ + EditVert *eve, *v1, *nextve; + EditEdge *eed, *e1, *nexted; + EditVlak *evl, *nextvl; + struct xvertsort *sortblock, *sb, *sb1; + struct vlaksort *vlsortblock, *vsb, *vsb1; + float dist; + int a, b, test, aantal; + + /* flag 128 wordt gewist, aantal tellen */ + eve= G.edve.first; + aantal= 0; + while(eve) { + eve->f&= ~128; + if(eve->f & flag) aantal++; + eve= eve->next; + } + if(aantal==0) return 0; + + /* geheugen reserveren en qsorten */ + sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*aantal,"sortremovedoub"); + eve= G.edve.first; + while(eve) { + if(eve->f & flag) { + sb->x= eve->co[0]+eve->co[1]+eve->co[2]; + sb->v1= eve; + sb++; + } + eve= eve->next; + } + qsort(sortblock, aantal, sizeof(struct xvertsort), vergxco); + + /* testen op doubles */ + sb= sortblock; + for(a=0; a<aantal; a++) { + eve= sb->v1; + if( (eve->f & 128)==0 ) { + sb1= sb+1; + for(b=a+1; b<aantal; b++) { + /* eerste test: simpel dist */ + dist= sb1->x - sb->x; + if(dist > limit) break; + + /* tweede test: is vertex toegestaan */ + v1= sb1->v1; + if( (v1->f & 128)==0 ) { + + dist= fabs(v1->co[0]-eve->co[0]); + if(dist<=limit) { + dist= fabs(v1->co[1]-eve->co[1]); + if(dist<=limit) { + dist= fabs(v1->co[2]-eve->co[2]); + if(dist<=limit) { + v1->f|= 128; + v1->vn= eve; + } + } + } + } + sb1++; + } + } + sb++; + } + MEM_freeN(sortblock); + + /* edges testen en opnieuw invoegen */ + eed= G.eded.first; + while(eed) { + eed->f= 0; + eed= eed->next; + } + eed= G.eded.last; + while(eed) { + nexted= eed->prev; + + if(eed->f==0) { + if( (eed->v1->f & 128) || (eed->v2->f & 128) ) { + remedge(eed); + + 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); + + if(e1) e1->f= 1; + if(e1!=eed) free(eed); + } + } + eed= nexted; + } + + /* eerst aantal testvlakken tellen */ + evl= (struct EditVlak *)G.edvl.first; + aantal= 0; + while(evl) { + evl->f= 0; + if(evl->v1->f & 128) evl->f= 1; + else if(evl->v2->f & 128) evl->f= 1; + else if(evl->v3->f & 128) evl->f= 1; + else if(evl->v4 && (evl->v4->f & 128)) evl->f= 1; + + if(evl->f==1) aantal++; + evl= evl->next; + } + + /* vlakken testen op dubbele punten en eventueel verwijderen */ + evl= (struct EditVlak *)G.edvl.first; + while(evl) { + nextvl= evl->next; + if(evl->f==1) { + + if(evl->v1->f & 128) evl->v1= evl->v1->vn; + if(evl->v2->f & 128) evl->v2= evl->v2->vn; + if(evl->v3->f & 128) evl->v3= evl->v3->vn; + if(evl->v4 && (evl->v4->f & 128)) evl->v4= evl->v4->vn; + + test= 0; + if(evl->v1==evl->v2) test+=1; + if(evl->v2==evl->v3) test+=2; + if(evl->v3==evl->v1) test+=4; + if(evl->v4==evl->v1) test+=8; + if(evl->v3==evl->v4) test+=16; + if(evl->v2==evl->v4) test+=32; + + if(test) { + if(evl->v4) { + if(test==1 || test==2) { + evl->v2= evl->v3; + evl->v3= evl->v4; + evl->v4= 0; + test= 0; + } + else if(test==8 || test==16) { + evl->v4= 0; + test= 0; + } + else { + BLI_remlink(&G.edvl, evl); + freevlak(evl); + aantal--; + } + } + else { + BLI_remlink(&G.edvl, evl); + freevlak(evl); + aantal--; + } + } + + if(test==0) { + /* edgepointers goedzetten */ + evl->e1= findedgelist(evl->v1, evl->v2); + evl->e2= findedgelist(evl->v2, evl->v3); + if(evl->v4==0) { + evl->e3= findedgelist(evl->v3, evl->v1); + evl->e4= 0; + } + else { + evl->e3= findedgelist(evl->v3, evl->v4); + evl->e4= findedgelist(evl->v4, evl->v1); + } + } + } + evl= nextvl; + } + + /* dubbele vlakken: sortblock */ + /* opnieuw tellen, nu alle selected vlakken */ + aantal= 0; + evl= G.edvl.first; + while(evl) { + evl->f= 0; + if(vlakselectedAND(evl, 1)) { + evl->f= 1; + aantal++; + } + evl= evl->next; + } + + if(aantal) { + /* dubbele vlakken: sortblock */ + vsb= vlsortblock= MEM_mallocN(sizeof(struct vlaksort)*aantal, "sortremovedoub"); + evl= G.edvl.first; + while(evl) { + if(evl->f & 1) { + if(evl->v4) vsb->x= (long) MIN4( (long)evl->v1, (long)evl->v2, (long)evl->v3, (long)evl->v4); + else vsb->x= (long) MIN3( (long)evl->v1, (long)evl->v2, (long)evl->v3); + + vsb->evl= evl; + vsb++; + } + evl= evl->next; + } + + qsort(vlsortblock, aantal, sizeof(struct vlaksort), vergvlak); + + vsb= vlsortblock; + for(a=0; a<aantal; a++) { + evl= vsb->evl; + if( (evl->f & 128)==0 ) { + vsb1= vsb+1; + + for(b=a+1; b<aantal; b++) { + + /* eerste test: zelfde poin? */ + if(vsb->x != vsb1->x) break; + + /* tweede test: is test toegestaan */ + evl= vsb1->evl; + if( (evl->f & 128)==0 ) { + if( comparevlak(evl, vsb->evl)) evl->f |= 128; + + } + vsb1++; + } + } + vsb++; + } + + MEM_freeN(vlsortblock); + + /* dubbele vlakken eruit */ + evl= (struct EditVlak *)G.edvl.first; + while(evl) { + nextvl= evl->next; + if(evl->f & 128) { + BLI_remlink(&G.edvl, evl); + freevlak(evl); + } + evl= nextvl; + } + } + + /* dubbele vertices eruit */ + a= 0; + eve= (struct EditVert *)G.edve.first; + while(eve) { + nextve= eve->next; + if(eve->f & flag) { + if(eve->f & 128) { + a++; + BLI_remlink(&G.edve, eve); + +// free(eve); + free_editvert(eve); + } + } + eve= nextve; + } + return a; /* aantal */ +} + +void xsortvert_flag(int flag) +//short flag; +{ + /* alle verts met (flag & 'flag') worden gesorteerd */ + EditVert *eve; + struct xvertsort *sortblock, *sb; + ListBase tbase; + int aantal; + + /* aantal tellen */ + eve= G.edve.first; + aantal= 0; + while(eve) { + if(eve->f & flag) aantal++; + eve= eve->next; + } + if(aantal==0) return; + + /* geheugen reserveren en qsorten */ + sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*aantal,"sortremovedoub"); + eve= G.edve.first; + while(eve) { + if(eve->f & flag) { + sb->x= eve->xs; + sb->v1= eve; + sb++; + } + eve= eve->next; + } + qsort(sortblock, aantal, sizeof(struct xvertsort), vergxco); + + /* tijdelijke listbase maken */ + tbase.first= tbase.last= 0; + sb= sortblock; + while(aantal--) { + eve= sb->v1; + BLI_remlink(&G.edve, eve); + BLI_addtail(&tbase, eve); + sb++; + } + + addlisttolist(&G.edve, &tbase); + + MEM_freeN(sortblock); +} + + +void hashvert_flag(int flag) +{ + EditVert *eve; + struct xvertsort *sortblock, *sb, onth, *newsort; + ListBase tbase; + int aantal, a, b; + + /* aantal tellen */ + eve= G.edve.first; + aantal= 0; + while(eve) { + if(eve->f & flag) aantal++; + eve= eve->next; + } + if(aantal==0) return; + + /* geheugen reserveren */ + sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*aantal,"sortremovedoub"); + eve= G.edve.first; + while(eve) { + if(eve->f & flag) { + sb->v1= eve; + sb++; + } + eve= eve->next; + } + + BLI_srand(1); + + sb= sortblock; + for(a=0; a<aantal; a++, sb++) { + b= aantal*BLI_drand(); + if(b>=0 && b<aantal) { + newsort= sortblock+b; + onth= *sb; + *sb= *newsort; + *newsort= onth; + } + } + + /* tijdelijke listbase maken */ + tbase.first= tbase.last= 0; + sb= sortblock; + while(aantal--) { + eve= sb->v1; + BLI_remlink(&G.edve, eve); + BLI_addtail(&tbase, eve); + sb++; + } + + addlisttolist(&G.edve, &tbase); + + MEM_freeN(sortblock); +} + +static unsigned int cpack_half(unsigned int col1, unsigned int col2) +{ + char *cp1, *cp2, *cp; + unsigned int col=0; + + cp1= (char *)&col1; + cp2= (char *)&col2; + cp= (char *)&col; + + cp[0]= (cp1[0]+cp2[0])>>1; + cp[1]= (cp1[1]+cp2[1])>>1; + cp[2]= (cp1[2]+cp2[2])>>1; + cp[3]= (cp1[3]+cp2[3])>>1; + + return col; +} + + +static void uv_half(float *uv, float *uv1, float *uv2) +{ + uv[0]= (uv1[0]+uv2[0])/2.0; + uv[1]= (uv1[1]+uv2[1])/2.0; + +} + +static void uv_quart(float *uv, float *uv1) +{ + uv[0]= (uv1[0]+uv1[2]+uv1[4]+uv1[6])/4.0; + 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) +{ + /* deze vreemde fie alleen bij de subdiv te gebruiken, de 'w' in de naam slaat nergens op! */ + float *uv, uvo[4][2]; + unsigned int *col, colo[4], col1, col2; + int a, v; + + memcpy(uvo, evl->uv, sizeof(uvo)); + uv= evl->uv[0]; + + memcpy(colo, evl->col, sizeof(colo)); + col= evl->col; + + if(tot==4) { + for(a=0; a<4; a++, uv+=2, col++) { + if(a==0) v= v1; + else if(a==1) v= v2; + else if(a==2) v= v3; + else v= v4; + + if(a==3 && v4==0) break; + + if(v<=4) { + uv[0]= uvo[v-1][0]; + uv[1]= uvo[v-1][1]; + *col= colo[v-1]; + } + else if(v==8) { + uv_half(uv, uvo[3], uvo[0]); + *col= cpack_half(colo[3], colo[0]); + } + else if(v==9) { + uv_quart(uv, uvo[0]); + col1= cpack_half(colo[1], colo[0]); + col2= cpack_half(colo[2], colo[3]); + *col= cpack_half(col1, col2); + } + else { + uv_half(uv, uvo[v-5], uvo[v-4]); + *col= cpack_half(colo[v-5], colo[v-4]); + } + } + } + else { + for(a=0; a<3; a++, uv+=2, col++) { + if(a==0) v= v1; + else if(a==1) v= v2; + else v= v3; + + if(v<=4) { + uv[0]= uvo[v-1][0]; + uv[1]= uvo[v-1][1]; + *col= colo[v-1]; + } + else if(v==7) { + uv_half(uv, uvo[2], uvo[0]); + *col= cpack_half(colo[2], colo[0]); + } + else { + uv_half(uv, uvo[v-5], uvo[v-4]); + *col= cpack_half(colo[v-5], colo[v-4]); + } + } + } +} + +static EditVert *vert_from_number(EditVlak *evl, int nr) +{ + switch(nr) { + case 0: + return 0; + case 1: + return evl->v1; + case 2: + return evl->v2; + case 3: + return evl->v3; + case 4: + return evl->v4; + case 5: + return evl->e1->vn; + case 6: + return evl->e2->vn; + case 7: + return evl->e3->vn; + case 8: + return evl->e4->vn; + } + + return NULL; +} + +static void addvlak_subdiv(EditVlak *evl, int val1, int val2, int val3, int val4, EditVert *eve) +{ + EditVlak *w; + EditVert *v1, *v2, *v3, *v4; + + if(val1==9) v1= eve; + else v1= vert_from_number(evl, val1); + + if(val2==9) v2= eve; + else v2= vert_from_number(evl, val2); + + if(val3==9) v3= eve; + else v3= vert_from_number(evl, val3); + + if(val4==9) v4= eve; + else v4= vert_from_number(evl, 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); + } +} + +static float smoothperc= 0.0; + +static void smooth_subdiv_vec(float *v1, float *v2, float *n1, float *n2, float *vec) +{ + float len, fac, nor[3], nor1[3], nor2[3]; + + VecSubf(nor, v1, v2); + len= 0.5*Normalise(nor); + + VECCOPY(nor1, n1); + VECCOPY(nor2, n2); + + /* cosine angle */ + fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ; + + vec[0]= fac*nor1[0]; + vec[1]= fac*nor1[1]; + vec[2]= fac*nor1[2]; + + /* cosine angle */ + fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ; + + vec[0]+= fac*nor2[0]; + vec[1]+= fac*nor2[1]; + vec[2]+= fac*nor2[2]; + + vec[0]*= smoothperc*len; + vec[1]*= smoothperc*len; + vec[2]*= smoothperc*len; +} + +static void smooth_subdiv_quad(EditVlak *evl, float *vec) +{ + + float nor1[3], nor2[3]; + float vec1[3], vec2[3]; + float cent[3]; + + /* vlr->e1->vn is new vertex inbetween v1 / v2 */ + + VecMidf(nor1, evl->v1->no, evl->v2->no); + Normalise(nor1); + VecMidf(nor2, evl->v3->no, evl->v4->no); + Normalise(nor2); + + smooth_subdiv_vec( evl->e1->vn->co, evl->e3->vn->co, nor1, nor2, vec1); + + VecMidf(nor1, evl->v2->no, evl->v3->no); + Normalise(nor1); + VecMidf(nor2, evl->v4->no, evl->v1->no); + Normalise(nor2); + + smooth_subdiv_vec( evl->e2->vn->co, evl->e4->vn->co, nor1, nor2, vec2); + + VecAddf(vec1, vec1, vec2); + + CalcCent4f(cent, evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co); + VecAddf(vec, cent, vec1); +} + +void subdivideflag(int flag, float rad, int beauty) +{ + /* divide alle vlakken met (vertflag & flag) */ + /* als rad>0.0 zet dan nieuw vert op afstand rad van 0,0,0 */ + extern float doublimit; + EditVert *eve; + EditEdge *eed, *e1, *e2, *e3, *e4, *nexted; + EditVlak *evl; + float fac, vec[3], vec1[3], len1, len2, len3; + short test; + + if(beauty & B_SMOOTH) { + short perc= 100; + + if(button(&perc, 10, 500, "Percentage:")==0) return; + + smoothperc= 0.292*perc/100.0; + } + + /* edgeflags */ + eed= G.eded.first; + while(eed) { + + if( (eed->v1->f & flag) && (eed->v2->f & flag) ) eed->f= flag; + else eed->f= 0; + + eed= eed->next; + } + + /* als beauty: opp testen en edgeflags wissen van 'lelijke' edges */ + if(beauty & B_BEAUTY) { + evl= G.edvl.first; + while(evl) { + if( vlakselectedAND(evl, flag) ) { + if(evl->v4) { + + /* opp */ + len1= AreaQ3Dfl(evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co); + if(len1 <= doublimit) { + evl->e1->f = 0; + evl->e2->f = 0; + evl->e3->f = 0; + evl->e4->f = 0; + } + else { + len1= VecLenf(evl->v1->co, evl->v2->co) + VecLenf(evl->v3->co, evl->v4->co); + len2= VecLenf(evl->v2->co, evl->v3->co) + VecLenf(evl->v1->co, evl->v4->co); + + if(len1 < len2) { + evl->e1->f = 0; + evl->e3->f = 0; + } + else if(len1 > len2) { + evl->e2->f = 0; + evl->e4->f = 0; + } + } + } + else { + + /* opp */ + len1= AreaT3Dfl(evl->v1->co, evl->v2->co, evl->v3->co); + if(len1 <= doublimit) { + evl->e1->f = 0; + evl->e2->f = 0; + evl->e3->f = 0; + } + else { + + len1= VecLenf(evl->v1->co, evl->v2->co) ; + len2= VecLenf(evl->v2->co, evl->v3->co) ; + len3= VecLenf(evl->v3->co, evl->v1->co) ; + + if(len1<len2 && len1<len3) { + evl->e1->f = 0; + } + else if(len2<len3 && len2<len1) { + evl->e2->f = 0; + } + else if(len3<len2 && len3<len1) { + evl->e3->f = 0; + } + } + } + } + evl= evl->next; + } + } + + if(beauty & B_SMOOTH) { + + vertexnormals(0); /* no1*/ + + } + + /* nieuw punt maken en in edge wegschrijven, flag wissen! is voor vlakkenmaak stuk nodig */ + eed= G.eded.first; + while(eed) { + if(eed->f & flag) { + + vec[0]= (eed->v1->co[0]+eed->v2->co[0])/2.0; + vec[1]= (eed->v1->co[1]+eed->v2->co[1])/2.0; + vec[2]= (eed->v1->co[2]+eed->v2->co[2])/2.0; + + if(rad > 0.0) { /* perf sph */ + Normalise(vec); + vec[0]*= rad; + vec[1]*= rad; + vec[2]*= rad; + } + else if(rad< 0.0) { /* fract */ + fac= rad* VecLenf(eed->v1->co, eed->v2->co); + vec1[0]= fac*BLI_drand(); + vec1[1]= fac*BLI_drand(); + vec1[2]= fac*BLI_drand(); + VecAddf(vec, vec, vec1); + } + + if(beauty & B_SMOOTH) { + smooth_subdiv_vec(eed->v1->co, eed->v2->co, eed->v1->no, eed->v2->no, vec1); + VecAddf(vec, vec, vec1); + } + + eed->vn= addvertlist(vec); + eed->vn->f= eed->v1->f; + + } + else eed->vn= 0; + + eed->f= 0; /* moet! */ + + eed= eed->next; + } + + /* alle vlakken testen op subdiv edges, 8 of 16 gevallen! */ + + evl= G.edvl.last; + while(evl) { + if( vlakselectedOR(evl, flag) ) { + e1= evl->e1; + e2= evl->e2; + e3= evl->e3; + e4= evl->e4; + + test= 0; + if(e1 && e1->vn) { + test+= 1; + e1->f= 1; + } + if(e2 && e2->vn) { + test+= 2; + e2->f= 1; + } + if(e3 && e3->vn) { + test+= 4; + e3->f= 1; + } + if(e4 && e4->vn) { + test+= 8; + e4->f= 1; + } + + if(test) { + if(evl->v4==0) { + 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==7) { /* vier nieuwe vlakken, oude vernieuwt */ + evl->v1= e1->vn; + evl->v2= e2->vn; + evl->v3= e3->vn; + set_wuv(3, evl, 1+4, 2+4, 3+4, 0); + } + else if(test==3) { + addvlak_subdiv(evl, 1+4, 2+4, 3, 0, 0); + evl->v2= e1->vn; + set_wuv(3, evl, 1, 1+4, 3, 0); + } + else if(test==6) { + addvlak_subdiv(evl, 2+4, 3+4, 1, 0, 0); + evl->v3= e2->vn; + set_wuv(3, evl, 1, 2, 2+4, 0); + } + else if(test==5) { + addvlak_subdiv(evl, 3+4, 1+4, 2, 0, 0); + evl->v1= e3->vn; + set_wuv(3, evl, 3+4, 2, 3, 0); + } + else if(test==1) { + addvlak_subdiv(evl, 1+4, 2, 3, 0, 0); + evl->v2= e1->vn; + set_wuv(3, evl, 1, 1+4, 3, 0); + } + else if(test==2) { + addvlak_subdiv(evl, 2+4, 3, 1, 0, 0); + evl->v3= e2->vn; + set_wuv(3, evl, 1, 2, 2+4, 0); + } + else if(test==4) { + addvlak_subdiv(evl, 3+4, 1, 2, 0, 0); + evl->v1= e3->vn; + set_wuv(3, evl, 3+4, 2, 3, 0); + } + evl->e1= addedgelist(evl->v1, evl->v2); + evl->e2= addedgelist(evl->v2, evl->v3); + evl->e3= addedgelist(evl->v3, evl->v1); + + } + else { + if(test==15) { + /* nog een nieuw punt toevoegen */ + CalcCent4f(vec, evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co); + + if(beauty & B_SMOOTH) { + smooth_subdiv_quad(evl, vec); /* adds */ + } + 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); + + evl->v2= e1->vn; + evl->v3= eve; + evl->v4= e4->vn; + set_wuv(4, evl, 1, 1+4, 9, 4+4); + } + else { + /* kleine hoekpunten */ + if((test & 3)==3) addvlak_subdiv(evl, 1+4, 2, 2+4, 0, 0); + if((test & 6)==6) addvlak_subdiv(evl, 2+4, 3, 3+4, 0, 0); + if((test & 12)==12) addvlak_subdiv(evl, 3+4, 4, 4+4, 0, 0); + if((test & 9)==9) addvlak_subdiv(evl, 4+4, 1, 1+4, 0, 0); + + if(test==1) { + addvlak_subdiv(evl, 1+4, 2, 3, 0, 0); + addvlak_subdiv(evl, 1+4, 3, 4, 0, 0); + evl->v2= e1->vn; + evl->v3= evl->v4; + evl->v4= 0; + set_wuv(4, evl, 1, 1+4, 4, 0); + } + else if(test==2) { + addvlak_subdiv(evl, 2+4, 3, 4, 0, 0); + addvlak_subdiv(evl, 2+4, 4, 1, 0, 0); + evl->v3= e2->vn; + evl->v4= 0; + set_wuv(4, evl, 1, 2, 2+4, 0); + } + else if(test==4) { + addvlak_subdiv(evl, 3+4, 4, 1, 0, 0); + addvlak_subdiv(evl, 3+4, 1, 2, 0, 0); + evl->v1= evl->v2; + evl->v2= evl->v3; + evl->v3= e3->vn; + evl->v4= 0; + set_wuv(4, evl, 2, 3, 3+4, 0); + } + else if(test==8) { + addvlak_subdiv(evl, 4+4, 1, 2, 0, 0); + addvlak_subdiv(evl, 4+4, 2, 3, 0, 0); + evl->v1= evl->v3; + evl->v2= evl->v4; + evl->v3= e4->vn; + evl->v4= 0; + set_wuv(4, evl, 3, 4, 4+4, 0); + } + else if(test==3) { + addvlak_subdiv(evl, 1+4, 2+4, 4, 0, 0); + addvlak_subdiv(evl, 2+4, 3, 4, 0, 0); + evl->v2= e1->vn; + evl->v3= evl->v4; + evl->v4= 0; + set_wuv(4, evl, 1, 1+4, 4, 0); + } + else if(test==6) { + addvlak_subdiv(evl, 2+4, 3+4, 1, 0, 0); + addvlak_subdiv(evl, 3+4, 4, 1, 0, 0); + evl->v3= e2->vn; + evl->v4= 0; + set_wuv(4, evl, 1, 2, 2+4, 0); + } + else if(test==12) { + addvlak_subdiv(evl, 3+4, 4+4, 2, 0, 0); + addvlak_subdiv(evl, 4+4, 1, 2, 0, 0); + evl->v1= evl->v2; + evl->v2= evl->v3; + evl->v3= e3->vn; + evl->v4= 0; + set_wuv(4, evl, 2, 3, 3+4, 0); + } + else if(test==9) { + addvlak_subdiv(evl, 4+4, 1+4, 3, 0, 0); + addvlak_subdiv(evl, 1+4, 2, 3, 0, 0); + evl->v1= evl->v3; + evl->v2= evl->v4; + evl->v3= e4->vn; + evl->v4= 0; + set_wuv(4, evl, 3, 4, 4+4, 0); + } + else if(test==5) { + addvlak_subdiv(evl, 1+4, 2, 3, 3+4, 0); + evl->v2= e1->vn; + evl->v3= e3->vn; + set_wuv(4, evl, 1, 1+4, 3+4, 4); + } + else if(test==10) { + addvlak_subdiv(evl, 2+4, 3, 4, 4+4, 0); + evl->v3= e2->vn; + evl->v4= e4->vn; + set_wuv(4, evl, 1, 2, 2+4, 4+4); + } + + else if(test==7) { + addvlak_subdiv(evl, 1+4, 2+4, 3+4, 0, 0); + evl->v2= e1->vn; + evl->v3= e3->vn; + set_wuv(4, evl, 1, 1+4, 3+4, 4); + } + else if(test==14) { + addvlak_subdiv(evl, 2+4, 3+4, 4+4, 0, 0); + evl->v3= e2->vn; + evl->v4= e4->vn; + set_wuv(4, evl, 1, 2, 2+4, 4+4); + } + else if(test==13) { + addvlak_subdiv(evl, 3+4, 4+4, 1+4, 0, 0); + evl->v4= e3->vn; + evl->v1= e1->vn; + set_wuv(4, evl, 1+4, 3, 3, 3+4); + } + else if(test==11) { + addvlak_subdiv(evl, 4+4, 1+4, 2+4, 0, 0); + evl->v1= e4->vn; + evl->v2= e2->vn; + set_wuv(4, evl, 4+4, 2+4, 3, 4); + } + } + evl->e1= addedgelist(evl->v1, evl->v2); + evl->e2= addedgelist(evl->v2, evl->v3); + if(evl->v4) evl->e3= addedgelist(evl->v3, evl->v4); + else evl->e3= addedgelist(evl->v3, evl->v1); + if(evl->v4) evl->e4= addedgelist(evl->v4, evl->v1); + else evl->e4= 0; + } + } + } + evl= evl->prev; + } + + /* alle oude edges verwijderen, eventueel nog nieuwe maken */ + eed= G.eded.first; + while(eed) { + nexted= eed->next; + if( eed->vn ) { + if(eed->f==0) { /* niet gebruikt in vlak */ + addedgelist(eed->v1,eed->vn); + addedgelist(eed->vn,eed->v2); + } + remedge(eed); + free(eed); + } + eed= nexted; + } + countall(); + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + +void adduplicateflag(int flag) +{ + /* oude verts hebben flag 128 gezet en flag 'flag' gewist + nieuwe verts hebben flag 'flag' gezet */ + EditVert *eve, *v1, *v2, *v3, *v4; + EditEdge *eed; + EditVlak *evl; + + /* eerst vertices */ + eve= G.edve.last; + while(eve) { + eve->f&= ~128; + if(eve->f & flag) { + v1= addvertlist(eve->co); + v1->f= eve->f; + eve->f-= flag; + eve->f|= 128; + eve->vn= v1; +#ifdef __NLA + /* >>>>> FIXME: Copy deformation weight ? */ + v1->totweight = eve->totweight; + if (eve->totweight){ + v1->dw = MEM_mallocN (eve->totweight * sizeof(MDeformWeight), "deformWeight"); + memcpy (v1->dw, eve->dw, eve->totweight * sizeof(MDeformWeight)); + } + else + v1->dw=NULL; +#endif + } + eve= eve->prev; + } + eed= G.eded.first; + while(eed) { + if( (eed->v1->f & 128) && (eed->v2->f & 128) ) { + v1= eed->v1->vn; + v2= eed->v2->vn; + addedgelist(v1,v2); + } + eed= eed->next; + } + + /* tenslotte de vlakken dupliceren */ + evl= G.edvl.first; + while(evl) { + if( (evl->v1->f & 128) && (evl->v2->f & 128) && (evl->v3->f & 128) ) { + if(evl->v4) { + if(evl->v4->f & 128) { + v1= evl->v1->vn; + v2= evl->v2->vn; + v3= evl->v3->vn; + v4= evl->v4->vn; + addvlaklist(v1, v2, v3, v4, evl); + } + } + else { + v1= evl->v1->vn; + v2= evl->v2->vn; + v3= evl->v3->vn; + addvlaklist(v1, v2, v3, 0, evl); + } + } + evl= evl->next; + } +} + +static void delvlakflag(int flag) +{ + /* alle vlak 3/4 verts flag + edges + losse vertices deleten */ + /* van alle verts wordt 'flag' gewist */ + EditVert *eve,*nextve; + EditEdge *eed, *nexted; + EditVlak *evl,*nextvl; + + eed= G.eded.first; + while(eed) { + eed->f= 0; + eed= eed->next; + } + + evl= G.edvl.first; + while(evl) { + nextvl= evl->next; + if(vlakselectedAND(evl, flag)) { + + evl->e1->f= 1; + evl->e2->f= 1; + evl->e3->f= 1; + if(evl->e4) { + evl->e4->f= 1; + } + + BLI_remlink(&G.edvl, evl); + freevlak(evl); + } + evl= nextvl; + } + /* alle vlakken 1, 2 (3) verts select edges behouden */ + evl= G.edvl.first; + while(evl) { + evl->e1->f= 0; + evl->e2->f= 0; + evl->e3->f= 0; + if(evl->e4) { + evl->e4->f= 0; + } + + evl= evl->next; + } + + /* alle edges testen op vertices met flag en wissen */ + eed= G.eded.first; + while(eed) { + nexted= eed->next; + if(eed->f==1) { + remedge(eed); + free(eed); + } + else if( (eed->v1->f & flag) || (eed->v2->f & flag) ) { + eed->v1->f&= ~flag; + eed->v2->f&= ~flag; + } + eed= nexted; + } + /* vertices met flag nog gezet zijn losse en worden verwijderd */ + eve= G.edve.first; + while(eve) { + nextve= eve->next; + if(eve->f & flag) { + BLI_remlink(&G.edve, eve); +// free(eve); + free_editvert(eve); + } + eve= nextve; + } + +} + +void extrude_mesh(void) +{ + short a; + + TEST_EDITMESH + + if(okee("Extrude")==0) return; + + waitcursor(1); + + a= extrudeflag(1,1); + waitcursor(0); + if(a==0) { + error("Can't extrude"); + } + else { + countall(); /* voor G.totvert in calc_meshverts() */ + calc_meshverts(); + transform('d'); + } + +} + +void adduplicate_mesh(void) +{ + + TEST_EDITMESH + + waitcursor(1); + adduplicateflag(1); + waitcursor(0); + + countall(); /* voor G.totvert in calc_meshverts() */ + transform('d'); +} + +void split_mesh(void) +{ + + TEST_EDITMESH + + if(okee(" Split ")==0) return; + + waitcursor(1); + + /* eerst duplicate maken */ + adduplicateflag(1); + /* oude vlakken hebben 3x flag 128 gezet, deze deleten */ + delvlakflag(128); + + waitcursor(0); + + countall(); + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + +void separate_mesh(void) +{ + EditVert *eve, *v1; + EditEdge *eed, *e1; + EditVlak *evl, *vl1; + Object *oldob; + Mesh *me, *men; + Base *base, *oldbase; + ListBase edve, eded, edvl; + float trans[9]; + int ok, flag; + + TEST_EDITMESH + + if(okee("Separate")==0) return; + + waitcursor(1); + + me= get_mesh(G.obedit); + if(me->key) { + error("Can't separate with vertex keys"); + return; + } + + /* we gaan de zaak als volgt neppen: + * 1. duplicate object: dit wordt de nieuwe, oude pointer onthouden + * 2: split doen als modig. + * 3. alle NIET geselecteerde verts, edges, vlakken apart zetten + * 4. loadobeditdata(): dit is de nieuwe ob + * 5. freelist en oude verts, eds, vlakken weer terughalen + */ + + /* alleen obedit geselecteerd */ + base= FIRSTBASE; + while(base) { + if(base->lay & G.vd->lay) { + if(base->object==G.obedit) base->flag |= SELECT; + else base->flag &= ~SELECT; + } + base= base->next; + } + + /* testen of split */ + ok= 0; + eed= G.eded.first; + while(eed) { + flag= (eed->v1->f & 1)+(eed->v2->f & 1); + if(flag==1) { + ok= 1; + break; + } + eed= eed->next; + } + if(ok) { + /* SPLIT: eerst duplicate maken */ + adduplicateflag(1); + /* SPLIT: oude vlakken hebben 3x flag 128 gezet, deze deleten */ + delvlakflag(128); + } + + /* apart zetten: alles wat maar enigszins NIET select is */ + edve.first= edve.last= eded.first= eded.last= edvl.first= edvl.last= 0; + eve= G.edve.first; + while(eve) { + v1= eve->next; + if((eve->f & 1)==0) { + BLI_remlink(&G.edve, eve); + BLI_addtail(&edve, eve); + } + eve= v1; + } + eed= G.eded.first; + while(eed) { + e1= eed->next; + if( (eed->v1->f & 1)==0 || (eed->v2->f & 1)==0 ) { + BLI_remlink(&G.eded, eed); + BLI_addtail(&eded, eed); + } + eed= e1; + } + evl= G.edvl.first; + while(evl) { + vl1= evl->next; + if( (evl->v1->f & 1)==0 || (evl->v2->f & 1)==0 || (evl->v3->f & 1)==0 ) { + BLI_remlink(&G.edvl, evl); + BLI_addtail(&edvl, evl); + } + evl= vl1; + } + + oldob= G.obedit; + oldbase= BASACT; + + trans[0]=trans[1]=trans[2]=trans[3]=trans[4]=trans[5]= 0.0; + trans[6]=trans[7]=trans[8]= 1.0; + G.qual |= LR_ALTKEY; /* patch om zeker te zijn van gelinkte dupli */ + adduplicate(trans); + G.qual &= ~LR_ALTKEY; + + G.obedit= BASACT->object; /* basact wordt in adduplicate() gezet */ + + men= copy_mesh(me); + set_mesh(G.obedit, men); + /* omdat nieuwe mesh een kopie is: aantal users verlagen */ + men->id.us--; + + load_editMesh(); + + BASACT->flag &= ~SELECT; + + makeDispList(G.obedit); + free_editMesh(); + + G.edve= edve; + G.eded= eded; + G.edvl= edvl; + + /* hashedges are freed now, make new! */ + eed= G.eded.first; + while(eed) { + if( findedgelist(eed->v1, eed->v2)==NULL ) + insert_hashedge(eed); + eed= eed->next; + } + + G.obedit= oldob; + BASACT= oldbase; + BASACT->flag |= SELECT; + + waitcursor(0); + + countall(); + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); + +} + +void extrude_repeat_mesh(int steps, float offs) +{ + float dvec[3], tmat[3][3], bmat[3][3]; +/* float phi; */ + short a,ok; + + TEST_EDITMESH + waitcursor(1); + + /* dvec */ + dvec[0]= G.vd->persinv[2][0]; + dvec[1]= G.vd->persinv[2][1]; + dvec[2]= G.vd->persinv[2][2]; + Normalise(dvec); + dvec[0]*= offs; + dvec[1]*= offs; + dvec[2]*= offs; + + /* base correctie */ + Mat3CpyMat4(bmat, G.obedit->obmat); + /* phi= ((struct ObData *)G.obedit->d)->vv->ws; */ + /* Mat3MulFloat(bmat, phi); */ + Mat3Inv(tmat, bmat); + Mat3MulVecfl(tmat, dvec); + + for(a=0;a<steps;a++) { + ok= extrudeflag(1,1); + if(ok==0) { + error("Can't extrude"); + break; + } + translateflag(1, dvec); + } + + countall(); + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); + waitcursor(0); +} + +void spin_mesh(int steps,int degr,float *dvec, int mode) +{ + EditVert *eve,*nextve; + float *curs, si,n[3],q[4],cmat[3][3],imat[3][3], tmat[3][3]; + float cent[3],bmat[3][3]; + float phi; + short a,ok; + + TEST_EDITMESH + + waitcursor(1); + + /* imat en centrum en afmeting */ + Mat3CpyMat4(bmat, G.obedit->obmat); + Mat3Inv(imat,bmat); + + curs= give_cursor(); + VECCOPY(cent, curs); + cent[0]-= G.obedit->obmat[3][0]; + cent[1]-= G.obedit->obmat[3][1]; + cent[2]-= G.obedit->obmat[3][2]; + Mat3MulVecfl(imat, cent); + + phi= degr*M_PI/360.0; + phi/= steps; + if(editbutflag & B_CLOCKWISE) phi= -phi; + + if(dvec) { + n[0]=n[1]= 0.0; + n[2]= 1.0; + } else { + n[0]= G.vd->viewinv[2][0]; + n[1]= G.vd->viewinv[2][1]; + n[2]= G.vd->viewinv[2][2]; + Normalise(n); + } + + q[0]= cos(phi); + si= sin(phi); + q[1]= n[0]*si; + q[2]= n[1]*si; + q[3]= n[2]*si; + QuatToMat3(q, cmat); + + Mat3MulMat3(tmat,cmat,bmat); + Mat3MulMat3(bmat,imat,tmat); + + if(mode==0) if(editbutflag & B_KEEPORIG) adduplicateflag(1); + ok= 1; + + for(a=0;a<steps;a++) { + if(mode==0) ok= extrudeflag(1,1); + else adduplicateflag(1); + if(ok==0) { + error("Can't spin"); + break; + } + rotateflag(1, cent, bmat); + if(dvec) { + Mat3MulVecfl(bmat,dvec); + translateflag(1,dvec); + } + } + + waitcursor(0); + if(ok==0) { + /* geen of alleen losse verts select, dups verwijderen */ + eve= G.edve.first; + while(eve) { + nextve= eve->next; + if(eve->f & 1) { + BLI_remlink(&G.edve,eve); +// free(eve); + free_editvert(eve); + } + eve= nextve; + } + } + countall(); + recalc_editnormals(); + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + +void screw_mesh(int steps,int turns) +{ + EditVert *eve,*v1=0,*v2=0; + EditEdge *eed; + float dvec[3], nor[3]; + + TEST_EDITMESH + + /* eerste voorwaarde: frontview! */ + if(G.vd->view!=1) { + error("Only in frontview!"); + return; + } + + /* flags wissen */ + eve= G.edve.first; + while(eve) { + eve->f1= 0; + eve= eve->next; + } + /* edges zetten flags in verts */ + eed= G.eded.first; + while(eed) { + if(eed->v1->f & 1) { + if(eed->v2->f & 1) { + /* oppassen f1 is een byte */ + if(eed->v1->f1<2) eed->v1->f1++; + if(eed->v2->f1<2) eed->v2->f1++; + } + } + eed= eed->next; + } + /* vind twee vertices met eve->f1==1, meer of minder is fout */ + eve= G.edve.first; + while(eve) { + if(eve->f1==1) { + if(v1==0) v1= eve; + else if(v2==0) v2= eve; + else { + v1=0; + break; + } + } + eve= eve->next; + } + if(v1==0 || v2==0) { + error("No curve selected"); + return; + } + + /* bereken dvec */ + dvec[0]= ( (v1->co[0]- v2->co[0]) )/(steps); + dvec[1]= ( (v1->co[1]- v2->co[1]) )/(steps); + dvec[2]= ( (v1->co[2]- v2->co[2]) )/(steps); + + VECCOPY(nor, G.obedit->obmat[2]); + + if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.000) { + dvec[0]= -dvec[0]; + dvec[1]= -dvec[1]; + dvec[2]= -dvec[2]; + } + + spin_mesh(turns*steps, turns*360, dvec, 0); + +} + +void selectswap_mesh(void) +{ + EditVert *eve; + + eve= G.edve.first; + while(eve) { + if(eve->h==0) { + if(eve->f & 1) eve->f&= ~1; + else eve->f|= 1; + } + eve= eve->next; + } + countall(); + allqueue(REDRAWVIEW3D, 0); + +} + +/* ******************************* ADD ********************* */ + +void addvert_mesh(void) +{ + EditVert *eve,*v1=0; + float *curs, mat[3][3],imat[3][3]; + + TEST_EDITMESH + + Mat3CpyMat4(mat, G.obedit->obmat); + Mat3Inv(imat, mat); + + v1= G.edve.first; + while(v1) { + if(v1->f & 1) break; + v1= v1->next; + } + eve= v1; /* voorkomen dat er nog meer select zijn */ + while(eve) { + eve->f&= ~1; + eve= eve->next; + } + + eve= addvertlist(0); + + curs= give_cursor(); + VECCOPY(eve->co, curs); + eve->xs= G.vd->mx; + eve->ys= G.vd->my; + VecSubf(eve->co, eve->co, G.obedit->obmat[3]); + + Mat3MulVecfl(imat, eve->co); + eve->f= 1; + + if(v1) { + addedgelist(v1, eve); + v1->f= 0; + } + countall(); + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); + + while(get_mbut()&R_MOUSE); + +} + +void addedgevlak_mesh(void) +{ + EditVert *eve, *neweve[4]; + EditVlak *evl; + float con1, con2, con3; + short aantal=0; + + if( (G.vd->lay & G.obedit->lay)==0 ) return; + + /* hoeveel geselecteerd ? */ + eve= G.edve.first; + while(eve) { + if(eve->f & 1) { + aantal++; + if(aantal>4) break; + neweve[aantal-1]= eve; + } + eve= eve->next; + } + if(aantal==2) { + addedgelist(neweve[0], neweve[1]); + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); + return; + } + if(aantal<2 || aantal>4) { + error("Can't make edge/face"); + return; + } + + evl= NULL; // check later + + if(aantal==3) { + if(exist_vlak(neweve[0], neweve[1], neweve[2], 0)==0) { + + evl= addvlaklist(neweve[0], neweve[1], neweve[2], 0, NULL); + + } + else error("Already a face"); + } + else if(aantal==4) { + if(exist_vlak(neweve[0], neweve[1], neweve[2], neweve[3])==0) { + + con1= convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co); + con2= convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co); + con3= convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co); + + if(con1>=con2 && con1>=con3) + evl= addvlaklist(neweve[0], neweve[1], neweve[2], neweve[3], NULL); + else if(con2>=con1 && con2>=con3) + evl= addvlaklist(neweve[0], neweve[2], neweve[3], neweve[1], NULL); + else + evl= addvlaklist(neweve[0], neweve[2], neweve[1], neweve[3], NULL); + + } + else error("Already a face"); + } + + if(evl) { // now we're calculating direction of normal + float inp; + /* dot product view mat with normal, should give info! */ + + CalcNormFloat(evl->v1->co, evl->v2->co, evl->v3->co, evl->n); + + inp= evl->n[0]*G.vd->viewmat[0][2] + evl->n[1]*G.vd->viewmat[1][2] + evl->n[2]*G.vd->viewmat[2][2]; + + if(inp < 0.0) flipvlak(evl); + } + + countall(); + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + +static void erase_edges(ListBase *l) +{ + EditEdge *ed, *nexted; + + ed = (EditEdge *) l->first; + while(ed) { + nexted= ed->next; + if( (ed->v1->f & 1) || (ed->v2->f & 1) ) { + remedge(ed); + free(ed); + } + ed= nexted; + } +} + +static void erase_faces(ListBase *l) +{ + EditVlak *f, *nextf; + + f = (EditVlak *) l->first; + + while(f) { + nextf= f->next; + if( vlakselectedOR(f, 1) ) { + BLI_remlink(l, f); + freevlak(f); + } + f = nextf; + } +} + +static void erase_vertices(ListBase *l) +{ + EditVert *v, *nextv; + + v = (EditVert *) l->first; + while(v) { + nextv= v->next; + if(v->f & 1) { + BLI_remlink(l, v); + free_editvert(v); + } + v = nextv; + } +} + +void delete_mesh(void) +{ + EditVlak *evl, *nextvl; + EditVert *eve,*nextve; + EditEdge *eed,*nexted; + short event; + int count; + + TEST_EDITMESH + + event= pupmenu("ERASE %t|Vertices%x10|Edges%x1|Faces%x2|All%x3|Edges & Faces%x4|Only Faces%x5"); + if(event<1) return; + + if(event==10 ) { + erase_edges(&G.eded); + erase_faces(&G.edvl); + erase_vertices(&G.edve); + } + else if(event==4) { + evl= G.edvl.first; + while(evl) { + nextvl= evl->next; + /* delete only faces with 2 or more vertices selected */ + count= 0; + if(evl->v1->f & 1) count++; + if(evl->v2->f & 1) count++; + if(evl->v3->f & 1) count++; + if(evl->v4 && (evl->v4->f & 1)) count++; + if(count>1) { + BLI_remlink(&G.edvl, evl); + freevlak(evl); + } + evl= nextvl; + } + eed= G.eded.first; + while(eed) { + nexted= eed->next; + if( (eed->v1->f & 1) && (eed->v2->f & 1) ) { + remedge(eed); + free(eed); + } + eed= nexted; + } + evl= G.edvl.first; + while(evl) { + nextvl= evl->next; + event=0; + if( evl->v1->f & 1) event++; + if( evl->v2->f & 1) event++; + if( evl->v3->f & 1) event++; + if(evl->v4 && (evl->v4->f & 1)) event++; + + if(event>1) { + BLI_remlink(&G.edvl, evl); + freevlak(evl); + } + evl= nextvl; + } + } + else if(event==1) { + eed= G.eded.first; + while(eed) { + nexted= eed->next; + if( (eed->v1->f & 1) && (eed->v2->f & 1) ) { + remedge(eed); + free(eed); + } + eed= nexted; + } + evl= G.edvl.first; + while(evl) { + nextvl= evl->next; + event=0; + if( evl->v1->f & 1) event++; + if( evl->v2->f & 1) event++; + if( evl->v3->f & 1) event++; + if(evl->v4 && (evl->v4->f & 1)) event++; + + if(event>1) { + BLI_remlink(&G.edvl, evl); + freevlak(evl); + } + evl= nextvl; + } + /* om losse vertices te wissen: */ + eed= G.eded.first; + while(eed) { + if( eed->v1->f & 1) eed->v1->f-=1; + if( eed->v2->f & 1) eed->v2->f-=1; + eed= eed->next; + } + eve= G.edve.first; + while(eve) { + nextve= eve->next; + if(eve->f & 1) { + BLI_remlink(&G.edve,eve); +// free(eve); + free_editvert(eve); + } + eve= nextve; + } + + } + else if(event==2) delvlakflag(1); + else if(event==3) { +// if(G.edve.first) BLI_freelist(&G.edve); + if(G.edve.first) free_editverts(&G.edve); + if(G.eded.first) BLI_freelist(&G.eded); + if(G.edvl.first) freevlaklist(&G.edvl); + } + else if(event==5) { + evl= G.edvl.first; + while(evl) { + nextvl= evl->next; + if(vlakselectedAND(evl, 1)) { + BLI_remlink(&G.edvl, evl); + freevlak(evl); + } + evl= nextvl; + } + } + + countall(); + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + + + +void add_primitiveMesh(int type) +{ + Mesh *me; + EditVert *eve, *v1=NULL, *v2, *v3, *v4=NULL, *vtop, *vdown; + float *curs, d, dia, phi, phid, cent[3], vec[3], imat[3][3], mat[3][3]; + float q[4], cmat[3][3]; + static short tot=32, seg=32, subdiv=2; + short a, b, ext=0, fill=0, totoud, newob=0; + + if(G.scene->id.lib) return; + + /* this function also comes from an info window */ + if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return; + if(G.vd==0) return; + + check_editmode(OB_MESH); + + G.f &= ~(G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT); + setcursor_space(SPACE_VIEW3D, CURSOR_STD); + + /* als geen obedit: nieuw object en in editmode gaan */ + if(G.obedit==0) { + /* add_object actually returns an object ! :-) + But it also stores the added object struct in + G.scene->basact->object (BASACT->object) */ + + add_object(OB_MESH); + base_init_from_view3d(BASACT, G.vd); + G.obedit= BASACT->object; + + where_is_object(G.obedit); + + make_editMesh(); + setcursor_space(SPACE_VIEW3D, CURSOR_EDIT); + newob= 1; + } + me= G.obedit->data; + + /* deselectall */ + eve= G.edve.first; + while(eve) { + if(eve->f & 1) eve->f&= ~1; + eve= eve->next; + } + + totoud= tot; /* onthouden en terugzetten als cube/plane */ + + /* imat en centrum en afmeting */ + Mat3CpyMat4(mat, G.obedit->obmat); + + curs= give_cursor(); + VECCOPY(cent, curs); + cent[0]-= G.obedit->obmat[3][0]; + cent[1]-= G.obedit->obmat[3][1]; + cent[2]-= G.obedit->obmat[3][2]; + + if(type!= 11) { + Mat3CpyMat4(imat, G.vd->viewmat); + Mat3MulVecfl(imat, cent); + Mat3MulMat3(cmat, imat, mat); + Mat3Inv(imat,cmat); + } else { + Mat3Inv(imat, mat); + } + + /* ext==extrudeflag, tot==aantal verts in basis */ + + switch(type) { + case 0: /* plane */ + tot= 4; + ext= 0; + fill= 1; + if(newob) rename_id((ID *)G.obedit, "Plane"); + if(newob) rename_id((ID *)me, "Plane"); + break; + case 1: /* cube */ + tot= 4; + ext= 1; + fill= 1; + if(newob) rename_id((ID *)G.obedit, "Cube"); + if(newob) rename_id((ID *)me, "Cube"); + break; + case 4: /* circle */ + if(button(&tot,3,100,"Vertices:")==0) return; + ext= 0; + fill= 0; + if(newob) rename_id((ID *)G.obedit, "Circle"); + if(newob) rename_id((ID *)me, "Circle"); + break; + case 5: /* cylinder */ + if(button(&tot,3,100,"Vertices:")==0) return; + ext= 1; + fill= 1; + if(newob) rename_id((ID *)G.obedit, "Cylinder"); + if(newob) rename_id((ID *)me, "Cylinder"); + break; + case 6: /* tube */ + if(button(&tot,3,100,"Vertices:")==0) return; + ext= 1; + fill= 0; + if(newob) rename_id((ID *)G.obedit, "Tube"); + if(newob) rename_id((ID *)me, "Tube"); + break; + case 7: /* cone */ + if(button(&tot,3,100,"Vertices:")==0) return; + ext= 0; + fill= 1; + if(newob) rename_id((ID *)G.obedit, "Cone"); + if(newob) rename_id((ID *)me, "Cone"); + break; + case 10: /* grid */ + if(button(&tot,2,100,"X res:")==0) return; + if(button(&seg,2,100,"Y res:")==0) return; + if(newob) rename_id((ID *)G.obedit, "Grid"); + if(newob) rename_id((ID *)me, "Grid"); + break; + case 11: /* UVsphere */ + if(button(&seg,3,100,"Segments:")==0) return; + if(button(&tot,3,100,"Rings:")==0) return; + if(newob) rename_id((ID *)G.obedit, "Sphere"); + if(newob) rename_id((ID *)me, "Sphere"); + break; + case 12: /* Icosphere */ + if(button(&subdiv,1,5,"Subdivision:")==0) return; + if(newob) rename_id((ID *)G.obedit, "Sphere"); + if(newob) rename_id((ID *)me, "Sphere"); + break; + case 13: /* Monkey */ + if(newob) rename_id((ID *)G.obedit, "Suzanne"); + if(newob) rename_id((ID *)me, "Suzanne"); + break; + } + + dia= sqrt(2.0)*G.vd->grid; + d= -G.vd->grid; + phid= 2*M_PI/tot; + phi= .25*M_PI; + + + if(type<10) { /* alles behalve grid of sphere */ + if(ext==0 && type!=7) d= 0; + + /* de vertices */ + vtop= vdown= v1= v2= 0; + for(b=0; b<=ext; b++) { + for(a=0; a<tot; a++) { + + vec[0]= cent[0]+dia*sin(phi); + vec[1]= cent[1]+dia*cos(phi); + vec[2]= cent[2]+d; + + Mat3MulVecfl(imat, vec); + eve= addvertlist(vec); + eve->f= 1; + if(a==0) { + if(b==0) v1= eve; + else v2= eve; + } + phi+=phid; + } + d= -d; + } + /* centrum vertices */ + if(fill && type>1) { + VECCOPY(vec,cent); + vec[2]-= -d; + Mat3MulVecfl(imat,vec); + vdown= addvertlist(vec); + if(ext || type==7) { + VECCOPY(vec,cent); + vec[2]-= d; + Mat3MulVecfl(imat,vec); + vtop= addvertlist(vec); + } + } else { + vdown= v1; + vtop= v2; + } + if(vtop) vtop->f= 1; + if(vdown) vdown->f= 1; + + /* boven en ondervlak */ + if(fill) { + if(tot==4 && (type==0 || type==1)) { + v3= v1->next->next; + if(ext) v4= v2->next->next; + + addvlaklist(v3, v1->next, v1, v3->next, NULL); + if(ext) addvlaklist(v2, v2->next, v4, v4->next, NULL); + + } + else { + v3= v1; + v4= v2; + for(a=1; a<tot; a++) { + addvlaklist(vdown, v3, v3->next, 0, NULL); + v3= v3->next; + if(ext) { + addvlaklist(vtop, v4, v4->next, 0, NULL); + v4= v4->next; + } + } + if(type>1) { + addvlaklist(vdown, v3, v1, 0, NULL); + if(ext) addvlaklist(vtop, v4, v2, 0, NULL); + } + } + } + else if(type==4) { /* wel edges bij circle */ + v3= v1; + for(a=1;a<tot;a++) { + addedgelist(v3,v3->next); + v3= v3->next; + } + addedgelist(v3,v1); + } + /* zijvlakken */ + if(ext) { + v3= v1; + v4= v2; + for(a=1; a<tot; a++) { + addvlaklist(v3, v3->next, v4->next, v4, NULL); + v3= v3->next; + v4= v4->next; + } + addvlaklist(v3, v1, v2, v4, NULL); + } + else if(type==7) { /* cone */ + v3= v1; + for(a=1; a<tot; a++) { + addvlaklist(vtop, v3->next, v3, 0, NULL); + v3= v3->next; + } + addvlaklist(vtop, v1, v3, 0, NULL); + } + + if(type<2) tot= totoud; + + } + else if(type==10) { /* grid */ + /* alle flags wissen */ + eve= G.edve.first; + while(eve) { + eve->f= 0; + eve= eve->next; + } + dia= G.vd->grid; + /* eerst een segment: de X as */ + phi= -1.0; + phid= 2.0/((float)tot-1); + for(a=0;a<tot;a++) { + vec[0]= cent[0]+dia*phi; + vec[1]= cent[1]- dia; + vec[2]= cent[2]; + Mat3MulVecfl(imat,vec); + eve= addvertlist(vec); + eve->f= 1+2+4; + if (a) addedgelist(eve->prev,eve); + phi+=phid; + } + /* extruden en transleren */ + vec[0]= vec[2]= 0.0; + vec[1]= dia*phid; + Mat3MulVecfl(imat, vec); + for(a=0;a<seg-1;a++) { + extrudeflag(2,0); + translateflag(2, vec); + } + } + else if(type==11) { /* UVsphere */ + float tmat[3][3]; + + /* alle flags wissen */ + eve= G.edve.first; + while(eve) { + eve->f= 0; + eve= eve->next; + } + + /* eerst een segment */ + phi= 0; + phid/=2; + for(a=0; a<=tot; a++) { + vec[0]= cent[0]+dia*sin(phi); + vec[1]= cent[1]; + vec[2]= cent[2]+dia*cos(phi); + Mat3MulVecfl(imat,vec); + eve= addvertlist(vec); + eve->f= 1+2+4; + if(a==0) v1= eve; + else addedgelist(eve->prev, eve); + phi+= phid; + } + + /* extruden en roteren */ + phi= M_PI/seg; + q[0]= cos(phi); + q[3]= sin(phi); + q[1]=q[2]= 0; + QuatToMat3(q, cmat); + Mat3MulMat3(tmat, cmat, mat); + Mat3MulMat3(cmat, imat, tmat); + + for(a=0; a<seg; a++) { + extrudeflag(2, 0); + rotateflag(2, v1->co, cmat); + } + removedoublesflag(4, 0.01); + } + else if(type==12) { /* Icosphere */ + EditVert *eva[12]; + + /* alle flags wissen */ + eve= G.edve.first; + while(eve) { + eve->f= 0; + eve= eve->next; + } + dia/=200; + for(a=0;a<12;a++) { + vec[0]= dia*icovert[a][0]; + vec[1]= dia*icovert[a][1]; + vec[2]= dia*icovert[a][2]; + eva[a]= addvertlist(vec); + eva[a]->f= 1+2; + } + for(a=0;a<20;a++) { + v1= eva[ icovlak[a][0] ]; + v2= eva[ icovlak[a][1] ]; + v3= eva[ icovlak[a][2] ]; + addvlaklist(v1, v2, v3, 0, NULL); + } + + dia*=200; + for(a=1; a<subdiv; a++) subdivideflag(2, dia, 0); + /* nu pas met imat */ + eve= G.edve.first; + while(eve) { + if(eve->f & 2) { + VecAddf(eve->co,eve->co,cent); + Mat3MulVecfl(imat,eve->co); + } + eve= eve->next; + } + } else if (type==13) { /* Monkey */ + extern int monkeyo, monkeynv, monkeynf; + extern signed char monkeyf[][4]; + extern signed char monkeyv[][3]; + EditVert **tv= MEM_mallocN(sizeof(*tv)*monkeynv*2, "tv"); + int i; + + for (i=0; i<monkeynv; i++) { + float v[3]; + v[0]= (monkeyv[i][0]+127)/128.0, v[1]= monkeyv[i][1]/128.0, v[2]= monkeyv[i][2]/128.0; + tv[i]= addvertlist(v); + tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]:addvertlist(v); + } + for (i=0; i<monkeynf; i++) { + addvlaklist(tv[monkeyf[i][0]+i-monkeyo], tv[monkeyf[i][1]+i-monkeyo], tv[monkeyf[i][2]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeyf[i][3]+i-monkeyo]:NULL, NULL); + addvlaklist(tv[monkeynv+monkeyf[i][2]+i-monkeyo], tv[monkeynv+monkeyf[i][1]+i-monkeyo], tv[monkeynv+monkeyf[i][0]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeynv+monkeyf[i][3]+i-monkeyo]:NULL, NULL); + } + + MEM_freeN(tv); + } + + if(type!=0 && type!=10) righthandfaces(1); + countall(); + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWIPO, 0); + allqueue(REDRAWHEADERS, 0); + allqueue(REDRAWINFO, 1); /* 1, want header->win==0! */ + allqueue(REDRAWBUTSEDIT, 0); + makeDispList(G.obedit); + + if (type==13) notice("Oooh Oooh Oooh"); +} + +void vertexsmooth(void) +{ + struct EditVert *eve; + struct EditEdge *eed; + float *adror, *adr, fac; + float fvec[3]; + int teller=0; + + if(G.obedit==0) return; + + /* aantal tellen */ + eve= G.edve.first; + while(eve) { + if(eve->f & 1) teller++; + eve= eve->next; + } + if(teller==0) return; + + adr=adror= (float *)MEM_callocN(3*sizeof(float *)*teller, "vertsmooth"); + eve= G.edve.first; + while(eve) { + if(eve->f & 1) { + eve->vn= (EditVert *)adr; + eve->f1= 0; + adr+= 3; + } + eve= eve->next; + } + + eed= G.eded.first; + while(eed) { + if( (eed->v1->f & 1) || (eed->v2->f & 1) ) { + fvec[0]= (eed->v1->co[0]+eed->v2->co[0])/2.0; + fvec[1]= (eed->v1->co[1]+eed->v2->co[1])/2.0; + fvec[2]= (eed->v1->co[2]+eed->v2->co[2])/2.0; + + if((eed->v1->f & 1) && eed->v1->f1<255) { + eed->v1->f1++; + VecAddf((float *)eed->v1->vn, (float *)eed->v1->vn, fvec); + } + if((eed->v2->f & 1) && eed->v2->f1<255) { + eed->v2->f1++; + VecAddf((float *)eed->v2->vn, (float *)eed->v2->vn, fvec); + } + } + eed= eed->next; + } + + eve= G.edve.first; + while(eve) { + if(eve->f & 1) { + if(eve->f1) { + adr= (float *)eve->vn; + fac= 0.5/(float)eve->f1; + + eve->co[0]= 0.5*eve->co[0]+fac*adr[0]; + eve->co[1]= 0.5*eve->co[1]+fac*adr[1]; + eve->co[2]= 0.5*eve->co[2]+fac*adr[2]; + } + eve->vn= 0; + } + eve= eve->next; + } + MEM_freeN(adror); + + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + + +void vertexnoise(void) +{ + extern float Tin; + Material *ma; + Tex *tex; + EditVert *eve; + float b2, ofs, vec[3]; + + if(G.obedit==0) return; + + ma= give_current_material(G.obedit, G.obedit->actcol); + if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) { + return; + } + tex= ma->mtex[0]->tex; + + ofs= tex->turbul/200.0; + + eve= (struct EditVert *)G.edve.first; + while(eve) { + if(eve->f & 1) { + + if(tex->type==TEX_STUCCI) { + + b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]); + if(tex->stype) ofs*=(b2*b2); + vec[0]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2])); + vec[1]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2])); + vec[2]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs)); + + VecAddf(eve->co, eve->co, vec); + } + else { + + externtex(ma->mtex[0], eve->co); + + eve->co[2]+= 0.05*Tin; + } + } + eve= eve->next; + } + + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + +void hide_mesh(int swap) +{ + struct EditVert *eve; + struct EditEdge *eed; + + if(G.obedit==0) return; + + if(swap) { + eve= G.edve.first; + while(eve) { + if((eve->f & 1)==0) { + eve->xs= 3200; + eve->h= 1; + } + eve= eve->next; + } + } + else { + eve= G.edve.first; + while(eve) { + if(eve->f & 1) { + eve->f-=1; + eve->xs= 3200; + eve->h= 1; + } + eve= eve->next; + } + } + eed= G.eded.first; + while(eed) { + if(eed->v1->h || eed->v2->h) eed->h= 1; + else eed->h= 0; + eed= eed->next; + } + + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + + +void reveal_mesh(void) +{ + struct EditVert *eve; + struct EditEdge *eed; + + if(G.obedit==0) return; + + eve= G.edve.first; + while(eve) { + if(eve->h) { + eve->h= 0; + eve->f|=1; + } + eve= eve->next; + } + + eed= G.eded.first; + while(eed) { + eed->h= 0; + eed= eed->next; + } + + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + +static float convex(float *v1, float *v2, float *v3, float *v4) +{ + float cross[3], test[3]; + float inpr; + + CalcNormFloat(v1, v2, v3, cross); + CalcNormFloat(v1, v3, v4, test); + + inpr= cross[0]*test[0]+cross[1]*test[1]+cross[2]*test[2]; + + return inpr; +} + +/* returns vertices of two adjacent triangles forming a quad + - can be righthand or lefthand + + 4-----3 + |\ | + | \ 2 | <- evl1 + | \ | + evl-> | 1 \ | + | \| + 1-----2 + +*/ +#define VTEST(face, num, other) \ + (face->v##num != other->v1 && face->v##num != other->v2 && face->v##num != other->v3) + +static void givequadverts(EditVlak *evl, EditVlak *evl1, EditVert **v1, EditVert **v2, EditVert **v3, EditVert **v4, float **uv, unsigned int *col) +{ + if VTEST(evl, 1, evl1) { + //if(evl->v1!=evl1->v1 && evl->v1!=evl1->v2 && evl->v1!=evl1->v3) { + *v1= evl->v1; + *v2= evl->v2; + uv[0] = evl->uv[0]; + uv[1] = evl->uv[1]; + col[0] = evl->col[0]; + col[1] = evl->col[1]; + } + else if VTEST(evl, 2, evl1) { + //else if(evl->v2!=evl1->v1 && evl->v2!=evl1->v2 && evl->v2!=evl1->v3) { + *v1= evl->v2; + *v2= evl->v3; + uv[0] = evl->uv[1]; + uv[1] = evl->uv[2]; + col[0] = evl->col[1]; + col[1] = evl->col[2]; + } + else if VTEST(evl, 3, evl1) { + // else if(evl->v3!=evl1->v1 && evl->v3!=evl1->v2 && evl->v3!=evl1->v3) { + *v1= evl->v3; + *v2= evl->v1; + uv[0] = evl->uv[2]; + uv[1] = evl->uv[0]; + col[0] = evl->col[2]; + col[1] = evl->col[0]; + } + + if VTEST(evl1, 1, evl) { + // if(evl1->v1!=evl->v1 && evl1->v1!=evl->v2 && evl1->v1!=evl->v3) { + *v3= evl1->v1; + uv[2] = evl1->uv[0]; + col[2] = evl1->col[0]; + + *v4= evl1->v2; + uv[3] = evl1->uv[1]; + col[3] = evl1->col[1]; +/* +if(evl1->v2== *v2) { + *v4= evl1->v3; + uv[3] = evl1->uv[2]; + } else { + *v4= evl1->v2; + uv[3] = evl1->uv[1]; + } + */ + } + else if VTEST(evl1, 2, evl) { + // else if(evl1->v2!=evl->v1 && evl1->v2!=evl->v2 && evl1->v2!=evl->v3) { + *v3= evl1->v2; + uv[2] = evl1->uv[1]; + col[2] = evl1->col[1]; + + *v4= evl1->v3; + uv[3] = evl1->uv[2]; + col[3] = evl1->col[2]; +/* +if(evl1->v3== *v2) { + *v4= evl1->v1; + uv[3] = evl1->uv[0]; + } else { + *v4= evl1->v3; + uv[3] = evl1->uv[2]; + } + */ + } + else if VTEST(evl1, 3, evl) { + // else if(evl1->v3!=evl->v1 && evl1->v3!=evl->v2 && evl1->v3!=evl->v3) { + *v3= evl1->v3; + uv[2] = evl1->uv[2]; + col[2] = evl1->col[2]; + + *v4= evl1->v1; + uv[3] = evl1->uv[0]; + col[3] = evl1->col[0]; +/* +if(evl1->v1== *v2) { + *v4= evl1->v2; + uv[3] = evl1->uv[3]; + } else { + *v4= evl1->v1; + uv[3] = evl1->uv[0]; + } + */ + } + else { + pupmenu("Wanna crash?%t|Yes Please!%x1"); + return; + } + +} + + +/* ook weer twee zeer vreemde 'patch' functies om de uv van tfaces te bewaren */ +/* +static float *set_correct_uv(EditVert *eve, EditVlak **evla) +{ + + if(eve== evla[1]->v3) return evla[1]->uv[2]; + if(eve== evla[0]->v3) return evla[0]->uv[2]; + if(eve== evla[1]->v2) return evla[1]->uv[1]; + if(eve== evla[0]->v2) return evla[0]->uv[1]; + if(eve== evla[1]->v1) return evla[1]->uv[0]; + if(eve== evla[0]->v1) return evla[0]->uv[0]; + return 0; +} + +crazy code commented out.. +static void restore_wuv(EditVlak *evl, void **evla) +{ + int *lp; + + lp= (int *)set_correct_uv(evl->v1, (EditVlak **)evla); + ((int *)(evl->uv[0]))[0]= lp[0]; + ((int *)(evl->uv[0]))[4]= lp[4]; + + lp= (int *)set_correct_uv(evl->v2, (EditVlak **)evla); + ((int *)(evl->uv[1]))[0]= lp[0]; + ((int *)(evl->uv[1]))[4]= lp[4]; + + lp= (int *)set_correct_uv(evl->v3, (EditVlak **)evla); + ((int *)(evl->uv[2]))[0]= lp[0]; + ((int *)(evl->uv[2]))[4]= lp[4]; + +} +*/ + + +/* Helper functions for edge/quad edit features*/ +/* + +*/ + +static void untag_edges(EditVlak *f) +{ + f->e1->f = 0; + f->e2->f = 0; + if (f->e3) f->e3->f = 0; + if (f->e4) f->e4->f = 0; +} + +#if 0 +static void mark_clear_edges(EditVlak *f) +{ + f->e1->f1 = 1; + f->e2->f1 = 1; + if (f->e3) f->e3->f1 = 1; + if (f->e4) f->e4->f1 = 1; +} +#endif + +static int count_edges(EditEdge *ed) +{ + int totedge = 0; + while(ed) { + ed->vn= 0; + if( (ed->v1->f & 1) && (ed->v2->f & 1) ) totedge++; + ed= ed->next; + } + return totedge; +} + +/** remove and free list of tagged edges */ +static void free_tagged_edgelist(EditEdge *eed) +{ + EditEdge *nexted; + + while(eed) { + nexted= eed->next; + if(eed->f1) { + remedge(eed); + free(eed); + } + eed= nexted; + } +} +/** remove and free list of tagged faces */ + +static void free_tagged_facelist(EditVlak *evl) +{ + EditVlak *nextvl; + + while(evl) { + nextvl= evl->next; + if(evl->f1) { + BLI_remlink(&G.edvl, evl); + freevlak(evl); + } + evl= nextvl; + } +} + +typedef EditVlak *EVPtr; +typedef EVPtr EVPTuple[2]; + +/** builds EVPTuple array evla of face tuples (in fact pointers to EditVlaks) + sharing one edge. + arguments: selected edge list, face list. + Edges will also be tagged accordingly (see eed->f) */ + +static int collect_quadedges(EVPTuple *evla, EditEdge *eed, EditVlak *evl) +{ + int i = 0; + EditEdge *e1, *e2, *e3; + EVPtr *evp; + + /* run through edges, if selected, set pointer edge-> facearray */ + while(eed) { + eed->f= 0; + eed->f1= 0; + if( (eed->v1->f & 1) && (eed->v2->f & 1) ) { + eed->vn= (EditVert *) (&evla[i]); + i++; + } + eed= eed->next; + } + + + /* find edges pointing to 2 faces by procedure: + + - run through faces and their edges, increase + face counter e->f for each face + */ + + while(evl) { + evl->f1= 0; + if(evl->v4==0) { /* if triangle */ + if(vlakselectedAND(evl, 1)) { + + e1= evl->e1; + e2= evl->e2; + e3= evl->e3; + if(e1->f<3) { + if(e1->f<2) { + evp= (EVPtr *) e1->vn; + evp[(int)e1->f]= evl; + } + e1->f+= 1; + } + if(e2->f<3) { + if(e2->f<2) { + evp= (EVPtr *) e2->vn; + evp[(int)e2->f]= evl; + } + e2->f+= 1; + } + if(e3->f<3) { + if(e3->f<2) { + evp= (EVPtr *) e3->vn; + evp[(int)e3->f]= evl; + } + e3->f+= 1; + } + } + } + evl= evl->next; + } + return i; +} + + +void join_triangles(void) +{ + EditVert *v1, *v2, *v3, *v4; + EditVlak *evl, *w; + EVPTuple *evlar; + EVPtr *evla; + EditEdge *eed, *nexted; + int totedge, ok; + float *uv[4]; + unsigned int col[4]; + + + totedge = count_edges(G.eded.first); + if(totedge==0) return; + + evlar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "jointris"); + + ok = collect_quadedges(evlar, G.eded.first, G.edvl.first); + if (G.f & G_DEBUG) { + printf("edges selected: %d\n", ok); + } + + eed= G.eded.first; + while(eed) { + nexted= eed->next; + + if(eed->f==2) { /* points to 2 faces */ + + evla= (EVPtr *) eed->vn; + + /* don't do it if flagged */ + + ok= 1; + evl= evla[0]; + if(evl->e1->f1 || evl->e2->f1 || evl->e3->f1) ok= 0; + evl= evla[1]; + if(evl->e1->f1 || evl->e2->f1 || evl->e3->f1) ok= 0; + + if(ok) { + /* test convex */ + givequadverts(evla[0], evla[1], &v1, &v2, &v3, &v4, uv, col); + +/* + 4-----3 4-----3 + |\ | | | + | \ 1 | | | + | \ | -> | | + | 0 \ | | | + | \| | | + 1-----2 1-----2 +*/ + /* make new faces */ + if( convex(v1->co, v2->co, v3->co, v4->co) > 0.01) { + if(exist_vlak(v1, v2, v3, v4)==0) { + w = addvlaklist(v1, v2, v3, v4, evla[0]); + untag_edges(w); + if (w->tface) { + UVCOPY(w->uv[0], uv[0]); + UVCOPY(w->uv[1], uv[1]); + UVCOPY(w->uv[2], uv[2]); + UVCOPY(w->uv[3], uv[3]); + } + memcpy(w->col, col, sizeof(w->col)); + } + /* tag as to-be-removed */ + FACE_MARKCLEAR(evla[0]); + FACE_MARKCLEAR(evla[1]); + eed->f1 = 1; + } /* endif test convex */ + } + } + eed= nexted; + } + free_tagged_edgelist(G.eded.first); + free_tagged_facelist(G.edvl.first); + + MEM_freeN(evlar); + + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); + +} + +/* quick hack, basically a copy of beauty_fill */ +void edge_flip(void) +{ + EditVert *v1, *v2, *v3, *v4; + EditEdge *eed, *nexted; + EditVlak *evl, *w; + //void **evlar, **evla; + EVPTuple *evlar; + EVPtr *evla; + + float *uv[4]; + unsigned int col[4]; + + int totedge, ok; + + /* - alle geselecteerde edges met 2 vlakken + * - vind die vlakken: opslaan in edges (extra datablok) + * - per edge: - test convex + * - test edge: flip? + - zoja: remedge, addedge, alle randedges nieuwe vlakpointers + */ + + totedge = count_edges(G.eded.first); + if(totedge==0) return; + + /* temporary array for : edge -> face[1], face[2] */ + evlar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "edgeflip"); + + ok = collect_quadedges(evlar, G.eded.first, G.edvl.first); + + eed= G.eded.first; + while(eed) { + nexted= eed->next; + + if(eed->f==2) { /* points to 2 faces */ + + evla= (EVPtr *) eed->vn; + + /* don't do it if flagged */ + + ok= 1; + evl= evla[0]; + if(evl->e1->f1 || evl->e2->f1 || evl->e3->f1) ok= 0; + evl= evla[1]; + if(evl->e1->f1 || evl->e2->f1 || evl->e3->f1) ok= 0; + + if(ok) { + /* test convex */ + givequadverts(evla[0], evla[1], &v1, &v2, &v3, &v4, uv, col); + +/* + 4-----3 4-----3 + |\ | | /| + | \ 1 | | 1 / | + | \ | -> | / | + | 0 \ | | / 0 | + | \| |/ | + 1-----2 1-----2 +*/ + /* make new faces */ + if (v1 && v2 && v3){ + if( convex(v1->co, v2->co, v3->co, v4->co) > 0.01) { + if(exist_vlak(v1, v2, v3, v4)==0) { + w = addvlaklist(v1, v2, v3, 0, evla[1]); + + untag_edges(w); + if (w->tface) { + UVCOPY(w->uv[0], uv[0]); + UVCOPY(w->uv[1], uv[1]); + UVCOPY(w->uv[2], uv[2]); + } + w->col[0] = col[0]; w->col[1] = col[1]; w->col[2] = col[2]; + + w = addvlaklist(v1, v3, v4, 0, evla[1]); + untag_edges(w); + if (w->tface) { + UVCOPY(w->uv[0], uv[0]); + UVCOPY(w->uv[1], uv[2]); + UVCOPY(w->uv[2], uv[3]); + } + w->col[0] = col[0]; w->col[1] = col[2]; w->col[2] = col[3]; + + /* erase old faces and edge */ + } + /* tag as to-be-removed */ + FACE_MARKCLEAR(evla[1]); + FACE_MARKCLEAR(evla[0]); + eed->f1 = 1; + + } /* endif test convex */ + } + } + } + eed= nexted; + } + + /* clear tagged edges and faces: */ + free_tagged_edgelist(G.eded.first); + free_tagged_facelist(G.edvl.first); + + MEM_freeN(evlar); + + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + +void beauty_fill(void) +{ + EditVert *v1, *v2, *v3, *v4; + EditEdge *eed, *nexted; + EditEdge dia1, dia2; + EditVlak *evl, *w; + // void **evlar, **evla; + EVPTuple *evlar; + EVPtr *evla; + float *uv[4]; + unsigned int col[4]; + float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2; + int totedge, ok, notbeauty=8, onedone; + + /* - alle geselecteerde edges met 2 vlakken + * - vind die vlakken: opslaan in edges (extra datablok) + * - per edge: - test convex + * - test edge: flip? + - zoja: remedge, addedge, alle randedges nieuwe vlakpointers + */ + + totedge = count_edges(G.eded.first); + if(totedge==0) return; + + if(okee("Beauty Fill")==0) return; + + /* tempblok met vlakpointers */ + evlar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "beautyfill"); + + while (notbeauty) { + notbeauty--; + + ok = collect_quadedges(evlar, G.eded.first, G.edvl.first); + + /* gaatie */ + onedone= 0; + + eed= G.eded.first; + while(eed) { + nexted= eed->next; + + if(eed->f==2) { + + evla = (EVPtr *) eed->vn; + + /* geen van de vlakken mag al gedaan zijn */ + ok= 1; + evl= evla[0]; + if(evl->e1->f1 || evl->e2->f1 || evl->e3->f1) ok= 0; + evl= evla[1]; + if(evl->e1->f1 || evl->e2->f1 || evl->e3->f1) ok= 0; + + if(ok) { + /* test convex */ + givequadverts(evla[0], evla[1], &v1, &v2, &v3, &v4, uv, col); + if( convex(v1->co, v2->co, v3->co, v4->co) > -0.5) { + + /* test edges */ + if( ((long)v1) > ((long)v3) ) { + dia1.v1= v3; + dia1.v2= v1; + } + else { + dia1.v1= v1; + dia1.v2= v3; + } + + if( ((long)v2) > ((long)v4) ) { + dia2.v1= v4; + dia2.v2= v2; + } + else { + dia2.v1= v2; + dia2.v2= v4; + } + + /* testregel: + * de oppervlakte gedeeld door de totale edgelengte + * + */ + + len1= VecLenf(v1->co, v2->co); + len2= VecLenf(v2->co, v3->co); + len3= VecLenf(v3->co, v4->co); + len4= VecLenf(v4->co, v1->co); + len5= VecLenf(v1->co, v3->co); + len6= VecLenf(v2->co, v4->co); + + opp1= AreaT3Dfl(v1->co, v2->co, v3->co); + opp2= AreaT3Dfl(v1->co, v3->co, v4->co); + + fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5); + + opp1= AreaT3Dfl(v2->co, v3->co, v4->co); + opp2= AreaT3Dfl(v2->co, v4->co, v1->co); + + fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6); + + ok= 0; + if(fac1 > fac2) { + if(dia2.v1==eed->v1 && dia2.v2==eed->v2) { + eed->f1= 1; + evl= evla[0]; + evl->f1= 1; + evl= evla[1]; + evl->f1= 1; + + w= addvlaklist(v1, v2, v3, 0, evl); + if (w->tface) { + UVCOPY(w->uv[0], uv[0]); + UVCOPY(w->uv[1], uv[1]); + UVCOPY(w->uv[2], uv[2]); + } + w->col[0] = col[0]; w->col[1] = col[1]; w->col[2] = col[2]; + w= addvlaklist(v1, v3, v4, 0, evl); + if (w->tface) { + UVCOPY(w->uv[0], uv[0]); + UVCOPY(w->uv[1], uv[2]); + UVCOPY(w->uv[2], uv[3]); + } + w->col[0] = col[0]; w->col[1] = col[2]; w->col[2] = col[3]; + + onedone= 1; + } + } + else if(fac1 < fac2) { + if(dia1.v1==eed->v1 && dia1.v2==eed->v2) { + eed->f1= 1; + evl= evla[0]; + evl->f1= 1; + evl= evla[1]; + evl->f1= 1; + + w= addvlaklist(v2, v3, v4, 0, evl); + if (w->tface) { + UVCOPY(w->uv[0], uv[1]); + UVCOPY(w->uv[1], uv[3]); + UVCOPY(w->uv[2], uv[4]); + } + + w= addvlaklist(v1, v2, v4, 0, evl); + if (w->tface) { + UVCOPY(w->uv[0], uv[0]); + UVCOPY(w->uv[1], uv[1]); + UVCOPY(w->uv[2], uv[3]); + } + onedone= 1; + } + } + } + } + + } + eed= nexted; + } + + free_tagged_edgelist(G.eded.first); + free_tagged_facelist(G.edvl.first); + + if(onedone==0) break; + } + + MEM_freeN(evlar); + + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + +/** tests whether selected mesh objects have tfaces */ +static int testSelected_TfaceMesh(void) +{ + Base *base; + Mesh *me; + + base = FIRSTBASE; + while (base) { + if TESTBASE(base) { + if(base->object->type==OB_MESH) { + me= base->object->data; + if (me->tface) + return 1; + } + } + base= base->next; + } + return 0; +} + +void join_mesh(void) +{ + Base *base, *nextb; + Object *ob; + Material **matar, *ma; + Mesh *me; + MVert *mvert, *mvertmain; + MFace *mface = NULL, *mfacemain; + TFace *tface = NULL, *tfacemain; + unsigned int *mcol=NULL, *mcolmain; + float imat[4][4], cmat[4][4]; + int a, b, totcol, totvert=0, totface=0, ok=0, vertofs, map[MAXMAT]; +#ifdef __NLA + int i, j, index; + bDeformGroup *dg, *odg; + MDeformVert *dvert, *dvertmain; +#endif + + if(G.obedit) return; + + ob= OBACT; + if(!ob || ob->type!=OB_MESH) return; + + /* tellen */ + + base= FIRSTBASE; + while(base) { + if TESTBASE(base) { + if(base->object->type==OB_MESH) { + me= base->object->data; + totvert+= me->totvert; + totface+= me->totface; + + if(base->object == ob) ok= 1; + } + } + base= base->next; + } + + /* zodoende is het aktieve object altijd select */ + if(ok==0) return; + + if(totvert==0 || totvert>65000) return; + + if(okee("Join selected Meshes")==0) return; + + /* nieuwe materiaal indexen en hoofdarray */ + matar= MEM_callocN(sizeof(void *)*MAXMAT, "join_mesh"); + totcol= ob->totcol; + + /* obact materials in nieuw hoofdarray, is mooiere start! */ + for(a=1; a<=ob->totcol; a++) { + matar[a-1]= give_current_material(ob, a); + id_us_plus((ID *)matar[a-1]); + /* id->us ophogen: wordt ook verlaagd */ + } + + base= FIRSTBASE; + while(base) { + if TESTBASE(base) { + if(ob!=base->object && base->object->type==OB_MESH) { + me= base->object->data; +#ifdef __NLA + // Join this object's vertex groups to the base one's + for (dg=base->object->defbase.first; dg; dg=dg->next){ + /* See if this group exists in the object */ + for (odg=ob->defbase.first; odg; odg=odg->next){ + if (!strcmp(odg->name, dg->name)){ + break; + } + } + if (!odg){ + odg = MEM_callocN (sizeof(bDeformGroup), "deformGroup"); + memcpy (odg, dg, sizeof(bDeformGroup)); + BLI_addtail(&ob->defbase, odg); + } + + } + if (ob->defbase.first && ob->actdef==0) + ob->actdef=1; +#endif + if(me->totvert) { + for(a=1; a<=base->object->totcol; a++) { + ma= give_current_material(base->object, a); + if(ma) { + for(b=0; b<totcol; b++) { + if(ma == matar[b]) break; + } + if(b==totcol) { + matar[b]= ma; + ma->id.us++; + totcol++; + } + if(totcol>=MAXMAT-1) break; + } + } + } + } + if(totcol>=MAXMAT-1) break; + } + base= base->next; + } + + me= ob->data; + mvert= mvertmain= MEM_mallocN(totvert*sizeof(MVert), "joinmesh1"); + + if (totface) mface= mfacemain= MEM_mallocN(totface*sizeof(MFace), "joinmesh2"); + else mfacemain= 0; + + if(me->mcol) mcol= mcolmain= MEM_callocN(totface*4*sizeof(int), "joinmesh3"); + else mcolmain= 0; + + /* if active object doesn't have Tfaces, but one in the selection does, + make TFaces for active, so we don't lose texture information in the + join process */ + if(me->tface || testSelected_TfaceMesh()) tface= tfacemain= MEM_callocN(totface*4*sizeof(TFace), "joinmesh4"); + else + tfacemain= 0; + +#ifdef __NLA + if(me->dvert) + dvert= dvertmain= MEM_callocN(totvert*sizeof(MDeformVert), "joinmesh5"); + else dvert=dvertmain= NULL; +#endif + + vertofs= 0; + + /* alle geselecteerde meshes invers transformen in obact */ + Mat4Invert(imat, ob->obmat); + + base= FIRSTBASE; + while(base) { + nextb= base->next; + if TESTBASE(base) { + if(base->object->type==OB_MESH) { + + me= base->object->data; + + if(me->totvert) { + + memcpy(mvert, me->mvert, me->totvert*sizeof(MVert)); + +#ifdef __NLA + copy_dverts(dvert, me->dvert, me->totvert); + + /* >>>>> FIXME: Ensure that deformation groups are updated correctly */ + /* OLD VERSION */ + /* + for (i=0; i<me->totvert; i++){ + for (j=0; j<mvert[i].totweight; j++){ + // Find the old vertex group + odg = BLI_findlink (&base->object->defbase, mvert[i].dw[j].def_nr); + + // Search for a match in the new object + for (dg=ob->defbase.first, index=0; dg; dg=dg->next, index++){ + if (!strcmp(dg->name, odg->name)){ + mvert[i].dw[j].def_nr = index; + break; + } + } + } + } + */ + /* NEW VERSION */ + if (dvertmain){ + for (i=0; i<me->totvert; i++){ + for (j=0; j<dvert[i].totweight; j++){ + // Find the old vertex group + odg = BLI_findlink (&base->object->defbase, dvert[i].dw[j].def_nr); + + // Search for a match in the new object + for (dg=ob->defbase.first, index=0; dg; dg=dg->next, index++){ + if (!strcmp(dg->name, odg->name)){ + dvert[i].dw[j].def_nr = index; + break; + } + } + } + } + dvert+=me->totvert; + } + +#endif + if(base->object != ob) { + /* let op: matmul omkeren is ECHT fout */ + Mat4MulMat4(cmat, base->object->obmat, imat); + + a= me->totvert; + while(a--) { + Mat4MulVecfl(cmat, mvert->co); + mvert++; + } + } + else mvert+= me->totvert; + + if(mcolmain) { + if(me->mcol) memcpy(mcol, me->mcol, me->totface*4*4); + mcol+= 4*me->totface; + } + } + if(me->totface) { + + /* mapping maken voor materialen */ + memset(map, 0, 4*MAXMAT); + for(a=1; a<=base->object->totcol; a++) { + ma= give_current_material(base->object, a); + if(ma) { + for(b=0; b<totcol; b++) { + if(ma == matar[b]) { + map[a-1]= b; + break; + } + } + } + } + + memcpy(mface, me->mface, me->totface*sizeof(MFace)); + + a= me->totface; + while(a--) { + mface->v1+= vertofs; + mface->v2+= vertofs; + if(mface->v3) mface->v3+= vertofs; + if(mface->v4) mface->v4+= vertofs; + + mface->mat_nr= map[(int)mface->mat_nr]; + + mface++; + } + + if(tfacemain) { + if(me->tface) memcpy(tface, me->tface, me->totface*sizeof(TFace)); + tface+= me->totface; + } + + } + vertofs+= me->totvert; + + if(base->object!=ob) { + free_and_unlink_base(base); + } + } + } + base= nextb; + } + + me= ob->data; + + if(me->mface) MEM_freeN(me->mface); + me->mface= mfacemain; + if(me->mvert) MEM_freeN(me->mvert); +#ifdef __NLA + if(me->dvert) free_dverts(me->dvert, me->totvert); + me->dvert = dvertmain; +#endif + me->mvert= mvertmain; + if(me->mcol) MEM_freeN(me->mcol); + me->mcol= (MCol *)mcolmain; + if(me->tface) MEM_freeN(me->tface); + me->tface= tfacemain; + me->totvert= totvert; + me->totface= totface; + + /* oude material array */ + for(a=1; a<=ob->totcol; a++) { + ma= ob->mat[a-1]; + if(ma) ma->id.us--; + } + for(a=1; a<=me->totcol; a++) { + ma= me->mat[a-1]; + if(ma) ma->id.us--; + } + if(ob->mat) MEM_freeN(ob->mat); + if(me->mat) MEM_freeN(me->mat); + ob->mat= me->mat= 0; + + if(totcol) { + me->mat= matar; + ob->mat= MEM_callocN(sizeof(void *)*totcol, "join obmatar"); + } + else MEM_freeN(matar); + + ob->totcol= me->totcol= totcol; + ob->colbits= 0; + + /* andere mesh gebruikers */ + test_object_materials((ID *)me); + + enter_editmode(); + exit_editmode(1); + + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSMAT, 0); + makeDispList(G.obedit); + +} + +void clever_numbuts_mesh(void) +{ + EditVert *eve; + + eve= G.edve.first; + while(eve) { + if(eve->f & 1) break; + eve= eve->next; + } + if(eve==0) return; + + add_numbut(0, NUM|FLO, "LocX:", -G.vd->far, G.vd->far, eve->co, 0); + add_numbut(1, NUM|FLO, "LocY:", -G.vd->far, G.vd->far, eve->co+1, 0); + add_numbut(2, NUM|FLO, "LocZ:", -G.vd->far, G.vd->far, eve->co+2, 0); + + do_clever_numbuts("Active Vertex", 3, REDRAW); +} + +/* never used, see CVS */ +/* static void insert_radiogour(char *str) */ + +static void permutate(void *list, int num, int size, int *index) +{ + void *buf; + int len; + int i; + + len = num * size; + + buf = malloc(len); + memcpy(buf, list, len); + + for (i = 0; i < num; i++) { + memcpy((char *)list + (i * size), (char *)buf + (index[i] * size), size); + } + free(buf); +} + +static MVert *mvertbase; +static MFace *mfacebase; + +static int verg_mface(const void *v1, const void *v2) +{ + MFace *x1, *x2; + + MVert *ve1, *ve2; + int i1, i2; + + i1 = ((int *) v1)[0]; + i2 = ((int *) v2)[0]; + + x1 = mfacebase + i1; + x2 = mfacebase + i2; + + ve1= mvertbase+x1->v1; + ve2= mvertbase+x2->v1; + + if( ve1->co[2] > ve2->co[2] ) return 1; + else if( ve1->co[2] < ve2->co[2]) return -1; + return 0; +} + + +void sort_faces(void) +{ + Object *ob= OBACT; + Mesh *me; + + int i, *index; + + if(ob==0) return; + if(G.obedit) return; + if(ob->type!=OB_MESH) return; + + if(okee("Sort Faces in Z")==0) return; + me= ob->data; + if(me->totface==0) return; + +/* create index list */ + index = (int *) malloc(sizeof(int) * me->totface); + for (i = 0; i < me->totface; i++) { + index[i] = i; + } + mvertbase= me->mvert; + mfacebase = me->mface; + +/* sort index list instead of faces itself + and apply this permutation to the face list plus + to the texture faces */ + qsort(index, me->totface, sizeof(int), verg_mface); + + permutate(mfacebase, me->totface, sizeof(MFace), index); + if (me->tface) + permutate(me->tface, me->totface, sizeof(TFace), index); + + free(index); + + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + +void vertices_to_sphere(void) +{ + EditVert *eve; + Object *ob= OBACT; + float *curs, len, vec[3], cent[3], fac, facm, imat[3][3], bmat[3][3]; + int tot; + short perc=100; + + if(ob==0) return; + TEST_EDITMESH + + if(button(&perc, 1, 100, "Percentage:")==0) return; + fac= perc/100.0; + facm= 1.0-fac; + + Mat3CpyMat4(bmat, ob->obmat); + Mat3Inv(imat, bmat); + + /* centrum */ + curs= give_cursor(); + cent[0]= curs[0]-ob->obmat[3][0]; + cent[1]= curs[1]-ob->obmat[3][1]; + cent[2]= curs[2]-ob->obmat[3][2]; + Mat3MulVecfl(imat, cent); + + len= 0.0; + tot= 0; + eve= G.edve.first; + while(eve) { + if(eve->f & 1) { + tot++; + len+= VecLenf(cent, eve->co); + } + eve= eve->next; + } + len/=tot; + + if(len==0.0) len= 10.0; + + eve= G.edve.first; + while(eve) { + if(eve->f & 1) { + vec[0]= eve->co[0]-cent[0]; + vec[1]= eve->co[1]-cent[1]; + vec[2]= eve->co[2]-cent[2]; + + Normalise(vec); + + eve->co[0]= fac*(cent[0]+vec[0]*len) + facm*eve->co[0]; + eve->co[1]= fac*(cent[1]+vec[1]*len) + facm*eve->co[1]; + eve->co[2]= fac*(cent[2]+vec[2]*len) + facm*eve->co[2]; + + } + eve= eve->next; + } + + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + +/* Got this from scanfill.c. You will need to juggle around the + * callbacks for the scanfill.c code a bit for this to work. */ +void fill_mesh(void) +{ + EditVert *eve,*v1; + EditEdge *eed,*e1,*nexted; + EditVlak *evl,*nextvl; + short ok; + + if(G.obedit==0 || (G.obedit->type!=OB_MESH)) return; + + waitcursor(1); + + /* alle selected vertices kopieeren */ + eve= G.edve.first; + while(eve) { + if(eve->f & 1) { + v1= BLI_addfillvert(eve->co); + eve->vn= v1; + v1->vn= eve; + v1->h= 0; + } + eve= eve->next; + } + /* alle selected edges kopieeren */ + eed= G.eded.first; + while(eed) { + if( (eed->v1->f & 1) && (eed->v2->f & 1) ) { + e1= BLI_addfilledge(eed->v1->vn, eed->v2->vn); + e1->v1->h++; + e1->v2->h++; + } + eed= eed->next; + } + /* van alle selected vlakken vertices en edges verwijderen om dubbels te voorkomen */ + /* alle edges tellen punten op, vlakken trekken af, + edges met vertices ->h<2 verwijderen */ + evl= G.edvl.first; + ok= 0; + while(evl) { + nextvl= evl->next; + if( vlakselectedAND(evl, 1) ) { + evl->v1->vn->h--; + evl->v2->vn->h--; + evl->v3->vn->h--; + if(evl->v4) evl->v4->vn->h--; + ok= 1; + + } + evl= nextvl; + } + if(ok) { /* er zijn vlakken geselecteerd */ + eed= filledgebase.first; + while(eed) { + nexted= eed->next; + if(eed->v1->h<2 || eed->v2->h<2) { + BLI_remlink(&filledgebase,eed); + } + eed= nexted; + } + } + + /* tijd=clock(); */ + + /* to make edgefill work */ + BLI_setScanFillObjectRef(G.obedit); + BLI_setScanFillColourRef(&G.obedit->actcol); + + ok= BLI_edgefill(0); + + /* printf("time: %d\n",(clock()-tijd)/1000); */ + + if(ok) { + evl= fillvlakbase.first; + while(evl) { + addvlaklist(evl->v1->vn, evl->v2->vn, evl->v3->vn, 0, evl); + evl= evl->next; + } + } + /* else printf("fill error\n"); */ + + BLI_end_edgefill(); + + waitcursor(0); + + countall(); + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); +} + +/* ***************** */ + +/* this one for NOT in editmode + +(only used by external modules, that is, until now by the +python NMesh module) + +TODO: Probably it's better to convert the mesh into a EditMesh, call +vertexnormals() and convert it back to a Mesh again. + +*/ + +void vertexnormals_mesh(Mesh *me, float *extverts) +{ + MVert *mvert; + MFace *mface; + float n1[3], n2[3], n3[3], n4[3], co[4], fac1, fac2, fac3, fac4, *temp; + float *f1, *f2, *f3, *f4, xn, yn, zn, *normals; + float *v1, *v2, *v3, *v4, len, vnor[3]; + int a, testflip; + + if(me->totvert==0) return; + + testflip= (me->flag & ME_NOPUNOFLIP)==0; + if((me->flag & ME_TWOSIDED)==0) testflip= 0; /* grote hoeken */ + + if(me->totface==0) { + /* namaak puno's voor halopuno! */ + mvert= me->mvert; + for(a=0; a<me->totvert; a++, mvert++) { + VECCOPY(n1, mvert->co); + Normalise(n1); + mvert->no[0]= 32767.0*n1[0]; + mvert->no[1]= 32767.0*n1[1]; + mvert->no[2]= 32767.0*n1[2]; + } + return; + } + + normals= MEM_callocN(me->totvert*3*sizeof(float), "normals"); + + /* berekenen cos hoeken en oppervlakte en optellen bij puno */ + mface= me->mface; + mvert= me->mvert; + for(a=0; a<me->totface; a++, mface++) { + + if(mface->v3==0) continue; + + if(extverts) { + v1= extverts+3*mface->v1; + v2= extverts+3*mface->v2; + v3= extverts+3*mface->v3; + v4= extverts+3*mface->v4; + } + else { + v1= (mvert+mface->v1)->co; + v2= (mvert+mface->v2)->co; + v3= (mvert+mface->v3)->co; + v4= (mvert+mface->v4)->co; + } + + VecSubf(n1, v2, v1); + VecSubf(n2, v3, v2); + Normalise(n1); + Normalise(n2); + + if(mface->v4==0) { + VecSubf(n3, v1, v3); + Normalise(n3); + + co[0]= saacos(-n3[0]*n1[0]-n3[1]*n1[1]-n3[2]*n1[2]); + co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]); + co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]); + + } + else { + VecSubf(n3, v4, v3); + VecSubf(n4, v1, v4); + Normalise(n3); + Normalise(n4); + + co[0]= saacos(-n4[0]*n1[0]-n4[1]*n1[1]-n4[2]*n1[2]); + co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]); + co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]); + co[3]= saacos(-n3[0]*n4[0]-n3[1]*n4[1]-n3[2]*n4[2]); + } + + CalcNormFloat(v1, v2, v3, vnor); + + temp= normals+3*mface->v1; + if(testflip && contrpuntnorm(vnor, temp) ) co[0]= -co[0]; + temp[0]+= co[0]*vnor[0]; + temp[1]+= co[0]*vnor[1]; + temp[2]+= co[0]*vnor[2]; + + temp= normals+3*mface->v2; + if(testflip && contrpuntnorm(vnor, temp) ) co[1]= -co[1]; + temp[0]+= co[1]*vnor[0]; + temp[1]+= co[1]*vnor[1]; + temp[2]+= co[1]*vnor[2]; + + temp= normals+3*mface->v3; + if(testflip && contrpuntnorm(vnor, temp) ) co[2]= -co[2]; + temp[0]+= co[2]*vnor[0]; + temp[1]+= co[2]*vnor[1]; + temp[2]+= co[2]*vnor[2]; + + if(mface->v4) { + temp= normals+3*mface->v4; + if(testflip && contrpuntnorm(vnor, temp) ) co[3]= -co[3]; + temp[0]+= co[3]*vnor[0]; + temp[1]+= co[3]*vnor[1]; + temp[2]+= co[3]*vnor[2]; + } + } + + /* normaliseren puntnormalen */ + mvert= me->mvert; + for(a=0; a<me->totvert; a++, mvert++) { + len= Normalise(normals+3*a); + if(len!=0.0) { + VECCOPY(n1, normals+3*a); + Normalise(n1); + + mvert->no[0]= 32767.0*n1[0]; + mvert->no[1]= 32767.0*n1[1]; + mvert->no[2]= 32767.0*n1[2]; + } + } + + /* puntnormaal omklap-vlaggen voor bij shade */ + mface= me->mface; + mvert= me->mvert; + for(a=0; a<me->totface; a++, mface++) { + mface->puno=0; + + if(mface->v3==0) continue; + + if(extverts) { + v1= extverts+3*mface->v1; + v2= extverts+3*mface->v2; + v3= extverts+3*mface->v3; + } + else { + v1= (mvert+mface->v1)->co; + v2= (mvert+mface->v2)->co; + v3= (mvert+mface->v3)->co; + } + + CalcNormFloat(v1, v2, v3, vnor); + + if(testflip) { + f1= normals + 3*mface->v1; + f2= normals + 3*mface->v2; + f3= normals + 3*mface->v3; + + fac1= vnor[0]*f1[0] + vnor[1]*f1[1] + vnor[2]*f1[2]; + if(fac1<0.0) { + mface->puno = ME_FLIPV1; + } + fac2= vnor[0]*f2[0] + vnor[1]*f2[1] + vnor[2]*f2[2]; + if(fac2<0.0) { + mface->puno += ME_FLIPV2; + } + fac3= vnor[0]*f3[0] + vnor[1]*f3[1] + vnor[2]*f3[2]; + if(fac3<0.0) { + mface->puno += ME_FLIPV3; + } + if(mface->v4) { + f4= normals + 3*mface->v4; + fac4= vnor[0]*f4[0] + vnor[1]*f4[1] + vnor[2]*f4[2]; + if(fac4<0.0) { + mface->puno += ME_FLIPV4; + } + } + } + /* proj voor cubemap! */ + xn= fabs(vnor[0]); + yn= fabs(vnor[1]); + zn= fabs(vnor[2]); + + if(zn>xn && zn>yn) mface->puno += ME_PROJXY; + else if(yn>xn && yn>zn) mface->puno += ME_PROJXZ; + else mface->puno += ME_PROJYZ; + + } + + MEM_freeN(normals); +} + +/***/ + +static int editmesh_nfaces_selected(void) +{ + EditVlak *evl; + int count= 0; + + for (evl= G.edvl.first; evl; evl= evl->next) + if (vlakselectedAND(evl, SELECT)) + count++; + + return count; +} + +static int editmesh_nvertices_selected(void) +{ + EditVert *eve; + int count= 0; + + for (eve= G.edve.first; eve; eve= eve->next) + if (eve->f & SELECT) + count++; + + return count; +} + +static void editmesh_calc_selvert_center(float cent_r[3]) +{ + EditVert *eve; + int nsel= 0; + + cent_r[0]= cent_r[1]= cent_r[0]= 0.0; + + for (eve= G.edve.first; eve; eve= eve->next) { + if (eve->f & SELECT) { + cent_r[0]+= eve->co[0]; + cent_r[1]+= eve->co[1]; + cent_r[2]+= eve->co[2]; + nsel++; + } + } + + if (nsel) { + cent_r[0]/= nsel; + cent_r[1]/= nsel; + cent_r[2]/= nsel; + } +} + +static int tface_is_selected(TFace *tf) +{ + return (!(tf->flag & TF_HIDE) && (tf->flag & TF_SELECT)); +} + +static int faceselect_nfaces_selected(Mesh *me) +{ + int i, count= 0; + + for (i=0; i<me->totface; i++) { + MFace *mf= ((MFace*) me->mface) + i; + TFace *tf= ((TFace*) me->tface) + i; + + if (mf->v3 && tface_is_selected(tf)) + count++; + } + + return count; +} + + /* XXX, code for both these functions should be abstract, + * then unified, then written for other things (like objects, + * which would use same as vertices method), then added + * to interface! Hoera! - zr + */ +void faceselect_align_view_to_selected(View3D *v3d, Mesh *me, int axis) +{ + if (!faceselect_nfaces_selected(me)) { + error("No faces selected."); + } else { + float norm[3]; + int i; + + norm[0]= norm[1]= norm[2]= 0.0; + for (i=0; i<me->totface; i++) { + MFace *mf= ((MFace*) me->mface) + i; + TFace *tf= ((TFace*) me->tface) + i; + + if (mf->v3 && tface_is_selected(tf)) { + float *v1, *v2, *v3, fno[3]; + + v1= me->mvert[mf->v1].co; + v2= me->mvert[mf->v2].co; + v3= me->mvert[mf->v3].co; + if (mf->v4) { + float *v4= me->mvert[mf->v4].co; + CalcNormFloat4(v1, v2, v3, v4, fno); + } else { + CalcNormFloat(v1, v2, v3, fno); + } + + norm[0]+= fno[0]; + norm[1]+= fno[1]; + norm[2]+= fno[2]; + } + } + + view3d_align_axis_to_vector(v3d, axis, norm); + } +} + +void editmesh_align_view_to_selected(View3D *v3d, int axis) +{ + int nselverts= editmesh_nvertices_selected(); + + if (nselverts<3) { + if (nselverts==0) { + error("No faces or vertices selected."); + } else { + error("At least one face or three vertices must be selected."); + } + } else if (editmesh_nfaces_selected()) { + float norm[3]; + EditVlak *evl; + + norm[0]= norm[1]= norm[2]= 0.0; + for (evl= G.edvl.first; evl; evl= evl->next) { + if (vlakselectedAND(evl, SELECT)) { + float fno[3]; + if (evl->v4) CalcNormFloat4(evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co, fno); + else CalcNormFloat(evl->v1->co, evl->v2->co, evl->v3->co, fno); + /* XXX, fixme, should be flipped intp a + * consistent direction. -zr + */ + norm[0]+= fno[0]; + norm[1]+= fno[1]; + norm[2]+= fno[2]; + } + } + + view3d_align_axis_to_vector(v3d, axis, norm); + } else { + float cent[3], norm[3]; + EditVert *eve, *leve= NULL; + + norm[0]= norm[1]= norm[2]= 0.0; + editmesh_calc_selvert_center(cent); + for (eve= G.edve.first; eve; eve= eve->next) { + if (eve->f & SELECT) { + if (leve) { + float tno[3]; + CalcNormFloat(cent, leve->co, eve->co, tno); + + /* XXX, fixme, should be flipped intp a + * consistent direction. -zr + */ + norm[0]+= tno[0]; + norm[1]+= tno[1]; + norm[2]+= tno[2]; + } + leve= eve; + } + } + + view3d_align_axis_to_vector(v3d, axis, norm); + } +}
\ No newline at end of file |