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