edit mesh operators for edit mesh view
[blender.git] / source / blender / editors / mesh / editmesh_mods.c
1 /**
2  * $Id: 
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2004 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /*
31
32 editmesh_mods.c, UI level access, no geometry changes 
33
34 */
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <math.h>
39
40 #include "MEM_guardedalloc.h"
41
42 #include "MTC_matrixops.h"
43
44 #include "DNA_mesh_types.h"
45 #include "DNA_material_types.h"
46 #include "DNA_meshdata_types.h"
47 #include "DNA_modifier_types.h"
48 #include "DNA_object_types.h"
49 #include "DNA_texture_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_space_types.h"
53 #include "DNA_view3d_types.h"
54
55 #include "BLI_blenlib.h"
56 #include "BLI_arithb.h"
57 #include "BLI_editVert.h"
58 #include "BLI_rand.h"
59
60 #include "BKE_context.h"
61 #include "BKE_displist.h"
62 #include "BKE_depsgraph.h"
63 #include "BKE_DerivedMesh.h"
64 #include "BKE_customdata.h"
65 #include "BKE_global.h"
66 #include "BKE_mesh.h"
67 #include "BKE_material.h"
68 #include "BKE_texture.h"
69 #include "BKE_utildefines.h"
70
71 #include "IMB_imbuf_types.h"
72 #include "IMB_imbuf.h"
73
74 #include "RE_render_ext.h"  /* externtex */
75
76 #include "WM_api.h"
77 #include "WM_types.h"
78
79 #include "RNA_access.h"
80 #include "RNA_define.h"
81
82 #include "ED_mesh.h"
83 #include "ED_screen.h"
84 #include "ED_view3d.h"
85
86 #include "BIF_gl.h"
87 #include "BIF_glutil.h"
88
89 #include "mesh_intern.h"
90
91 #include "BLO_sys_types.h" // for intptr_t support
92
93 static void BIF_undo_push() {}
94 static void waitcursor() {}
95 static void error() {}
96 static int pupmenu() {return 0;}
97
98 /* ****************************** MIRROR **************** */
99
100 void EM_select_mirrored(Object *obedit, EditMesh *em)
101 {
102         if(em->selectmode & SCE_SELECT_VERTEX) {
103                 EditVert *eve, *v1;
104                 
105                 for(eve= em->verts.first; eve; eve= eve->next) {
106                         if(eve->f & SELECT) {
107                                 v1= editmesh_get_x_mirror_vert(obedit, em, eve->co);
108                                 if(v1) {
109                                         eve->f &= ~SELECT;
110                                         v1->f |= SELECT;
111                                 }
112                         }
113                 }
114         }
115 }
116
117 void EM_automerge(int update) 
118 {
119 // XXX  int len;
120         
121 //      if ((scene->automerge) &&
122 //              (obedit && obedit->type==OB_MESH) &&
123 //              (((Mesh*)obedit->data)->mr==NULL)
124 //        ) {
125 //              len = removedoublesflag(1, 1, scene->toolsettings->doublimit);
126 //              if (len) {
127 //                      G.totvert -= len; /* saves doing a countall */
128 //                      if (update) {
129 //                              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
130 //                      }
131 //              }
132 //      }
133 }
134
135 /* ****************************** SELECTION ROUTINES **************** */
136
137 unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0;      /* set in drawobject.c ... for colorindices */
138
139 /* facilities for border select and circle select */
140 static char *selbuf= NULL;
141
142 /* opengl doesn't support concave... */
143 static void draw_triangulated(short mcords[][2], short tot)
144 {
145         ListBase lb={NULL, NULL};
146         DispList *dl;
147         float *fp;
148         int a;
149         
150         /* make displist */
151         dl= MEM_callocN(sizeof(DispList), "poly disp");
152         dl->type= DL_POLY;
153         dl->parts= 1;
154         dl->nr= tot;
155         dl->verts= fp=  MEM_callocN(tot*3*sizeof(float), "poly verts");
156         BLI_addtail(&lb, dl);
157         
158         for(a=0; a<tot; a++, fp+=3) {
159                 fp[0]= (float)mcords[a][0];
160                 fp[1]= (float)mcords[a][1];
161         }
162         
163         /* do the fill */
164         filldisplist(&lb, &lb);
165
166         /* do the draw */
167         dl= lb.first;   /* filldisplist adds in head of list */
168         if(dl->type==DL_INDEX3) {
169                 int *index;
170                 
171                 a= dl->parts;
172                 fp= dl->verts;
173                 index= dl->index;
174                 glBegin(GL_TRIANGLES);
175                 while(a--) {
176                         glVertex3fv(fp+3*index[0]);
177                         glVertex3fv(fp+3*index[1]);
178                         glVertex3fv(fp+3*index[2]);
179                         index+= 3;
180                 }
181                 glEnd();
182         }
183         
184         freedisplist(&lb);
185 }
186
187
188 /* reads rect, and builds selection array for quick lookup */
189 /* returns if all is OK */
190 int EM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
191 {
192         struct ImBuf *buf;
193         unsigned int *dr;
194         int a;
195         
196         if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
197         
198         buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
199         if(buf==NULL) return 0;
200         if(em_vertoffs==0) return 0;
201
202         dr = buf->rect;
203         
204         /* build selection lookup */
205         selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
206         
207         a= (xmax-xmin+1)*(ymax-ymin+1);
208         while(a--) {
209                 if(*dr>0 && *dr<=em_vertoffs) 
210                         selbuf[*dr]= 1;
211                 dr++;
212         }
213         IMB_freeImBuf(buf);
214         return 1;
215 }
216
217 int EM_check_backbuf(unsigned int index)
218 {
219         if(selbuf==NULL) return 1;
220         if(index>0 && index<=em_vertoffs)
221                 return selbuf[index];
222         return 0;
223 }
224
225 void EM_free_backbuf(void)
226 {
227         if(selbuf) MEM_freeN(selbuf);
228         selbuf= NULL;
229 }
230
231 /* mcords is a polygon mask
232    - grab backbuffer,
233    - draw with black in backbuffer, 
234    - grab again and compare
235    returns 'OK' 
236 */
237 int EM_mask_init_backbuf_border(ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
238 {
239         unsigned int *dr, *drm;
240         struct ImBuf *buf, *bufmask;
241         int a;
242         
243         /* method in use for face selecting too */
244         if(vc->obedit==NULL) {
245                 if(FACESEL_PAINT_TEST);
246                 else return 0;
247         }
248         else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
249
250         if(em_vertoffs==0) return 0;
251         
252         buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
253         if(buf==NULL) return 0;
254
255         dr = buf->rect;
256
257         /* draw the mask */
258 #ifdef __APPLE__
259         glDrawBuffer(GL_AUX0);
260 #endif
261         glDisable(GL_DEPTH_TEST);
262         
263 // XXX  persp(PERSP_WIN);
264         glColor3ub(0, 0, 0);
265         
266         /* yah, opengl doesn't do concave... tsk! */
267         draw_triangulated(mcords, tot); 
268         
269         glBegin(GL_LINE_LOOP);  /* for zero sized masks, lines */
270         for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
271         glEnd();
272         
273 // XXX  persp(PERSP_VIEW);
274         glFinish();     /* to be sure readpixels sees mask */
275         
276         glDrawBuffer(GL_BACK);
277         
278         /* grab mask */
279         bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
280         drm = bufmask->rect;
281         if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
282         
283         /* build selection lookup */
284         selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
285         
286         a= (xmax-xmin+1)*(ymax-ymin+1);
287         while(a--) {
288                 if(*dr>0 && *dr<=em_vertoffs && *drm==0) selbuf[*dr]= 1;
289                 dr++; drm++;
290         }
291         IMB_freeImBuf(buf);
292         IMB_freeImBuf(bufmask);
293         return 1;
294         
295 }
296
297 /* circle shaped sample area */
298 int EM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
299 {
300         struct ImBuf *buf;
301         unsigned int *dr;
302         short xmin, ymin, xmax, ymax, xc, yc;
303         int radsq;
304         
305         /* method in use for face selecting too */
306         if(vc->obedit==NULL) {
307                 if(FACESEL_PAINT_TEST);
308                 else return 0;
309         }
310         else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
311         if(em_vertoffs==0) return 0;
312         
313         xmin= xs-rads; xmax= xs+rads;
314         ymin= ys-rads; ymax= ys+rads;
315         buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
316         if(buf==NULL) return 0;
317
318         dr = buf->rect;
319         
320         /* build selection lookup */
321         selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
322         radsq= rads*rads;
323         for(yc= -rads; yc<=rads; yc++) {
324                 for(xc= -rads; xc<=rads; xc++, dr++) {
325                         if(xc*xc + yc*yc < radsq) {
326                                 if(*dr>0 && *dr<=em_vertoffs) selbuf[*dr]= 1;
327                         }
328                 }
329         }
330
331         IMB_freeImBuf(buf);
332         return 1;
333         
334 }
335
336 static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index)
337 {
338         struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } *data = userData;
339
340         if (data->pass==0) {
341                 if (index<=data->lastIndex)
342                         return;
343         } else {
344                 if (index>data->lastIndex)
345                         return;
346         }
347
348         if (data->dist>3) {
349                 int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
350                 if ((eve->f&1) == data->select) {
351                         if (data->strict == 1)
352                                 return;
353                         else
354                                 temp += 5;
355                 }
356
357                 if (temp<data->dist) {
358                         data->dist = temp;
359                         data->closest = eve;
360                         data->closestIndex = index;
361                 }
362         }
363 }
364
365
366
367
368 static unsigned int findnearestvert__backbufIndextest(unsigned int index)
369 {
370         EditMesh *em= NULL; // XXX
371         EditVert *eve = BLI_findlink(&em->verts, index-1);
372
373         if(eve && (eve->f & SELECT)) return 0;
374         return 1; 
375 }
376 /**
377  * findnearestvert
378  * 
379  * dist (in/out): minimal distance to the nearest and at the end, actual distance
380  * sel: selection bias
381  *              if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
382  *              if 0, unselected vertice are given the bias
383  * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased 
384  */
385 EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
386 {
387         if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){
388                 int distance;
389                 unsigned int index;
390                 EditVert *eve;
391                 
392                 if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, strict, findnearestvert__backbufIndextest); 
393                 else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, 0, NULL); 
394                 
395                 eve = BLI_findlink(&vc->em->verts, index-1);
396                 
397                 if(eve && distance < *dist) {
398                         *dist = distance;
399                         return eve;
400                 } else {
401                         return NULL;
402                 }
403                         
404         }
405         else {
406                 struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } data;
407                 static int lastSelectedIndex=0;
408                 static EditVert *lastSelected=NULL;
409
410                 if (lastSelected && BLI_findlink(&vc->em->verts, lastSelectedIndex)!=lastSelected) {
411                         lastSelectedIndex = 0;
412                         lastSelected = NULL;
413                 }
414
415                 data.lastIndex = lastSelectedIndex;
416                 data.mval[0] = vc->mval[0];
417                 data.mval[1] = vc->mval[1];
418                 data.select = sel;
419                 data.dist = *dist;
420                 data.strict = strict;
421                 data.closest = NULL;
422                 data.closestIndex = 0;
423
424                 data.pass = 0;
425                 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
426
427                 if (data.dist>3) {
428                         data.pass = 1;
429                         mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
430                 }
431
432                 *dist = data.dist;
433                 lastSelected = data.closest;
434                 lastSelectedIndex = data.closestIndex;
435
436                 return data.closest;
437         }
438 }
439
440 /* returns labda for closest distance v1 to line-piece v2-v3 */
441 static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3) 
442 {
443         float rc[2], len;
444         
445         rc[0]= v3[0]-v2[0];
446         rc[1]= v3[1]-v2[1];
447         len= rc[0]*rc[0]+ rc[1]*rc[1];
448         if(len==0.0f)
449                 return 0.0f;
450         
451         return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
452 }
453
454 /* note; uses v3d, so needs active 3d window */
455 static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
456 {
457         struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } *data = userData;
458         float v1[2], v2[2];
459         int distance;
460                 
461         v1[0] = x0;
462         v1[1] = y0;
463         v2[0] = x1;
464         v2[1] = y1;
465                 
466         distance= PdistVL2Dfl(data->mval, v1, v2);
467                 
468         if(eed->f & SELECT) distance+=5;
469         if(distance < data->dist) {
470                 if(data->vc.v3d->flag & V3D_CLIPPING) {
471                         float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
472                         float vec[3];
473
474                         vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
475                         vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
476                         vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
477                         Mat4MulVecfl(data->vc.obedit->obmat, vec);
478
479                         if(view3d_test_clipping(data->vc.v3d, vec)==0) {
480                                 data->dist = distance;
481                                 data->closest = eed;
482                         }
483                 }
484                 else {
485                         data->dist = distance;
486                         data->closest = eed;
487                 }
488         }
489 }
490 EditEdge *findnearestedge(ViewContext *vc, int *dist)
491 {
492
493         if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
494                 int distance;
495                 unsigned int index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_solidoffs, em_wireoffs, &distance,0, NULL);
496                 EditEdge *eed = BLI_findlink(&vc->em->edges, index-1);
497
498                 if (eed && distance<*dist) {
499                         *dist = distance;
500                         return eed;
501                 } else {
502                         return NULL;
503                 }
504         }
505         else {
506                 struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } data;
507
508                 data.vc= *vc;
509                 data.mval[0] = vc->mval[0];
510                 data.mval[1] = vc->mval[1];
511                 data.dist = *dist;
512                 data.closest = NULL;
513
514                 mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2);
515
516                 *dist = data.dist;
517                 return data.closest;
518         }
519 }
520
521 static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int index)
522 {
523         struct { short mval[2]; int dist; EditFace *toFace; } *data = userData;
524
525         if (efa==data->toFace) {
526                 int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
527
528                 if (temp<data->dist)
529                         data->dist = temp;
530         }
531 }
532 static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int y, int index)
533 {
534         struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } *data = userData;
535
536         if (data->pass==0) {
537                 if (index<=data->lastIndex)
538                         return;
539         } else {
540                 if (index>data->lastIndex)
541                         return;
542         }
543
544         if (data->dist>3) {
545                 int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
546
547                 if (temp<data->dist) {
548                         data->dist = temp;
549                         data->closest = efa;
550                         data->closestIndex = index;
551                 }
552         }
553 }
554 static EditFace *findnearestface(ViewContext *vc, int *dist)
555 {
556
557         if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
558                 unsigned int index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
559                 EditFace *efa = BLI_findlink(&vc->em->faces, index-1);
560
561                 if (efa) {
562                         struct { short mval[2]; int dist; EditFace *toFace; } data;
563
564                         data.mval[0] = vc->mval[0];
565                         data.mval[1] = vc->mval[1];
566                         data.dist = 0x7FFF;             /* largest short */
567                         data.toFace = efa;
568
569                         mesh_foreachScreenFace(vc, findnearestface__getDistance, &data);
570
571                         if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) {  /* only faces, no dist check */
572                                 *dist= data.dist;
573                                 return efa;
574                         }
575                 }
576                 
577                 return NULL;
578         }
579         else {
580                 struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } data;
581                 static int lastSelectedIndex=0;
582                 static EditFace *lastSelected=NULL;
583
584                 if (lastSelected && BLI_findlink(&vc->em->faces, lastSelectedIndex)!=lastSelected) {
585                         lastSelectedIndex = 0;
586                         lastSelected = NULL;
587                 }
588
589                 data.lastIndex = lastSelectedIndex;
590                 data.mval[0] = vc->mval[0];
591                 data.mval[1] = vc->mval[1];
592                 data.dist = *dist;
593                 data.closest = NULL;
594                 data.closestIndex = 0;
595
596                 data.pass = 0;
597                 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
598
599                 if (data.dist>3) {
600                         data.pass = 1;
601                         mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
602                 }
603
604                 *dist = data.dist;
605                 lastSelected = data.closest;
606                 lastSelectedIndex = data.closestIndex;
607
608                 return data.closest;
609         }
610 }
611
612 /* best distance based on screen coords. 
613    use em->selectmode to define how to use 
614    selected vertices and edges get disadvantage
615    return 1 if found one
616 */
617 static int unified_findnearest(ViewContext *vc, EditVert **eve, EditEdge **eed, EditFace **efa) 
618 {
619         EditMesh *em= vc->em;
620         int dist= 75;
621         
622         *eve= NULL;
623         *eed= NULL;
624         *efa= NULL;
625         
626         if(em->selectmode & SCE_SELECT_VERTEX)
627                 *eve= findnearestvert(vc, &dist, SELECT, 0);
628         if(em->selectmode & SCE_SELECT_FACE)
629                 *efa= findnearestface(vc, &dist);
630
631         dist-= 20;      /* since edges select lines, we give dots advantage of 20 pix */
632         if(em->selectmode & SCE_SELECT_EDGE)
633                 *eed= findnearestedge(vc, &dist);
634
635         /* return only one of 3 pointers, for frontbuffer redraws */
636         if(*eed) {
637                 *efa= NULL; *eve= NULL;
638         }
639         else if(*efa) {
640                 *eve= NULL;
641         }
642         
643         return (*eve || *eed || *efa);
644 }
645
646 /* this as a way to compare the ares, perim  of 2 faces thay will scale to different sizes
647  *0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
648 #define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5) <= b))
649
650 /* ****************  GROUP SELECTS ************** */
651 /* selects new faces/edges/verts based on the
652  existing selection
653
654 FACES GROUP
655  mode 1: same material
656  mode 2: same image
657  mode 3: same area
658  mode 4: same perimeter
659  mode 5: same normal
660  mode 6: same co-planer
661 */
662 int facegroup_select(EditMesh *em, short mode)
663 {
664         EditFace *efa, *base_efa=NULL;
665         unsigned int selcount=0; /*count how many new faces we select*/
666         
667         /*deselcount, count how many deselected faces are left, so we can bail out early
668         also means that if there are no deselected faces, we can avoid a lot of looping */
669         unsigned int deselcount=0; 
670         
671         short ok=0;
672         float thresh=0; // XXX scene->toolsettings->select_thresh;
673         
674         for(efa= em->faces.first; efa; efa= efa->next) {
675                 if (!efa->h) {
676                         if (efa->f & SELECT) {
677                                 efa->f1=1;
678                                 ok=1;
679                         } else {
680                                 efa->f1=0;
681                                 deselcount++; /* a deselected face we may select later */
682                         }
683                 }
684         }
685         
686         if (!ok || !deselcount) /* no data selected OR no more data to select */
687                 return 0;
688         
689         /*if mode is 3 then record face areas, 4 record perimeter */
690         if (mode==3) {
691                 for(efa= em->faces.first; efa; efa= efa->next) {
692                         efa->tmp.fp= EM_face_area(efa);
693                 }
694         } else if (mode==4) {
695                 for(efa= em->faces.first; efa; efa= efa->next) {
696                         efa->tmp.fp= EM_face_perimeter(efa);
697                 }
698         }
699         
700         for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) {
701                 if (base_efa->f1) { /* This was one of the faces originaly selected */
702                         if (mode==1) { /* same material */
703                                 for(efa= em->faces.first; efa; efa= efa->next) {
704                                         if (
705                                                 !(efa->f & SELECT) &&
706                                                 !efa->h &&
707                                                 base_efa->mat_nr == efa->mat_nr
708                                         ) {
709                                                 EM_select_face(efa, 1);
710                                                 selcount++;
711                                                 deselcount--;
712                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
713                                                         return selcount;
714                                         }
715                                 }
716                         } else if (mode==2) { /* same image */
717                                 MTFace *tf, *base_tf;
718
719                                 base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data,
720                                                                      CD_MTFACE);
721
722                                 if(!base_tf)
723                                         return selcount;
724
725                                 for(efa= em->faces.first; efa; efa= efa->next) {
726                                         if (!(efa->f & SELECT) && !efa->h) {
727                                                 tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data,
728                                                                                 CD_MTFACE);
729
730                                                 if(base_tf->tpage == tf->tpage) {
731                                                         EM_select_face(efa, 1);
732                                                         selcount++;
733                                                         deselcount--;
734                                                         if (!deselcount) /*have we selected all posible faces?, if so return*/
735                                                                 return selcount;
736                                                 }
737                                         }
738                                 }
739                         } else if (mode==3 || mode==4) { /* same area OR same perimeter, both use the same temp var */
740                                 for(efa= em->faces.first; efa; efa= efa->next) {
741                                         if (
742                                                 (!(efa->f & SELECT) && !efa->h) &&
743                                                 SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp)
744                                         ) {
745                                                 EM_select_face(efa, 1);
746                                                 selcount++;
747                                                 deselcount--;
748                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
749                                                         return selcount;
750                                         }
751                                 }
752                         } else if (mode==5) { /* same normal */
753                                 float angle;
754                                 for(efa= em->faces.first; efa; efa= efa->next) {
755                                         if (!(efa->f & SELECT) && !efa->h) {
756                                                 angle= VecAngle2(base_efa->n, efa->n);
757                                                 if (angle/180.0<=thresh) {
758                                                         EM_select_face(efa, 1);
759                                                         selcount++;
760                                                         deselcount--;
761                                                         if (!deselcount) /*have we selected all posible faces?, if so return*/
762                                                                 return selcount;
763                                                 }
764                                         }
765                                 }
766                         } else if (mode==6) { /* same planer */
767                                 float angle, base_dot, dot;
768                                 base_dot= Inpf(base_efa->cent, base_efa->n);
769                                 for(efa= em->faces.first; efa; efa= efa->next) {
770                                         if (!(efa->f & SELECT) && !efa->h) {
771                                                 angle= VecAngle2(base_efa->n, efa->n);
772                                                 if (angle/180.0<=thresh) {
773                                                         dot=Inpf(efa->cent, base_efa->n);
774                                                         if (fabs(base_dot-dot) <= thresh) {
775                                                                 EM_select_face(efa, 1);
776                                                                 selcount++;
777                                                                 deselcount--;
778                                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
779                                                                         return selcount;
780                                                         }
781                                                 }
782                                         }
783                                 }
784                         }
785                 }
786         } /* end base_efa loop */
787         return selcount;
788 }
789
790
791 /*
792 EDGE GROUP
793  mode 1: same length
794  mode 2: same direction
795  mode 3: same number of face users
796  mode 4: similar face angles.
797  mode 5: similar crease
798  mode 6: similar seam
799  mode 7: similar sharp
800 */
801
802 /* this function is only used by edgegroup_select's edge angle */
803
804
805
806 static int edgegroup_select__internal(EditMesh *em, short mode)
807 {
808         EditEdge *eed, *base_eed=NULL;
809         unsigned int selcount=0; /* count how many new edges we select*/
810         
811         /*count how many visible selected edges there are,
812         so we can return when there are none left */
813         unsigned int deselcount=0;
814         
815         short ok=0;
816         float thresh=0; // XXX scene->toolsettings->select_thresh;
817         
818         for(eed= em->edges.first; eed; eed= eed->next) {
819                 if (!eed->h) {
820                         if (eed->f & SELECT) {
821                                 eed->f1=1;
822                                 ok=1;
823                         } else {
824                                 eed->f1=0;
825                                 deselcount++;
826                         }
827                         /* set all eed->tmp.l to 0 we use it later.
828                         for counting face users*/
829                         eed->tmp.l=0;
830                         eed->f2=0; /* only for mode 4, edge animations */
831                 }
832         }
833         
834         if (!ok || !deselcount) /* no data selected OR no more data to select*/
835                 return 0;
836         
837         if (mode==1) { /*store length*/
838                 for(eed= em->edges.first; eed; eed= eed->next) {
839                         if (!eed->h) /* dont calc data for hidden edges*/
840                                 eed->tmp.fp= VecLenf(eed->v1->co, eed->v2->co);
841                 }
842         } else if (mode==3) { /*store face users*/
843                 EditFace *efa;
844                 /* cound how many faces each edge uses use tmp->l */
845                 for(efa= em->faces.first; efa; efa= efa->next) {
846                         efa->e1->tmp.l++;
847                         efa->e2->tmp.l++;
848                         efa->e3->tmp.l++;
849                         if (efa->e4) efa->e4->tmp.l++;
850                 }
851         } else if (mode==4) { /*store edge angles */
852                 EditFace *efa;
853                 int j;
854                 /* cound how many faces each edge uses use tmp.l */
855                 for(efa= em->faces.first; efa; efa= efa->next) {
856                         /* here we use the edges temp data to assign a face
857                         if a face has alredy been assigned (eed->f2==1)
858                         we calculate the angle between the current face and
859                         the edges previously found face.
860                         store the angle in eed->tmp.fp (loosing the face eed->tmp.f)
861                         but tagging eed->f2==2, so we know not to look at it again.
862                         This only works for edges that connect to 2 faces. but its good enough
863                         */
864                         
865                         /* se we can loop through face edges*/
866                         j=0;
867                         eed= efa->e1;
868                         while (j<4) {
869                                 if (j==1) eed= efa->e2;
870                                 else if (j==2) eed= efa->e3;
871                                 else if (j==3) {
872                                         eed= efa->e4;
873                                         if (!eed)
874                                                 break;
875                                 } /* done looping */
876                                 
877                                 if (!eed->h) { /* dont calc data for hidden edges*/
878                                         if (eed->f2==2)
879                                                 break;
880                                         else if (eed->f2==0) /* first access, assign the face */
881                                                 eed->tmp.f= efa;
882                                         else if (eed->f2==1) /* second, we assign the angle*/
883                                                 eed->tmp.fp= VecAngle2(eed->tmp.f->n, efa->n)/180;
884                                         eed->f2++; /* f2==0 no face assigned. f2==1 one face found. f2==2 angle calculated.*/
885                                 }
886                                 j++;
887                         }
888                 }
889         }
890         
891         for(base_eed= em->edges.first; base_eed; base_eed= base_eed->next) {
892                 if (base_eed->f1) {
893                         if (mode==1) { /* same length */
894                                 for(eed= em->edges.first; eed; eed= eed->next) {
895                                         if (
896                                                 !(eed->f & SELECT) &&
897                                                 !eed->h &&
898                                                 SCALE_CMP(base_eed->tmp.fp, eed->tmp.fp)
899                                         ) {
900                                                 EM_select_edge(eed, 1);
901                                                 selcount++;
902                                                 deselcount--;
903                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
904                                                         return selcount;
905                                         }
906                                 }
907                         } else if (mode==2) { /* same direction */
908                                 float base_dir[3], dir[3], angle;
909                                 VecSubf(base_dir, base_eed->v1->co, base_eed->v2->co);
910                                 for(eed= em->edges.first; eed; eed= eed->next) {
911                                         if (!(eed->f & SELECT) && !eed->h) {
912                                                 VecSubf(dir, eed->v1->co, eed->v2->co);
913                                                 angle= VecAngle2(base_dir, dir);
914                                                 
915                                                 if (angle>90) /* use the smallest angle between the edges */
916                                                         angle= fabs(angle-180.0f);
917                                                 
918                                                 if (angle/90.0<=thresh) {
919                                                         EM_select_edge(eed, 1);
920                                                         selcount++;
921                                                         deselcount--;
922                                                         if (!deselcount) /*have we selected all posible faces?, if so return*/
923                                                                 return selcount;
924                                                 }
925                                         }
926                                 }
927                         } else if (mode==3) { /* face users */                          
928                                 for(eed= em->edges.first; eed; eed= eed->next) {
929                                         if (
930                                                 !(eed->f & SELECT) &&
931                                                 !eed->h &&
932                                                 base_eed->tmp.l==eed->tmp.l
933                                         ) {
934                                                 EM_select_edge(eed, 1);
935                                                 selcount++;
936                                                 deselcount--;
937                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
938                                                         return selcount;
939                                         }
940                                 }
941                         } else if (mode==4 && base_eed->f2==2) { /* edge angles, f2==2 means the edge has an angle. */                          
942                                 for(eed= em->edges.first; eed; eed= eed->next) {
943                                         if (
944                                                 !(eed->f & SELECT) &&
945                                                 !eed->h &&
946                                                 eed->f2==2 &&
947                                                 (fabs(base_eed->tmp.fp-eed->tmp.fp)<=thresh)
948                                         ) {
949                                                 EM_select_edge(eed, 1);
950                                                 selcount++;
951                                                 deselcount--;
952                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
953                                                         return selcount;
954                                         }
955                                 }
956                         } else if (mode==5) { /* edge crease */
957                                 for(eed= em->edges.first; eed; eed= eed->next) {
958                                         if (
959                                                 !(eed->f & SELECT) &&
960                                                 !eed->h &&
961                                                 (fabs(base_eed->crease-eed->crease) <= thresh)
962                                         ) {
963                                                 EM_select_edge(eed, 1);
964                                                 selcount++;
965                                                 deselcount--;
966                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
967                                                         return selcount;
968                                         }
969                                 }
970                         } else if (mode==6) { /* edge seam */
971                                 for(eed= em->edges.first; eed; eed= eed->next) {
972                                         if (
973                                                 !(eed->f & SELECT) &&
974                                                 !eed->h &&
975                                                 (eed->seam == base_eed->seam)
976                                         ) {
977                                                 EM_select_edge(eed, 1);
978                                                 selcount++;
979                                                 deselcount--;
980                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
981                                                         return selcount;
982                                         }
983                                 }
984                         } else if (mode==7) { /* edge sharp */
985                                 for(eed= em->edges.first; eed; eed= eed->next) {
986                                         if (
987                                                 !(eed->f & SELECT) &&
988                                                 !eed->h &&
989                                                 (eed->sharp == base_eed->sharp)
990                                         ) {
991                                                 EM_select_edge(eed, 1);
992                                                 selcount++;
993                                                 deselcount--;
994                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
995                                                         return selcount;
996                                         }
997                                 }
998                         }
999                 }
1000         }       
1001         return selcount;
1002 }
1003 /* wrap the above function but do selection flushing edge to face */
1004 int edgegroup_select(EditMesh *em, short mode)
1005 {
1006         int selcount = edgegroup_select__internal(em, mode);
1007         
1008         if (selcount) {
1009                 /* Could run a generic flush function,
1010                  * but the problem is only that all edges of a face
1011                  * can be selected without the face becoming selected */
1012                 EditFace *efa;
1013                 for(efa= em->faces.first; efa; efa= efa->next) {
1014                         if (efa->v4) {
1015                                 if (efa->e1->f&SELECT && efa->e2->f&SELECT && efa->e3->f&SELECT && efa->e4->f&SELECT)
1016                                         efa->f |= SELECT;
1017                         }  else {
1018                                 if (efa->e1->f&SELECT && efa->e2->f&SELECT && efa->e3->f&SELECT)
1019                                         efa->f |= SELECT;
1020                         }
1021                 }
1022         }
1023         return selcount;
1024 }
1025
1026
1027
1028 /*
1029 VERT GROUP
1030  mode 1: same normal
1031  mode 2: same number of face users
1032  mode 3: same vertex groups
1033 */
1034 int vertgroup_select(EditMesh *em, short mode)
1035 {
1036         EditVert *eve, *base_eve=NULL;
1037         
1038         unsigned int selcount=0; /* count how many new edges we select*/
1039         
1040         /*count how many visible selected edges there are,
1041         so we can return when there are none left */
1042         unsigned int deselcount=0;
1043         
1044         short ok=0;
1045         float thresh=0; // XXX scene->toolsettings->select_thresh;
1046         
1047         for(eve= em->verts.first; eve; eve= eve->next) {
1048                 if (!eve->h) {
1049                         if (eve->f & SELECT) {
1050                                 eve->f1=1;
1051                                 ok=1;
1052                         } else {
1053                                 eve->f1=0;
1054                                 deselcount++;
1055                         }
1056                         /* set all eve->tmp.l to 0 we use them later.*/
1057                         eve->tmp.l=0;
1058                 }
1059                 
1060         }
1061         
1062         if (!ok || !deselcount) /* no data selected OR no more data to select*/
1063                 return 0;
1064         
1065         
1066         if (mode==2) { /* store face users */
1067                 EditFace *efa;
1068                 
1069                 /* count how many faces each edge uses use tmp->l */
1070                 for(efa= em->faces.first; efa; efa= efa->next) {
1071                         efa->v1->tmp.l++;
1072                         efa->v2->tmp.l++;
1073                         efa->v3->tmp.l++;
1074                         if (efa->v4) efa->v4->tmp.l++;
1075                 }
1076         }
1077         
1078         
1079         for(base_eve= em->verts.first; base_eve; base_eve= base_eve->next) {
1080                 if (base_eve->f1) {
1081                                 
1082                         if (mode==1) { /* same normal */
1083                                 float angle;
1084                                 for(eve= em->verts.first; eve; eve= eve->next) {
1085                                         if (!(eve->f & SELECT) && !eve->h) {
1086                                                 angle= VecAngle2(base_eve->no, eve->no);
1087                                                 if (angle/180.0<=thresh) {
1088                                                         eve->f |= SELECT;
1089                                                         selcount++;
1090                                                         deselcount--;
1091                                                         if (!deselcount) /*have we selected all posible faces?, if so return*/
1092                                                                 return selcount;
1093                                                 }
1094                                         }
1095                                 }
1096                         } else if (mode==2) { /* face users */
1097                                 for(eve= em->verts.first; eve; eve= eve->next) {
1098                                         if (
1099                                                 !(eve->f & SELECT) &&
1100                                                 !eve->h &&
1101                                                 base_eve->tmp.l==eve->tmp.l
1102                                         ) {
1103                                                 eve->f |= SELECT;
1104                                                 selcount++;
1105                                                 deselcount--;
1106                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
1107                                                         return selcount;
1108                                         }
1109                                 }
1110                         } else if (mode==3) { /* vertex groups */
1111                                 MDeformVert *dvert, *base_dvert;
1112                                 short i, j; /* weight index */
1113
1114                                 base_dvert= CustomData_em_get(&em->vdata, base_eve->data,
1115                                         CD_MDEFORMVERT);
1116
1117                                 if (!base_dvert || base_dvert->totweight == 0)
1118                                         return selcount;
1119                                 
1120                                 for(eve= em->verts.first; eve; eve= eve->next) {
1121                                         dvert= CustomData_em_get(&em->vdata, eve->data,
1122                                                 CD_MDEFORMVERT);
1123
1124                                         if (dvert && !(eve->f & SELECT) && !eve->h && dvert->totweight) {
1125                                                 /* do the extra check for selection in the following if, so were not
1126                                                 checking verts that may be alredy selected */
1127                                                 for (i=0; base_dvert->totweight >i && !(eve->f & SELECT); i++) { 
1128                                                         for (j=0; dvert->totweight >j; j++) {
1129                                                                 if (base_dvert->dw[i].def_nr==dvert->dw[j].def_nr) {
1130                                                                         eve->f |= SELECT;
1131                                                                         selcount++;
1132                                                                         deselcount--;
1133                                                                         if (!deselcount) /*have we selected all posible faces?, if so return*/
1134                                                                                 return selcount;
1135                                                                         break;
1136                                                                 }
1137                                                         }
1138                                                 }
1139                                         }
1140                                 }
1141                         }
1142                 }
1143         } /* end basevert loop */
1144         return selcount;
1145 }
1146
1147 /* EditMode menu triggered from space.c by pressing Shift+G
1148 handles face/edge vert context and
1149 facegroup_select/edgegroup_select/vertgroup_select do all the work
1150 */
1151
1152 void select_mesh_group_menu(EditMesh *em)
1153 {
1154         short ret;
1155         int selcount, first_item=1, multi=0;
1156         char str[512] = "Select Similar "; /* total max length is 404 at the moment */
1157         
1158         if (!ELEM3(em->selectmode, SCE_SELECT_VERTEX, SCE_SELECT_EDGE, SCE_SELECT_FACE)) {
1159                 multi=1;
1160         }
1161         
1162         if(em->selectmode & SCE_SELECT_VERTEX) {
1163                 if (multi) strcat(str, "%t|Vertices%x-1|");
1164                 else strcat(str, "Vertices %t|");
1165                 strcat(str, "    Normal %x1|    Face Users %x2|    Shared Vertex Groups%x3");
1166                 first_item=0;
1167         }
1168
1169         if(em->selectmode & SCE_SELECT_EDGE) {
1170                 if (multi) {
1171                         if (first_item) strcat(str, "%t|Edges%x-1|");
1172                         else strcat(str, "|%l|Edges%x-1|");
1173                 } else strcat(str, "Edges %t|");
1174                 
1175                 strcat(str, "    Length %x10|    Direction %x20|    Face Users%x30|    Face Angle%x40|    Crease%x50|    Seam%x60|    Sharp%x70");
1176                 first_item=0;
1177         }
1178         
1179         if(em->selectmode & SCE_SELECT_FACE) {
1180                 if (multi) {
1181                         strcat(str, "|%l|Faces%x-1|");
1182                 } else strcat(str, "Faces %t|");
1183                 strcat(str, "    Material %x100|    Image %x200|    Area %x300|    Perimeter %x400|    Normal %x500|    Co-Planar %x600");
1184         
1185         }
1186         
1187         ret= pupmenu(str);
1188         if (ret<1) return;
1189         
1190         if (ret<10) {
1191                 selcount= vertgroup_select(em, ret);
1192                 if (selcount) { /* update if data was selected */
1193                         EM_select_flush(em); /* so that selected verts, go onto select faces */
1194                         G.totvertsel += selcount;
1195 //                      if (EM_texFaceCheck())
1196                         BIF_undo_push("Select Similar Vertices");
1197                 }
1198                 return;
1199         }
1200         
1201         if (ret<100) {
1202                 selcount= edgegroup_select(em, ret/10);
1203                 
1204                 if (selcount) { /* update if data was selected */
1205                         /*EM_select_flush(em);*/ /* dont use because it can end up selecting more edges and is not usefull*/
1206                         G.totedgesel+=selcount;
1207 //                      if (EM_texFaceCheck())
1208                         BIF_undo_push("Select Similar Edges");
1209                 }
1210                 return;
1211         }
1212         
1213         if (ret<1000) {
1214                 selcount= facegroup_select(em, ret/100);
1215                 if (selcount) { /* update if data was selected */
1216                         G.totfacesel+=selcount;
1217 //                      if (EM_texFaceCheck())
1218                         BIF_undo_push("Select Similar Faces");
1219                 }
1220                 return;
1221         }
1222 }
1223
1224 int mesh_layers_menu_charlen(CustomData *data, int type)
1225 {
1226         int i, len = 0;
1227         /* see if there is a duplicate */
1228         for(i=0; i<data->totlayer; i++) {
1229                 if((&data->layers[i])->type == type) {
1230                         /* we could count the chars here but we'll just assumeme each
1231                          * is 32 chars with some room for the menu text - 40 should be fine */
1232                         len+=40; 
1233                 }
1234         }
1235         return len;
1236 }
1237
1238 /* this function adds menu text into an existing string.
1239  * this string's size should be allocated with mesh_layers_menu_charlen */
1240 void mesh_layers_menu_concat(CustomData *data, int type, char *str) {
1241         int i, count = 0;
1242         char *str_pt = str;
1243         CustomDataLayer *layer;
1244         
1245         /* see if there is a duplicate */
1246         for(i=0; i<data->totlayer; i++) {
1247                 layer = &data->layers[i];
1248                 if(layer->type == type) {
1249                         str_pt += sprintf(str_pt, "%s%%x%d|", layer->name, count);
1250                         count++;
1251                 }
1252         }
1253 }
1254
1255 int mesh_layers_menu(CustomData *data, int type) {
1256         int ret;
1257         char *str_pt, *str;
1258         
1259         str_pt = str = MEM_mallocN(mesh_layers_menu_charlen(data, type) + 18, "layer menu");
1260         str[0] = '\0';
1261         
1262         str_pt += sprintf(str_pt, "Layers%%t|");
1263         
1264         mesh_layers_menu_concat(data, type, str_pt);
1265         
1266         ret = pupmenu(str);
1267         MEM_freeN(str);
1268         return ret;
1269 }
1270
1271 void EM_mesh_copy_edge(EditMesh *em, short type) 
1272 {
1273         EditSelection *ese;
1274         short change=0;
1275         
1276         EditEdge *eed, *eed_act;
1277         float vec[3], vec_mid[3], eed_len, eed_len_act;
1278         
1279         if (!em) return;
1280         
1281         ese = em->selected.last;
1282         if (!ese) return;
1283         
1284         eed_act = (EditEdge*)ese->data;
1285         
1286         switch (type) {
1287         case 1: /* copy crease */
1288                 for(eed=em->edges.first; eed; eed=eed->next) {
1289                         if (eed->f & SELECT && eed != eed_act && eed->crease != eed_act->crease) {
1290                                 eed->crease = eed_act->crease;
1291                                 change = 1;
1292                         }
1293                 }
1294                 break;
1295         case 2: /* copy bevel weight */
1296                 for(eed=em->edges.first; eed; eed=eed->next) {
1297                         if (eed->f & SELECT && eed != eed_act && eed->bweight != eed_act->bweight) {
1298                                 eed->bweight = eed_act->bweight;
1299                                 change = 1;
1300                         }
1301                 }
1302                 break;
1303
1304         case 3: /* copy length */
1305                 eed_len_act = VecLenf(eed_act->v1->co, eed_act->v2->co);
1306                 for(eed=em->edges.first; eed; eed=eed->next) {
1307                         if (eed->f & SELECT && eed != eed_act) {
1308
1309                                 eed_len = VecLenf(eed->v1->co, eed->v2->co);
1310
1311                                 if (eed_len == eed_len_act) continue;
1312                                 /* if this edge is zero length we cont do anything with it*/
1313                                 if (eed_len == 0.0f) continue;
1314                                 if (eed_len_act == 0.0f) {
1315                                         VecAddf(vec_mid, eed->v1->co, eed->v2->co);
1316                                         VecMulf(vec_mid, 0.5);
1317                                         VECCOPY(eed->v1->co, vec_mid);
1318                                         VECCOPY(eed->v2->co, vec_mid);
1319                                 } else {
1320                                         /* copy the edge length */
1321                                         VecAddf(vec_mid, eed->v1->co, eed->v2->co);
1322                                         VecMulf(vec_mid, 0.5);
1323
1324                                         /* SCALE 1 */
1325                                         VecSubf(vec, eed->v1->co, vec_mid);
1326                                         VecMulf(vec, eed_len_act/eed_len);
1327                                         VecAddf(eed->v1->co, vec, vec_mid);
1328
1329                                         /* SCALE 2 */
1330                                         VecSubf(vec, eed->v2->co, vec_mid);
1331                                         VecMulf(vec, eed_len_act/eed_len);
1332                                         VecAddf(eed->v2->co, vec, vec_mid);
1333                                 }
1334                                 change = 1;
1335                         }
1336                 }
1337
1338                 if (change)
1339                         recalc_editnormals(em);
1340
1341                 break;
1342         }
1343         
1344         if (change) {
1345 //              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1346                 
1347                 BIF_undo_push("Copy Edge Attribute");
1348         }
1349 }
1350
1351 void EM_mesh_copy_face(EditMesh *em, short type)
1352 {
1353         short change=0;
1354         
1355         EditFace *efa, *efa_act;
1356         MTFace *tf, *tf_act = NULL;
1357         MCol *mcol, *mcol_act = NULL;
1358         if (!em) return;
1359         efa_act = EM_get_actFace(em, 0);
1360         
1361         if (!efa_act) return;
1362         
1363         tf_act =        CustomData_em_get(&em->fdata, efa_act->data, CD_MTFACE);
1364         mcol_act =      CustomData_em_get(&em->fdata, efa_act->data, CD_MCOL);
1365         
1366         switch (type) {
1367         case 1: /* copy material */
1368                 for(efa=em->faces.first; efa; efa=efa->next) {
1369                         if (efa->f & SELECT && efa->mat_nr != efa_act->mat_nr) {
1370                                 efa->mat_nr = efa_act->mat_nr;
1371                                 change = 1;
1372                         }
1373                 }
1374                 break;
1375         case 2: /* copy image */
1376                 if (!tf_act) {
1377                         error("mesh has no uv/image layers");
1378                         return;
1379                 }
1380                 for(efa=em->faces.first; efa; efa=efa->next) {
1381                         if (efa->f & SELECT && efa != efa_act) {
1382                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1383                                 if (tf_act->tpage) {
1384                                         tf->tpage = tf_act->tpage;
1385                                         tf->mode |= TF_TEX;
1386                                 } else {
1387                                         tf->tpage = NULL;
1388                                         tf->mode &= ~TF_TEX;
1389                                 }
1390                                 tf->tile= tf_act->tile;
1391                                 change = 1;
1392                         }
1393                 }
1394                 break;
1395
1396         case 3: /* copy UV's */
1397                 if (!tf_act) {
1398                         error("mesh has no uv/image layers");
1399                         return;
1400                 }
1401                 for(efa=em->faces.first; efa; efa=efa->next) {
1402                         if (efa->f & SELECT && efa != efa_act) {
1403                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1404                                 memcpy(tf->uv, tf_act->uv, sizeof(tf->uv));
1405                                 change = 1;
1406                         }
1407                 }
1408                 break;
1409         case 4: /* mode's */
1410                 if (!tf_act) {
1411                         error("mesh has no uv/image layers");
1412                         return;
1413                 }
1414                 for(efa=em->faces.first; efa; efa=efa->next) {
1415                         if (efa->f & SELECT && efa != efa_act) {
1416                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1417                                 tf->mode= tf_act->mode;
1418                                 change = 1;
1419                         }
1420                 }
1421                 break;
1422         case 5: /* copy transp's */
1423                 if (!tf_act) {
1424                         error("mesh has no uv/image layers");
1425                         return;
1426                 }
1427                 for(efa=em->faces.first; efa; efa=efa->next) {
1428                         if (efa->f & SELECT && efa != efa_act) {
1429                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1430                                 tf->transp= tf_act->transp;
1431                                 change = 1;
1432                         }
1433                 }
1434                 break;
1435
1436         case 6: /* copy vcols's */
1437                 if (!mcol_act) {
1438                         error("mesh has no color layers");
1439                         return;
1440                 } else {
1441                         /* guess the 4th color if needs be */
1442                         float val =- 1;
1443
1444                         if (!efa_act->v4) {
1445                                 /* guess the othe vale, we may need to use it
1446                                  * 
1447                                  * Modifying the 4th value of the mcol is ok here since its not seen
1448                                  * on a triangle
1449                                  * */
1450                                 val = ((float)(mcol_act->r +  (mcol_act+1)->r + (mcol_act+2)->r)) / 3; CLAMP(val, 0, 255);
1451                                 (mcol_act+3)->r = (char)val;
1452
1453                                 val = ((float)(mcol_act->g +  (mcol_act+1)->g + (mcol_act+2)->g)) / 3; CLAMP(val, 0, 255);
1454                                 (mcol_act+3)->g = (char)val;
1455
1456                                 val = ((float)(mcol_act->b +  (mcol_act+1)->b + (mcol_act+2)->b)) / 3; CLAMP(val, 0, 255);
1457                                 (mcol_act+3)->b = (char)val;
1458                         } 
1459
1460
1461                         for(efa=em->faces.first; efa; efa=efa->next) {
1462                                 if (efa->f & SELECT && efa != efa_act) {
1463                                         /* TODO - make copy from tri to quad guess the 4th vert */
1464                                         mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
1465                                         memcpy(mcol, mcol_act, sizeof(MCol)*4); 
1466                                         change = 1;
1467                                 }
1468                         }
1469                 }
1470                 break;
1471         }
1472         
1473         if (change) {
1474 //              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1475                 if (type==3) {
1476 // XXX                  allqueue(REDRAWIMAGE, 0);                       
1477                 }
1478                 
1479                 BIF_undo_push("Copy Face Attribute");
1480         }
1481 }
1482
1483
1484 void EM_mesh_copy_face_layer(EditMesh *em, short type) 
1485 {
1486         short change=0;
1487         
1488         EditFace *efa;
1489         MTFace *tf, *tf_from;
1490         MCol *mcol, *mcol_from;
1491         
1492         if (!em) return;
1493         
1494         switch(type) {
1495         case 7:
1496         case 8:
1497         case 9:
1498                 if (CustomData_number_of_layers(&em->fdata, CD_MTFACE)<2) {
1499                         error("mesh does not have multiple uv/image layers");
1500                         return;
1501                 } else {
1502                         int layer_orig_idx, layer_idx;
1503
1504                         layer_idx = mesh_layers_menu(&em->fdata, CD_MTFACE);
1505                         if (layer_idx<0) return;
1506
1507                         /* warning, have not updated mesh pointers however this is not needed since we swicth back */
1508                         layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MTFACE);
1509                         if (layer_idx==layer_orig_idx)
1510                                 return;
1511
1512                         /* get the tfaces */
1513                         CustomData_set_layer_active(&em->fdata, CD_MTFACE, (int)layer_idx);
1514                         /* store the tfaces in our temp */
1515                         for(efa=em->faces.first; efa; efa=efa->next) {
1516                                 if (efa->f & SELECT) {
1517                                         efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1518                                 }       
1519                         }
1520                         CustomData_set_layer_active(&em->fdata, CD_MTFACE, layer_orig_idx);
1521                 }
1522                 break;
1523
1524         case 10: /* select vcol layers - make sure this stays in sync with above code */
1525                 if (CustomData_number_of_layers(&em->fdata, CD_MCOL)<2) {
1526                         error("mesh does not have multiple color layers");
1527                         return;
1528                 } else {
1529                         int layer_orig_idx, layer_idx;
1530
1531                         layer_idx = mesh_layers_menu(&em->fdata, CD_MCOL);
1532                         if (layer_idx<0) return;
1533
1534                         /* warning, have not updated mesh pointers however this is not needed since we swicth back */
1535                         layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MCOL);
1536                         if (layer_idx==layer_orig_idx)
1537                                 return;
1538
1539                         /* get the tfaces */
1540                         CustomData_set_layer_active(&em->fdata, CD_MCOL, (int)layer_idx);
1541                         /* store the tfaces in our temp */
1542                         for(efa=em->faces.first; efa; efa=efa->next) {
1543                                 if (efa->f & SELECT) {
1544                                         efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
1545                                 }       
1546                         }
1547                         CustomData_set_layer_active(&em->fdata, CD_MCOL, layer_orig_idx);
1548
1549                 }
1550                 break;
1551         }
1552
1553         /* layer copy only - sanity checks done above */
1554         switch (type) {
1555         case 7: /* copy UV's only */
1556                 for(efa=em->faces.first; efa; efa=efa->next) {
1557                         if (efa->f & SELECT) {
1558                                 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
1559                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1560                                 memcpy(tf->uv, tf_from->uv, sizeof(tf->uv));
1561                                 change = 1;
1562                         }
1563                 }
1564                 break;
1565         case 8: /* copy image settings only */
1566                 for(efa=em->faces.first; efa; efa=efa->next) {
1567                         if (efa->f & SELECT) {
1568                                 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
1569                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1570                                 if (tf_from->tpage) {
1571                                         tf->tpage = tf_from->tpage;
1572                                         tf->mode |= TF_TEX;
1573                                 } else {
1574                                         tf->tpage = NULL;
1575                                         tf->mode &= ~TF_TEX;
1576                                 }
1577                                 tf->tile= tf_from->tile;
1578                                 change = 1;
1579                         }
1580                 }
1581                 break;
1582         case 9: /* copy all tface info */
1583                 for(efa=em->faces.first; efa; efa=efa->next) {
1584                         if (efa->f & SELECT) {
1585                                 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
1586                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1587                                 memcpy(tf->uv, ((MTFace *)efa->tmp.p)->uv, sizeof(tf->uv));
1588                                 tf->tpage = tf_from->tpage;
1589                                 tf->mode = tf_from->mode;
1590                                 tf->transp = tf_from->transp;
1591                                 change = 1;
1592                         }
1593                 }
1594                 break;
1595         case 10:
1596                 for(efa=em->faces.first; efa; efa=efa->next) {
1597                         if (efa->f & SELECT) {
1598                                 mcol_from = (MCol *)efa->tmp.p; 
1599                                 mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
1600                                 memcpy(mcol, mcol_from, sizeof(MCol)*4);        
1601                                 change = 1;
1602                         }
1603                 }
1604                 break;
1605         }
1606
1607         if (change) {
1608 //              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1609                 
1610                 BIF_undo_push("Copy Face Layer");
1611         }
1612 }
1613
1614
1615 /* ctrl+c in mesh editmode */
1616 void mesh_copy_menu(EditMesh *em)
1617 {
1618         EditSelection *ese;
1619         int ret;
1620         if (!em) return;
1621         
1622         ese = em->selected.last;
1623         
1624         /* Faces can have a NULL ese, so dont return on a NULL ese here */
1625         
1626         if(ese && ese->type == EDITVERT) {
1627                 /* EditVert *ev, *ev_act = (EditVert*)ese->data;
1628                 ret= pupmenu(""); */
1629         } else if(ese && ese->type == EDITEDGE) {
1630                 ret= pupmenu("Copy Active Edge to Selected%t|Crease%x1|Bevel Weight%x2|Length%x3");
1631                 if (ret<1) return;
1632                 
1633                 EM_mesh_copy_edge(em, ret);
1634                 
1635         } else if(ese==NULL || ese->type == EDITFACE) {
1636                 ret= pupmenu(
1637                         "Copy Face Selected%t|"
1638                         "Active Material%x1|Active Image%x2|Active UV Coords%x3|"
1639                         "Active Mode%x4|Active Transp%x5|Active Vertex Colors%x6|%l|"
1640
1641                         "TexFace UVs from layer%x7|"
1642                         "TexFace Images from layer%x8|"
1643                         "TexFace All from layer%x9|"
1644                         "Vertex Colors from layer%x10");
1645                 if (ret<1) return;
1646                 
1647                 if (ret<=6) {
1648                         EM_mesh_copy_face(em, ret);
1649                 } else {
1650                         EM_mesh_copy_face_layer(em, ret);
1651                 }
1652         }
1653 }
1654
1655
1656 /* ****************  LOOP SELECTS *************** */
1657
1658 /* selects quads in loop direction of indicated edge */
1659 /* only flush over edges with valence <= 2 */
1660 void faceloop_select(EditMesh *em, EditEdge *startedge, int select)
1661 {
1662         EditEdge *eed;
1663         EditFace *efa;
1664         int looking= 1;
1665         
1666         /* in eed->f1 we put the valence (amount of faces in edge) */
1667         /* in eed->f2 we put tagged flag as correct loop */
1668         /* in efa->f1 we put tagged flag as correct to select */
1669
1670         for(eed= em->edges.first; eed; eed= eed->next) {
1671                 eed->f1= 0;
1672                 eed->f2= 0;
1673         }
1674         for(efa= em->faces.first; efa; efa= efa->next) {
1675                 efa->f1= 0;
1676                 if(efa->h==0) {
1677                         efa->e1->f1++;
1678                         efa->e2->f1++;
1679                         efa->e3->f1++;
1680                         if(efa->e4) efa->e4->f1++;
1681                 }
1682         }
1683         
1684         /* tag startedge OK*/
1685         startedge->f2= 1;
1686         
1687         while(looking) {
1688                 looking= 0;
1689                 
1690                 for(efa= em->faces.first; efa; efa= efa->next) {
1691                         if(efa->h==0 && efa->e4 && efa->f1==0) {        /* not done quad */
1692                                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
1693
1694                                         /* if edge tagged, select opposing edge and mark face ok */
1695                                         if(efa->e1->f2) {
1696                                                 efa->e3->f2= 1;
1697                                                 efa->f1= 1;
1698                                                 looking= 1;
1699                                         }
1700                                         else if(efa->e2->f2) {
1701                                                 efa->e4->f2= 1;
1702                                                 efa->f1= 1;
1703                                                 looking= 1;
1704                                         }
1705                                         if(efa->e3->f2) {
1706                                                 efa->e1->f2= 1;
1707                                                 efa->f1= 1;
1708                                                 looking= 1;
1709                                         }
1710                                         if(efa->e4->f2) {
1711                                                 efa->e2->f2= 1;
1712                                                 efa->f1= 1;
1713                                                 looking= 1;
1714                                         }
1715                                 }
1716                         }
1717                 }
1718         }
1719         
1720         /* (de)select the faces */
1721         if(select!=2) {
1722                 for(efa= em->faces.first; efa; efa= efa->next) {
1723                         if(efa->f1) EM_select_face(efa, select);
1724                 }
1725         }
1726 }
1727
1728
1729 /* helper for edgeloop_select, checks for eed->f2 tag in faces */
1730 static int edge_not_in_tagged_face(EditMesh *em, EditEdge *eed)
1731 {
1732         EditFace *efa;
1733         
1734         for(efa= em->faces.first; efa; efa= efa->next) {
1735                 if(efa->h==0) {
1736                         if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) {      /* edge is in face */
1737                                 if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) {     /* face is tagged */
1738                                         return 0;
1739                                 }
1740                         }
1741                 }
1742         }
1743         return 1;
1744 }
1745
1746 /* selects or deselects edges that:
1747 - if edges has 2 faces:
1748         - has vertices with valence of 4
1749         - not shares face with previous edge
1750 - if edge has 1 face:
1751         - has vertices with valence 4
1752         - not shares face with previous edge
1753         - but also only 1 face
1754 - if edge no face:
1755         - has vertices with valence 2
1756 */
1757 static void edgeloop_select(EditMesh *em, EditEdge *starteed, int select)
1758 {
1759         EditVert *eve;
1760         EditEdge *eed;
1761         EditFace *efa;
1762         int looking= 1;
1763         
1764         /* in f1 we put the valence (amount of edges in a vertex, or faces in edge) */
1765         /* in eed->f2 and efa->f1 we put tagged flag as correct loop */
1766         for(eve= em->verts.first; eve; eve= eve->next) {
1767                 eve->f1= 0;
1768                 eve->f2= 0;
1769         }
1770         for(eed= em->edges.first; eed; eed= eed->next) {
1771                 eed->f1= 0;
1772                 eed->f2= 0;
1773                 if((eed->h & 1)==0) {   /* fgon edges add to valence too */
1774                         eed->v1->f1++; eed->v2->f1++;
1775                 }
1776         }
1777         for(efa= em->faces.first; efa; efa= efa->next) {
1778                 efa->f1= 0;
1779                 if(efa->h==0) {
1780                         efa->e1->f1++;
1781                         efa->e2->f1++;
1782                         efa->e3->f1++;
1783                         if(efa->e4) efa->e4->f1++;
1784                 }
1785         }
1786         
1787         /* looped edges & vertices get tagged f2 */
1788         starteed->f2= 1;
1789         if(starteed->v1->f1<5) starteed->v1->f2= 1;
1790         if(starteed->v2->f1<5) starteed->v2->f2= 1;
1791         /* sorry, first edge isnt even ok */
1792         if(starteed->v1->f2==0 && starteed->v2->f2==0) looking= 0;
1793         
1794         while(looking) {
1795                 looking= 0;
1796                 
1797                 /* find correct valence edges which are not tagged yet, but connect to tagged one */
1798                 for(eed= em->edges.first; eed; eed= eed->next) {
1799                         if(eed->h==0 && eed->f2==0) { /* edge not hidden, not tagged */
1800                                 if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { /* valence of vertex OK, and is tagged */
1801                                         /* new edge is not allowed to be in face with tagged edge */
1802                                         if(edge_not_in_tagged_face(em, eed)) {
1803                                                 if(eed->f1==starteed->f1) {     /* same amount of faces */
1804                                                         looking= 1;
1805                                                         eed->f2= 1;
1806                                                         if(eed->v2->f1<5) eed->v2->f2= 1;
1807                                                         if(eed->v1->f1<5) eed->v1->f2= 1;
1808                                                 }
1809                                         }
1810                                 }
1811                         }
1812                 }
1813         }
1814         /* and we do the select */
1815         for(eed= em->edges.first; eed; eed= eed->next) {
1816                 if(eed->f2) EM_select_edge(eed, select);
1817         }
1818 }
1819
1820 /* 
1821    Almostly exactly the same code as faceloop select
1822 */
1823 static void edgering_select(EditMesh *em, EditEdge *startedge, int select)
1824 {
1825         EditEdge *eed;
1826         EditFace *efa;
1827         int looking= 1;
1828         
1829         /* in eed->f1 we put the valence (amount of faces in edge) */
1830         /* in eed->f2 we put tagged flag as correct loop */
1831         /* in efa->f1 we put tagged flag as correct to select */
1832
1833         for(eed= em->edges.first; eed; eed= eed->next) {
1834                 eed->f1= 0;
1835                 eed->f2= 0;
1836         }
1837         for(efa= em->faces.first; efa; efa= efa->next) {
1838                 efa->f1= 0;
1839                 if(efa->h==0) {
1840                         efa->e1->f1++;
1841                         efa->e2->f1++;
1842                         efa->e3->f1++;
1843                         if(efa->e4) efa->e4->f1++;
1844                 }
1845         }
1846         
1847         /* tag startedge OK */
1848         startedge->f2= 1;
1849         
1850         while(looking) {
1851                 looking= 0;
1852                 
1853                 for(efa= em->faces.first; efa; efa= efa->next) {
1854                         if(efa->e4 && efa->f1==0 && !efa->h) {  /* not done quad */
1855                                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
1856
1857                                         /* if edge tagged, select opposing edge and mark face ok */
1858                                         if(efa->e1->f2) {
1859                                                 efa->e3->f2= 1;
1860                                                 efa->f1= 1;
1861                                                 looking= 1;
1862                                         }
1863                                         else if(efa->e2->f2) {
1864                                                 efa->e4->f2= 1;
1865                                                 efa->f1= 1;
1866                                                 looking= 1;
1867                                         }
1868                                         if(efa->e3->f2) {
1869                                                 efa->e1->f2= 1;
1870                                                 efa->f1= 1;
1871                                                 looking= 1;
1872                                         }
1873                                         if(efa->e4->f2) {
1874                                                 efa->e2->f2= 1;
1875                                                 efa->f1= 1;
1876                                                 looking= 1;
1877                                         }
1878                                 }
1879                         }
1880                 }
1881         }
1882         
1883         /* (de)select the edges */
1884         for(eed= em->edges.first; eed; eed= eed->next) {
1885                 if(eed->f2) EM_select_edge(eed, select);
1886         }
1887 }
1888
1889 void loop_multiselect(EditMesh *em, int looptype)
1890 {
1891         EditEdge *eed;
1892         EditEdge **edarray;
1893         int edindex, edfirstcount;
1894         
1895         /*edarray = MEM_mallocN(sizeof(*edarray)*G.totedgesel,"edge array");*/
1896         edarray = MEM_mallocN(sizeof(EditEdge*)*G.totedgesel,"edge array");
1897         edindex = 0;
1898         edfirstcount = G.totedgesel;
1899         
1900         for(eed=em->edges.first; eed; eed=eed->next){
1901                 if(eed->f&SELECT){
1902                         edarray[edindex] = eed;
1903                         edindex += 1;
1904                 }
1905         }
1906         
1907         if(looptype){
1908                 for(edindex = 0; edindex < edfirstcount; edindex +=1){
1909                         eed = edarray[edindex];
1910                         edgering_select(em, eed,SELECT);
1911                 }
1912                 EM_selectmode_flush(em);
1913                 BIF_undo_push("Edge Ring Multi-Select");
1914         }
1915         else{
1916                 for(edindex = 0; edindex < edfirstcount; edindex +=1){
1917                         eed = edarray[edindex];
1918                         edgeloop_select(em, eed,SELECT);
1919                 }
1920                 EM_selectmode_flush(em);
1921                 BIF_undo_push("Edge Loop Multi-Select");
1922         }
1923         MEM_freeN(edarray);
1924 //      if (EM_texFaceCheck())
1925 }
1926                 
1927 /* ***************** MAIN MOUSE SELECTION ************** */
1928
1929 /* just to have the functions nice together */
1930
1931 static void mouse_mesh_loop(ViewContext *vc)
1932 {
1933         EditMesh *em= vc->em;
1934         EditEdge *eed;
1935         int select= 1;
1936         int dist= 50;
1937         int shift= 0, alt= 0, ctrl= 0; // XXX
1938         
1939         eed= findnearestedge(vc, &dist);
1940         if(eed) {
1941                 if (vc->scene->toolsettings->edge_mode == EDGE_MODE_SELECT) {
1942                         if(shift==0) EM_clear_flag_all(em, SELECT);
1943                 
1944                         if((eed->f & SELECT)==0) select=1;
1945                         else if(shift) select=0;
1946
1947                         if(em->selectmode & SCE_SELECT_FACE) {
1948                                 faceloop_select(em, eed, select);
1949                         }
1950                         else if(em->selectmode & SCE_SELECT_EDGE) {
1951                         if((alt && ctrl))
1952                                         edgering_select(em, eed, select);
1953                         else if(alt)
1954                                         edgeloop_select(em, eed, select);
1955                         }
1956                     else if(em->selectmode & SCE_SELECT_VERTEX) {
1957                         if((alt && ctrl))
1958                                         edgering_select(em, eed, select);
1959                         else if(alt)
1960                                         edgeloop_select(em, eed, select);
1961                         }
1962
1963                         EM_selectmode_flush(em);
1964 //                      if (EM_texFaceCheck())
1965                         
1966                 } 
1967                 else {
1968                         int act = (edgetag_context_check(vc->scene, eed)==0);
1969                         int path = 0;
1970                         
1971                         if (alt && ctrl && em->selected.last) {
1972                                 EditSelection *ese = em->selected.last;
1973         
1974                                 if(ese && ese->type == EDITEDGE) {
1975                                         EditEdge *eed_act;
1976                                         eed_act = (EditEdge*)ese->data;
1977                                         if (eed_act != eed) {
1978                                                 /* If shift is pressed we need to use the last active edge, (if it exists) */
1979                                                 if (edgetag_shortest_path(vc->scene, em, eed_act, eed)) {
1980                                                         EM_remove_selection(em, eed_act, EDITEDGE);
1981                                                         EM_select_edge(eed_act, 0);
1982                                                         path = 1;
1983                                                 }
1984                                         }
1985                                 }
1986                         }
1987                         if (path==0) {
1988                                 edgetag_context_set(vc->scene, eed, act); /* switch the edge option */
1989                         }
1990                         
1991                         if (act) {
1992                                 if ((eed->f & SELECT)==0) {
1993                                         EM_select_edge(eed, 1);
1994                                         EM_selectmode_flush(em);
1995                                 }
1996                                 /* even if this is selected it may not be in the selection list */
1997                                 EM_store_selection(em, eed, EDITEDGE);
1998                         } else {
1999                                 if (eed->f & SELECT) {
2000                                         EM_select_edge(eed, 0);
2001                                         /* logic is differnt from above here since if this was selected we dont know if its in the selection list or not */
2002                                         EM_remove_selection(em, eed, EDITEDGE);
2003                                         
2004                                         EM_selectmode_flush(em);
2005                                 }
2006                         }
2007                         
2008                         switch (0) { // XXX scene->toolsettings->edge_mode) {
2009                         case EDGE_MODE_TAG_SEAM:
2010                                 G.f |= G_DRAWSEAMS;
2011                                 break;
2012                         case EDGE_MODE_TAG_SHARP:
2013                                 G.f |= G_DRAWSHARP;
2014                                 break;
2015                         case EDGE_MODE_TAG_CREASE:      
2016                                 G.f |= G_DRAWCREASES;
2017                                 break;
2018                         case EDGE_MODE_TAG_BEVEL:
2019                                 G.f |= G_DRAWBWEIGHTS;
2020                                 break;
2021                         }
2022                         
2023 //                      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
2024                 }
2025                                 
2026         }
2027 }
2028
2029
2030 /* here actual select happens */
2031 /* gets called via generic mouse select operator */
2032 void mouse_mesh(bContext *C, short mval[2], short extend)
2033 {
2034         ViewContext vc;
2035         EditVert *eve;
2036         EditEdge *eed;
2037         EditFace *efa;
2038         int  alt= 0; // XXX
2039         
2040         /* setup view context for argument to callbacks */
2041         em_setup_viewcontext(C, &vc);
2042         vc.mval[0]= mval[0];
2043         vc.mval[1]= mval[1];
2044         
2045         if(alt) mouse_mesh_loop(&vc);
2046         else if(unified_findnearest(&vc, &eve, &eed, &efa)) {
2047                 
2048                 if(extend==0) EM_clear_flag_all(vc.em, SELECT);
2049                 
2050                 if(efa) {
2051                         /* set the last selected face */
2052                         EM_set_actFace(vc.em, efa);
2053                         
2054                         if( (efa->f & SELECT)==0 ) {
2055                                 EM_store_selection(vc.em, efa, EDITFACE);
2056                                 EM_select_face_fgon(vc.em, efa, 1);
2057                         }
2058                         else if(extend) {
2059                                 EM_remove_selection(vc.em, efa, EDITFACE);
2060                                 EM_select_face_fgon(vc.em, efa, 0);
2061                         }
2062                 }
2063                 else if(eed) {
2064                         if((eed->f & SELECT)==0) {
2065                                 EM_store_selection(vc.em, eed, EDITEDGE);
2066                                 EM_select_edge(eed, 1);
2067                         }
2068                         else if(extend) {
2069                                 EM_remove_selection(vc.em, eed, EDITEDGE);
2070                                 EM_select_edge(eed, 0);
2071                         }
2072                 }
2073                 else if(eve) {
2074                         if((eve->f & SELECT)==0) {
2075                                 eve->f |= SELECT;
2076                                 EM_store_selection(vc.em, eve, EDITVERT);
2077                         }
2078                         else if(extend){ 
2079                                 EM_remove_selection(vc.em, eve, EDITVERT);
2080                                 eve->f &= ~SELECT;
2081                         }
2082                 }
2083                 
2084                 EM_selectmode_flush(vc.em);
2085                   
2086 //              if (EM_texFaceCheck()) {
2087
2088                 if (efa && efa->mat_nr != vc.obedit->actcol-1) {
2089                         vc.obedit->actcol= efa->mat_nr+1;
2090                         vc.em->mat_nr= efa->mat_nr;
2091 //                      BIF_preview_changed(ID_MA);
2092                 }
2093         }
2094
2095         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
2096         
2097 //      rightmouse_transform();
2098 }
2099
2100 // XXX should we use CTX_scene(C)->selectmode & SCE_SELECT_FACE like it was in the past ? calls selectconnected_delimit_mesh_all if true
2101 void selectconnected_mesh_all(EditMesh *em)
2102 {
2103         EditVert *v1,*v2;
2104         EditEdge *eed;
2105         short done=1, toggle=0;
2106
2107         if(em->edges.first==0) return;
2108         
2109         while(done==1) {
2110                 done= 0;
2111                 
2112                 toggle++;
2113                 if(toggle & 1) eed= em->edges.first;
2114                 else eed= em->edges.last;
2115                 
2116                 while(eed) {
2117                         v1= eed->v1;
2118                         v2= eed->v2;
2119                         if(eed->h==0) {
2120                                 if(v1->f & SELECT) {
2121                                         if( (v2->f & SELECT)==0 ) {
2122                                                 v2->f |= SELECT;
2123                                                 done= 1;
2124                                         }
2125                                 }
2126                                 else if(v2->f & SELECT) {
2127                                         if( (v1->f & SELECT)==0 ) {
2128                                                 v1->f |= SELECT;
2129                                                 done= 1;
2130                                         }
2131                                 }
2132                         }
2133                         if(toggle & 1) eed= eed->next;
2134                         else eed= eed->prev;
2135                 }
2136         }
2137
2138         /* now use vertex select flag to select rest */
2139         EM_select_flush(em);
2140         
2141 //      if (EM_texFaceCheck())
2142         BIF_undo_push("Select Connected (All)");
2143 }
2144
2145 static int selectconnected_mesh_all_exec(bContext *C, wmOperator *op)
2146 {
2147         Object *obedit= CTX_data_edit_object(C);
2148         EditMesh *em= ((Mesh *)obedit->data)->edit_mesh;
2149         
2150         selectconnected_mesh_all(em);
2151         
2152         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2153         return OPERATOR_FINISHED;       
2154 }
2155
2156 void MESH_OT_selectconnected_mesh_all(wmOperatorType *ot)
2157 {
2158         /* identifiers */
2159         ot->name= "Select All of the Connected Mesh";
2160         ot->idname= "MESH_OT_selectconnected_mesh_all";
2161         
2162         /* api callbacks */
2163         ot->exec= selectconnected_mesh_all_exec;
2164         ot->poll= ED_operator_editmesh;
2165 }
2166
2167 // XXX should we use CTX_scene(C)->selectmode & SCE_SELECT_FACE like it was in the past ? calls selectconnected_delimit_mesh if true
2168 void selectconnected_mesh(bContext *C)
2169 {
2170         ViewContext vc;
2171         EditVert *eve, *v1, *v2;
2172         EditEdge *eed;
2173         EditFace *efa;
2174         short done=1, sel, toggle=0;
2175         int shift= 0; // XXX
2176                 
2177         /* setup view context for argument to callbacks */
2178         em_setup_viewcontext(C, &vc);
2179         
2180         if(vc.em->edges.first==0) return;
2181         
2182         if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
2183                 /* error("Nothing indicated "); */ /* this is mostly annoying, eps with occluded geometry */
2184                 return;
2185         }
2186         
2187         sel= 1;
2188         if(shift) sel=0;
2189
2190         /* clear test flags */
2191         for(v1= vc.em->verts.first; v1; v1= v1->next) v1->f1= 0;
2192         
2193         /* start vertex/face/edge */
2194         if(eve) eve->f1= 1;
2195         else if(eed) eed->v1->f1= eed->v2->f1= 1;
2196         else efa->v1->f1= efa->v2->f1= efa->v3->f1= 1;
2197         
2198         /* set flag f1 if affected */
2199         while(done==1) {
2200                 done= 0;
2201                 toggle++;
2202                 
2203                 if(toggle & 1) eed= vc.em->edges.first;
2204                 else eed= vc.em->edges.last;
2205                 
2206                 while(eed) {
2207                         v1= eed->v1;
2208                         v2= eed->v2;
2209                         
2210                         if(eed->h==0) {
2211                                 if(v1->f1 && v2->f1==0) {
2212                                         v2->f1= 1;
2213                                         done= 1;
2214                                 }
2215                                 else if(v1->f1==0 && v2->f1) {
2216                                         v1->f1= 1;
2217                                         done= 1;
2218                                 }
2219                         }
2220                         
2221                         if(toggle & 1) eed= eed->next;
2222                         else eed= eed->prev;
2223                 }
2224         }
2225         
2226         /* now use vertex f1 flag to select/deselect */
2227         for(eed= vc.em->edges.first; eed; eed= eed->next) {
2228                 if(eed->v1->f1 && eed->v2->f1) 
2229                         EM_select_edge(eed, sel);
2230         }
2231         for(efa= vc.em->faces.first; efa; efa= efa->next) {
2232                 if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1)) 
2233                         EM_select_face(efa, sel);
2234         }
2235         /* no flush needed, connected geometry is done */
2236         
2237 //      if (EM_texFaceCheck())
2238         
2239         BIF_undo_push("Select Linked");
2240         
2241 }
2242
2243 static int selectconnected_mesh_exec(bContext *C, wmOperator *op)
2244 {
2245         Object *obedit= CTX_data_edit_object(C);
2246         
2247         selectconnected_mesh(C);
2248         
2249         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2250         return OPERATOR_FINISHED;       
2251 }
2252
2253 void MESH_OT_selectconnected_mesh(wmOperatorType *ot)
2254 {
2255         /* identifiers */
2256         ot->name= "Select Connected Mesh";
2257         ot->idname= "MESH_OT_selectconnected_mesh";
2258         
2259         /* api callbacks */
2260         ot->exec= selectconnected_mesh_exec;
2261         ot->poll= ED_operator_editmesh;
2262 }
2263
2264 /* for use with selectconnected_delimit_mesh only! */
2265 #define is_edge_delimit_ok(eed) ((eed->tmp.l == 1) && (eed->seam==0))
2266 #define is_face_tag(efa) is_edge_delimit_ok(efa->e1) || is_edge_delimit_ok(efa->e2) || is_edge_delimit_ok(efa->e3) || (efa->v4 && is_edge_delimit_ok(efa->e4))
2267
2268 #define face_tag(efa)\
2269         if(efa->v4)     efa->tmp.l=             efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;\
2270         else            efa->tmp.l=             efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
2271
2272 /* all - 1) use all faces for extending the selection  2) only use the mouse face
2273  * sel - 1) select  0) deselect 
2274  * */
2275 static void selectconnected_delimit_mesh__internal(ViewContext *vc, short all, short sel)
2276 {
2277         EditMesh *em= vc->em;
2278         EditFace *efa;
2279         EditEdge *eed;
2280         short done=1, change=0;
2281         int dist = 75;
2282         
2283         if(em->faces.first==0) return;
2284         
2285         /* flag all edges as off*/
2286         for(eed= em->edges.first; eed; eed= eed->next)
2287                 eed->tmp.l=0;
2288         
2289         if (all) {
2290                 for(efa= em->faces.first; efa; efa= efa->next) {
2291                         if (efa->f & SELECT) {
2292                                 face_tag(efa);
2293                         } else {
2294                                 efa->tmp.l = 0;
2295                         }
2296                 }
2297         } else {
2298                 EditFace *efa_mouse = findnearestface(vc, &dist);
2299                 
2300                 if( !efa_mouse ) {
2301                         /* error("Nothing indicated "); */ /* this is mostly annoying, eps with occluded geometry */
2302                         return;
2303                 }
2304                 
2305                 for(efa= em->faces.first; efa; efa= efa->next) {
2306                         efa->tmp.l = 0;
2307                 }
2308                 efa_mouse->tmp.l = 1;
2309                 face_tag(efa_mouse);
2310         }
2311         
2312         while(done==1) {
2313                 done= 0;
2314                 /* simple algo - select all faces that have a selected edge
2315                  * this intern selects the edge, repeat until nothing is left to do */
2316                 for(efa= em->faces.first; efa; efa= efa->next) {
2317                         if ((efa->tmp.l == 0) && (!efa->h)) {
2318                                 if (is_face_tag(efa)) {
2319                                         face_tag(efa);
2320                                         done= 1;
2321                                 }
2322                         }
2323                 }
2324         }
2325         
2326         for(efa= em->faces.first; efa; efa= efa->next) {
2327                 if (efa->tmp.l) {
2328                         if (sel) {
2329                                 if (!(efa->f & SELECT)) {
2330                                         EM_select_face(efa, 1);
2331                                         change = 1;
2332                                 }
2333                         } else {
2334                                 if (efa->f & SELECT) {
2335                                         EM_select_face(efa, 0);
2336                                         change = 1;
2337                                 }
2338                         }
2339                 }
2340         }
2341         
2342         if (!change)
2343                 return;
2344         
2345         if (!sel) /* make sure de-selecting faces didnt de-select the verts/edges connected to selected faces, this is common with boundries */
2346                 for(efa= em->faces.first; efa; efa= efa->next)
2347                         if (efa->f & SELECT)
2348                                 EM_select_face(efa, 1);
2349         
2350 //      if (EM_texFaceCheck())
2351         
2352         BIF_undo_push("Select Linked Delimeted");
2353         
2354 }
2355
2356 #undef is_edge_delimit_ok
2357 #undef is_face_tag
2358 #undef face_tag
2359
2360 void selectconnected_delimit_mesh(EditMesh *em)
2361 {
2362         
2363         // XXX selectconnected_delimit_mesh__internal(em, 0, ((G.qual & LR_SHIFTKEY)==0));
2364 }
2365 void selectconnected_delimit_mesh_all(ViewContext *vc)
2366 {
2367         selectconnected_delimit_mesh__internal(vc, 1, 1);
2368 }       
2369         
2370         
2371 /* swap is 0 or 1, if 1 it hides not selected */
2372 void hide_mesh(EditMesh *em, int swap)
2373 {
2374         EditVert *eve;
2375         EditEdge *eed;
2376         EditFace *efa;
2377         int a;
2378         
2379         if(em==NULL) return;
2380
2381         /* hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
2382         /*  - vertex hidden, always means edge is hidden too
2383                 - edge hidden, always means face is hidden too
2384                 - face hidden, only set face hide
2385                 - then only flush back down what's absolute hidden
2386         */
2387         if(em->selectmode & SCE_SELECT_VERTEX) {
2388                 for(eve= em->verts.first; eve; eve= eve->next) {
2389                         if((eve->f & SELECT)!=swap) {
2390                                 eve->f &= ~SELECT;
2391                                 eve->h= 1;
2392                         }
2393                 }
2394         
2395                 for(eed= em->edges.first; eed; eed= eed->next) {
2396                         if(eed->v1->h || eed->v2->h) {
2397                                 eed->h |= 1;
2398                                 eed->f &= ~SELECT;
2399                         }
2400                 }
2401         
2402                 for(efa= em->faces.first; efa; efa= efa->next) {
2403                         if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
2404                                 efa->h= 1;
2405                                 efa->f &= ~SELECT;
2406                         }
2407                 }
2408         }
2409         else if(em->selectmode & SCE_SELECT_EDGE) {
2410
2411                 for(eed= em->edges.first; eed; eed= eed->next) {
2412                         if((eed->f & SELECT)!=swap) {
2413                                 eed->h |= 1;
2414                                 EM_select_edge(eed, 0);
2415                         }
2416                 }
2417
2418                 for(efa= em->faces.first; efa; efa= efa->next) {
2419                         if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
2420                                 efa->h= 1;
2421                                 efa->f &= ~SELECT;
2422                         }
2423                 }
2424         }
2425         else {
2426
2427                 for(efa= em->faces.first; efa; efa= efa->next) {
2428                         if((efa->f & SELECT)!=swap) {
2429                                 efa->h= 1;
2430                                 EM_select_face(efa, 0);
2431                         }
2432                 }
2433         }
2434         
2435         /* flush down, only whats 100% hidden */
2436         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
2437         for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
2438         
2439         if(em->selectmode & SCE_SELECT_FACE) {
2440                 for(efa= em->faces.first; efa; efa= efa->next) {
2441                         if(efa->h) a= 1; else a= 2;
2442                         efa->e1->f1 |= a;
2443                         efa->e2->f1 |= a;
2444                         efa->e3->f1 |= a;
2445                         if(efa->e4) efa->e4->f1 |= a;
2446                         /* When edges are not delt with in their own loop, we need to explicitly re-selct select edges that are joined to unselected faces */
2447                         if (swap && (em->selectmode == SCE_SELECT_FACE) && (efa->f & SELECT)) {
2448                                 EM_select_face(efa, 1);
2449                         }
2450                 }
2451         }
2452         
2453         if(em->selectmode >= SCE_SELECT_EDGE) {
2454                 for(eed= em->edges.first; eed; eed= eed->next) {
2455                         if(eed->f1==1) eed->h |= 1;
2456                         if(eed->h & 1) a= 1; else a= 2;
2457                         eed->v1->f1 |= a;
2458                         eed->v2->f1 |= a;
2459                 }
2460         }
2461
2462         if(em->selectmode >= SCE_SELECT_VERTEX) {
2463                 for(eve= em->verts.first; eve; eve= eve->next) {
2464                         if(eve->f1==1) eve->h= 1;
2465                 }
2466         }
2467         
2468         G.totedgesel= G.totfacesel= G.totvertsel= 0;
2469 //      if(EM_texFaceCheck())
2470
2471         //      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
2472         BIF_undo_push("Hide");
2473 }
2474
2475 static int hide_mesh_exec(bContext *C, wmOperator *op)
2476 {
2477         Object *obedit= CTX_data_edit_object(C);
2478         EditMesh *em= ((Mesh *)obedit->data)->edit_mesh;
2479         
2480         /* 'standard' behaviour - check if selected, then apply relevant selection */
2481         if (RNA_boolean_get(op->ptr, "swap"))
2482                 hide_mesh(em,1);
2483         else
2484                 hide_mesh(em,0);
2485                 
2486         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2487         return OPERATOR_FINISHED;       
2488 }
2489
2490 void MESH_OT_hide_mesh(wmOperatorType *ot)
2491 {
2492         /* identifiers */
2493         ot->name= "Hide vertice or Hide All of the Mesh";
2494         ot->idname= "MESH_OT_hide_mesh";
2495         
2496         /* api callbacks */
2497         ot->exec= hide_mesh_exec;
2498         ot->poll= ED_operator_editmesh;
2499         
2500         /* flags */
2501         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
2502         
2503         /* props */
2504         RNA_def_property(ot->srna, "swap", PROP_BOOLEAN, PROP_NONE);
2505 }
2506
2507 void reveal_mesh(EditMesh *em)
2508 {
2509         EditVert *eve;
2510         EditEdge *eed;
2511         EditFace *efa;
2512         
2513         if(em==NULL) return;
2514
2515         for(eve= em->verts.first; eve; eve= eve->next) {
2516                 if(eve->h) {
2517                         eve->h= 0;
2518                         eve->f |= SELECT;
2519                 }
2520         }
2521         for(eed= em->edges.first; eed; eed= eed->next) {
2522                 if(eed->h & 1) {
2523                         eed->h &= ~1;
2524                         if(em->selectmode & SCE_SELECT_VERTEX); 
2525                         else EM_select_edge(eed, 1);
2526                 }
2527         }
2528         for(efa= em->faces.first; efa; efa= efa->next) {
2529                 if(efa->h) {
2530                         efa->h= 0;
2531                         if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX)); 
2532                         else EM_select_face(efa, 1);
2533                 }
2534         }
2535
2536         EM_fgon_flags(em);      /* redo flags and indices for fgons */
2537         EM_selectmode_flush(em);
2538
2539 //      if (EM_texFaceCheck())
2540 //      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
2541         BIF_undo_push("Reveal");
2542 }
2543
2544 static int reveal_mesh_exec(bContext *C, wmOperator *op)
2545 {
2546         Object *obedit= CTX_data_edit_object(C);
2547         EditMesh *em= ((Mesh *)obedit->data)->edit_mesh;
2548         
2549         reveal_mesh(em);
2550                 
2551         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2552         return OPERATOR_FINISHED;       
2553 }
2554
2555 void MESH_OT_reveal_mesh(wmOperatorType *ot)
2556 {
2557         /* identifiers */
2558         ot->name= "Reveal the Mesh";
2559         ot->idname= "MESH_OT_reveal_mesh";
2560         
2561         /* api callbacks */
2562         ot->exec= reveal_mesh_exec;
2563         ot->poll= ED_operator_editmesh;
2564 }
2565
2566 void hide_tface_uv(EditMesh *em, int swap)
2567 {
2568 #if 0
2569         /* no space image here */
2570         EditFace *efa;
2571         MTFace *tface;
2572         
2573         if( is_uv_tface_editing_allowed()==0 ) return;
2574
2575         /* call the mesh function if we are in mesh sync sel */
2576         if (G.sima->flag & SI_SYNC_UVSEL) {
2577                 hide_mesh(swap);
2578                 return;
2579         }
2580         
2581         if(swap) {
2582                 for (efa= em->faces.first; efa; efa= efa->next) {
2583                         if(efa->f & SELECT) {
2584                                 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2585                                 if (G.sima->flag & SI_SELACTFACE) {
2586                                         /* Pretend face mode */
2587                                         if ((   (efa->v4==NULL && 
2588                                                         (       tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) ==                     (TF_SEL1|TF_SEL2|TF_SEL3) )                      ||
2589                                                         (       tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) ==     (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)       ) == 0) {
2590                                                 
2591                                                 if (em->selectmode == SCE_SELECT_FACE) {
2592                                                         efa->f &= ~SELECT;
2593                                                         /* must re-select after */
2594                                                         efa->e1->f &= ~SELECT;
2595                                                         efa->e2->f &= ~SELECT;
2596                                                         efa->e3->f &= ~SELECT;
2597                                                         if(efa->e4) efa->e4->f &= ~SELECT;
2598                                                 } else {
2599                                                         EM_select_face(efa, 0);
2600                                                 }
2601                                         }
2602                                         tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2603                                 } else if (em->selectmode == SCE_SELECT_FACE) {
2604                                         if((tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))==0) {
2605                                                 if(!efa->v4)
2606                                                         EM_select_face(efa, 0);
2607                                                 else if(!(tface->flag & TF_SEL4))
2608                                                         EM_select_face(efa, 0);
2609                                                 tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2610                                         }
2611                                 } else {
2612                                         /* EM_deselect_flush will deselect the face */
2613                                         if((tface->flag & TF_SEL1)==0)                          efa->v1->f &= ~SELECT;
2614                                         if((tface->flag & TF_SEL2)==0)                          efa->v2->f &= ~SELECT;
2615                                         if((tface->flag & TF_SEL3)==0)                          efa->v3->f &= ~SELECT;
2616                                         if((efa->v4) && (tface->flag & TF_SEL4)==0)     efa->v4->f &= ~SELECT;                  
2617                                         tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2618                                 }
2619                         }
2620                 }
2621         } else {
2622                 for (efa= em->faces.first; efa; efa= efa->next) {
2623                         if(efa->f & SELECT) {
2624                                 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2625                                 if (G.sima->flag & SI_SELACTFACE) {
2626                                         if (    (efa->v4==NULL && 
2627                                                         (       tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) ==                     (TF_SEL1|TF_SEL2|TF_SEL3) )                      ||
2628                                                         (       tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) ==     (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)       ) {
2629                                                 
2630                                                 if (em->selectmode == SCE_SELECT_FACE) {
2631                                                         efa->f &= ~SELECT;
2632                                                         /* must re-select after */
2633                                                         efa->e1->f &= ~SELECT;
2634                                                         efa->e2->f &= ~SELECT;
2635                                                         efa->e3->f &= ~SELECT;
2636                                                         if(efa->e4) efa->e4->f &= ~SELECT;
2637                                                 } else {
2638                                                         EM_select_face(efa, 0);
2639                                                 }
2640                                         }
2641                                         tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2642                                 } else if (em->selectmode == SCE_SELECT_FACE) {
2643                                         if(tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
2644                                                 EM_select_face(efa, 0);
2645                                         else if(efa->v4 && tface->flag & TF_SEL4)
2646                                                 EM_select_face(efa, 0);
2647                                         tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2648                                 } else {
2649                                         /* EM_deselect_flush will deselect the face */
2650                                         if(tface->flag & TF_SEL1)                               efa->v1->f &= ~SELECT;
2651                                         if(tface->flag & TF_SEL2)                               efa->v2->f &= ~SELECT;
2652                                         if(tface->flag & TF_SEL3)                               efa->v3->f &= ~SELECT;
2653                                         if((efa->v4) && tface->flag & TF_SEL4)  efa->v4->f &= ~SELECT;
2654                                         tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2655                                 }
2656                         }
2657                 }
2658         }
2659         
2660         
2661         /*deselects too many but ok for now*/
2662         if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX)) {
2663                 EM_deselect_flush(em);
2664         }
2665         
2666         if (em->selectmode==SCE_SELECT_FACE) {
2667                 /* de-selected all edges from faces that were de-selected.
2668                  * now make sure all faces that are selected also have selected edges */
2669                 for (efa= em->faces.first; efa; efa= efa->next) {
2670                         if (efa->f & SELECT) {
2671                                 EM_select_face(efa, 1);
2672                         }
2673                 }
2674         }
2675         
2676         EM_validate_selections();
2677         
2678         BIF_undo_push("Hide UV");
2679
2680 // XXX  object_tface_flags_changed(OBACT, 0);
2681 #endif
2682 }
2683
2684 void reveal_tface_uv(EditMesh *em)
2685 {
2686 #if 0
2687         /* function should move away? */
2688         EditFace *efa;
2689         MTFace *tface;
2690
2691         if( is_uv_tface_editing_allowed()==0 ) return;
2692         
2693         /* call the mesh function if we are in mesh sync sel */
2694         if (G.sima->flag & SI_SYNC_UVSEL) {
2695                 reveal_mesh();
2696                 return;
2697         }
2698         
2699         if (G.sima->flag & SI_SELACTFACE) {
2700                 if (em->selectmode == SCE_SELECT_FACE) {
2701                         for (efa= em->faces.first; efa; efa= efa->next) {
2702                                 if (!(efa->h) && !(efa->f & SELECT)) {
2703                                         tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2704                                         EM_select_face(efa, 1);
2705                                         tface->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
2706                                 }
2707                         }
2708                 } else {
2709                         /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
2710                         if (G.sima->sticky == SI_STICKY_DISABLE) {
2711                                 for (efa= em->faces.first; efa; efa= efa->next) {
2712                                         if (!(efa->h) && !(efa->f & SELECT)) {
2713                                                 /* All verts must be unselected for the face to be selected in the UV view */
2714                                                 if ((efa->v1->f&SELECT)==0 && (efa->v2->f&SELECT)==0 && (efa->v3->f&SELECT)==0 && (efa->v4==0 || (efa->v4->f&SELECT)==0)) {
2715                                                         tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2716                                                         tface->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
2717                                                         /* Cant use EM_select_face here because it unselects the verts
2718                                                          * and we cant tell if the face was totally unselected or not */
2719                                                         /*EM_select_face(efa, 1);
2720                                                          * 
2721                                                          * See Loop with EM_select_face() below... */
2722                                                         efa->f |= SELECT;
2723                                                 }
2724                                         }
2725                                 }
2726                         } else {
2727                                 for (efa= em->faces.first; efa; efa= efa->next) {
2728                                         if (!(efa->h) && !(efa->f & SELECT)) {
2729                                                 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2730                                                 if ((efa->v1->f & SELECT)==0)                           {tface->flag |= TF_SEL1;}
2731                                                 if ((efa->v2->f & SELECT)==0)                           {tface->flag |= TF_SEL2;}
2732                                                 if ((efa->v3->f & SELECT)==0)                           {tface->flag |= TF_SEL3;}
2733                                                 if ((efa->v4 && (efa->v4->f & SELECT)==0))      {tface->flag |= TF_SEL4;}
2734                                                 efa->f |= SELECT;
2735                                         }
2736                                 }
2737                         }
2738                         
2739                         /* Select all edges and verts now */
2740                         for (efa= em->faces.first; efa; efa= efa->next) {
2741                                 /* we only selected the face flags, and didnt changes edges or verts, fix this now */
2742                                 if (!(efa->h) && (efa->f & SELECT)) {
2743                                         EM_select_face(efa, 1);
2744                                 }
2745                         }
2746                         EM_select_flush(em);
2747                 }
2748         } else if (em->selectmode == SCE_SELECT_FACE) {
2749                 for (efa= em->faces.first; efa; efa= efa->next) {
2750                         if (!(efa->h) && !(efa->f & SELECT)) {
2751                                 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2752                                 efa->f |= SELECT;
2753                                 tface->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
2754                         }
2755                 }
2756                 
2757                 /* Select all edges and verts now */
2758                 for (efa= em->faces.first; efa; efa= efa->next) {
2759                         /* we only selected the face flags, and didnt changes edges or verts, fix this now */
2760                         if (!(efa->h) && (efa->f & SELECT)) {
2761                                 EM_select_face(efa, 1);
2762                         }
2763                 }
2764                 
2765         } else {
2766                 for (efa= em->faces.first; efa; efa= efa->next) {
2767                         if (!(efa->h) && !(efa->f & SELECT)) {
2768                                 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2769                                 if ((efa->v1->f & SELECT)==0)                           {tface->flag |= TF_SEL1;}
2770                                 if ((efa->v2->f & SELECT)==0)                           {tface->flag |= TF_SEL2;}
2771                                 if ((efa->v3->f & SELECT)==0)                           {tface->flag |= TF_SEL3;}
2772                                 if ((efa->v4 && (efa->v4->f & SELECT)==0))      {tface->flag |= TF_SEL4;}
2773                                 efa->f |= SELECT;
2774                         }
2775                 }
2776                 
2777                 /* Select all edges and verts now */
2778                 for (efa= em->faces.first; efa; efa= efa->next) {
2779                         /* we only selected the face flags, and didnt changes edges or verts, fix this now */
2780                         if (!(efa->h) && (efa->f & SELECT)) {
2781                                 EM_select_face(efa, 1);
2782                         }
2783                 }
2784         }
2785         
2786         BIF_undo_push("Reveal UV");
2787         
2788 // XXX  object_tface_flags_changed(OBACT, 0);
2789 #endif
2790 }
2791
2792 void select_faces_by_numverts(EditMesh *em, int numverts)
2793 {
2794         EditFace *efa;
2795
2796         /* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring
2797          * faces
2798          */
2799
2800         /* for loose vertices/edges, we first select all, loop below will deselect */
2801         if(numverts==5)
2802                 EM_set_flag_all(em, SELECT);
2803         else if(em->selectmode!=SCE_SELECT_FACE) {
2804                 error("Only works in face selection mode");
2805                 return;
2806         }
2807         
2808         for(efa= em->faces.first; efa; efa= efa->next) {
2809                 if (efa->e4) {
2810                         EM_select_face(efa, (numverts==4) );
2811                 }
2812                 else {
2813                         EM_select_face(efa, (numverts==3) );
2814                 }
2815         }
2816
2817 //      if (EM_texFaceCheck())
2818         
2819         if (numverts==3)
2820                 BIF_undo_push("Select Triangles");
2821         else if (numverts==4)
2822                 BIF_undo_push("Select Quads");
2823         else
2824                 BIF_undo_push("Select non-Triangles/Quads");
2825 }
2826
2827 void select_sharp_edges(EditMesh *em, float fsharpness)
2828 {
2829         /* Find edges that have exactly two neighboring faces,
2830          * check the angle between those faces, and if angle is
2831          * small enough, select the edge
2832          */
2833         EditEdge *eed;
2834         EditFace *efa;
2835         EditFace **efa1;
2836         EditFace **efa2;
2837         intptr_t edgecount = 0, i;
2838         static short sharpness = 135;
2839
2840         if(em->selectmode==SCE_SELECT_FACE) {
2841                 error("Doesn't work in face selection mode");
2842                 return;
2843         }
2844
2845 // XXX  if(button(&sharpness,0, 180,"Max Angle:")==0) return;
2846         /* if faces are at angle 'sharpness', then the face normals
2847          * are at angle 180.0 - 'sharpness' (convert to radians too)
2848          */
2849         fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
2850
2851         i=0;
2852         /* count edges, use tmp.l  */
2853         eed= em->edges.first;
2854         while(eed) {
2855                 edgecount++;
2856                 eed->tmp.l = i;
2857                 eed= eed->next;
2858                 ++i;
2859         }
2860
2861         /* for each edge, we want a pointer to two adjacent faces */
2862         efa1 = MEM_callocN(edgecount*sizeof(EditFace *), 
2863                                            "pairs of edit face pointers");
2864         efa2 = MEM_callocN(edgecount*sizeof(EditFace *), 
2865                                            "pairs of edit face pointers");
2866
2867 #define face_table_edge(eed) { \
2868                 i = eed->tmp.l; \
2869                 if (i != -1) { \
2870                         if (efa1[i]) { \
2871                                 if (efa2[i]) { \
2872                                         /* invalidate, edge has more than two neighbors */ \
2873                                         eed->tmp.l = -1; \
2874                                 } \
2875                                 else { \
2876                                         efa2[i] = efa; \
2877                                 } \
2878                         } \
2879                         else { \