2.5: warning fixes
[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 #include "BKE_report.h"
71
72 #include "IMB_imbuf_types.h"
73 #include "IMB_imbuf.h"
74
75 #include "RE_render_ext.h"  /* externtex */
76
77 #include "WM_api.h"
78 #include "WM_types.h"
79
80 #include "RNA_access.h"
81 #include "RNA_define.h"
82
83 #include "ED_mesh.h"
84 #include "ED_screen.h"
85 #include "ED_view3d.h"
86
87 #include "BIF_gl.h"
88 #include "BIF_glutil.h"
89
90 #include "mesh_intern.h"
91
92 #include "BLO_sys_types.h" // for intptr_t support
93
94 /* XXX */
95 static void waitcursor(int val) {}
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 existing selection */
646
647 /* FACES GROUP */
648
649 #define SIMFACE_MATERIAL        201
650 #define SIMFACE_IMAGE           202
651 #define SIMFACE_AREA            203
652 #define SIMFACE_PERIMETER       204
653 #define SIMFACE_NORMAL          205
654 #define SIMFACE_COPLANAR        206
655
656 static EnumPropertyItem prop_simface_types[] = {
657         {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
658         {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
659         {SIMFACE_AREA, "AREA", 0, "Area", ""},
660         {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
661         {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
662         {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
663         {0, NULL, 0, NULL, NULL}
664 };
665
666
667 /* this as a way to compare the ares, perim  of 2 faces thay will scale to different sizes
668 *0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
669 #define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5) <= b))
670
671 static int similar_face_select__internal(Scene *scene, EditMesh *em, int mode)
672 {
673         EditFace *efa, *base_efa=NULL;
674         unsigned int selcount=0; /*count how many new faces we select*/
675         
676         /*deselcount, count how many deselected faces are left, so we can bail out early
677         also means that if there are no deselected faces, we can avoid a lot of looping */
678         unsigned int deselcount=0; 
679         float thresh= scene->toolsettings->select_thresh;
680         short ok=0;
681         
682         for(efa= em->faces.first; efa; efa= efa->next) {
683                 if (!efa->h) {
684                         if (efa->f & SELECT) {
685                                 efa->f1=1;
686                                 ok=1;
687                         } else {
688                                 efa->f1=0;
689                                 deselcount++; /* a deselected face we may select later */
690                         }
691                 }
692         }
693         
694         if (!ok || !deselcount) /* no data selected OR no more data to select */
695                 return 0;
696         
697         if (mode==SIMFACE_AREA) {
698                 for(efa= em->faces.first; efa; efa= efa->next) {
699                         efa->tmp.fp= EM_face_area(efa);
700                 }
701         } else if (mode==SIMFACE_PERIMETER) {
702                 for(efa= em->faces.first; efa; efa= efa->next) {
703                         efa->tmp.fp= EM_face_perimeter(efa);
704                 }
705         }
706         
707         for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) {
708                 if (base_efa->f1) { /* This was one of the faces originaly selected */
709                         if (mode==SIMFACE_MATERIAL) { /* same material */
710                                 for(efa= em->faces.first; efa; efa= efa->next) {
711                                         if (
712                                                 !(efa->f & SELECT) &&
713                                                 !efa->h &&
714                                                 base_efa->mat_nr == efa->mat_nr
715                                         ) {
716                                                 EM_select_face(efa, 1);
717                                                 selcount++;
718                                                 deselcount--;
719                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
720                                                         return selcount;
721                                         }
722                                 }
723                         } else if (mode==SIMFACE_IMAGE) { /* same image */
724                                 MTFace *tf, *base_tf;
725
726                                 base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data,
727                                                                      CD_MTFACE);
728
729                                 if(!base_tf)
730                                         return selcount;
731
732                                 for(efa= em->faces.first; efa; efa= efa->next) {
733                                         if (!(efa->f & SELECT) && !efa->h) {
734                                                 tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data,
735                                                                                 CD_MTFACE);
736
737                                                 if(base_tf->tpage == tf->tpage) {
738                                                         EM_select_face(efa, 1);
739                                                         selcount++;
740                                                         deselcount--;
741                                                         if (!deselcount) /*have we selected all posible faces?, if so return*/
742                                                                 return selcount;
743                                                 }
744                                         }
745                                 }
746                         } else if (mode==SIMFACE_AREA || mode==SIMFACE_PERIMETER) { /* same area OR same perimeter, both use the same temp var */
747                                 for(efa= em->faces.first; efa; efa= efa->next) {
748                                         if (
749                                                 (!(efa->f & SELECT) && !efa->h) &&
750                                                 SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp)
751                                         ) {
752                                                 EM_select_face(efa, 1);
753                                                 selcount++;
754                                                 deselcount--;
755                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
756                                                         return selcount;
757                                         }
758                                 }
759                         } else if (mode==SIMFACE_NORMAL) {
760                                 float angle;
761                                 for(efa= em->faces.first; efa; efa= efa->next) {
762                                         if (!(efa->f & SELECT) && !efa->h) {
763                                                 angle= VecAngle2(base_efa->n, efa->n);
764                                                 if (angle/180.0<=thresh) {
765                                                         EM_select_face(efa, 1);
766                                                         selcount++;
767                                                         deselcount--;
768                                                         if (!deselcount) /*have we selected all posible faces?, if so return*/
769                                                                 return selcount;
770                                                 }
771                                         }
772                                 }
773                         } else if (mode==SIMFACE_COPLANAR) { /* same planer */
774                                 float angle, base_dot, dot;
775                                 base_dot= Inpf(base_efa->cent, base_efa->n);
776                                 for(efa= em->faces.first; efa; efa= efa->next) {
777                                         if (!(efa->f & SELECT) && !efa->h) {
778                                                 angle= VecAngle2(base_efa->n, efa->n);
779                                                 if (angle/180.0<=thresh) {
780                                                         dot=Inpf(efa->cent, base_efa->n);
781                                                         if (fabs(base_dot-dot) <= thresh) {
782                                                                 EM_select_face(efa, 1);
783                                                                 selcount++;
784                                                                 deselcount--;
785                                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
786                                                                         return selcount;
787                                                         }
788                                                 }
789                                         }
790                                 }
791                         }
792                 }
793         } /* end base_efa loop */
794         return selcount;
795 }
796
797 static int similar_face_select_exec(bContext *C, wmOperator *op)
798 {
799         Scene *scene= CTX_data_scene(C);
800         Object *obedit= CTX_data_edit_object(C);
801         Mesh *me= obedit->data;
802         EditMesh *em= BKE_mesh_get_editmesh(me); 
803
804         int selcount = similar_face_select__internal(scene, em, RNA_int_get(op->ptr, "type"));
805         
806         if (selcount) {
807                 /* here was an edge-mode only select flush case, has to be generalized */
808                 EM_selectmode_flush(em);
809                 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
810                 BKE_mesh_end_editmesh(me, em);
811                 return OPERATOR_FINISHED;
812         }
813         
814         BKE_mesh_end_editmesh(me, em);
815         return OPERATOR_CANCELLED;
816 }       
817
818 /* ***************************************************** */
819
820 /* EDGE GROUP */
821
822 #define SIMEDGE_LENGTH          101
823 #define SIMEDGE_DIR                     102
824 #define SIMEDGE_FACE            103
825 #define SIMEDGE_FACE_ANGLE      104
826 #define SIMEDGE_CREASE          105
827 #define SIMEDGE_SEAM            106
828 #define SIMEDGE_SHARP           107
829
830 static EnumPropertyItem prop_simedge_types[] = {
831         {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
832         {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
833         {SIMEDGE_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
834         {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
835         {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
836         {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
837         {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
838         {0, NULL, 0, NULL, NULL}
839 };
840
841 static int similar_edge_select__internal(Scene *scene, EditMesh *em, int mode)
842 {
843         EditEdge *eed, *base_eed=NULL;
844         unsigned int selcount=0; /* count how many new edges we select*/
845         
846         /*count how many visible selected edges there are,
847         so we can return when there are none left */
848         unsigned int deselcount=0;
849         
850         short ok=0;
851         float thresh= scene->toolsettings->select_thresh;
852         
853         for(eed= em->edges.first; eed; eed= eed->next) {
854                 if (!eed->h) {
855                         if (eed->f & SELECT) {
856                                 eed->f1=1;
857                                 ok=1;
858                         } else {
859                                 eed->f1=0;
860                                 deselcount++;
861                         }
862                         /* set all eed->tmp.l to 0 we use it later.
863                         for counting face users*/
864                         eed->tmp.l=0;
865                         eed->f2=0; /* only for mode SIMEDGE_FACE_ANGLE, edge animations */
866                 }
867         }
868         
869         if (!ok || !deselcount) /* no data selected OR no more data to select*/
870                 return 0;
871         
872         if (mode==SIMEDGE_LENGTH) { /*store length*/
873                 for(eed= em->edges.first; eed; eed= eed->next) {
874                         if (!eed->h) /* dont calc data for hidden edges*/
875                                 eed->tmp.fp= VecLenf(eed->v1->co, eed->v2->co);
876                 }
877         } else if (mode==SIMEDGE_FACE) { /*store face users*/
878                 EditFace *efa;
879                 /* cound how many faces each edge uses use tmp->l */
880                 for(efa= em->faces.first; efa; efa= efa->next) {
881                         efa->e1->tmp.l++;
882                         efa->e2->tmp.l++;
883                         efa->e3->tmp.l++;
884                         if (efa->e4) efa->e4->tmp.l++;
885                 }
886         } else if (mode==SIMEDGE_FACE_ANGLE) { /*store edge angles */
887                 EditFace *efa;
888                 int j;
889                 /* cound how many faces each edge uses use tmp.l */
890                 for(efa= em->faces.first; efa; efa= efa->next) {
891                         /* here we use the edges temp data to assign a face
892                         if a face has alredy been assigned (eed->f2==1)
893                         we calculate the angle between the current face and
894                         the edges previously found face.
895                         store the angle in eed->tmp.fp (loosing the face eed->tmp.f)
896                         but tagging eed->f2==2, so we know not to look at it again.
897                         This only works for edges that connect to 2 faces. but its good enough
898                         */
899                         
900                         /* se we can loop through face edges*/
901                         j=0;
902                         eed= efa->e1;
903                         while (j<4) {
904                                 if (j==1) eed= efa->e2;
905                                 else if (j==2) eed= efa->e3;
906                                 else if (j==3) {
907                                         eed= efa->e4;
908                                         if (!eed)
909                                                 break;
910                                 } /* done looping */
911                                 
912                                 if (!eed->h) { /* dont calc data for hidden edges*/
913                                         if (eed->f2==2)
914                                                 break;
915                                         else if (eed->f2==0) /* first access, assign the face */
916                                                 eed->tmp.f= efa;
917                                         else if (eed->f2==1) /* second, we assign the angle*/
918                                                 eed->tmp.fp= VecAngle2(eed->tmp.f->n, efa->n)/180;
919                                         eed->f2++; /* f2==0 no face assigned. f2==1 one face found. f2==2 angle calculated.*/
920                                 }
921                                 j++;
922                         }
923                 }
924         }
925         
926         for(base_eed= em->edges.first; base_eed; base_eed= base_eed->next) {
927                 if (base_eed->f1) {
928                         if (mode==SIMEDGE_LENGTH) { /* same length */
929                                 for(eed= em->edges.first; eed; eed= eed->next) {
930                                         if (
931                                                 !(eed->f & SELECT) &&
932                                                 !eed->h &&
933                                                 SCALE_CMP(base_eed->tmp.fp, eed->tmp.fp)
934                                         ) {
935                                                 EM_select_edge(eed, 1);
936                                                 selcount++;
937                                                 deselcount--;
938                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
939                                                         return selcount;
940                                         }
941                                 }
942                         } else if (mode==SIMEDGE_DIR) { /* same direction */
943                                 float base_dir[3], dir[3], angle;
944                                 VecSubf(base_dir, base_eed->v1->co, base_eed->v2->co);
945                                 for(eed= em->edges.first; eed; eed= eed->next) {
946                                         if (!(eed->f & SELECT) && !eed->h) {
947                                                 VecSubf(dir, eed->v1->co, eed->v2->co);
948                                                 angle= VecAngle2(base_dir, dir);
949                                                 
950                                                 if (angle>90) /* use the smallest angle between the edges */
951                                                         angle= fabs(angle-180.0f);
952                                                 
953                                                 if (angle/90.0<=thresh) {
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                                 }
962                         } else if (mode==SIMEDGE_FACE) { /* face users */                               
963                                 for(eed= em->edges.first; eed; eed= eed->next) {
964                                         if (
965                                                 !(eed->f & SELECT) &&
966                                                 !eed->h &&
967                                                 base_eed->tmp.l==eed->tmp.l
968                                         ) {
969                                                 EM_select_edge(eed, 1);
970                                                 selcount++;
971                                                 deselcount--;
972                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
973                                                         return selcount;
974                                         }
975                                 }
976                         } else if (mode==SIMEDGE_FACE_ANGLE && base_eed->f2==2) { /* edge angles, f2==2 means the edge has an angle. */                         
977                                 for(eed= em->edges.first; eed; eed= eed->next) {
978                                         if (
979                                                 !(eed->f & SELECT) &&
980                                                 !eed->h &&
981                                                 eed->f2==2 &&
982                                                 (fabs(base_eed->tmp.fp-eed->tmp.fp)<=thresh)
983                                         ) {
984                                                 EM_select_edge(eed, 1);
985                                                 selcount++;
986                                                 deselcount--;
987                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
988                                                         return selcount;
989                                         }
990                                 }
991                         } else if (mode==SIMEDGE_CREASE) { /* edge crease */
992                                 for(eed= em->edges.first; eed; eed= eed->next) {
993                                         if (
994                                                 !(eed->f & SELECT) &&
995                                                 !eed->h &&
996                                                 (fabs(base_eed->crease-eed->crease) <= thresh)
997                                         ) {
998                                                 EM_select_edge(eed, 1);
999                                                 selcount++;
1000                                                 deselcount--;
1001                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
1002                                                         return selcount;
1003                                         }
1004                                 }
1005                         } else if (mode==SIMEDGE_SEAM) { /* edge seam */
1006                                 for(eed= em->edges.first; eed; eed= eed->next) {
1007                                         if (
1008                                                 !(eed->f & SELECT) &&
1009                                                 !eed->h &&
1010                                                 (eed->seam == base_eed->seam)
1011                                         ) {
1012                                                 EM_select_edge(eed, 1);
1013                                                 selcount++;
1014                                                 deselcount--;
1015                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
1016                                                         return selcount;
1017                                         }
1018                                 }
1019                         } else if (mode==SIMEDGE_SHARP) { /* edge sharp */
1020                                 for(eed= em->edges.first; eed; eed= eed->next) {
1021                                         if (
1022                                                 !(eed->f & SELECT) &&
1023                                                 !eed->h &&
1024                                                 (eed->sharp == base_eed->sharp)
1025                                         ) {
1026                                                 EM_select_edge(eed, 1);
1027                                                 selcount++;
1028                                                 deselcount--;
1029                                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
1030                                                         return selcount;
1031                                         }
1032                                 }
1033                         }
1034                 }
1035         }       
1036         return selcount;
1037 }
1038 /* wrap the above function but do selection flushing edge to face */
1039 static int similar_edge_select_exec(bContext *C, wmOperator *op)
1040 {
1041         Scene *scene= CTX_data_scene(C);
1042         Object *obedit= CTX_data_edit_object(C);
1043         Mesh *me= obedit->data;
1044         EditMesh *em= BKE_mesh_get_editmesh(me); 
1045
1046         int selcount = similar_edge_select__internal(scene, em, RNA_int_get(op->ptr, "type"));
1047         
1048         if (selcount) {
1049                 /* here was an edge-mode only select flush case, has to be generalized */
1050                 EM_selectmode_flush(em);
1051                 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1052                 BKE_mesh_end_editmesh(me, em);
1053                 return OPERATOR_FINISHED;
1054         }
1055         
1056         BKE_mesh_end_editmesh(me, em);
1057         return OPERATOR_CANCELLED;
1058 }
1059
1060 /* ********************************* */
1061
1062 /*
1063 VERT GROUP
1064  mode 1: same normal
1065  mode 2: same number of face users
1066  mode 3: same vertex groups
1067 */
1068
1069 #define SIMVERT_NORMAL  0
1070 #define SIMVERT_FACE    1
1071 #define SIMVERT_VGROUP  2
1072
1073 static EnumPropertyItem prop_simvertex_types[] = {
1074         {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
1075         {SIMVERT_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
1076         {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
1077         {0, NULL, 0, NULL, NULL}
1078 };
1079
1080
1081 static int similar_vert_select_exec(bContext *C, wmOperator *op)
1082 {
1083         Scene *scene= CTX_data_scene(C);
1084         Object *obedit= CTX_data_edit_object(C);
1085         Mesh *me= obedit->data;
1086         EditMesh *em= BKE_mesh_get_editmesh(me); 
1087         EditVert *eve, *base_eve=NULL;
1088         unsigned int selcount=0; /* count how many new edges we select*/
1089         
1090         /*count how many visible selected edges there are,
1091         so we can return when there are none left */
1092         unsigned int deselcount=0;
1093         int mode= RNA_enum_get(op->ptr, "type");
1094         
1095         short ok=0;
1096         float thresh= scene->toolsettings->select_thresh;
1097         
1098         for(eve= em->verts.first; eve; eve= eve->next) {
1099                 if (!eve->h) {
1100                         if (eve->f & SELECT) {
1101                                 eve->f1=1;
1102                                 ok=1;
1103                         } else {
1104                                 eve->f1=0;
1105                                 deselcount++;
1106                         }
1107                         /* set all eve->tmp.l to 0 we use them later.*/
1108                         eve->tmp.l=0;
1109                 }
1110                 
1111         }
1112         
1113         if (!ok || !deselcount) { /* no data selected OR no more data to select*/
1114                 BKE_mesh_end_editmesh(me, em);
1115                 return 0;
1116         }
1117         
1118         if(mode == SIMVERT_FACE) {
1119                 /* store face users */
1120                 EditFace *efa;
1121                 
1122                 /* count how many faces each edge uses use tmp->l */
1123                 for(efa= em->faces.first; efa; efa= efa->next) {
1124                         efa->v1->tmp.l++;
1125                         efa->v2->tmp.l++;
1126                         efa->v3->tmp.l++;
1127                         if (efa->v4) efa->v4->tmp.l++;
1128                 }
1129         }
1130         
1131         
1132         for(base_eve= em->verts.first; base_eve; base_eve= base_eve->next) {
1133                 if (base_eve->f1) {
1134                                 
1135                         if(mode == SIMVERT_NORMAL) {
1136                                 float angle;
1137                                 for(eve= em->verts.first; eve; eve= eve->next) {
1138                                         if (!(eve->f & SELECT) && !eve->h) {
1139                                                 angle= VecAngle2(base_eve->no, eve->no);
1140                                                 if (angle/180.0<=thresh) {
1141                                                         eve->f |= SELECT;
1142                                                         selcount++;
1143                                                         deselcount--;
1144                                                         if (!deselcount) {/*have we selected all posible faces?, if so return*/
1145                                                                 BKE_mesh_end_editmesh(me, em);
1146                                                                 return selcount;
1147                                                         }
1148                                                 }
1149                                         }
1150                                 }
1151                         }
1152                         else if(mode == SIMVERT_FACE) {
1153                                 for(eve= em->verts.first; eve; eve= eve->next) {
1154                                         if (
1155                                                 !(eve->f & SELECT) &&
1156                                                 !eve->h &&
1157                                                 base_eve->tmp.l==eve->tmp.l
1158                                         ) {
1159                                                 eve->f |= SELECT;
1160                                                 selcount++;
1161                                                 deselcount--;
1162                                                 if (!deselcount) {/*have we selected all posible faces?, if so return*/
1163                                                         BKE_mesh_end_editmesh(me, em);
1164                                                         return selcount;
1165                                                 }
1166                                         }
1167                                 }
1168                         } 
1169                         else if(mode == SIMVERT_VGROUP) {
1170                                 MDeformVert *dvert, *base_dvert;
1171                                 short i, j; /* weight index */
1172
1173                                 base_dvert= CustomData_em_get(&em->vdata, base_eve->data,
1174                                         CD_MDEFORMVERT);
1175
1176                                 if (!base_dvert || base_dvert->totweight == 0) {
1177                                         BKE_mesh_end_editmesh(me, em);
1178                                         return selcount;
1179                                 }
1180                                 
1181                                 for(eve= em->verts.first; eve; eve= eve->next) {
1182                                         dvert= CustomData_em_get(&em->vdata, eve->data,
1183                                                 CD_MDEFORMVERT);
1184
1185                                         if (dvert && !(eve->f & SELECT) && !eve->h && dvert->totweight) {
1186                                                 /* do the extra check for selection in the following if, so were not
1187                                                 checking verts that may be alredy selected */
1188                                                 for (i=0; base_dvert->totweight >i && !(eve->f & SELECT); i++) { 
1189                                                         for (j=0; dvert->totweight >j; j++) {
1190                                                                 if (base_dvert->dw[i].def_nr==dvert->dw[j].def_nr) {
1191                                                                         eve->f |= SELECT;
1192                                                                         selcount++;
1193                                                                         deselcount--;
1194                                                                         if (!deselcount) { /*have we selected all posible faces?, if so return*/
1195                                                                                 BKE_mesh_end_editmesh(me, em);
1196                                                                                 return selcount;
1197                                                                         }
1198                                                                         break;
1199                                                                 }
1200                                                         }
1201                                                 }
1202                                         }
1203                                 }
1204                         }
1205                 }
1206         } /* end basevert loop */
1207
1208         if(selcount) {
1209                 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1210                 BKE_mesh_end_editmesh(me, em);
1211                 return OPERATOR_FINISHED;
1212         }
1213
1214         BKE_mesh_end_editmesh(me, em);
1215         return OPERATOR_CANCELLED;
1216 }
1217
1218 static int select_similar_exec(bContext *C, wmOperator *op)
1219 {
1220         int type= RNA_enum_get(op->ptr, "type");
1221
1222         if(type < 100)
1223                 return similar_vert_select_exec(C, op);
1224         else if(type < 200)
1225                 return similar_edge_select_exec(C, op);
1226         else
1227                 return similar_face_select_exec(C, op);
1228 }
1229
1230 static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *ptr, int *free)
1231 {
1232         Object *obedit;
1233         EnumPropertyItem *item= NULL;
1234         int totitem= 0;
1235         
1236         if(C==NULL) {
1237                 /* needed for doc generation */
1238                 RNA_enum_items_add(&item, &totitem, prop_simvertex_types);
1239                 RNA_enum_items_add(&item, &totitem, prop_simedge_types);
1240                 RNA_enum_items_add(&item, &totitem, prop_simface_types);
1241                 RNA_enum_item_end(&item, &totitem);
1242                 *free= 1;
1243                 
1244                 return item;
1245         }
1246         
1247         obedit= CTX_data_edit_object(C);
1248         
1249         if(obedit && obedit->type == OB_MESH) {
1250                 EditMesh *em= BKE_mesh_get_editmesh(obedit->data); 
1251
1252                 if(em->selectmode & SCE_SELECT_VERTEX)
1253                         RNA_enum_items_add(&item, &totitem, prop_simvertex_types);
1254                 else if(em->selectmode & SCE_SELECT_EDGE)
1255                         RNA_enum_items_add(&item, &totitem, prop_simedge_types);
1256                 else if(em->selectmode & SCE_SELECT_FACE)
1257                         RNA_enum_items_add(&item, &totitem, prop_simface_types);
1258                 RNA_enum_item_end(&item, &totitem);
1259
1260                 *free= 1;
1261
1262                 return item;
1263         }
1264         
1265         return NULL;
1266 }
1267
1268 void MESH_OT_select_similar(wmOperatorType *ot)
1269 {
1270         PropertyRNA *prop;
1271
1272         /* identifiers */
1273         ot->name= "Select Similar";
1274         ot->idname= "MESH_OT_select_similar";
1275         
1276         /* api callbacks */
1277         ot->invoke= WM_menu_invoke;
1278         ot->exec= select_similar_exec;
1279         ot->poll= ED_operator_editmesh;
1280         
1281         /* flags */
1282         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1283         
1284         /* properties */
1285         prop= RNA_def_enum(ot->srna, "type", prop_simvertex_types, 0, "Type", "");
1286         RNA_def_enum_funcs(prop, select_similar_type_itemf);
1287 }
1288
1289 /* ******************************************* */
1290
1291
1292 int mesh_layers_menu_charlen(CustomData *data, int type)
1293 {
1294         int i, len = 0;
1295         /* see if there is a duplicate */
1296         for(i=0; i<data->totlayer; i++) {
1297                 if((&data->layers[i])->type == type) {
1298                         /* we could count the chars here but we'll just assumeme each
1299                          * is 32 chars with some room for the menu text - 40 should be fine */
1300                         len+=40; 
1301                 }
1302         }
1303         return len;
1304 }
1305
1306 /* this function adds menu text into an existing string.
1307  * this string's size should be allocated with mesh_layers_menu_charlen */
1308 void mesh_layers_menu_concat(CustomData *data, int type, char *str) 
1309 {
1310         int i, count = 0;
1311         char *str_pt = str;
1312         CustomDataLayer *layer;
1313         
1314         /* see if there is a duplicate */
1315         for(i=0; i<data->totlayer; i++) {
1316                 layer = &data->layers[i];
1317                 if(layer->type == type) {
1318                         str_pt += sprintf(str_pt, "%s%%x%d|", layer->name, count);
1319                         count++;
1320                 }
1321         }
1322 }
1323
1324 int mesh_layers_menu(CustomData *data, int type) {
1325         int ret;
1326         char *str_pt, *str;
1327         
1328         str_pt = str = MEM_mallocN(mesh_layers_menu_charlen(data, type) + 18, "layer menu");
1329         str[0] = '\0';
1330         
1331         str_pt += sprintf(str_pt, "Layers%%t|");
1332         
1333         mesh_layers_menu_concat(data, type, str_pt);
1334         
1335         ret = pupmenu(str);
1336         MEM_freeN(str);
1337         return ret;
1338 }
1339
1340 void EM_mesh_copy_edge(EditMesh *em, short type) 
1341 {
1342         EditSelection *ese;
1343         short change=0;
1344         
1345         EditEdge *eed, *eed_act;
1346         float vec[3], vec_mid[3], eed_len, eed_len_act;
1347         
1348         if (!em) return;
1349         
1350         ese = em->selected.last;
1351         if (!ese) return;
1352         
1353         eed_act = (EditEdge*)ese->data;
1354         
1355         switch (type) {
1356         case 1: /* copy crease */
1357                 for(eed=em->edges.first; eed; eed=eed->next) {
1358                         if (eed->f & SELECT && eed != eed_act && eed->crease != eed_act->crease) {
1359                                 eed->crease = eed_act->crease;
1360                                 change = 1;
1361                         }
1362                 }
1363                 break;
1364         case 2: /* copy bevel weight */
1365                 for(eed=em->edges.first; eed; eed=eed->next) {
1366                         if (eed->f & SELECT && eed != eed_act && eed->bweight != eed_act->bweight) {
1367                                 eed->bweight = eed_act->bweight;
1368                                 change = 1;
1369                         }
1370                 }
1371                 break;
1372
1373         case 3: /* copy length */
1374                 eed_len_act = VecLenf(eed_act->v1->co, eed_act->v2->co);
1375                 for(eed=em->edges.first; eed; eed=eed->next) {
1376                         if (eed->f & SELECT && eed != eed_act) {
1377
1378                                 eed_len = VecLenf(eed->v1->co, eed->v2->co);
1379
1380                                 if (eed_len == eed_len_act) continue;
1381                                 /* if this edge is zero length we cont do anything with it*/
1382                                 if (eed_len == 0.0f) continue;
1383                                 if (eed_len_act == 0.0f) {
1384                                         VecAddf(vec_mid, eed->v1->co, eed->v2->co);
1385                                         VecMulf(vec_mid, 0.5);
1386                                         VECCOPY(eed->v1->co, vec_mid);
1387                                         VECCOPY(eed->v2->co, vec_mid);
1388                                 } else {
1389                                         /* copy the edge length */
1390                                         VecAddf(vec_mid, eed->v1->co, eed->v2->co);
1391                                         VecMulf(vec_mid, 0.5);
1392
1393                                         /* SCALE 1 */
1394                                         VecSubf(vec, eed->v1->co, vec_mid);
1395                                         VecMulf(vec, eed_len_act/eed_len);
1396                                         VecAddf(eed->v1->co, vec, vec_mid);
1397
1398                                         /* SCALE 2 */
1399                                         VecSubf(vec, eed->v2->co, vec_mid);
1400                                         VecMulf(vec, eed_len_act/eed_len);
1401                                         VecAddf(eed->v2->co, vec, vec_mid);
1402                                 }
1403                                 change = 1;
1404                         }
1405                 }
1406
1407                 if (change)
1408                         recalc_editnormals(em);
1409
1410                 break;
1411         }
1412         
1413         if (change) {
1414 //              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1415                 
1416         }
1417 }
1418
1419 void EM_mesh_copy_face(EditMesh *em, wmOperator *op, short type)
1420 {
1421         short change=0;
1422         
1423         EditFace *efa, *efa_act;
1424         MTFace *tf, *tf_act = NULL;
1425         MCol *mcol, *mcol_act = NULL;
1426         if (!em) return;
1427         efa_act = EM_get_actFace(em, 0);
1428         
1429         if (!efa_act) return;
1430         
1431         tf_act =        CustomData_em_get(&em->fdata, efa_act->data, CD_MTFACE);
1432         mcol_act =      CustomData_em_get(&em->fdata, efa_act->data, CD_MCOL);
1433         
1434         switch (type) {
1435         case 1: /* copy material */
1436                 for(efa=em->faces.first; efa; efa=efa->next) {
1437                         if (efa->f & SELECT && efa->mat_nr != efa_act->mat_nr) {
1438                                 efa->mat_nr = efa_act->mat_nr;
1439                                 change = 1;
1440                         }
1441                 }
1442                 break;
1443         case 2: /* copy image */
1444                 if (!tf_act) {
1445                         BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
1446                         return;
1447                 }
1448                 for(efa=em->faces.first; efa; efa=efa->next) {
1449                         if (efa->f & SELECT && efa != efa_act) {
1450                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1451                                 if (tf_act->tpage) {
1452                                         tf->tpage = tf_act->tpage;
1453                                         tf->mode |= TF_TEX;
1454                                 } else {
1455                                         tf->tpage = NULL;
1456                                         tf->mode &= ~TF_TEX;
1457                                 }
1458                                 tf->tile= tf_act->tile;
1459                                 change = 1;
1460                         }
1461                 }
1462                 break;
1463
1464         case 3: /* copy UV's */
1465                 if (!tf_act) {
1466                         BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
1467                         return;
1468                 }
1469                 for(efa=em->faces.first; efa; efa=efa->next) {
1470                         if (efa->f & SELECT && efa != efa_act) {
1471                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1472                                 memcpy(tf->uv, tf_act->uv, sizeof(tf->uv));
1473                                 change = 1;
1474                         }
1475                 }
1476                 break;
1477         case 4: /* mode's */
1478                 if (!tf_act) {
1479                         BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
1480                         return;
1481                 }
1482                 for(efa=em->faces.first; efa; efa=efa->next) {
1483                         if (efa->f & SELECT && efa != efa_act) {
1484                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1485                                 tf->mode= tf_act->mode;
1486                                 change = 1;
1487                         }
1488                 }
1489                 break;
1490         case 5: /* copy transp's */
1491                 if (!tf_act) {
1492                         BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
1493                         return;
1494                 }
1495                 for(efa=em->faces.first; efa; efa=efa->next) {
1496                         if (efa->f & SELECT && efa != efa_act) {
1497                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1498                                 tf->transp= tf_act->transp;
1499                                 change = 1;
1500                         }
1501                 }
1502                 break;
1503
1504         case 6: /* copy vcols's */
1505                 if (!mcol_act) {
1506                         BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers.");
1507                         return;
1508                 } else {
1509                         /* guess the 4th color if needs be */
1510                         float val =- 1;
1511
1512                         if (!efa_act->v4) {
1513                                 /* guess the othe vale, we may need to use it
1514                                  * 
1515                                  * Modifying the 4th value of the mcol is ok here since its not seen
1516                                  * on a triangle
1517                                  * */
1518                                 val = ((float)(mcol_act->r +  (mcol_act+1)->r + (mcol_act+2)->r)) / 3; CLAMP(val, 0, 255);
1519                                 (mcol_act+3)->r = (char)val;
1520
1521                                 val = ((float)(mcol_act->g +  (mcol_act+1)->g + (mcol_act+2)->g)) / 3; CLAMP(val, 0, 255);
1522                                 (mcol_act+3)->g = (char)val;
1523
1524                                 val = ((float)(mcol_act->b +  (mcol_act+1)->b + (mcol_act+2)->b)) / 3; CLAMP(val, 0, 255);
1525                                 (mcol_act+3)->b = (char)val;
1526                         } 
1527
1528
1529                         for(efa=em->faces.first; efa; efa=efa->next) {
1530                                 if (efa->f & SELECT && efa != efa_act) {
1531                                         /* TODO - make copy from tri to quad guess the 4th vert */
1532                                         mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
1533                                         memcpy(mcol, mcol_act, sizeof(MCol)*4); 
1534                                         change = 1;
1535                                 }
1536                         }
1537                 }
1538                 break;
1539         }
1540         
1541         if (change) {
1542 //              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1543                 
1544         }
1545 }
1546
1547
1548 void EM_mesh_copy_face_layer(EditMesh *em, wmOperator *op, short type) 
1549 {
1550         short change=0;
1551         
1552         EditFace *efa;
1553         MTFace *tf, *tf_from;
1554         MCol *mcol, *mcol_from;
1555         
1556         if (!em) return;
1557         
1558         switch(type) {
1559         case 7:
1560         case 8:
1561         case 9:
1562                 if (CustomData_number_of_layers(&em->fdata, CD_MTFACE)<2) {
1563                         BKE_report(op->reports, RPT_ERROR, "mesh does not have multiple uv/image layers");
1564                         return;
1565                 } else {
1566                         int layer_orig_idx, layer_idx;
1567
1568                         layer_idx = mesh_layers_menu(&em->fdata, CD_MTFACE);
1569                         if (layer_idx<0) return;
1570
1571                         /* warning, have not updated mesh pointers however this is not needed since we swicth back */
1572                         layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MTFACE);
1573                         if (layer_idx==layer_orig_idx)
1574                                 return;
1575
1576                         /* get the tfaces */
1577                         CustomData_set_layer_active(&em->fdata, CD_MTFACE, (int)layer_idx);
1578                         /* store the tfaces in our temp */
1579                         for(efa=em->faces.first; efa; efa=efa->next) {
1580                                 if (efa->f & SELECT) {
1581                                         efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1582                                 }       
1583                         }
1584                         CustomData_set_layer_active(&em->fdata, CD_MTFACE, layer_orig_idx);
1585                 }
1586                 break;
1587
1588         case 10: /* select vcol layers - make sure this stays in sync with above code */
1589                 if (CustomData_number_of_layers(&em->fdata, CD_MCOL)<2) {
1590                         BKE_report(op->reports, RPT_ERROR, "mesh does not have multiple color layers");
1591                         return;
1592                 } else {
1593                         int layer_orig_idx, layer_idx;
1594
1595                         layer_idx = mesh_layers_menu(&em->fdata, CD_MCOL);
1596                         if (layer_idx<0) return;
1597
1598                         /* warning, have not updated mesh pointers however this is not needed since we swicth back */
1599                         layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MCOL);
1600                         if (layer_idx==layer_orig_idx)
1601                                 return;
1602
1603                         /* get the tfaces */
1604                         CustomData_set_layer_active(&em->fdata, CD_MCOL, (int)layer_idx);
1605                         /* store the tfaces in our temp */
1606                         for(efa=em->faces.first; efa; efa=efa->next) {
1607                                 if (efa->f & SELECT) {
1608                                         efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
1609                                 }       
1610                         }
1611                         CustomData_set_layer_active(&em->fdata, CD_MCOL, layer_orig_idx);
1612
1613                 }
1614                 break;
1615         }
1616
1617         /* layer copy only - sanity checks done above */
1618         switch (type) {
1619         case 7: /* copy UV's only */
1620                 for(efa=em->faces.first; efa; efa=efa->next) {
1621                         if (efa->f & SELECT) {
1622                                 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
1623                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1624                                 memcpy(tf->uv, tf_from->uv, sizeof(tf->uv));
1625                                 change = 1;
1626                         }
1627                 }
1628                 break;
1629         case 8: /* copy image settings only */
1630                 for(efa=em->faces.first; efa; efa=efa->next) {
1631                         if (efa->f & SELECT) {
1632                                 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
1633                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1634                                 if (tf_from->tpage) {
1635                                         tf->tpage = tf_from->tpage;
1636                                         tf->mode |= TF_TEX;
1637                                 } else {
1638                                         tf->tpage = NULL;
1639                                         tf->mode &= ~TF_TEX;
1640                                 }
1641                                 tf->tile= tf_from->tile;
1642                                 change = 1;
1643                         }
1644                 }
1645                 break;
1646         case 9: /* copy all tface info */
1647                 for(efa=em->faces.first; efa; efa=efa->next) {
1648                         if (efa->f & SELECT) {
1649                                 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
1650                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1651                                 memcpy(tf->uv, ((MTFace *)efa->tmp.p)->uv, sizeof(tf->uv));
1652                                 tf->tpage = tf_from->tpage;
1653                                 tf->mode = tf_from->mode;
1654                                 tf->transp = tf_from->transp;
1655                                 change = 1;
1656                         }
1657                 }
1658                 break;
1659         case 10:
1660                 for(efa=em->faces.first; efa; efa=efa->next) {
1661                         if (efa->f & SELECT) {
1662                                 mcol_from = (MCol *)efa->tmp.p; 
1663                                 mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
1664                                 memcpy(mcol, mcol_from, sizeof(MCol)*4);        
1665                                 change = 1;
1666                         }
1667                 }
1668                 break;
1669         }
1670
1671         if (change) {
1672 //              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1673                 
1674         }
1675 }
1676
1677
1678 /* ctrl+c in mesh editmode */
1679 void mesh_copy_menu(EditMesh *em, wmOperator *op)
1680 {
1681         EditSelection *ese;
1682         int ret;
1683         if (!em) return;
1684         
1685         ese = em->selected.last;
1686         
1687         /* Faces can have a NULL ese, so dont return on a NULL ese here */
1688         
1689         if(ese && ese->type == EDITVERT) {
1690                 /* EditVert *ev, *ev_act = (EditVert*)ese->data;
1691                 ret= pupmenu(""); */
1692         } else if(ese && ese->type == EDITEDGE) {
1693                 ret= pupmenu("Copy Active Edge to Selected%t|Crease%x1|Bevel Weight%x2|Length%x3");
1694                 if (ret<1) return;
1695                 
1696                 EM_mesh_copy_edge(em, ret);
1697                 
1698         } else if(ese==NULL || ese->type == EDITFACE) {
1699                 ret= pupmenu(
1700                         "Copy Face Selected%t|"
1701                         "Active Material%x1|Active Image%x2|Active UV Coords%x3|"
1702                         "Active Mode%x4|Active Transp%x5|Active Vertex Colors%x6|%l|"
1703
1704                         "TexFace UVs from layer%x7|"
1705                         "TexFace Images from layer%x8|"
1706                         "TexFace All from layer%x9|"
1707                         "Vertex Colors from layer%x10");
1708                 if (ret<1) return;
1709                 
1710                 if (ret<=6) {
1711                         EM_mesh_copy_face(em, op, ret);
1712                 } else {
1713                         EM_mesh_copy_face_layer(em, op, ret);
1714                 }
1715         }
1716 }
1717
1718
1719 /* ****************  LOOP SELECTS *************** */
1720
1721 /* selects quads in loop direction of indicated edge */
1722 /* only flush over edges with valence <= 2 */
1723 void faceloop_select(EditMesh *em, EditEdge *startedge, int select)
1724 {
1725         EditEdge *eed;
1726         EditFace *efa;
1727         int looking= 1;
1728         
1729         /* in eed->f1 we put the valence (amount of faces in edge) */
1730         /* in eed->f2 we put tagged flag as correct loop */
1731         /* in efa->f1 we put tagged flag as correct to select */
1732
1733         for(eed= em->edges.first; eed; eed= eed->next) {
1734                 eed->f1= 0;
1735                 eed->f2= 0;
1736         }
1737         for(efa= em->faces.first; efa; efa= efa->next) {
1738                 efa->f1= 0;
1739                 if(efa->h==0) {
1740                         efa->e1->f1++;
1741                         efa->e2->f1++;
1742                         efa->e3->f1++;
1743                         if(efa->e4) efa->e4->f1++;
1744                 }
1745         }
1746         
1747         /* tag startedge OK*/
1748         startedge->f2= 1;
1749         
1750         while(looking) {
1751                 looking= 0;
1752                 
1753                 for(efa= em->faces.first; efa; efa= efa->next) {
1754                         if(efa->h==0 && efa->e4 && efa->f1==0) {        /* not done quad */
1755                                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
1756
1757                                         /* if edge tagged, select opposing edge and mark face ok */
1758                                         if(efa->e1->f2) {
1759                                                 efa->e3->f2= 1;
1760                                                 efa->f1= 1;
1761                                                 looking= 1;
1762                                         }
1763                                         else if(efa->e2->f2) {
1764                                                 efa->e4->f2= 1;
1765                                                 efa->f1= 1;
1766                                                 looking= 1;
1767                                         }
1768                                         if(efa->e3->f2) {
1769                                                 efa->e1->f2= 1;
1770                                                 efa->f1= 1;
1771                                                 looking= 1;
1772                                         }
1773                                         if(efa->e4->f2) {
1774                                                 efa->e2->f2= 1;
1775                                                 efa->f1= 1;
1776                                                 looking= 1;
1777                                         }
1778                                 }
1779                         }
1780                 }
1781         }
1782         
1783         /* (de)select the faces */
1784         if(select!=2) {
1785                 for(efa= em->faces.first; efa; efa= efa->next) {
1786                         if(efa->f1) EM_select_face(efa, select);
1787                 }
1788         }
1789 }
1790
1791
1792 /* helper for edgeloop_select, checks for eed->f2 tag in faces */
1793 static int edge_not_in_tagged_face(EditMesh *em, EditEdge *eed)
1794 {
1795         EditFace *efa;
1796         
1797         for(efa= em->faces.first; efa; efa= efa->next) {
1798                 if(efa->h==0) {
1799                         if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) {      /* edge is in face */
1800                                 if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) {     /* face is tagged */
1801                                         return 0;
1802                                 }
1803                         }
1804                 }
1805         }
1806         return 1;
1807 }
1808
1809 /* selects or deselects edges that:
1810 - if edges has 2 faces:
1811         - has vertices with valence of 4
1812         - not shares face with previous edge
1813 - if edge has 1 face:
1814         - has vertices with valence 4
1815         - not shares face with previous edge
1816         - but also only 1 face
1817 - if edge no face:
1818         - has vertices with valence 2
1819 */
1820 static void edgeloop_select(EditMesh *em, EditEdge *starteed, int select)
1821 {
1822         EditVert *eve;
1823         EditEdge *eed;
1824         EditFace *efa;
1825         int looking= 1;
1826         
1827         /* in f1 we put the valence (amount of edges in a vertex, or faces in edge) */
1828         /* in eed->f2 and efa->f1 we put tagged flag as correct loop */
1829         for(eve= em->verts.first; eve; eve= eve->next) {
1830                 eve->f1= 0;
1831                 eve->f2= 0;
1832         }
1833         for(eed= em->edges.first; eed; eed= eed->next) {
1834                 eed->f1= 0;
1835                 eed->f2= 0;
1836                 if((eed->h & 1)==0) {   /* fgon edges add to valence too */
1837                         eed->v1->f1++; eed->v2->f1++;
1838                 }
1839         }
1840         for(efa= em->faces.first; efa; efa= efa->next) {
1841                 efa->f1= 0;
1842                 if(efa->h==0) {
1843                         efa->e1->f1++;
1844                         efa->e2->f1++;
1845                         efa->e3->f1++;
1846                         if(efa->e4) efa->e4->f1++;
1847                 }
1848         }
1849         
1850         /* looped edges & vertices get tagged f2 */
1851         starteed->f2= 1;
1852         if(starteed->v1->f1<5) starteed->v1->f2= 1;
1853         if(starteed->v2->f1<5) starteed->v2->f2= 1;
1854         /* sorry, first edge isnt even ok */
1855         if(starteed->v1->f2==0 && starteed->v2->f2==0) looking= 0;
1856         
1857         while(looking) {
1858                 looking= 0;
1859                 
1860                 /* find correct valence edges which are not tagged yet, but connect to tagged one */
1861                 for(eed= em->edges.first; eed; eed= eed->next) {
1862                         if(eed->h==0 && eed->f2==0) { /* edge not hidden, not tagged */
1863                                 if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { /* valence of vertex OK, and is tagged */
1864                                         /* new edge is not allowed to be in face with tagged edge */
1865                                         if(edge_not_in_tagged_face(em, eed)) {
1866                                                 if(eed->f1==starteed->f1) {     /* same amount of faces */
1867                                                         looking= 1;
1868                                                         eed->f2= 1;
1869                                                         if(eed->v2->f1<5) eed->v2->f2= 1;
1870                                                         if(eed->v1->f1<5) eed->v1->f2= 1;
1871                                                 }
1872                                         }
1873                                 }
1874                         }
1875                 }
1876         }
1877         /* and we do the select */
1878         for(eed= em->edges.first; eed; eed= eed->next) {
1879                 if(eed->f2) EM_select_edge(eed, select);
1880         }
1881 }
1882
1883 /* 
1884    Almostly exactly the same code as faceloop select
1885 */
1886 static void edgering_select(EditMesh *em, EditEdge *startedge, int select)
1887 {
1888         EditEdge *eed;
1889         EditFace *efa;
1890         int looking= 1;
1891         
1892         /* in eed->f1 we put the valence (amount of faces in edge) */
1893         /* in eed->f2 we put tagged flag as correct loop */
1894         /* in efa->f1 we put tagged flag as correct to select */
1895
1896         for(eed= em->edges.first; eed; eed= eed->next) {
1897                 eed->f1= 0;
1898                 eed->f2= 0;
1899         }
1900         for(efa= em->faces.first; efa; efa= efa->next) {
1901                 efa->f1= 0;
1902                 if(efa->h==0) {
1903                         efa->e1->f1++;
1904                         efa->e2->f1++;
1905                         efa->e3->f1++;
1906                         if(efa->e4) efa->e4->f1++;
1907                 }
1908         }
1909         
1910         /* tag startedge OK */
1911         startedge->f2= 1;
1912         
1913         while(looking) {
1914                 looking= 0;
1915                 
1916                 for(efa= em->faces.first; efa; efa= efa->next) {
1917                         if(efa->e4 && efa->f1==0 && !efa->h) {  /* not done quad */
1918                                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
1919
1920                                         /* if edge tagged, select opposing edge and mark face ok */
1921                                         if(efa->e1->f2) {
1922                                                 efa->e3->f2= 1;
1923                                                 efa->f1= 1;
1924                                                 looking= 1;
1925                                         }
1926                                         else if(efa->e2->f2) {
1927                                                 efa->e4->f2= 1;
1928                                                 efa->f1= 1;
1929                                                 looking= 1;
1930                                         }
1931                                         if(efa->e3->f2) {
1932                                                 efa->e1->f2= 1;
1933                                                 efa->f1= 1;
1934                                                 looking= 1;
1935                                         }
1936                                         if(efa->e4->f2) {
1937                                                 efa->e2->f2= 1;
1938                                                 efa->f1= 1;
1939                                                 looking= 1;
1940                                         }
1941                                 }
1942                         }
1943                 }
1944         }
1945         
1946         /* (de)select the edges */
1947         for(eed= em->edges.first; eed; eed= eed->next) {
1948                 if(eed->f2) EM_select_edge(eed, select);
1949         }
1950 }
1951
1952 static int loop_multiselect(bContext *C, wmOperator *op)
1953 {
1954         Object *obedit= CTX_data_edit_object(C);
1955         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
1956         EditEdge *eed;
1957         EditEdge **edarray;
1958         int edindex, edfirstcount;
1959         int looptype= RNA_boolean_get(op->ptr, "ring");
1960         
1961         /* sets em->totedgesel */
1962         EM_nedges_selected(em);
1963         
1964         edarray = MEM_mallocN(sizeof(EditEdge*)*em->totedgesel,"edge array");
1965         edindex = 0;
1966         edfirstcount = em->totedgesel;
1967         
1968         for(eed=em->edges.first; eed; eed=eed->next){
1969                 if(eed->f&SELECT){
1970                         edarray[edindex] = eed;
1971                         edindex += 1;
1972                 }
1973         }
1974         
1975         if(looptype){
1976                 for(edindex = 0; edindex < edfirstcount; edindex +=1){
1977                         eed = edarray[edindex];
1978                         edgering_select(em, eed,SELECT);
1979                 }
1980                 EM_selectmode_flush(em);
1981         }
1982         else{
1983                 for(edindex = 0; edindex < edfirstcount; edindex +=1){
1984                         eed = edarray[edindex];
1985                         edgeloop_select(em, eed,SELECT);
1986                 }
1987                 EM_selectmode_flush(em);
1988         }
1989         MEM_freeN(edarray);
1990 //      if (EM_texFaceCheck())
1991         
1992         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1993
1994         BKE_mesh_end_editmesh(obedit->data, em);
1995         return OPERATOR_FINISHED;       
1996 }
1997
1998 void MESH_OT_loop_multi_select(wmOperatorType *ot)
1999 {
2000         /* identifiers */
2001         ot->name= "Multi Select Loops";
2002         ot->idname= "MESH_OT_loop_multi_select";
2003         
2004         /* api callbacks */
2005         ot->exec= loop_multiselect;
2006         ot->poll= ED_operator_editmesh;
2007         
2008         /* flags */
2009         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2010         
2011         /* properties */
2012         RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
2013 }
2014
2015                 
2016 /* ***************** MAIN MOUSE SELECTION ************** */
2017
2018
2019 /* ***************** loop select (non modal) ************** */
2020
2021 static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring)
2022 {
2023         ViewContext vc;
2024         EditMesh *em;
2025         EditEdge *eed;
2026         int select= 1;
2027         int dist= 50;
2028         
2029         em_setup_viewcontext(C, &vc);
2030         vc.mval[0]= mval[0];
2031         vc.mval[1]= mval[1];
2032         em= vc.em;
2033         
2034         eed= findnearestedge(&vc, &dist);
2035         if(eed) {
2036                 if(extend==0) EM_clear_flag_all(em, SELECT);
2037         
2038                 if((eed->f & SELECT)==0) select=1;
2039                 else if(extend) select=0;
2040
2041                 if(em->selectmode & SCE_SELECT_FACE) {
2042                         faceloop_select(em, eed, select);
2043                 }
2044                 else if(em->selectmode & SCE_SELECT_EDGE) {
2045                         if(ring)
2046                                 edgering_select(em, eed, select);
2047                         else
2048                                 edgeloop_select(em, eed, select);
2049                 }
2050                 else if(em->selectmode & SCE_SELECT_VERTEX) {
2051                         if(ring)
2052                                 edgering_select(em, eed, select);
2053                         else 
2054                                 edgeloop_select(em, eed, select);
2055                 }
2056
2057                 EM_selectmode_flush(em);
2058 //                      if (EM_texFaceCheck())
2059                 
2060                 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
2061         }
2062 }
2063
2064 static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
2065 {
2066         
2067         view3d_operator_needs_opengl(C);
2068         
2069         mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
2070                                         RNA_boolean_get(op->ptr, "ring"));
2071         
2072         /* cannot do tweaks for as long this keymap is after transform map */
2073         return OPERATOR_FINISHED;
2074 }
2075
2076 void MESH_OT_loop_select(wmOperatorType *ot)
2077 {
2078         /* identifiers */
2079         ot->name= "Loop Select";
2080         ot->idname= "MESH_OT_loop_select";
2081         
2082         /* api callbacks */
2083         ot->invoke= mesh_select_loop_invoke;
2084         ot->poll= ED_operator_editmesh;
2085         
2086         /* flags */
2087         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2088         
2089         /* properties */
2090         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
2091         RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
2092 }
2093
2094 /* ******************* mesh shortest path select, uses prev-selected edge ****************** */
2095
2096 /* since you want to create paths with multiple selects, it doesn't have extend option */
2097 static void mouse_mesh_shortest_path(bContext *C, short mval[2])
2098 {
2099         ViewContext vc;
2100         EditMesh *em;
2101         EditEdge *eed;
2102         int dist= 50;
2103         
2104         em_setup_viewcontext(C, &vc);
2105         vc.mval[0]= mval[0];
2106         vc.mval[1]= mval[1];
2107         em= vc.em;
2108         
2109         eed= findnearestedge(&vc, &dist);
2110         if(eed) {
2111                 Mesh *me= vc.obedit->data;
2112                 int path = 0;
2113                 
2114                 if (em->selected.last) {
2115                         EditSelection *ese = em->selected.last;
2116                         
2117                         if(ese && ese->type == EDITEDGE) {
2118                                 EditEdge *eed_act;
2119                                 eed_act = (EditEdge*)ese->data;
2120                                 if (eed_act != eed) {
2121                                         if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) {
2122                                                 EM_remove_selection(em, eed_act, EDITEDGE);
2123                                                 path = 1;
2124                                         }
2125                                 }
2126                         }
2127                 }
2128                 if (path==0) {
2129                         int act = (edgetag_context_check(vc.scene, eed)==0);
2130                         edgetag_context_set(vc.scene, eed, act); /* switch the edge option */
2131                 }
2132                 
2133                 EM_selectmode_flush(em);
2134
2135                 /* even if this is selected it may not be in the selection list */
2136                 if(edgetag_context_check(vc.scene, eed)==0)
2137                         EM_remove_selection(em, eed, EDITEDGE);
2138                 else
2139                         EM_store_selection(em, eed, EDITEDGE);
2140         
2141                 /* force drawmode for mesh */
2142                 switch (vc.scene->toolsettings->edge_mode) {
2143                         
2144                         case EDGE_MODE_TAG_SEAM:
2145                                 me->drawflag |= ME_DRAWSEAMS;
2146                                 break;
2147                         case EDGE_MODE_TAG_SHARP:
2148                                 me->drawflag |= ME_DRAWSHARP;
2149                                 break;
2150                         case EDGE_MODE_TAG_CREASE:      
2151                                 me->drawflag |= ME_DRAWCREASES;
2152                                 break;
2153                         case EDGE_MODE_TAG_BEVEL:
2154                                 me->drawflag |= ME_DRAWBWEIGHTS;
2155                                 break;
2156                 }
2157                 
2158                 DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA);
2159         
2160                 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
2161         }
2162 }
2163
2164
2165 static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
2166 {
2167         
2168         view3d_operator_needs_opengl(C);
2169
2170         mouse_mesh_shortest_path(C, event->mval);
2171         
2172         return OPERATOR_FINISHED;
2173 }
2174         
2175 void MESH_OT_select_shortest_path(wmOperatorType *ot)
2176 {
2177         /* identifiers */
2178         ot->name= "Shortest Path Select";
2179         ot->idname= "MESH_OT_select_shortest_path";
2180         
2181         /* api callbacks */
2182         ot->invoke= mesh_shortest_path_select_invoke;
2183         ot->poll= ED_operator_editmesh;
2184         
2185         /* flags */
2186         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2187         
2188         /* properties */
2189         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
2190 }
2191
2192
2193 /* ************************************************** */
2194
2195
2196 /* here actual select happens */
2197 /* gets called via generic mouse select operator */
2198 void mouse_mesh(bContext *C, short mval[2], short extend)
2199 {
2200         ViewContext vc;
2201         EditVert *eve;
2202         EditEdge *eed;
2203         EditFace *efa;
2204         
2205         /* setup view context for argument to callbacks */
2206         em_setup_viewcontext(C, &vc);
2207         vc.mval[0]= mval[0];
2208         vc.mval[1]= mval[1];
2209         
2210         if(unified_findnearest(&vc, &eve, &eed, &efa)) {
2211                 
2212                 if(extend==0) EM_clear_flag_all(vc.em, SELECT);
2213                 
2214                 if(efa) {
2215                         /* set the last selected face */
2216                         EM_set_actFace(vc.em, efa);
2217                         
2218                         if( (efa->f & SELECT)==0 ) {
2219                                 EM_store_selection(vc.em, efa, EDITFACE);
2220                                 EM_select_face_fgon(vc.em, efa, 1);
2221                         }
2222                         else if(extend) {
2223                                 EM_remove_selection(vc.em, efa, EDITFACE);
2224                                 EM_select_face_fgon(vc.em, efa, 0);
2225                         }
2226                 }
2227                 else if(eed) {
2228                         if((eed->f & SELECT)==0) {
2229                                 EM_store_selection(vc.em, eed, EDITEDGE);
2230                                 EM_select_edge(eed, 1);
2231                         }
2232                         else if(extend) {
2233                                 EM_remove_selection(vc.em, eed, EDITEDGE);
2234                                 EM_select_edge(eed, 0);
2235                         }
2236                 }
2237                 else if(eve) {
2238                         if((eve->f & SELECT)==0) {
2239                                 eve->f |= SELECT;
2240                                 EM_store_selection(vc.em, eve, EDITVERT);
2241                         }
2242                         else if(extend){ 
2243                                 EM_remove_selection(vc.em, eve, EDITVERT);
2244                                 eve->f &= ~SELECT;
2245                         }
2246                 }
2247                 
2248                 EM_selectmode_flush(vc.em);
2249                   
2250 //              if (EM_texFaceCheck()) {
2251
2252                 if (efa && efa->mat_nr != vc.obedit->actcol-1) {
2253                         vc.obedit->actcol= efa->mat_nr+1;
2254                         vc.em->mat_nr= efa->mat_nr;
2255 //                      BIF_preview_changed(ID_MA);
2256                 }
2257         }
2258
2259         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
2260         
2261 }
2262
2263 /* *********** select linked ************* */
2264
2265 /* for use with selectconnected_delimit_mesh only! */
2266 #define is_edge_delimit_ok(eed) ((eed->tmp.l == 1) && (eed->seam==0))
2267 #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))
2268
2269 #define face_tag(efa)\
2270 if(efa->v4)     efa->tmp.l=             efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;\
2271 else            efa->tmp.l=             efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
2272
2273 /* all - 1) use all faces for extending the selection  2) only use the mouse face
2274 * sel - 1) select  0) deselect 
2275 * */
2276
2277 /* legacy warning, this function combines too much :) */
2278 static int select_linked_limited_invoke(ViewContext *vc, short all, short sel)
2279 {
2280         EditMesh *em= vc->em;
2281         EditFace *efa;
2282         EditEdge *eed;
2283         EditVert *eve;
2284         short done=1, change=0;
2285         
2286         if(em->faces.first==0) return OPERATOR_CANCELLED;
2287         
2288         /* flag all edges+faces as off*/
2289         for(eed= em->edges.first; eed; eed= eed->next)
2290                 eed->tmp.l=0;
2291         
2292         for(efa= em->faces.first; efa; efa= efa->next) {
2293                 efa->tmp.l = 0;
2294         }
2295         
2296         if (all) {
2297                 // XXX verts?
2298                 for(eed= em->edges.first; eed; eed= eed->next) {
2299                         if(eed->f & SELECT)
2300                                 eed->tmp.l= 1;
2301                 }
2302                 for(efa= em->faces.first; efa; efa= efa->next) {
2303                         
2304                         if (efa->f & SELECT) {
2305                                 face_tag(efa);
2306                         } else {
2307                                 efa->tmp.l = 0;
2308                         }
2309                 }
2310         } 
2311         else {
2312                 if( unified_findnearest(vc, &eve, &eed, &efa) ) {
2313                         
2314                         if(efa) {
2315                                 efa->tmp.l = 1;
2316                                 face_tag(efa);
2317                         }
2318                         else if(eed)
2319                                 eed->tmp.l= 1;
2320                         else {
2321                                 for(eed= em->edges.first; eed; eed= eed->next)
2322                                         if(eed->v1==eve || eed->v2==eve)
2323                                                 break;
2324                                 eed->tmp.l= 1;
2325                         }
2326                 }
2327                 else
2328                         return OPERATOR_FINISHED;
2329         }
2330         
2331         while(done==1) {
2332                 done= 0;
2333                 /* simple algo - select all faces that have a selected edge
2334                 * this intern selects the edge, repeat until nothing is left to do */
2335                 for(efa= em->faces.first; efa; efa= efa->next) {
2336                         if ((efa->tmp.l == 0) && (!efa->h)) {
2337                                 if (is_face_tag(efa)) {
2338                                         face_tag(efa);
2339                                         done= 1;
2340                                 }
2341                         }
2342                 }
2343         }
2344         
2345         for(efa= em->faces.first; efa; efa= efa->next) {
2346                 if (efa->tmp.l) {
2347                         if (sel) {
2348                                 if (!(efa->f & SELECT)) {
2349                                         EM_select_face(efa, 1);
2350                                         change = 1;
2351                                 }
2352                         } else {
2353                                 if (efa->f & SELECT) {
2354                                         EM_select_face(efa, 0);
2355                                         change = 1;
2356                                 }
2357                         }
2358                 }
2359         }
2360         
2361         if (!change)
2362                 return OPERATOR_CANCELLED;
2363         
2364         if (!sel) /* make sure de-selecting faces didnt de-select the verts/edges connected to selected faces, this is common with boundries */
2365                 for(efa= em->faces.first; efa; efa= efa->next)
2366                         if (efa->f & SELECT)
2367                                 EM_select_face(efa, 1);
2368         
2369         //      if (EM_texFaceCheck())
2370         
2371         return OPERATOR_FINISHED;
2372 }
2373
2374 #undef is_edge_delimit_ok
2375 #undef is_face_tag
2376 #undef face_tag
2377
2378 static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
2379 {
2380         Object *obedit= CTX_data_edit_object(C);
2381         ViewContext vc;
2382         EditVert *eve, *v1, *v2;
2383         EditEdge *eed;
2384         EditFace *efa;
2385         short done=1, toggle=0;
2386         int sel= !RNA_boolean_get(op->ptr, "deselect");
2387         int limit= RNA_boolean_get(op->ptr, "limit");
2388         
2389         /* unified_finednearest needs ogl */
2390         view3d_operator_needs_opengl(C);
2391         
2392         /* setup view context for argument to callbacks */
2393         em_setup_viewcontext(C, &vc);
2394         
2395         if(vc.em->edges.first==0) return OPERATOR_CANCELLED;
2396         
2397         vc.mval[0]= event->mval[0];
2398         vc.mval[1]= event->mval[1];
2399         
2400         /* return warning! */
2401         if(limit) {
2402                 int retval= select_linked_limited_invoke(&vc, 0, sel);
2403                 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2404                 return retval;
2405         }
2406         
2407         if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
2408                 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2409         
2410                 return OPERATOR_CANCELLED;
2411         }
2412
2413         /* clear test flags */
2414         for(v1= vc.em->verts.first; v1; v1= v1->next) v1->f1= 0;
2415         
2416         /* start vertex/face/edge */
2417         if(eve) eve->f1= 1;
2418         else if(eed) eed->v1->f1= eed->v2->f1= 1;
2419         else efa->v1->f1= efa->v2->f1= efa->v3->f1= 1;
2420         
2421         /* set flag f1 if affected */
2422         while(done==1) {
2423                 done= 0;
2424                 toggle++;
2425                 
2426                 if(toggle & 1) eed= vc.em->edges.first;
2427                 else eed= vc.em->edges.last;
2428                 
2429                 while(eed) {
2430                         v1= eed->v1;
2431                         v2= eed->v2;
2432                         
2433                         if(eed->h==0) {
2434                                 if(v1->f1 && v2->f1==0) {
2435                                         v2->f1= 1;
2436                                         done= 1;
2437                                 }
2438                                 else if(v1->f1==0 && v2->f1) {
2439                                         v1->f1= 1;
2440                                         done= 1;
2441                                 }
2442                         }
2443                         
2444                         if(toggle & 1) eed= eed->next;
2445                         else eed= eed->prev;
2446                 }
2447         }
2448         
2449         /* now use vertex f1 flag to select/deselect */
2450         for(eed= vc.em->edges.first; eed; eed= eed->next) {
2451                 if(eed->v1->f1 && eed->v2->f1) 
2452                         EM_select_edge(eed, sel);
2453         }
2454         for(efa= vc.em->faces.first; efa; efa= efa->next) {
2455                 if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1)) 
2456                         EM_select_face(efa, sel);
2457         }
2458         /* no flush needed, connected geometry is done */
2459         
2460 //      if (EM_texFaceCheck())
2461         
2462         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2463         return OPERATOR_FINISHED;       
2464 }
2465
2466 void MESH_OT_select_linked_pick(wmOperatorType *ot)
2467 {
2468         /* identifiers */
2469         ot->name= "Select Linked";
2470         ot->idname= "MESH_OT_select_linked_pick";
2471         
2472         /* api callbacks */
2473         ot->invoke= select_linked_pick_invoke;
2474         ot->poll= ED_operator_editmesh;
2475         
2476         /* flags */
2477         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2478         
2479         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
2480         RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
2481 }
2482
2483
2484 /* ************************* */
2485
2486 void selectconnected_mesh_all(EditMesh *em)
2487 {
2488         EditVert *v1,*v2;
2489         EditEdge *eed;
2490         short done=1, toggle=0;
2491         
2492         if(em->edges.first==0) return;
2493         
2494         while(done==1) {
2495                 done= 0;
2496                 
2497                 toggle++;
2498                 if(toggle & 1) eed= em->edges.first;
2499                 else eed= em->edges.last;
2500                 
2501                 while(eed) {
2502                         v1= eed->v1;
2503                         v2= eed->v2;
2504                         if(eed->h==0) {
2505                                 if(v1->f & SELECT) {
2506                                         if( (v2->f & SELECT)==0 ) {
2507                                                 v2->f |= SELECT;
2508                                                 done= 1;
2509                                         }
2510                                 }
2511                                 else if(v2->f & SELECT) {
2512                                         if( (v1->f & SELECT)==0 ) {
2513                                                 v1->f |= SELECT;
2514                                                 done= 1;
2515                                         }
2516                                 }
2517                         }
2518                         if(toggle & 1) eed= eed->next;
2519                         else eed= eed->prev;
2520                 }
2521         }
2522         
2523         /* now use vertex select flag to select rest */
2524         EM_select_flush(em);
2525         
2526         //      if (EM_texFaceCheck())
2527 }
2528
2529 static int select_linked_exec(bContext *C, wmOperator *op)
2530 {
2531         Object *obedit= CTX_data_edit_object(C);
2532         EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
2533         
2534         if( RNA_boolean_get(op->ptr, "limit") ) {
2535                 ViewContext vc;
2536                 em_setup_viewcontext(C, &vc);
2537                 select_linked_limited_invoke(&vc, 1, 1);
2538         }
2539         else
2540                 selectconnected_mesh_all(em);
2541         
2542         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2543
2544         BKE_mesh_end_editmesh(obedit->data, em);
2545         return OPERATOR_FINISHED;       
2546 }
2547
2548 void MESH_OT_select_linked(wmOperatorType *ot)
2549 {
2550         /* identifiers */
2551         ot->name= "Select Linked All";
2552         ot->idname= "MESH_OT_select_linked";
2553         
2554         /* api callbacks */
2555         ot->exec= select_linked_exec;
2556         ot->poll= ED_operator_editmesh;
2557         
2558         /* flags */
2559         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2560         
2561         RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
2562 }
2563
2564
2565 /* ************************* */
2566
2567 /* swap is 0 or 1, if 1 it hides not selected */
2568 void EM_hide_mesh(EditMesh *em, int swap)
2569 {
2570         EditVert *eve;
2571         EditEdge *eed;
2572         EditFace *efa;
2573         int a;
2574         
2575         if(em==NULL) return;
2576
2577         /* hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
2578         /*  - vertex hidden, always means edge is hidden too
2579                 - edge hidden, always means face is hidden too
2580                 - face hidden, only set face hide
2581                 - then only flush back down what's absolute hidden
2582         */
2583         if(em->selectmode & SCE_SELECT_VERTEX) {
2584                 for(eve= em->verts.first; eve; eve= eve->next) {
2585                         if((eve->f & SELECT)!=swap) {
2586                                 eve->f &= ~SELECT;
2587                                 eve->h= 1;
2588                         }
2589                 }
2590         
2591                 for(eed= em->edges.first; eed; eed= eed->next) {
2592                         if(eed->v1->h || eed->v2->h) {
2593                                 eed->h |= 1;
2594                                 eed->f &= ~SELECT;
2595                         }
2596                 }
2597         
2598                 for(efa= em->faces.first; efa; efa= efa->next) {
2599                         if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
2600                                 efa->h= 1;
2601                                 efa->f &= ~SELECT;
2602                         }
2603                 }
2604         }
2605         else if(em->selectmode & SCE_SELECT_EDGE) {
2606
2607                 for(eed= em->edges.first; eed; eed= eed->next) {
2608                         if((eed->f & SELECT)!=swap) {
2609                                 eed->h |= 1;
2610                                 EM_select_edge(eed, 0);
2611                         }
2612                 }
2613
2614                 for(efa= em->faces.first; efa; efa= efa->next) {
2615                         if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
2616                                 efa->h= 1;
2617                                 efa->f &= ~SELECT;
2618                         }
2619                 }
2620         }
2621         else {
2622
2623                 for(efa= em->faces.first; efa; efa= efa->next) {
2624                         if((efa->f & SELECT)!=swap) {
2625                                 efa->h= 1;
2626                                 EM_select_face(efa, 0);
2627                         }
2628                 }
2629         }
2630         
2631         /* flush down, only whats 100% hidden */
2632         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
2633         for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
2634         
2635         if(em->selectmode & SCE_SELECT_FACE) {
2636                 for(efa= em->faces.first; efa; efa= efa->next) {
2637                         if(efa->h) a= 1; else a= 2;
2638                         efa->e1->f1 |= a;
2639                         efa->e2->f1 |= a;
2640                         efa->e3->f1 |= a;
2641                         if(efa->e4) efa->e4->f1 |= a;
2642                         /* When edges are not delt with in their own loop, we need to explicitly re-selct select edges that are joined to unselected faces */
2643                         if (swap && (em->selectmode == SCE_SELECT_FACE) && (efa->f & SELECT)) {
2644                                 EM_select_face(efa, 1);
2645                         }
2646                 }
2647         }
2648         
2649         if(em->selectmode >= SCE_SELECT_EDGE) {
2650                 for(eed= em->edges.first; eed; eed= eed->next) {
2651                         if(eed->f1==1) eed->h |= 1;
2652                         if(eed->h & 1) a= 1; else a= 2;
2653                         eed->v1->f1 |= a;
2654                         eed->v2->f1 |= a;
2655                 }
2656         }
2657
2658         if(em->selectmode >= SCE_SELECT_VERTEX) {
2659                 for(eve= em->verts.first; eve; eve= eve->next) {
2660                         if(eve->f1==1) eve->h= 1;
2661                 }
2662         }
2663         
2664         em->totedgesel= em->totfacesel= em->totvertsel= 0;
2665 //      if(EM_texFaceCheck())
2666
2667         //      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
2668 }
2669
2670 static int hide_mesh_exec(bContext *C, wmOperator *op)
2671 {
2672         Object *obedit= CTX_data_edit_object(C);
2673         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
2674         
2675         EM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
2676                 
2677         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2678
2679         BKE_mesh_end_editmesh(obedit->data, em);
2680         return OPERATOR_FINISHED;       
2681 }
2682
2683 void MESH_OT_hide(wmOperatorType *ot)
2684 {
2685         /* identifiers */
2686         ot->name= "Hide Selection";
2687         ot->idname= "MESH_OT_hide";
2688         
2689         /* api callbacks */
2690         ot->exec= hide_mesh_exec;
2691         ot->poll= ED_operator_editmesh;
2692         
2693         /* flags */
2694         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2695         
2696         /* props */
2697         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
2698 }
2699
2700 void EM_reveal_mesh(EditMesh *em)
2701 {
2702         EditVert *eve;
2703         EditEdge *eed;
2704         EditFace *efa;
2705         
2706         if(em==NULL) return;
2707
2708         for(eve= em->verts.first; eve; eve= eve->next) {
2709                 if(eve->h) {
2710                         eve->h= 0;
2711                         eve->f |= SELECT;
2712                 }
2713         }
2714         for(eed= em->edges.first; eed; eed= eed->next) {
2715                 if(eed->h & 1) {
2716                         eed->h &= ~1;
2717                         if(em->selectmode & SCE_SELECT_VERTEX); 
2718                         else EM_select_edge(eed, 1);
2719                 }
2720         }
2721         for(efa= em->faces.first; efa; efa= efa->next) {
2722                 if(efa->h) {
2723                         efa->h= 0;
2724                         if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX)); 
2725                         else EM_select_face(efa, 1);
2726                 }
2727         }
2728
2729         EM_fgon_flags(em);      /* redo flags and indices for fgons */
2730         EM_selectmode_flush(em);
2731
2732 //      if (EM_texFaceCheck())
2733 //      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
2734 }
2735
2736 static int reveal_mesh_exec(bContext *C, wmOperator *op)
2737 {
2738         Object *obedit= CTX_data_edit_object(C);
2739         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
2740         
2741         EM_reveal_mesh(em);
2742
2743         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2744
2745         BKE_mesh_end_editmesh(obedit->data, em);
2746         return OPERATOR_FINISHED;       
2747 }
2748
2749 void MESH_OT_reveal(wmOperatorType *ot)
2750 {
2751         /* identifiers */
2752         ot->name= "Reveal Hidden";
2753         ot->idname= "MESH_OT_reveal";
2754         
2755         /* api callbacks */
2756         ot->exec= reveal_mesh_exec;
2757         ot->poll= ED_operator_editmesh;
2758         
2759         /* flags */
2760         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2761 }
2762
2763 int select_by_number_vertices_exec(bContext *C, wmOperator *op)
2764 {
2765         Object *obedit= CTX_data_edit_object(C);
2766         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
2767         EditFace *efa;
2768         int numverts= RNA_enum_get(op->ptr, "type");
2769
2770         /* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring
2771          * faces
2772          */
2773
2774         /* for loose vertices/edges, we first select all, loop below will deselect */
2775         if(numverts==5) {
2776                 EM_set_flag_all(em, SELECT);
2777         }
2778         else if(em->selectmode!=SCE_SELECT_FACE) {
2779                 BKE_report(op->reports, RPT_ERROR, "Only works in face selection mode");
2780                 return OPERATOR_CANCELLED;
2781         }
2782         
2783         for(efa= em->faces.first; efa; efa= efa->next) {
2784                 if (efa->e4) {
2785                         EM_select_face(efa, (numverts==4) );
2786                 }
2787                 else {
2788                         EM_select_face(efa, (numverts==3) );
2789                 }
2790         }
2791
2792         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2793         
2794         return OPERATOR_FINISHED;
2795 }
2796
2797 void MESH_OT_select_by_number_vertices(wmOperatorType *ot)
2798 {
2799         static const EnumPropertyItem type_items[]= {
2800                 {3, "TRIANGLES", 0, "Triangles", NULL},
2801                 {4, "QUADS", 0, "Triangles", NULL},
2802                 {5, "OTHER", 0, "Other", NULL},
2803                 {0, NULL, 0, NULL, NULL}};
2804
2805         /* identifiers */
2806         ot->name= "Select by Number of Vertices";
2807         ot->idname= "MESH_OT_select_by_number_vertices";
2808         
2809         /* api callbacks */
2810         ot->exec= select_by_number_vertices_exec;
2811         ot->poll= ED_operator_editmesh;
2812         
2813         /* flags */
2814         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2815         
2816         /* props */
2817         RNA_def_enum(ot->srna, "type", type_items, 3, "Type", "Type of elements to select.");
2818 }
2819
2820 static int select_sharp_edges_exec(bContext *C, wmOperator *op)
2821 {
2822         /* Find edges that have exactly two neighboring faces,
2823         * check the angle between those faces, and if angle is
2824         * small enough, select the edge
2825         */
2826         Object *obedit= CTX_data_edit_object(C);
2827         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
2828         EditEdge *eed;
2829         EditFace *efa;
2830         EditFace **efa1;
2831         EditFace **efa2;
2832         intptr_t edgecount = 0, i = 0;
2833         float sharpness, fsharpness;
2834         
2835         /* 'standard' behaviour - check if selected, then apply relevant selection */
2836         
2837         if(em->selectmode==SCE_SELECT_FACE) {
2838                 BKE_report(op->reports, RPT_ERROR, "Doesn't work in face selection mode");
2839                 BKE_mesh_end_editmesh(obedit->data, em);
2840                 return OPERATOR_CANCELLED;
2841         }
2842
2843         sharpness= RNA_float_get(op->ptr, "sharpness");
2844         fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
2845
2846         /* count edges, use tmp.l  */
2847         eed= em->edges.first;
2848         while(eed) {
2849                 edgecount++;
2850                 eed->tmp.l = i;
2851                 eed= eed->next;
2852                 ++i;
2853         }
2854
2855         /* for each edge, we want a pointer to two adjacent faces */
2856         efa1 = MEM_callocN(edgecount*sizeof(EditFace *), 
2857                                            "pairs of edit face pointers");
2858         efa2 = MEM_callocN(edgecount*sizeof(EditFace *), 
2859                                            "pairs of edit face pointers");
2860
2861 #define face_table_edge(eed) { \
2862                 i = eed->tmp.l; \
2863                 if (i != -1) { \
2864                         if (efa1[i]) { \
2865                                 if (efa2[i]) { \
2866                                         /* invalidate, edge has more than two neighbors */ \
2867                                         eed->tmp.l = -1; \
2868                                 } \
2869                                 else { \
2870                                         efa2[i] = efa; \
2871                                 } \
2872                         } \
2873                         else { \
2874                                 efa1[i] = efa; \
2875                         } \
2876                 } \
2877         }
2878
2879         /* find the adjacent faces of each edge, we want only two */
2880         efa= em->faces.first;
2881         while(efa) {
2882                 face_table_edge(efa->e1);
2883                 face_table_edge(efa->e2);
2884                 face_table_edge(efa->e3);
2885                 if (efa->e4) {
2886                         face_table_edge(efa->e4);
2887                 }
2888                 efa= efa->next;
2889         }
2890
2891 #undef face_table_edge
2892
2893         eed = em->edges.first;
2894         while(eed) {
2895                 i = eed->tmp.l;
2896                 if (i != -1) { 
2897                         /* edge has two or less neighboring faces */
2898                         if ( (efa1[i]) && (efa2[i]) ) { 
2899                                 /* edge has exactly two neighboring faces, check angle */
2900                                 float angle;
2901                                 angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
2902                                                            efa1[i]->n[1]*efa2[i]->n[1] +
2903                                                            efa1[i]->n[2]*efa2[i]->n[2]);
2904                                 if (fabs(angle) >= fsharpness)
2905                                         EM_select_edge(eed, 1);
2906                         }
2907                 }
2908
2909                 eed= eed->next;
2910         }
2911
2912         MEM_freeN(efa1);
2913         MEM_freeN(efa2);
2914
2915 //      if (EM_texFaceCheck())
2916         
2917         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); //TODO is this needed ?
2918
2919         BKE_mesh_end_editmesh(obedit->data, em);
2920         return OPERATOR_FINISHED;       
2921 }
2922
2923 void MESH_OT_edges_select_sharp(wmOperatorType *ot)
2924 {
2925         /* identifiers */
2926         ot->name= "Select Sharp Edges";
2927         ot->idname= "MESH_OT_edges_select_sharp";
2928         
2929         /* api callbacks */
2930         ot->exec= select_sharp_edges_exec;
2931         ot->poll= ED_operator_editmesh;
2932         
2933         /* flags */
2934         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2935         
2936         /* props */
2937         RNA_def_float(ot->srna, "sharpness", 0.01f, 0.0f, FLT_MAX, "sharpness", "", 0.0f, 180.0f);
2938 }
2939
2940
2941 static void select_linked_flat_faces(EditMesh *em, wmOperator *op, float sharpness)
2942 {
2943         /* Find faces that are linked to selected faces that are 
2944          * relatively flat (angle between faces is higher than
2945          * specified angle)
2946          */
2947         EditEdge *eed;
2948         EditFace *efa;
2949         EditFace **efa1;
2950         EditFace **efa2;
2951         intptr_t edgecount = 0, i, faceselcount=0, faceselcountold=0;
2952         float fsharpness;
2953         
2954         if(em->selectmode!=SCE_SELECT_FACE) {
2955                 BKE_report(op->reports, RPT_ERROR, "Only works in face selection mode");
2956                 return;
2957         }
2958
2959         fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
2960
2961         i=0;
2962         /* count edges, use tmp.l */
2963         eed= em->edges.first;
2964         while(eed) {
2965                 edgecount++;
2966                 eed->tmp.l = i;
2967                 eed= eed->next;
2968                 ++i;
2969         }
2970
2971         /* for each edge, we want a pointer to two adjacent faces */
2972         efa1 = MEM_callocN(edgecount*sizeof(EditFace *), 
2973                                            "pairs of edit face pointers");
2974         efa2 = MEM_callocN(edgecount*sizeof(EditFace *), 
2975                                            "pairs of edit face pointers");
2976
2977 #define face_table_edge(eed) { \
2978                 i = eed->tmp.l; \
2979                 if (i != -1) { \
2980                         if (efa1[i]) { \
2981                                 if (efa2[i]) { \
2982                                         /* invalidate, edge has more than two neighbors */ \
2983                                         eed->tmp.l = -1; \
2984                                 } \
2985                                 else { \
2986                                         efa2[i] = efa; \
2987                                 } \
2988                         } \
2989                         else { \
2990                                 efa1[i] = efa; \
2991                         } \
2992                 } \
2993         }