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