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