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