Bugfix #25636
[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 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 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 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
1735 /* ****************  LOOP SELECTS *************** */
1736
1737 /* selects quads in loop direction of indicated edge */
1738 /* only flush over edges with valence <= 2 */
1739 void faceloop_select(EditMesh *em, EditEdge *startedge, int select)
1740 {
1741         EditEdge *eed;
1742         EditFace *efa;
1743         int looking= 1;
1744         
1745         /* in eed->f1 we put the valence (amount of faces in edge) */
1746         /* in eed->f2 we put tagged flag as correct loop */
1747         /* in efa->f1 we put tagged flag as correct to select */
1748
1749         for(eed= em->edges.first; eed; eed= eed->next) {
1750                 eed->f1= 0;
1751                 eed->f2= 0;
1752         }
1753         for(efa= em->faces.first; efa; efa= efa->next) {
1754                 efa->f1= 0;
1755                 if(efa->h==0) {
1756                         efa->e1->f1++;
1757                         efa->e2->f1++;
1758                         efa->e3->f1++;
1759                         if(efa->e4) efa->e4->f1++;
1760                 }
1761         }
1762         
1763         /* tag startedge OK*/
1764         startedge->f2= 1;
1765         
1766         while(looking) {
1767                 looking= 0;
1768                 
1769                 for(efa= em->faces.first; efa; efa= efa->next) {
1770                         if(efa->h==0 && efa->e4 && efa->f1==0) {        /* not done quad */
1771                                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
1772
1773                                         /* if edge tagged, select opposing edge and mark face ok */
1774                                         if(efa->e1->f2) {
1775                                                 efa->e3->f2= 1;
1776                                                 efa->f1= 1;
1777                                                 looking= 1;
1778                                         }
1779                                         else if(efa->e2->f2) {
1780                                                 efa->e4->f2= 1;
1781                                                 efa->f1= 1;
1782                                                 looking= 1;
1783                                         }
1784                                         if(efa->e3->f2) {
1785                                                 efa->e1->f2= 1;
1786                                                 efa->f1= 1;
1787                                                 looking= 1;
1788                                         }
1789                                         if(efa->e4->f2) {
1790                                                 efa->e2->f2= 1;
1791                                                 efa->f1= 1;
1792                                                 looking= 1;
1793                                         }
1794                                 }
1795                         }
1796                 }
1797         }
1798         
1799         /* (de)select the faces */
1800         if(select!=2) {
1801                 for(efa= em->faces.first; efa; efa= efa->next) {
1802                         if(efa->f1) EM_select_face(efa, select);
1803                 }
1804         }
1805 }
1806
1807
1808 /* helper for edgeloop_select, checks for eed->f2 tag in faces */
1809 static int edge_not_in_tagged_face(EditMesh *em, EditEdge *eed)
1810 {
1811         EditFace *efa;
1812         
1813         for(efa= em->faces.first; efa; efa= efa->next) {
1814                 if(efa->h==0) {
1815                         if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) {      /* edge is in face */
1816                                 if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) {     /* face is tagged */
1817                                         return 0;
1818                                 }
1819                         }
1820                 }
1821         }
1822         return 1;
1823 }
1824
1825 /* selects or deselects edges that:
1826 - if edges has 2 faces:
1827         - has vertices with valence of 4
1828         - not shares face with previous edge
1829 - if edge has 1 face:
1830         - has vertices with valence 4
1831         - not shares face with previous edge
1832         - but also only 1 face
1833 - if edge no face:
1834         - has vertices with valence 2
1835 */
1836 static void edgeloop_select(EditMesh *em, EditEdge *starteed, int select)
1837 {
1838         EditVert *eve;
1839         EditEdge *eed;
1840         EditFace *efa;
1841         int looking= 1;
1842         
1843         /* in f1 we put the valence (amount of edges in a vertex, or faces in edge) */
1844         /* in eed->f2 and efa->f1 we put tagged flag as correct loop */
1845         for(eve= em->verts.first; eve; eve= eve->next) {
1846                 eve->f1= 0;
1847                 eve->f2= 0;
1848         }
1849         for(eed= em->edges.first; eed; eed= eed->next) {
1850                 eed->f1= 0;
1851                 eed->f2= 0;
1852                 if((eed->h & 1)==0) {   /* fgon edges add to valence too */
1853                         eed->v1->f1++; eed->v2->f1++;
1854                 }
1855         }
1856         for(efa= em->faces.first; efa; efa= efa->next) {
1857                 efa->f1= 0;
1858                 if(efa->h==0) {
1859                         efa->e1->f1++;
1860                         efa->e2->f1++;
1861                         efa->e3->f1++;
1862                         if(efa->e4) efa->e4->f1++;
1863                 }
1864         }
1865         
1866         /* looped edges & vertices get tagged f2 */
1867         starteed->f2= 1;
1868         if(starteed->v1->f1<5) starteed->v1->f2= 1;
1869         if(starteed->v2->f1<5) starteed->v2->f2= 1;
1870         /* sorry, first edge isnt even ok */
1871         if(starteed->v1->f2==0 && starteed->v2->f2==0) looking= 0;
1872         
1873         while(looking) {
1874                 looking= 0;
1875                 
1876                 /* find correct valence edges which are not tagged yet, but connect to tagged one */
1877                 for(eed= em->edges.first; eed; eed= eed->next) {
1878                         if(eed->h==0 && eed->f2==0) { /* edge not hidden, not tagged */
1879                                 if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { /* valence of vertex OK, and is tagged */
1880                                         /* new edge is not allowed to be in face with tagged edge */
1881                                         if(edge_not_in_tagged_face(em, eed)) {
1882                                                 if(eed->f1==starteed->f1) {     /* same amount of faces */
1883                                                         looking= 1;
1884                                                         eed->f2= 1;
1885                                                         if(eed->v2->f1<5) eed->v2->f2= 1;
1886                                                         if(eed->v1->f1<5) eed->v1->f2= 1;
1887                                                 }
1888                                         }
1889                                 }
1890                         }
1891                 }
1892         }
1893         /* and we do the select */
1894         for(eed= em->edges.first; eed; eed= eed->next) {
1895                 if(eed->f2) EM_select_edge(eed, select);
1896         }
1897 }
1898
1899 /* 
1900    Almostly exactly the same code as faceloop select
1901 */
1902 static void edgering_select(EditMesh *em, EditEdge *startedge, int select)
1903 {
1904         EditEdge *eed;
1905         EditFace *efa;
1906         int looking= 1;
1907         
1908         /* in eed->f1 we put the valence (amount of faces in edge) */
1909         /* in eed->f2 we put tagged flag as correct loop */
1910         /* in efa->f1 we put tagged flag as correct to select */
1911
1912         for(eed= em->edges.first; eed; eed= eed->next) {
1913                 eed->f1= 0;
1914                 eed->f2= 0;
1915         }
1916         for(efa= em->faces.first; efa; efa= efa->next) {
1917                 efa->f1= 0;
1918                 if(efa->h==0) {
1919                         efa->e1->f1++;
1920                         efa->e2->f1++;
1921                         efa->e3->f1++;
1922                         if(efa->e4) efa->e4->f1++;
1923                 }
1924         }
1925         
1926         /* tag startedge OK */
1927         startedge->f2= 1;
1928         
1929         while(looking) {
1930                 looking= 0;
1931                 
1932                 for(efa= em->faces.first; efa; efa= efa->next) {
1933                         if(efa->e4 && efa->f1==0 && !efa->h) {  /* not done quad */
1934                                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
1935
1936                                         /* if edge tagged, select opposing edge and mark face ok */
1937                                         if(efa->e1->f2) {
1938                                                 efa->e3->f2= 1;
1939                                                 efa->f1= 1;
1940                                                 looking= 1;
1941                                         }
1942                                         else if(efa->e2->f2) {
1943                                                 efa->e4->f2= 1;
1944                                                 efa->f1= 1;
1945                                                 looking= 1;
1946                                         }
1947                                         if(efa->e3->f2) {
1948                                                 efa->e1->f2= 1;
1949                                                 efa->f1= 1;
1950                                                 looking= 1;
1951                                         }
1952                                         if(efa->e4->f2) {
1953                                                 efa->e2->f2= 1;
1954                                                 efa->f1= 1;
1955                                                 looking= 1;
1956                                         }
1957                                 }
1958                         }
1959                 }
1960         }
1961         
1962         /* (de)select the edges */
1963         for(eed= em->edges.first; eed; eed= eed->next) {
1964                         if(eed->f2) EM_select_edge(eed, select);
1965         }
1966 }
1967
1968 static int loop_multiselect(bContext *C, wmOperator *op)
1969 {
1970         Object *obedit= CTX_data_edit_object(C);
1971         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
1972         EditEdge *eed;
1973         EditEdge **edarray;
1974         int edindex, edfirstcount;
1975         int looptype= RNA_boolean_get(op->ptr, "ring");
1976         
1977         /* sets em->totedgesel */
1978         EM_nedges_selected(em);
1979         
1980         edarray = MEM_mallocN(sizeof(EditEdge*)*em->totedgesel,"edge array");
1981         edindex = 0;
1982         edfirstcount = em->totedgesel;
1983         
1984         for(eed=em->edges.first; eed; eed=eed->next){
1985                 if(eed->f&SELECT){
1986                         edarray[edindex] = eed;
1987                         edindex += 1;
1988                 }
1989         }
1990         
1991         if(looptype){
1992                 for(edindex = 0; edindex < edfirstcount; edindex +=1){
1993                         eed = edarray[edindex];
1994                         edgering_select(em, eed,SELECT);
1995                 }
1996                 EM_selectmode_flush(em);
1997         }
1998         else{
1999                 for(edindex = 0; edindex < edfirstcount; edindex +=1){
2000                         eed = edarray[edindex];
2001                         edgeloop_select(em, eed,SELECT);
2002                 }
2003                 EM_selectmode_flush(em);
2004         }
2005         MEM_freeN(edarray);
2006 //      if (EM_texFaceCheck())
2007         
2008         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2009
2010         BKE_mesh_end_editmesh(obedit->data, em);
2011         return OPERATOR_FINISHED;       
2012 }
2013
2014 void MESH_OT_loop_multi_select(wmOperatorType *ot)
2015 {
2016         /* identifiers */
2017         ot->name= "Multi Select Loops";
2018         ot->description= "Select a loop of connected edges by connection type";
2019         ot->idname= "MESH_OT_loop_multi_select";
2020         
2021         /* api callbacks */
2022         ot->exec= loop_multiselect;
2023         ot->poll= ED_operator_editmesh;
2024         
2025         /* flags */
2026         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2027         
2028         /* properties */
2029         RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
2030 }
2031
2032                 
2033 /* ***************** MAIN MOUSE SELECTION ************** */
2034
2035
2036 /* ***************** loop select (non modal) ************** */
2037
2038 static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring)
2039 {
2040         ViewContext vc;
2041         EditMesh *em;
2042         EditEdge *eed;
2043         int select= 1;
2044         int dist= 50;
2045         
2046         em_setup_viewcontext(C, &vc);
2047         vc.mval[0]= mval[0];
2048         vc.mval[1]= mval[1];
2049         em= vc.em;
2050
2051         /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
2052         view3d_validate_backbuf(&vc);
2053         
2054         eed= findnearestedge(&vc, &dist);
2055         if(eed) {
2056                 if(extend==0) EM_clear_flag_all(em, SELECT);
2057         
2058                 if((eed->f & SELECT)==0) select=1;
2059                 else if(extend) select=0;
2060
2061                 if(em->selectmode & SCE_SELECT_FACE) {
2062                         faceloop_select(em, eed, select);
2063                 }
2064                 else if(em->selectmode & SCE_SELECT_EDGE) {
2065                         if(ring)
2066                                 edgering_select(em, eed, select);
2067                         else
2068                                 edgeloop_select(em, eed, select);
2069                 }
2070                 else if(em->selectmode & SCE_SELECT_VERTEX) {
2071                         if(ring)
2072                                 edgering_select(em, eed, select);
2073                         else 
2074                                 edgeloop_select(em, eed, select);
2075                 }
2076
2077                 EM_selectmode_flush(em);
2078 //                      if (EM_texFaceCheck())
2079                 
2080                 /* sets as active, useful for other tools */
2081                 if(select) {
2082                         if(em->selectmode & SCE_SELECT_VERTEX)
2083                                 EM_store_selection(em, eed->v1, EDITVERT);
2084                         if(em->selectmode & SCE_SELECT_EDGE)
2085                                 EM_store_selection(em, eed, EDITEDGE);
2086                 }
2087
2088                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
2089         }
2090 }
2091
2092 static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
2093 {
2094         
2095         view3d_operator_needs_opengl(C);
2096         
2097         mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
2098                                         RNA_boolean_get(op->ptr, "ring"));
2099         
2100         /* cannot do tweaks for as long this keymap is after transform map */
2101         return OPERATOR_FINISHED;
2102 }
2103
2104 void MESH_OT_loop_select(wmOperatorType *ot)
2105 {
2106         /* identifiers */
2107         ot->name= "Loop Select";
2108         ot->description= "Select a loop of connected edges";
2109         ot->idname= "MESH_OT_loop_select";
2110         
2111         /* api callbacks */
2112         ot->invoke= mesh_select_loop_invoke;
2113         ot->poll= ED_operator_editmesh_region_view3d;
2114         
2115         /* flags */
2116         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2117         
2118         /* properties */
2119         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
2120         RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
2121 }
2122
2123 /* ******************* mesh shortest path select, uses prev-selected edge ****************** */
2124
2125 /* since you want to create paths with multiple selects, it doesn't have extend option */
2126 static void mouse_mesh_shortest_path(bContext *C, short mval[2])
2127 {
2128         ViewContext vc;
2129         EditMesh *em;
2130         EditEdge *eed, *eed_act= NULL;
2131         int dist= 50;
2132         
2133         em_setup_viewcontext(C, &vc);
2134         vc.mval[0]= mval[0];
2135         vc.mval[1]= mval[1];
2136         em= vc.em;
2137         
2138         /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
2139         view3d_validate_backbuf(&vc);
2140         
2141         eed= findnearestedge(&vc, &dist);
2142         if(eed) {
2143                 Mesh *me= vc.obedit->data;
2144                 int path = 0;
2145                 
2146                 if (em->selected.last) {
2147                         EditSelection *ese = em->selected.last;
2148                         
2149                         if(ese && ese->type == EDITEDGE) {
2150                                 eed_act = (EditEdge*)ese->data;
2151                                 if (eed_act != eed) {
2152                                         if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) { /* <- this is where the magic happens */
2153                                                 EM_remove_selection(em, eed_act, EDITEDGE);
2154                                                 path = 1;
2155                                         }
2156                                 }
2157                         }
2158                 }
2159                 if (path==0) {
2160                         int act = (edgetag_context_check(vc.scene, eed)==0);
2161                         edgetag_context_set(vc.scene, eed, act); /* switch the edge option */
2162                 }
2163
2164                 /* even if this is selected it may not be in the selection list */
2165                 if(edgetag_context_check(vc.scene, eed)==0) {
2166                         EM_remove_selection(em, eed, EDITEDGE);
2167                 }
2168                 else {
2169                         /* other modes need to keep the last edge tagged */
2170                         if(eed_act) {
2171                                 if(vc.scene->toolsettings->edge_mode!=EDGE_MODE_SELECT) {
2172                                         /* for non-select modes, always de-select the previous active edge */
2173                                         EM_select_edge(eed_act, 0);
2174                                 }
2175                         }
2176
2177                         /* set the new edge active */
2178                         EM_select_edge(eed, 1);
2179                         EM_store_selection(em, eed, EDITEDGE);
2180                 }
2181
2182                 EM_selectmode_flush(em);
2183         
2184                 /* force drawmode for mesh */
2185                 switch (vc.scene->toolsettings->edge_mode) {
2186                         
2187                         case EDGE_MODE_TAG_SEAM:
2188                                 me->drawflag |= ME_DRAWSEAMS;
2189                                 break;
2190                         case EDGE_MODE_TAG_SHARP:
2191                                 me->drawflag |= ME_DRAWSHARP;
2192                                 break;
2193                         case EDGE_MODE_TAG_CREASE:      
2194                                 me->drawflag |= ME_DRAWCREASES;
2195                                 break;
2196                         case EDGE_MODE_TAG_BEVEL:
2197                                 me->drawflag |= ME_DRAWBWEIGHTS;
2198                                 break;
2199                 }
2200                 
2201                 DAG_id_tag_update(vc.obedit->data, 0);
2202                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
2203         }
2204 }
2205
2206
2207 static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
2208 {
2209         
2210         view3d_operator_needs_opengl(C);
2211
2212         mouse_mesh_shortest_path(C, event->mval);
2213         
2214         return OPERATOR_FINISHED;
2215 }
2216
2217 static int mesh_shortest_path_select_poll(bContext *C)
2218 {
2219         if(ED_operator_editmesh_region_view3d(C)) {
2220                 Object *obedit= CTX_data_edit_object(C);
2221                 EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
2222                 return (em->selectmode & SCE_SELECT_EDGE);
2223         }
2224         return 0;
2225 }
2226         
2227 void MESH_OT_select_shortest_path(wmOperatorType *ot)
2228 {
2229         /* identifiers */
2230         ot->name= "Shortest Path Select";
2231         ot->description= "Select shortest path between two selections";
2232         ot->idname= "MESH_OT_select_shortest_path";
2233         
2234         /* api callbacks */
2235         ot->invoke= mesh_shortest_path_select_invoke;
2236         ot->poll= mesh_shortest_path_select_poll;
2237         
2238         /* flags */
2239         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2240         
2241         /* properties */
2242         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
2243 }
2244
2245
2246 /* ************************************************** */
2247
2248
2249 /* here actual select happens */
2250 /* gets called via generic mouse select operator */
2251 int mouse_mesh(bContext *C, short mval[2], short extend)
2252 {
2253         ViewContext vc;
2254         EditVert *eve;
2255         EditEdge *eed;
2256         EditFace *efa;
2257         
2258         /* setup view context for argument to callbacks */
2259         em_setup_viewcontext(C, &vc);
2260         vc.mval[0]= mval[0];
2261         vc.mval[1]= mval[1];
2262         
2263         if(unified_findnearest(&vc, &eve, &eed, &efa)) {
2264                 
2265                 if(extend==0) EM_clear_flag_all(vc.em, SELECT);
2266                 
2267                 if(efa) {
2268                         /* set the last selected face */
2269                         EM_set_actFace(vc.em, efa);
2270                         
2271                         if( (efa->f & SELECT)==0 ) {
2272                                 EM_store_selection(vc.em, efa, EDITFACE);
2273                                 EM_select_face_fgon(vc.em, efa, 1);
2274                         }
2275                         else if(extend) {
2276                                 EM_remove_selection(vc.em, efa, EDITFACE);
2277                                 EM_select_face_fgon(vc.em, efa, 0);
2278                         }
2279                 }
2280                 else if(eed) {
2281                         if((eed->f & SELECT)==0) {
2282                                 EM_store_selection(vc.em, eed, EDITEDGE);
2283                                 EM_select_edge(eed, 1);
2284                         }
2285                         else if(extend) {
2286                                 EM_remove_selection(vc.em, eed, EDITEDGE);
2287                                 EM_select_edge(eed, 0);
2288                         }
2289                 }
2290                 else if(eve) {
2291                         if((eve->f & SELECT)==0) {
2292                                 eve->f |= SELECT;
2293                                 EM_store_selection(vc.em, eve, EDITVERT);
2294                         }
2295                         else if(extend){ 
2296                                 EM_remove_selection(vc.em, eve, EDITVERT);
2297                                 eve->f &= ~SELECT;
2298                         }
2299                 }
2300                 
2301                 EM_selectmode_flush(vc.em);
2302                   
2303 //              if (EM_texFaceCheck()) {
2304
2305                 if (efa && efa->mat_nr != vc.obedit->actcol-1) {
2306                         vc.obedit->actcol= efa->mat_nr+1;
2307                         vc.em->mat_nr= efa->mat_nr;
2308 //                      BIF_preview_changed(ID_MA);
2309                 }
2310
2311                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
2312
2313                 return 1;
2314         }
2315         
2316         return 0;
2317 }
2318
2319 /* *********** select linked ************* */
2320
2321 /* for use with selectconnected_delimit_mesh only! */
2322 #define is_edge_delimit_ok(eed) ((eed->tmp.l == 1) && (eed->seam==0))
2323 #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))
2324
2325 #define face_tag(efa)\
2326 if(efa->v4)     efa->tmp.l=             efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;\
2327 else            efa->tmp.l=             efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
2328
2329 /* all - 1) use all faces for extending the selection  2) only use the mouse face
2330 * sel - 1) select  0) deselect 
2331 * */
2332
2333 /* legacy warning, this function combines too much :) */
2334 static int select_linked_limited_invoke(ViewContext *vc, short all, short sel)
2335 {
2336         EditMesh *em= vc->em;
2337         EditFace *efa;
2338         EditEdge *eed;
2339         EditVert *eve;
2340         short done=1, change=0;
2341         
2342         if(em->faces.first==0) return OPERATOR_CANCELLED;
2343         
2344         /* flag all edges+faces as off*/
2345         for(eed= em->edges.first; eed; eed= eed->next)
2346                 eed->tmp.l=0;
2347         
2348         for(efa= em->faces.first; efa; efa= efa->next) {
2349                 efa->tmp.l = 0;
2350         }
2351         
2352         if (all) {
2353                 // XXX verts?
2354                 for(eed= em->edges.first; eed; eed= eed->next) {
2355                         if(eed->f & SELECT)
2356                                 eed->tmp.l= 1;
2357                 }
2358                 for(efa= em->faces.first; efa; efa= efa->next) {
2359                         
2360                         if (efa->f & SELECT) {
2361                                 face_tag(efa);
2362                         } else {
2363                                 efa->tmp.l = 0;
2364                         }
2365                 }
2366         } 
2367         else {
2368                 if( unified_findnearest(vc, &eve, &eed, &efa) ) {
2369                         
2370                         if(efa) {
2371                                 efa->tmp.l = 1;
2372                                 face_tag(efa);
2373                         }
2374                         else if(eed)
2375                                 eed->tmp.l= 1;
2376                         else {
2377                                 for(eed= em->edges.first; eed; eed= eed->next)
2378                                         if(eed->v1==eve || eed->v2==eve)
2379                                                 break;
2380                                 eed->tmp.l= 1;
2381                         }
2382                 }
2383                 else
2384                         return OPERATOR_FINISHED;
2385         }
2386         
2387         while(done==1) {
2388                 done= 0;
2389                 /* simple algo - select all faces that have a selected edge
2390                 * this intern selects the edge, repeat until nothing is left to do */
2391                 for(efa= em->faces.first; efa; efa= efa->next) {
2392                         if ((efa->tmp.l == 0) && (!efa->h)) {
2393                                 if (is_face_tag(efa)) {
2394                                         face_tag(efa);
2395                                         done= 1;
2396                                 }
2397                         }
2398                 }
2399         }
2400         
2401         for(efa= em->faces.first; efa; efa= efa->next) {
2402                 if (efa->tmp.l) {
2403                         if (sel) {
2404                                 if (!(efa->f & SELECT)) {
2405                                         EM_select_face(efa, 1);
2406                                         change = 1;
2407                                 }
2408                         } else {
2409                                 if (efa->f & SELECT) {
2410                                         EM_select_face(efa, 0);
2411                                         change = 1;
2412                                 }
2413                         }
2414                 }
2415         }
2416         
2417         if (!change)
2418                 return OPERATOR_CANCELLED;
2419         
2420         if (!sel) /* make sure de-selecting faces didnt de-select the verts/edges connected to selected faces, this is common with boundries */
2421                 for(efa= em->faces.first; efa; efa= efa->next)
2422                         if (efa->f & SELECT)
2423                                 EM_select_face(efa, 1);
2424         
2425         //      if (EM_texFaceCheck())
2426         
2427         return OPERATOR_FINISHED;
2428 }
2429
2430 #undef is_edge_delimit_ok
2431 #undef is_face_tag
2432 #undef face_tag
2433
2434 static void linked_limit_default(bContext *C, wmOperator *op) {
2435         if(!RNA_property_is_set(op->ptr, "limit")) {
2436                 Object *obedit= CTX_data_edit_object(C);
2437                 EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
2438                 if(em->selectmode == SCE_SELECT_FACE)
2439                         RNA_boolean_set(op->ptr, "limit", TRUE);
2440         }
2441 }
2442
2443 static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
2444 {
2445         Object *obedit= CTX_data_edit_object(C);
2446         ViewContext vc;
2447         EditVert *eve, *v1, *v2;
2448         EditEdge *eed;
2449         EditFace *efa;
2450         short done=1, toggle=0;
2451         int sel= !RNA_boolean_get(op->ptr, "deselect");
2452         int limit;
2453         
2454         linked_limit_default(C, op);
2455
2456         limit = RNA_boolean_get(op->ptr, "limit");
2457
2458         /* unified_finednearest needs ogl */
2459         view3d_operator_needs_opengl(C);
2460         
2461         /* setup view context for argument to callbacks */
2462         em_setup_viewcontext(C, &vc);
2463         
2464         if(vc.em->edges.first==0) return OPERATOR_CANCELLED;
2465         
2466         vc.mval[0]= event->mval[0];
2467         vc.mval[1]= event->mval[1];
2468         
2469         /* return warning! */
2470         if(limit) {
2471                 int retval= select_linked_limited_invoke(&vc, 0, sel);
2472                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2473                 return retval;
2474         }
2475         
2476         if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
2477                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2478         
2479                 return OPERATOR_CANCELLED;
2480         }
2481
2482         /* clear test flags */
2483         for(v1= vc.em->verts.first; v1; v1= v1->next) v1->f1= 0;
2484         
2485         /* start vertex/face/edge */
2486         if(eve) eve->f1= 1;
2487         else if(eed) eed->v1->f1= eed->v2->f1= 1;
2488         else efa->v1->f1= efa->v2->f1= efa->v3->f1= 1;
2489         
2490         /* set flag f1 if affected */
2491         while(done==1) {
2492                 done= 0;
2493                 toggle++;
2494                 
2495                 if(toggle & 1) eed= vc.em->edges.first;
2496                 else eed= vc.em->edges.last;
2497                 
2498                 while(eed) {
2499                         v1= eed->v1;
2500                         v2= eed->v2;
2501                         
2502                         if(eed->h==0) {
2503                                 if(v1->f1 && v2->f1==0) {
2504                                         v2->f1= 1;
2505                                         done= 1;
2506                                 }
2507                                 else if(v1->f1==0 && v2->f1) {
2508                                         v1->f1= 1;
2509                                         done= 1;
2510                                 }
2511                         }
2512                         
2513                         if(toggle & 1) eed= eed->next;
2514                         else eed= eed->prev;
2515                 }
2516         }
2517         
2518         /* now use vertex f1 flag to select/deselect */
2519         for(eed= vc.em->edges.first; eed; eed= eed->next) {
2520                 if(eed->v1->f1 && eed->v2->f1) 
2521                         EM_select_edge(eed, sel);
2522         }
2523         for(efa= vc.em->faces.first; efa; efa= efa->next) {
2524                 if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1)) 
2525                         EM_select_face(efa, sel);
2526         }
2527         /* no flush needed, connected geometry is done */
2528         
2529 //      if (EM_texFaceCheck())
2530         
2531         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2532         return OPERATOR_FINISHED;       
2533 }
2534
2535 void MESH_OT_select_linked_pick(wmOperatorType *ot)
2536 {
2537         /* identifiers */
2538         ot->name= "Select Linked";
2539         ot->description= "(un)select all vertices linked to the active mesh";
2540         ot->idname= "MESH_OT_select_linked_pick";
2541         
2542         /* api callbacks */
2543         ot->invoke= select_linked_pick_invoke;
2544         ot->poll= ED_operator_editmesh_region_view3d;
2545         
2546         /* flags */
2547         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2548         
2549         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
2550         RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "Limit selection by seam boundries (faces only)");
2551 }
2552
2553
2554 /* ************************* */
2555
2556 void selectconnected_mesh_all(EditMesh *em)
2557 {
2558         EditVert *v1,*v2;
2559         EditEdge *eed;
2560         short done=1, toggle=0;
2561         
2562         if(em->edges.first==0) return;
2563         
2564         while(done==1) {
2565                 done= 0;
2566                 
2567                 toggle++;
2568                 if(toggle & 1) eed= em->edges.first;
2569                 else eed= em->edges.last;
2570                 
2571                 while(eed) {
2572                         v1= eed->v1;
2573                         v2= eed->v2;
2574                         if(eed->h==0) {
2575                                 if(v1->f & SELECT) {
2576                                         if( (v2->f & SELECT)==0 ) {
2577                                                 v2->f |= SELECT;
2578                                                 done= 1;
2579                                         }
2580                                 }
2581                                 else if(v2->f & SELECT) {
2582                                         if( (v1->f & SELECT)==0 ) {
2583                                                 v1->f |= SELECT;
2584                                                 done= 1;
2585                                         }
2586                                 }
2587                         }
2588                         if(toggle & 1) eed= eed->next;
2589                         else eed= eed->prev;
2590                 }
2591         }
2592         
2593         /* now use vertex select flag to select rest */
2594         EM_select_flush(em);
2595         
2596         //      if (EM_texFaceCheck())
2597 }
2598
2599 static int select_linked_exec(bContext *C, wmOperator *op)
2600 {
2601         Object *obedit= CTX_data_edit_object(C);
2602         EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
2603         
2604         if( RNA_boolean_get(op->ptr, "limit") ) {
2605                 ViewContext vc;
2606                 em_setup_viewcontext(C, &vc);
2607                 select_linked_limited_invoke(&vc, 1, 1);
2608         }
2609         else
2610                 selectconnected_mesh_all(em);
2611         
2612         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2613
2614         BKE_mesh_end_editmesh(obedit->data, em);
2615         return OPERATOR_FINISHED;       
2616 }
2617
2618 static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2619 {
2620         linked_limit_default(C, op);
2621         return select_linked_exec(C, op);
2622 }
2623
2624 void MESH_OT_select_linked(wmOperatorType *ot)
2625 {
2626         /* identifiers */
2627         ot->name= "Select Linked All";
2628         ot->description= "Select all vertices linked to the active mesh";
2629         ot->idname= "MESH_OT_select_linked";
2630         
2631         /* api callbacks */
2632         ot->exec= select_linked_exec;
2633         ot->invoke= select_linked_invoke;
2634         ot->poll= ED_operator_editmesh;
2635         
2636         /* flags */
2637         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2638         
2639         RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "Limit selection by seam boundries (faces only)");
2640 }
2641
2642
2643 /* ************************* */
2644
2645 /* swap is 0 or 1, if 1 it hides not selected */
2646 void EM_hide_mesh(EditMesh *em, int swap)
2647 {
2648         EditVert *eve;
2649         EditEdge *eed;
2650         EditFace *efa;
2651         int a;
2652         
2653         if(em==NULL) return;
2654
2655         /* hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
2656         /*  - vertex hidden, always means edge is hidden too
2657                 - edge hidden, always means face is hidden too
2658                 - face hidden, only set face hide
2659                 - then only flush back down what's absolute hidden
2660         */
2661         if(em->selectmode & SCE_SELECT_VERTEX) {
2662                 for(eve= em->verts.first; eve; eve= eve->next) {
2663                         if((eve->f & SELECT)!=swap) {
2664                                 eve->f &= ~SELECT;
2665                                 eve->h= 1;
2666                         }
2667                 }
2668         
2669                 for(eed= em->edges.first; eed; eed= eed->next) {
2670                         if(eed->v1->h || eed->v2->h) {
2671                                 eed->h |= 1;
2672                                 eed->f &= ~SELECT;
2673                         }
2674                 }
2675         
2676                 for(efa= em->faces.first; efa; efa= efa->next) {
2677                         if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
2678                                 efa->h= 1;
2679                                 efa->f &= ~SELECT;
2680                         }
2681                 }
2682         }
2683         else if(em->selectmode & SCE_SELECT_EDGE) {
2684
2685                 for(eed= em->edges.first; eed; eed= eed->next) {
2686                         if((eed->f & SELECT)!=swap) {
2687                                 eed->h |= 1;
2688                                 EM_select_edge(eed, 0);
2689                         }
2690                 }
2691
2692                 for(efa= em->faces.first; efa; efa= efa->next) {
2693                         if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
2694                                 efa->h= 1;
2695                                 efa->f &= ~SELECT;
2696                         }
2697                 }
2698         }
2699         else {
2700
2701                 for(efa= em->faces.first; efa; efa= efa->next) {
2702                         if((efa->f & SELECT)!=swap) {
2703                                 efa->h= 1;
2704                                 EM_select_face(efa, 0);
2705                         }
2706                 }
2707         }
2708         
2709         /* flush down, only whats 100% hidden */
2710         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
2711         for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
2712         
2713         if(em->selectmode & SCE_SELECT_FACE) {
2714                 for(efa= em->faces.first; efa; efa= efa->next) {
2715                         if(efa->h) a= 1; else a= 2;
2716                         efa->e1->f1 |= a;
2717                         efa->e2->f1 |= a;
2718                         efa->e3->f1 |= a;
2719                         if(efa->e4) efa->e4->f1 |= a;
2720                         /* When edges are not delt with in their own loop, we need to explicitly re-selct select edges that are joined to unselected faces */
2721                         if (swap && (em->selectmode == SCE_SELECT_FACE) && (efa->f & SELECT)) {
2722                                 EM_select_face(efa, 1);
2723                         }
2724                 }
2725         }
2726         
2727         if(em->selectmode >= SCE_SELECT_EDGE) {
2728                 for(eed= em->edges.first; eed; eed= eed->next) {
2729                         if(eed->f1==1) eed->h |= 1;
2730                         if(eed->h & 1) a= 1; else a= 2;
2731                         eed->v1->f1 |= a;
2732                         eed->v2->f1 |= a;
2733                 }
2734         }
2735
2736         if(em->selectmode >= SCE_SELECT_VERTEX) {
2737                 for(eve= em->verts.first; eve; eve= eve->next) {
2738                         if(eve->f1==1) eve->h= 1;
2739                 }
2740         }
2741         
2742         em->totedgesel= em->totfacesel= em->totvertsel= 0;
2743 //      if(EM_texFaceCheck())
2744
2745         //      DAG_id_tag_update(obedit->data, 0);
2746 }
2747
2748 static int hide_mesh_exec(bContext *C, wmOperator *op)
2749 {
2750         Object *obedit= CTX_data_edit_object(C);
2751         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
2752         
2753         EM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
2754                 
2755         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2756
2757         BKE_mesh_end_editmesh(obedit->data, em);
2758         return OPERATOR_FINISHED;       
2759 }
2760
2761 void MESH_OT_hide(wmOperatorType *ot)
2762 {
2763         /* identifiers */
2764         ot->name= "Hide Selection";
2765         ot->description= "Hide (un)selected vertices, edges or faces";
2766         ot->idname= "MESH_OT_hide";
2767         
2768         /* api callbacks */
2769         ot->exec= hide_mesh_exec;
2770         ot->poll= ED_operator_editmesh;
2771         
2772         /* flags */
2773         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2774         
2775         /* props */
2776         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
2777 }
2778
2779 void EM_reveal_mesh(EditMesh *em)
2780 {
2781         EditVert *eve;
2782         EditEdge *eed;
2783         EditFace *efa;
2784         
2785         if(em==NULL) return;
2786
2787         for(eve= em->verts.first; eve; eve= eve->next) {
2788                 if(eve->h) {
2789                         eve->h= 0;
2790                         eve->f |= SELECT;
2791                 }
2792         }
2793         for(eed= em->edges.first; eed; eed= eed->next) {
2794                 if(eed->h & 1) {
2795                         eed->h &= ~1;
2796                         if(em->selectmode & SCE_SELECT_VERTEX); 
2797                         else EM_select_edge(eed, 1);
2798                 }
2799         }
2800         for(efa= em->faces.first; efa; efa= efa->next) {
2801                 if(efa->h) {
2802                         efa->h= 0;
2803                         if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX)); 
2804                         else EM_select_face(efa, 1);
2805                 }
2806         }
2807
2808         EM_fgon_flags(em);      /* redo flags and indices for fgons */
2809         EM_selectmode_flush(em);
2810
2811 //      if (EM_texFaceCheck())
2812 //      DAG_id_tag_update(obedit->data, 0);
2813 }
2814
2815 static int reveal_mesh_exec(bContext *C, wmOperator *UNUSED(op))
2816 {
2817         Object *obedit= CTX_data_edit_object(C);
2818         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
2819         
2820         EM_reveal_mesh(em);
2821
2822         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2823
2824         BKE_mesh_end_editmesh(obedit->data, em);
2825         return OPERATOR_FINISHED;       
2826 }
2827
2828 void MESH_OT_reveal(wmOperatorType *ot)
2829 {
2830         /* identifiers */
2831         ot->name= "Reveal Hidden";
2832         ot->description= "Reveal all hidden vertices, edges and faces";
2833         ot->idname= "MESH_OT_reveal";
2834         
2835         /* api callbacks */
2836         ot->exec= reveal_mesh_exec;
2837         ot->poll= ED_operator_editmesh;
2838         
2839         /* flags */
2840         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2841 }
2842
2843 int select_by_number_vertices_exec(bContext *C, wmOperator *op)
2844 {
2845         Object *obedit= CTX_data_edit_object(C);
2846         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
2847         EditFace *efa;
2848         int numverts= RNA_enum_get(op->ptr, "type");
2849
2850         /* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring
2851          * faces
2852          */
2853
2854         /* for loose vertices/edges, we first select all, loop below will deselect */
2855         if(numverts==5) {
2856                 EM_set_flag_all(em, SELECT);
2857         }
2858         else if(em->selectmode!=SCE_SELECT_FACE) {
2859                 BKE_report(op->reports, RPT_WARNING, "Only works in face selection mode");
2860                 return OPERATOR_CANCELLED;
2861         }
2862         
2863         for(efa= em->faces.first; efa; efa= efa->next) {
2864                 if (efa->e4) {
2865                         EM_select_face(efa, (numverts==4) );
2866                 }
2867                 else {
2868                         EM_select_face(efa, (numverts==3) );
2869                 }
2870         }
2871         
2872         EM_selectmode_flush(em);
2873
2874         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2875         
2876         return OPERATOR_FINISHED;
2877 }
2878
2879 void MESH_OT_select_by_number_vertices(wmOperatorType *ot)
2880 {
2881         static const EnumPropertyItem type_items[]= {
2882                 {3, "TRIANGLES", 0, "Triangles", NULL},
2883                 {4, "QUADS", 0, "Quads", NULL},
2884                 {5, "OTHER", 0, "Other", NULL},
2885                 {0, NULL, 0, NULL, NULL}};
2886
2887         /* identifiers */
2888         ot->name= "Select by Number of Vertices";
2889         ot->description= "Select vertices or faces by vertex count";
2890         ot->idname= "MESH_OT_select_by_number_vertices";
2891         
2892         /* api callbacks */
2893         ot->exec= select_by_number_vertices_exec;
2894         ot->invoke= WM_menu_invoke;
2895         ot->poll= ED_operator_editmesh;
2896         
2897         /* flags */
2898         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2899         
2900         /* props */
2901         ot->prop= RNA_def_enum(ot->srna, "type", type_items, 3, "Type", "Type of elements to select.");
2902 }
2903
2904
2905 int select_mirror_exec(bContext *C, wmOperator *op)
2906 {
2907         Object *obedit= CTX_data_edit_object(C);
2908         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
2909
2910         int extend= RNA_boolean_get(op->ptr, "extend");
2911
2912         EM_select_mirrored(obedit, em, extend);
2913         EM_selectmode_flush(em);
2914         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2915
2916         return OPERATOR_FINISHED;
2917 }
2918
2919 void MESH_OT_select_mirror(wmOperatorType *ot)
2920 {
2921         /* identifiers */
2922         ot->name= "Select Mirror";
2923         ot->description= "Select mesh items at mirrored locations";
2924         ot->idname= "MESH_OT_select_mirror";
2925
2926         /* api callbacks */
2927         ot->exec= select_mirror_exec;
2928         ot->poll= ED_operator_editmesh;
2929
2930         /* flags */
2931         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2932
2933         /* props */
2934         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
2935 }
2936
2937 static int select_sharp_edges_exec(bContext *C, wmOperator *op)
2938 {
2939         /* Find edges that have exactly two neighboring faces,
2940         * check the angle between those faces, and if angle is
2941         * small enough, select the edge
2942         */
2943         Object *obedit= CTX_data_edit_object(C);
2944         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
2945         EditEdge *eed;
2946         EditFace *efa;
2947         EditFace **efa1;
2948         EditFace **efa2;
2949         intptr_t edgecount = 0, i = 0;
2950         float sharpness, fsharpness;
2951         
2952         /* 'standard' behaviour - check if selected, then apply relevant selection */
2953         
2954         if(em->selectmode==SCE_SELECT_FACE) {
2955                 BKE_report(op->reports, RPT_WARNING, "Doesn't work in face selection mode");
2956                 BKE_mesh_end_editmesh(obedit->data, em);
2957                 return OPERATOR_CANCELLED;
2958         }
2959
2960         sharpness= RNA_float_get(op->ptr, "sharpness");
2961         fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
2962
2963         /* count edges, use tmp.l  */
2964         eed= em->edges.first;
2965         while(eed) {
2966                 edgecount++;
2967                 eed->tmp.l = i;
2968                 eed= eed->next;
2969                 ++i;
2970         }
2971
2972         /* for each edge, we want a pointer to two adjacent faces */
2973         efa1 = MEM_callocN(edgecount*sizeof(EditFace *), 
2974                                            "pairs of edit face pointers");
2975         efa2 = MEM_callocN(edgecount*sizeof(EditFace *), 
2976                                            "pairs of edit face pointers");
2977
2978 #define face_table_edge(eed) { \
2979                 i = eed->tmp.l; \
2980                 if (i != -1) { \
2981                         if (efa1[i]) { \
2982                                 if (efa2[i]) { \
2983                                         /* invalidate, edge has more than two neighbors */ \
2984                                         eed->tmp.l = -1; \
2985                                 } \
2986                                 else { \
2987                                         efa2[i] = efa; \
2988                                 } \
2989                         } \
2990                         else { \
2991                                 efa1[i] = efa; \
2992                         } \
2993                 } \
2994         }