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