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