4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
20 * The Original Code is Copyright (C) 2004 Blender Foundation.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
32 editmesh_mods.c, UI level access, no geometry changes
40 #include "MEM_guardedalloc.h"
42 #include "MTC_matrixops.h"
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"
55 #include "BLI_blenlib.h"
56 #include "BLI_arithb.h"
57 #include "BLI_editVert.h"
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"
67 #include "BKE_material.h"
68 #include "BKE_texture.h"
69 #include "BKE_utildefines.h"
71 #include "IMB_imbuf_types.h"
72 #include "IMB_imbuf.h"
74 #include "RE_render_ext.h" /* externtex */
79 #include "RNA_access.h"
80 #include "RNA_define.h"
83 #include "ED_screen.h"
84 #include "ED_view3d.h"
87 #include "BIF_glutil.h"
89 #include "mesh_intern.h"
91 #include "BLO_sys_types.h" // for intptr_t support
93 static void BIF_undo_push() {}
94 static void waitcursor() {}
95 static void error() {}
96 static int pupmenu() {return 0;}
98 /* ****************************** MIRROR **************** */
100 void EM_select_mirrored(Object *obedit, EditMesh *em)
102 if(em->selectmode & SCE_SELECT_VERTEX) {
105 for(eve= em->verts.first; eve; eve= eve->next) {
106 if(eve->f & SELECT) {
107 v1= editmesh_get_x_mirror_vert(obedit, em, eve->co);
117 void EM_automerge(int update)
121 // if ((scene->automerge) &&
122 // (obedit && obedit->type==OB_MESH) &&
123 // (((Mesh*)obedit->data)->mr==NULL)
125 // len = removedoublesflag(1, 1, scene->toolsettings->doublimit);
127 // em->totvert -= len; /* saves doing a countall */
129 // DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
135 /* ****************************** SELECTION ROUTINES **************** */
137 unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0; /* set in drawobject.c ... for colorindices */
139 /* facilities for border select and circle select */
140 static char *selbuf= NULL;
142 /* opengl doesn't support concave... */
143 static void draw_triangulated(short mcords[][2], short tot)
145 ListBase lb={NULL, NULL};
151 dl= MEM_callocN(sizeof(DispList), "poly disp");
155 dl->verts= fp= MEM_callocN(tot*3*sizeof(float), "poly verts");
156 BLI_addtail(&lb, dl);
158 for(a=0; a<tot; a++, fp+=3) {
159 fp[0]= (float)mcords[a][0];
160 fp[1]= (float)mcords[a][1];
164 filldisplist(&lb, &lb);
167 dl= lb.first; /* filldisplist adds in head of list */
168 if(dl->type==DL_INDEX3) {
174 glBegin(GL_TRIANGLES);
176 glVertex3fv(fp+3*index[0]);
177 glVertex3fv(fp+3*index[1]);
178 glVertex3fv(fp+3*index[2]);
188 /* reads rect, and builds selection array for quick lookup */
189 /* returns if all is OK */
190 int EM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
196 if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
198 buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
199 if(buf==NULL) return 0;
200 if(em_vertoffs==0) return 0;
204 /* build selection lookup */
205 selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
207 a= (xmax-xmin+1)*(ymax-ymin+1);
209 if(*dr>0 && *dr<=em_vertoffs)
217 int EM_check_backbuf(unsigned int index)
219 if(selbuf==NULL) return 1;
220 if(index>0 && index<=em_vertoffs)
221 return selbuf[index];
225 void EM_free_backbuf(void)
227 if(selbuf) MEM_freeN(selbuf);
231 /* mcords is a polygon mask
233 - draw with black in backbuffer,
234 - grab again and compare
237 int EM_mask_init_backbuf_border(ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
239 unsigned int *dr, *drm;
240 struct ImBuf *buf, *bufmask;
243 /* method in use for face selecting too */
244 if(vc->obedit==NULL) {
245 if(FACESEL_PAINT_TEST);
248 else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
250 if(em_vertoffs==0) return 0;
252 buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
253 if(buf==NULL) return 0;
259 glDrawBuffer(GL_AUX0);
261 glDisable(GL_DEPTH_TEST);
263 // XXX persp(PERSP_WIN);
266 /* yah, opengl doesn't do concave... tsk! */
267 draw_triangulated(mcords, tot);
269 glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */
270 for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
273 // XXX persp(PERSP_VIEW);
274 glFinish(); /* to be sure readpixels sees mask */
276 glDrawBuffer(GL_BACK);
279 bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
281 if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
283 /* build selection lookup */
284 selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
286 a= (xmax-xmin+1)*(ymax-ymin+1);
288 if(*dr>0 && *dr<=em_vertoffs && *drm==0) selbuf[*dr]= 1;
292 IMB_freeImBuf(bufmask);
297 /* circle shaped sample area */
298 int EM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
302 short xmin, ymin, xmax, ymax, xc, yc;
305 /* method in use for face selecting too */
306 if(vc->obedit==NULL) {
307 if(FACESEL_PAINT_TEST);
310 else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
311 if(em_vertoffs==0) return 0;
313 xmin= xs-rads; xmax= xs+rads;
314 ymin= ys-rads; ymax= ys+rads;
315 buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
316 if(buf==NULL) return 0;
320 /* build selection lookup */
321 selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
323 for(yc= -rads; yc<=rads; yc++) {
324 for(xc= -rads; xc<=rads; xc++, dr++) {
325 if(xc*xc + yc*yc < radsq) {
326 if(*dr>0 && *dr<=em_vertoffs) selbuf[*dr]= 1;
336 static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index)
338 struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } *data = userData;
341 if (index<=data->lastIndex)
344 if (index>data->lastIndex)
349 int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
350 if ((eve->f&1) == data->select) {
351 if (data->strict == 1)
357 if (temp<data->dist) {
360 data->closestIndex = index;
368 static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
370 EditMesh *em= (EditMesh *)handle;
371 EditVert *eve = BLI_findlink(&em->verts, index-1);
373 if(eve && (eve->f & SELECT)) return 0;
379 * dist (in/out): minimal distance to the nearest and at the end, actual distance
380 * sel: selection bias
381 * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
382 * if 0, unselected vertice are given the bias
383 * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
385 EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
387 if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){
392 if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest);
393 else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL);
395 eve = BLI_findlink(&vc->em->verts, index-1);
397 if(eve && distance < *dist) {
406 struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } data;
407 static int lastSelectedIndex=0;
408 static EditVert *lastSelected=NULL;
410 if (lastSelected && BLI_findlink(&vc->em->verts, lastSelectedIndex)!=lastSelected) {
411 lastSelectedIndex = 0;
415 data.lastIndex = lastSelectedIndex;
416 data.mval[0] = vc->mval[0];
417 data.mval[1] = vc->mval[1];
420 data.strict = strict;
422 data.closestIndex = 0;
425 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
429 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
433 lastSelected = data.closest;
434 lastSelectedIndex = data.closestIndex;
440 /* returns labda for closest distance v1 to line-piece v2-v3 */
441 static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3)
447 len= rc[0]*rc[0]+ rc[1]*rc[1];
451 return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
454 /* note; uses v3d, so needs active 3d window */
455 static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
457 struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } *data = userData;
466 distance= PdistVL2Dfl(data->mval, v1, v2);
468 if(eed->f & SELECT) distance+=5;
469 if(distance < data->dist) {
470 if(data->vc.rv3d->rflag & RV3D_CLIPPING) {
471 float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
474 vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
475 vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
476 vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
477 Mat4MulVecfl(data->vc.obedit->obmat, vec);
479 if(view3d_test_clipping(data->vc.rv3d, vec)==0) {
480 data->dist = distance;
485 data->dist = distance;
490 EditEdge *findnearestedge(ViewContext *vc, int *dist)
493 if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
495 unsigned int index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_solidoffs, em_wireoffs, &distance,0, NULL, NULL);
496 EditEdge *eed = BLI_findlink(&vc->em->edges, index-1);
498 if (eed && distance<*dist) {
506 struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } data;
509 data.mval[0] = vc->mval[0];
510 data.mval[1] = vc->mval[1];
514 mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2);
521 static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int index)
523 struct { short mval[2]; int dist; EditFace *toFace; } *data = userData;
525 if (efa==data->toFace) {
526 int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
532 static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int y, int index)
534 struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } *data = userData;
537 if (index<=data->lastIndex)
540 if (index>data->lastIndex)
545 int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
547 if (temp<data->dist) {
550 data->closestIndex = index;
554 static EditFace *findnearestface(ViewContext *vc, int *dist)
557 if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
558 unsigned int index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
559 EditFace *efa = BLI_findlink(&vc->em->faces, index-1);
562 struct { short mval[2]; int dist; EditFace *toFace; } data;
564 data.mval[0] = vc->mval[0];
565 data.mval[1] = vc->mval[1];
566 data.dist = 0x7FFF; /* largest short */
569 mesh_foreachScreenFace(vc, findnearestface__getDistance, &data);
571 if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */
580 struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } data;
581 static int lastSelectedIndex=0;
582 static EditFace *lastSelected=NULL;
584 if (lastSelected && BLI_findlink(&vc->em->faces, lastSelectedIndex)!=lastSelected) {
585 lastSelectedIndex = 0;
589 data.lastIndex = lastSelectedIndex;
590 data.mval[0] = vc->mval[0];
591 data.mval[1] = vc->mval[1];
594 data.closestIndex = 0;
597 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
601 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
605 lastSelected = data.closest;
606 lastSelectedIndex = data.closestIndex;
612 /* best distance based on screen coords.
613 use em->selectmode to define how to use
614 selected vertices and edges get disadvantage
615 return 1 if found one
617 static int unified_findnearest(ViewContext *vc, EditVert **eve, EditEdge **eed, EditFace **efa)
619 EditMesh *em= vc->em;
626 /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
627 view3d_validate_backbuf(vc);
629 if(em->selectmode & SCE_SELECT_VERTEX)
630 *eve= findnearestvert(vc, &dist, SELECT, 0);
631 if(em->selectmode & SCE_SELECT_FACE)
632 *efa= findnearestface(vc, &dist);
634 dist-= 20; /* since edges select lines, we give dots advantage of 20 pix */
635 if(em->selectmode & SCE_SELECT_EDGE)
636 *eed= findnearestedge(vc, &dist);
638 /* return only one of 3 pointers, for frontbuffer redraws */
640 *efa= NULL; *eve= NULL;
646 return (*eve || *eed || *efa);
649 /* this as a way to compare the ares, perim of 2 faces thay will scale to different sizes
650 *0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
651 #define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5) <= b))
653 /* **************** GROUP SELECTS ************** */
654 /* selects new faces/edges/verts based on the
658 mode 1: same material
661 mode 4: same perimeter
663 mode 6: same co-planer
665 int facegroup_select(EditMesh *em, short mode)
667 EditFace *efa, *base_efa=NULL;
668 unsigned int selcount=0; /*count how many new faces we select*/
670 /*deselcount, count how many deselected faces are left, so we can bail out early
671 also means that if there are no deselected faces, we can avoid a lot of looping */
672 unsigned int deselcount=0;
675 float thresh=0; // XXX scene->toolsettings->select_thresh;
677 for(efa= em->faces.first; efa; efa= efa->next) {
679 if (efa->f & SELECT) {
684 deselcount++; /* a deselected face we may select later */
689 if (!ok || !deselcount) /* no data selected OR no more data to select */
692 /*if mode is 3 then record face areas, 4 record perimeter */
694 for(efa= em->faces.first; efa; efa= efa->next) {
695 efa->tmp.fp= EM_face_area(efa);
697 } else if (mode==4) {
698 for(efa= em->faces.first; efa; efa= efa->next) {
699 efa->tmp.fp= EM_face_perimeter(efa);
703 for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) {
704 if (base_efa->f1) { /* This was one of the faces originaly selected */
705 if (mode==1) { /* same material */
706 for(efa= em->faces.first; efa; efa= efa->next) {
708 !(efa->f & SELECT) &&
710 base_efa->mat_nr == efa->mat_nr
712 EM_select_face(efa, 1);
715 if (!deselcount) /*have we selected all posible faces?, if so return*/
719 } else if (mode==2) { /* same image */
720 MTFace *tf, *base_tf;
722 base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data,
728 for(efa= em->faces.first; efa; efa= efa->next) {
729 if (!(efa->f & SELECT) && !efa->h) {
730 tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data,
733 if(base_tf->tpage == tf->tpage) {
734 EM_select_face(efa, 1);
737 if (!deselcount) /*have we selected all posible faces?, if so return*/
742 } else if (mode==3 || mode==4) { /* same area OR same perimeter, both use the same temp var */
743 for(efa= em->faces.first; efa; efa= efa->next) {
745 (!(efa->f & SELECT) && !efa->h) &&
746 SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp)
748 EM_select_face(efa, 1);
751 if (!deselcount) /*have we selected all posible faces?, if so return*/
755 } else if (mode==5) { /* same normal */
757 for(efa= em->faces.first; efa; efa= efa->next) {
758 if (!(efa->f & SELECT) && !efa->h) {
759 angle= VecAngle2(base_efa->n, efa->n);
760 if (angle/180.0<=thresh) {
761 EM_select_face(efa, 1);
764 if (!deselcount) /*have we selected all posible faces?, if so return*/
769 } else if (mode==6) { /* same planer */
770 float angle, base_dot, dot;
771 base_dot= Inpf(base_efa->cent, base_efa->n);
772 for(efa= em->faces.first; efa; efa= efa->next) {
773 if (!(efa->f & SELECT) && !efa->h) {
774 angle= VecAngle2(base_efa->n, efa->n);
775 if (angle/180.0<=thresh) {
776 dot=Inpf(efa->cent, base_efa->n);
777 if (fabs(base_dot-dot) <= thresh) {
778 EM_select_face(efa, 1);
781 if (!deselcount) /*have we selected all posible faces?, if so return*/
789 } /* end base_efa loop */
797 mode 2: same direction
798 mode 3: same number of face users
799 mode 4: similar face angles.
800 mode 5: similar crease
802 mode 7: similar sharp
805 /* this function is only used by edgegroup_select's edge angle */
809 static int edgegroup_select__internal(EditMesh *em, short mode)
811 EditEdge *eed, *base_eed=NULL;
812 unsigned int selcount=0; /* count how many new edges we select*/
814 /*count how many visible selected edges there are,
815 so we can return when there are none left */
816 unsigned int deselcount=0;
819 float thresh=0; // XXX scene->toolsettings->select_thresh;
821 for(eed= em->edges.first; eed; eed= eed->next) {
823 if (eed->f & SELECT) {
830 /* set all eed->tmp.l to 0 we use it later.
831 for counting face users*/
833 eed->f2=0; /* only for mode 4, edge animations */
837 if (!ok || !deselcount) /* no data selected OR no more data to select*/
840 if (mode==1) { /*store length*/
841 for(eed= em->edges.first; eed; eed= eed->next) {
842 if (!eed->h) /* dont calc data for hidden edges*/
843 eed->tmp.fp= VecLenf(eed->v1->co, eed->v2->co);
845 } else if (mode==3) { /*store face users*/
847 /* cound how many faces each edge uses use tmp->l */
848 for(efa= em->faces.first; efa; efa= efa->next) {
852 if (efa->e4) efa->e4->tmp.l++;
854 } else if (mode==4) { /*store edge angles */
857 /* cound how many faces each edge uses use tmp.l */
858 for(efa= em->faces.first; efa; efa= efa->next) {
859 /* here we use the edges temp data to assign a face
860 if a face has alredy been assigned (eed->f2==1)
861 we calculate the angle between the current face and
862 the edges previously found face.
863 store the angle in eed->tmp.fp (loosing the face eed->tmp.f)
864 but tagging eed->f2==2, so we know not to look at it again.
865 This only works for edges that connect to 2 faces. but its good enough
868 /* se we can loop through face edges*/
872 if (j==1) eed= efa->e2;
873 else if (j==2) eed= efa->e3;
880 if (!eed->h) { /* dont calc data for hidden edges*/
883 else if (eed->f2==0) /* first access, assign the face */
885 else if (eed->f2==1) /* second, we assign the angle*/
886 eed->tmp.fp= VecAngle2(eed->tmp.f->n, efa->n)/180;
887 eed->f2++; /* f2==0 no face assigned. f2==1 one face found. f2==2 angle calculated.*/
894 for(base_eed= em->edges.first; base_eed; base_eed= base_eed->next) {
896 if (mode==1) { /* same length */
897 for(eed= em->edges.first; eed; eed= eed->next) {
899 !(eed->f & SELECT) &&
901 SCALE_CMP(base_eed->tmp.fp, eed->tmp.fp)
903 EM_select_edge(eed, 1);
906 if (!deselcount) /*have we selected all posible faces?, if so return*/
910 } else if (mode==2) { /* same direction */
911 float base_dir[3], dir[3], angle;
912 VecSubf(base_dir, base_eed->v1->co, base_eed->v2->co);
913 for(eed= em->edges.first; eed; eed= eed->next) {
914 if (!(eed->f & SELECT) && !eed->h) {
915 VecSubf(dir, eed->v1->co, eed->v2->co);
916 angle= VecAngle2(base_dir, dir);
918 if (angle>90) /* use the smallest angle between the edges */
919 angle= fabs(angle-180.0f);
921 if (angle/90.0<=thresh) {
922 EM_select_edge(eed, 1);
925 if (!deselcount) /*have we selected all posible faces?, if so return*/
930 } else if (mode==3) { /* face users */
931 for(eed= em->edges.first; eed; eed= eed->next) {
933 !(eed->f & SELECT) &&
935 base_eed->tmp.l==eed->tmp.l
937 EM_select_edge(eed, 1);
940 if (!deselcount) /*have we selected all posible faces?, if so return*/
944 } else if (mode==4 && base_eed->f2==2) { /* edge angles, f2==2 means the edge has an angle. */
945 for(eed= em->edges.first; eed; eed= eed->next) {
947 !(eed->f & SELECT) &&
950 (fabs(base_eed->tmp.fp-eed->tmp.fp)<=thresh)
952 EM_select_edge(eed, 1);
955 if (!deselcount) /*have we selected all posible faces?, if so return*/
959 } else if (mode==5) { /* edge crease */
960 for(eed= em->edges.first; eed; eed= eed->next) {
962 !(eed->f & SELECT) &&
964 (fabs(base_eed->crease-eed->crease) <= thresh)
966 EM_select_edge(eed, 1);
969 if (!deselcount) /*have we selected all posible faces?, if so return*/
973 } else if (mode==6) { /* edge seam */
974 for(eed= em->edges.first; eed; eed= eed->next) {
976 !(eed->f & SELECT) &&
978 (eed->seam == base_eed->seam)
980 EM_select_edge(eed, 1);
983 if (!deselcount) /*have we selected all posible faces?, if so return*/
987 } else if (mode==7) { /* edge sharp */
988 for(eed= em->edges.first; eed; eed= eed->next) {
990 !(eed->f & SELECT) &&
992 (eed->sharp == base_eed->sharp)
994 EM_select_edge(eed, 1);
997 if (!deselcount) /*have we selected all posible faces?, if so return*/
1006 /* wrap the above function but do selection flushing edge to face */
1007 int edgegroup_select(EditMesh *em, short mode)
1009 int selcount = edgegroup_select__internal(em, mode);
1012 /* Could run a generic flush function,
1013 * but the problem is only that all edges of a face
1014 * can be selected without the face becoming selected */
1016 for(efa= em->faces.first; efa; efa= efa->next) {
1018 if (efa->e1->f&SELECT && efa->e2->f&SELECT && efa->e3->f&SELECT && efa->e4->f&SELECT)
1021 if (efa->e1->f&SELECT && efa->e2->f&SELECT && efa->e3->f&SELECT)
1034 mode 2: same number of face users
1035 mode 3: same vertex groups
1037 int vertgroup_select(EditMesh *em, short mode)
1039 EditVert *eve, *base_eve=NULL;
1041 unsigned int selcount=0; /* count how many new edges we select*/
1043 /*count how many visible selected edges there are,
1044 so we can return when there are none left */
1045 unsigned int deselcount=0;
1048 float thresh=0; // XXX scene->toolsettings->select_thresh;
1050 for(eve= em->verts.first; eve; eve= eve->next) {
1052 if (eve->f & SELECT) {
1059 /* set all eve->tmp.l to 0 we use them later.*/
1065 if (!ok || !deselcount) /* no data selected OR no more data to select*/
1069 if (mode==2) { /* store face users */
1072 /* count how many faces each edge uses use tmp->l */
1073 for(efa= em->faces.first; efa; efa= efa->next) {
1077 if (efa->v4) efa->v4->tmp.l++;
1082 for(base_eve= em->verts.first; base_eve; base_eve= base_eve->next) {
1085 if (mode==1) { /* same normal */
1087 for(eve= em->verts.first; eve; eve= eve->next) {
1088 if (!(eve->f & SELECT) && !eve->h) {
1089 angle= VecAngle2(base_eve->no, eve->no);
1090 if (angle/180.0<=thresh) {
1094 if (!deselcount) /*have we selected all posible faces?, if so return*/
1099 } else if (mode==2) { /* face users */
1100 for(eve= em->verts.first; eve; eve= eve->next) {
1102 !(eve->f & SELECT) &&
1104 base_eve->tmp.l==eve->tmp.l
1109 if (!deselcount) /*have we selected all posible faces?, if so return*/
1113 } else if (mode==3) { /* vertex groups */
1114 MDeformVert *dvert, *base_dvert;
1115 short i, j; /* weight index */
1117 base_dvert= CustomData_em_get(&em->vdata, base_eve->data,
1120 if (!base_dvert || base_dvert->totweight == 0)
1123 for(eve= em->verts.first; eve; eve= eve->next) {
1124 dvert= CustomData_em_get(&em->vdata, eve->data,
1127 if (dvert && !(eve->f & SELECT) && !eve->h && dvert->totweight) {
1128 /* do the extra check for selection in the following if, so were not
1129 checking verts that may be alredy selected */
1130 for (i=0; base_dvert->totweight >i && !(eve->f & SELECT); i++) {
1131 for (j=0; dvert->totweight >j; j++) {
1132 if (base_dvert->dw[i].def_nr==dvert->dw[j].def_nr) {
1136 if (!deselcount) /*have we selected all posible faces?, if so return*/
1146 } /* end basevert loop */
1150 /* EditMode menu triggered from space.c by pressing Shift+G
1151 handles face/edge vert context and
1152 facegroup_select/edgegroup_select/vertgroup_select do all the work
1155 void select_mesh_group_menu(EditMesh *em)
1158 int selcount, first_item=1, multi=0;
1159 char str[512] = "Select Similar "; /* total max length is 404 at the moment */
1161 if (!ELEM3(em->selectmode, SCE_SELECT_VERTEX, SCE_SELECT_EDGE, SCE_SELECT_FACE)) {
1165 if(em->selectmode & SCE_SELECT_VERTEX) {
1166 if (multi) strcat(str, "%t|Vertices%x-1|");
1167 else strcat(str, "Vertices %t|");
1168 strcat(str, " Normal %x1| Face Users %x2| Shared Vertex Groups%x3");
1172 if(em->selectmode & SCE_SELECT_EDGE) {
1174 if (first_item) strcat(str, "%t|Edges%x-1|");
1175 else strcat(str, "|%l|Edges%x-1|");
1176 } else strcat(str, "Edges %t|");
1178 strcat(str, " Length %x10| Direction %x20| Face Users%x30| Face Angle%x40| Crease%x50| Seam%x60| Sharp%x70");
1182 if(em->selectmode & SCE_SELECT_FACE) {
1184 strcat(str, "|%l|Faces%x-1|");
1185 } else strcat(str, "Faces %t|");
1186 strcat(str, " Material %x100| Image %x200| Area %x300| Perimeter %x400| Normal %x500| Co-Planar %x600");
1194 selcount= vertgroup_select(em, ret);
1195 if (selcount) { /* update if data was selected */
1196 EM_select_flush(em); /* so that selected verts, go onto select faces */
1197 em->totvertsel += selcount;
1198 // if (EM_texFaceCheck())
1199 BIF_undo_push("Select Similar Vertices");
1205 selcount= edgegroup_select(em, ret/10);
1207 if (selcount) { /* update if data was selected */
1208 /*EM_select_flush(em);*/ /* dont use because it can end up selecting more edges and is not usefull*/
1209 em->totedgesel+=selcount;
1210 // if (EM_texFaceCheck())
1211 BIF_undo_push("Select Similar Edges");
1217 selcount= facegroup_select(em, ret/100);
1218 if (selcount) { /* update if data was selected */
1219 em->totfacesel+=selcount;
1220 // if (EM_texFaceCheck())
1221 BIF_undo_push("Select Similar Faces");
1227 int mesh_layers_menu_charlen(CustomData *data, int type)
1230 /* see if there is a duplicate */
1231 for(i=0; i<data->totlayer; i++) {
1232 if((&data->layers[i])->type == type) {
1233 /* we could count the chars here but we'll just assumeme each
1234 * is 32 chars with some room for the menu text - 40 should be fine */
1241 /* this function adds menu text into an existing string.
1242 * this string's size should be allocated with mesh_layers_menu_charlen */
1243 void mesh_layers_menu_concat(CustomData *data, int type, char *str) {
1246 CustomDataLayer *layer;
1248 /* see if there is a duplicate */
1249 for(i=0; i<data->totlayer; i++) {
1250 layer = &data->layers[i];
1251 if(layer->type == type) {
1252 str_pt += sprintf(str_pt, "%s%%x%d|", layer->name, count);
1258 int mesh_layers_menu(CustomData *data, int type) {
1262 str_pt = str = MEM_mallocN(mesh_layers_menu_charlen(data, type) + 18, "layer menu");
1265 str_pt += sprintf(str_pt, "Layers%%t|");
1267 mesh_layers_menu_concat(data, type, str_pt);
1274 void EM_mesh_copy_edge(EditMesh *em, short type)
1279 EditEdge *eed, *eed_act;
1280 float vec[3], vec_mid[3], eed_len, eed_len_act;
1284 ese = em->selected.last;
1287 eed_act = (EditEdge*)ese->data;
1290 case 1: /* copy crease */
1291 for(eed=em->edges.first; eed; eed=eed->next) {
1292 if (eed->f & SELECT && eed != eed_act && eed->crease != eed_act->crease) {
1293 eed->crease = eed_act->crease;
1298 case 2: /* copy bevel weight */
1299 for(eed=em->edges.first; eed; eed=eed->next) {
1300 if (eed->f & SELECT && eed != eed_act && eed->bweight != eed_act->bweight) {
1301 eed->bweight = eed_act->bweight;
1307 case 3: /* copy length */
1308 eed_len_act = VecLenf(eed_act->v1->co, eed_act->v2->co);
1309 for(eed=em->edges.first; eed; eed=eed->next) {
1310 if (eed->f & SELECT && eed != eed_act) {
1312 eed_len = VecLenf(eed->v1->co, eed->v2->co);
1314 if (eed_len == eed_len_act) continue;
1315 /* if this edge is zero length we cont do anything with it*/
1316 if (eed_len == 0.0f) continue;
1317 if (eed_len_act == 0.0f) {
1318 VecAddf(vec_mid, eed->v1->co, eed->v2->co);
1319 VecMulf(vec_mid, 0.5);
1320 VECCOPY(eed->v1->co, vec_mid);
1321 VECCOPY(eed->v2->co, vec_mid);
1323 /* copy the edge length */
1324 VecAddf(vec_mid, eed->v1->co, eed->v2->co);
1325 VecMulf(vec_mid, 0.5);
1328 VecSubf(vec, eed->v1->co, vec_mid);
1329 VecMulf(vec, eed_len_act/eed_len);
1330 VecAddf(eed->v1->co, vec, vec_mid);
1333 VecSubf(vec, eed->v2->co, vec_mid);
1334 VecMulf(vec, eed_len_act/eed_len);
1335 VecAddf(eed->v2->co, vec, vec_mid);
1342 recalc_editnormals(em);
1348 // DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1350 BIF_undo_push("Copy Edge Attribute");
1354 void EM_mesh_copy_face(EditMesh *em, short type)
1358 EditFace *efa, *efa_act;
1359 MTFace *tf, *tf_act = NULL;
1360 MCol *mcol, *mcol_act = NULL;
1362 efa_act = EM_get_actFace(em, 0);
1364 if (!efa_act) return;
1366 tf_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MTFACE);
1367 mcol_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MCOL);
1370 case 1: /* copy material */
1371 for(efa=em->faces.first; efa; efa=efa->next) {
1372 if (efa->f & SELECT && efa->mat_nr != efa_act->mat_nr) {
1373 efa->mat_nr = efa_act->mat_nr;
1378 case 2: /* copy image */
1380 error("mesh has no uv/image layers");
1383 for(efa=em->faces.first; efa; efa=efa->next) {
1384 if (efa->f & SELECT && efa != efa_act) {
1385 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1386 if (tf_act->tpage) {
1387 tf->tpage = tf_act->tpage;
1391 tf->mode &= ~TF_TEX;
1393 tf->tile= tf_act->tile;
1399 case 3: /* copy UV's */
1401 error("mesh has no uv/image layers");
1404 for(efa=em->faces.first; efa; efa=efa->next) {
1405 if (efa->f & SELECT && efa != efa_act) {
1406 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1407 memcpy(tf->uv, tf_act->uv, sizeof(tf->uv));
1412 case 4: /* mode's */
1414 error("mesh has no uv/image layers");
1417 for(efa=em->faces.first; efa; efa=efa->next) {
1418 if (efa->f & SELECT && efa != efa_act) {
1419 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1420 tf->mode= tf_act->mode;
1425 case 5: /* copy transp's */
1427 error("mesh has no uv/image layers");
1430 for(efa=em->faces.first; efa; efa=efa->next) {
1431 if (efa->f & SELECT && efa != efa_act) {
1432 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1433 tf->transp= tf_act->transp;
1439 case 6: /* copy vcols's */
1441 error("mesh has no color layers");
1444 /* guess the 4th color if needs be */
1448 /* guess the othe vale, we may need to use it
1450 * Modifying the 4th value of the mcol is ok here since its not seen
1453 val = ((float)(mcol_act->r + (mcol_act+1)->r + (mcol_act+2)->r)) / 3; CLAMP(val, 0, 255);
1454 (mcol_act+3)->r = (char)val;
1456 val = ((float)(mcol_act->g + (mcol_act+1)->g + (mcol_act+2)->g)) / 3; CLAMP(val, 0, 255);
1457 (mcol_act+3)->g = (char)val;
1459 val = ((float)(mcol_act->b + (mcol_act+1)->b + (mcol_act+2)->b)) / 3; CLAMP(val, 0, 255);
1460 (mcol_act+3)->b = (char)val;
1464 for(efa=em->faces.first; efa; efa=efa->next) {
1465 if (efa->f & SELECT && efa != efa_act) {
1466 /* TODO - make copy from tri to quad guess the 4th vert */
1467 mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
1468 memcpy(mcol, mcol_act, sizeof(MCol)*4);
1477 // DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1479 // XXX allqueue(REDRAWIMAGE, 0);
1482 BIF_undo_push("Copy Face Attribute");
1487 void EM_mesh_copy_face_layer(EditMesh *em, short type)
1492 MTFace *tf, *tf_from;
1493 MCol *mcol, *mcol_from;
1501 if (CustomData_number_of_layers(&em->fdata, CD_MTFACE)<2) {
1502 error("mesh does not have multiple uv/image layers");
1505 int layer_orig_idx, layer_idx;
1507 layer_idx = mesh_layers_menu(&em->fdata, CD_MTFACE);
1508 if (layer_idx<0) return;
1510 /* warning, have not updated mesh pointers however this is not needed since we swicth back */
1511 layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MTFACE);
1512 if (layer_idx==layer_orig_idx)
1515 /* get the tfaces */
1516 CustomData_set_layer_active(&em->fdata, CD_MTFACE, (int)layer_idx);
1517 /* store the tfaces in our temp */
1518 for(efa=em->faces.first; efa; efa=efa->next) {
1519 if (efa->f & SELECT) {
1520 efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1523 CustomData_set_layer_active(&em->fdata, CD_MTFACE, layer_orig_idx);
1527 case 10: /* select vcol layers - make sure this stays in sync with above code */
1528 if (CustomData_number_of_layers(&em->fdata, CD_MCOL)<2) {
1529 error("mesh does not have multiple color layers");
1532 int layer_orig_idx, layer_idx;
1534 layer_idx = mesh_layers_menu(&em->fdata, CD_MCOL);
1535 if (layer_idx<0) return;
1537 /* warning, have not updated mesh pointers however this is not needed since we swicth back */
1538 layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MCOL);
1539 if (layer_idx==layer_orig_idx)
1542 /* get the tfaces */
1543 CustomData_set_layer_active(&em->fdata, CD_MCOL, (int)layer_idx);
1544 /* store the tfaces in our temp */
1545 for(efa=em->faces.first; efa; efa=efa->next) {
1546 if (efa->f & SELECT) {
1547 efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
1550 CustomData_set_layer_active(&em->fdata, CD_MCOL, layer_orig_idx);
1556 /* layer copy only - sanity checks done above */
1558 case 7: /* copy UV's only */
1559 for(efa=em->faces.first; efa; efa=efa->next) {
1560 if (efa->f & SELECT) {
1561 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
1562 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1563 memcpy(tf->uv, tf_from->uv, sizeof(tf->uv));
1568 case 8: /* copy image settings only */
1569 for(efa=em->faces.first; efa; efa=efa->next) {
1570 if (efa->f & SELECT) {
1571 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
1572 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1573 if (tf_from->tpage) {
1574 tf->tpage = tf_from->tpage;
1578 tf->mode &= ~TF_TEX;
1580 tf->tile= tf_from->tile;
1585 case 9: /* copy all tface info */
1586 for(efa=em->faces.first; efa; efa=efa->next) {
1587 if (efa->f & SELECT) {
1588 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
1589 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1590 memcpy(tf->uv, ((MTFace *)efa->tmp.p)->uv, sizeof(tf->uv));
1591 tf->tpage = tf_from->tpage;
1592 tf->mode = tf_from->mode;
1593 tf->transp = tf_from->transp;
1599 for(efa=em->faces.first; efa; efa=efa->next) {
1600 if (efa->f & SELECT) {
1601 mcol_from = (MCol *)efa->tmp.p;
1602 mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
1603 memcpy(mcol, mcol_from, sizeof(MCol)*4);
1611 // DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1613 BIF_undo_push("Copy Face Layer");
1618 /* ctrl+c in mesh editmode */
1619 void mesh_copy_menu(EditMesh *em)
1625 ese = em->selected.last;
1627 /* Faces can have a NULL ese, so dont return on a NULL ese here */
1629 if(ese && ese->type == EDITVERT) {
1630 /* EditVert *ev, *ev_act = (EditVert*)ese->data;
1631 ret= pupmenu(""); */
1632 } else if(ese && ese->type == EDITEDGE) {
1633 ret= pupmenu("Copy Active Edge to Selected%t|Crease%x1|Bevel Weight%x2|Length%x3");
1636 EM_mesh_copy_edge(em, ret);
1638 } else if(ese==NULL || ese->type == EDITFACE) {
1640 "Copy Face Selected%t|"
1641 "Active Material%x1|Active Image%x2|Active UV Coords%x3|"
1642 "Active Mode%x4|Active Transp%x5|Active Vertex Colors%x6|%l|"
1644 "TexFace UVs from layer%x7|"
1645 "TexFace Images from layer%x8|"
1646 "TexFace All from layer%x9|"
1647 "Vertex Colors from layer%x10");
1651 EM_mesh_copy_face(em, ret);
1653 EM_mesh_copy_face_layer(em, ret);
1659 /* **************** LOOP SELECTS *************** */
1661 /* selects quads in loop direction of indicated edge */
1662 /* only flush over edges with valence <= 2 */
1663 void faceloop_select(EditMesh *em, EditEdge *startedge, int select)
1669 /* in eed->f1 we put the valence (amount of faces in edge) */
1670 /* in eed->f2 we put tagged flag as correct loop */
1671 /* in efa->f1 we put tagged flag as correct to select */
1673 for(eed= em->edges.first; eed; eed= eed->next) {
1677 for(efa= em->faces.first; efa; efa= efa->next) {
1683 if(efa->e4) efa->e4->f1++;
1687 /* tag startedge OK*/
1693 for(efa= em->faces.first; efa; efa= efa->next) {
1694 if(efa->h==0 && efa->e4 && efa->f1==0) { /* not done quad */
1695 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
1697 /* if edge tagged, select opposing edge and mark face ok */
1703 else if(efa->e2->f2) {
1723 /* (de)select the faces */
1725 for(efa= em->faces.first; efa; efa= efa->next) {
1726 if(efa->f1) EM_select_face(efa, select);
1732 /* helper for edgeloop_select, checks for eed->f2 tag in faces */
1733 static int edge_not_in_tagged_face(EditMesh *em, EditEdge *eed)
1737 for(efa= em->faces.first; efa; efa= efa->next) {
1739 if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) { /* edge is in face */
1740 if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) { /* face is tagged */
1749 /* selects or deselects edges that:
1750 - if edges has 2 faces:
1751 - has vertices with valence of 4
1752 - not shares face with previous edge
1753 - if edge has 1 face:
1754 - has vertices with valence 4
1755 - not shares face with previous edge
1756 - but also only 1 face
1758 - has vertices with valence 2
1760 static void edgeloop_select(EditMesh *em, EditEdge *starteed, int select)
1767 /* in f1 we put the valence (amount of edges in a vertex, or faces in edge) */
1768 /* in eed->f2 and efa->f1 we put tagged flag as correct loop */
1769 for(eve= em->verts.first; eve; eve= eve->next) {
1773 for(eed= em->edges.first; eed; eed= eed->next) {
1776 if((eed->h & 1)==0) { /* fgon edges add to valence too */
1777 eed->v1->f1++; eed->v2->f1++;
1780 for(efa= em->faces.first; efa; efa= efa->next) {
1786 if(efa->e4) efa->e4->f1++;
1790 /* looped edges & vertices get tagged f2 */
1792 if(starteed->v1->f1<5) starteed->v1->f2= 1;
1793 if(starteed->v2->f1<5) starteed->v2->f2= 1;
1794 /* sorry, first edge isnt even ok */
1795 if(starteed->v1->f2==0 && starteed->v2->f2==0) looking= 0;
1800 /* find correct valence edges which are not tagged yet, but connect to tagged one */
1801 for(eed= em->edges.first; eed; eed= eed->next) {
1802 if(eed->h==0 && eed->f2==0) { /* edge not hidden, not tagged */
1803 if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { /* valence of vertex OK, and is tagged */
1804 /* new edge is not allowed to be in face with tagged edge */
1805 if(edge_not_in_tagged_face(em, eed)) {
1806 if(eed->f1==starteed->f1) { /* same amount of faces */
1809 if(eed->v2->f1<5) eed->v2->f2= 1;
1810 if(eed->v1->f1<5) eed->v1->f2= 1;
1817 /* and we do the select */
1818 for(eed= em->edges.first; eed; eed= eed->next) {
1819 if(eed->f2) EM_select_edge(eed, select);
1824 Almostly exactly the same code as faceloop select
1826 static void edgering_select(EditMesh *em, EditEdge *startedge, int select)
1832 /* in eed->f1 we put the valence (amount of faces in edge) */
1833 /* in eed->f2 we put tagged flag as correct loop */
1834 /* in efa->f1 we put tagged flag as correct to select */
1836 for(eed= em->edges.first; eed; eed= eed->next) {
1840 for(efa= em->faces.first; efa; efa= efa->next) {
1846 if(efa->e4) efa->e4->f1++;
1850 /* tag startedge OK */
1856 for(efa= em->faces.first; efa; efa= efa->next) {
1857 if(efa->e4 && efa->f1==0 && !efa->h) { /* not done quad */
1858 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
1860 /* if edge tagged, select opposing edge and mark face ok */
1866 else if(efa->e2->f2) {
1886 /* (de)select the edges */
1887 for(eed= em->edges.first; eed; eed= eed->next) {
1888 if(eed->f2) EM_select_edge(eed, select);
1892 void loop_multiselect(EditMesh *em, int looptype)
1896 int edindex, edfirstcount;
1898 /* sets em->totedgesel */
1899 EM_nedges_selected(em);
1901 edarray = MEM_mallocN(sizeof(EditEdge*)*em->totedgesel,"edge array");
1903 edfirstcount = em->totedgesel;
1905 for(eed=em->edges.first; eed; eed=eed->next){
1907 edarray[edindex] = eed;
1913 for(edindex = 0; edindex < edfirstcount; edindex +=1){
1914 eed = edarray[edindex];
1915 edgering_select(em, eed,SELECT);
1917 EM_selectmode_flush(em);
1918 BIF_undo_push("Edge Ring Multi-Select");
1921 for(edindex = 0; edindex < edfirstcount; edindex +=1){
1922 eed = edarray[edindex];
1923 edgeloop_select(em, eed,SELECT);
1925 EM_selectmode_flush(em);
1926 BIF_undo_push("Edge Loop Multi-Select");
1929 // if (EM_texFaceCheck())
1932 /* ***************** MAIN MOUSE SELECTION ************** */
1934 /* just to have the functions nice together */
1936 static void mouse_mesh_loop(ViewContext *vc)
1938 EditMesh *em= vc->em;
1942 int shift= 0, alt= 0, ctrl= 0; // XXX
1944 eed= findnearestedge(vc, &dist);
1946 if (vc->scene->toolsettings->edge_mode == EDGE_MODE_SELECT) {
1947 if(shift==0) EM_clear_flag_all(em, SELECT);
1949 if((eed->f & SELECT)==0) select=1;
1950 else if(shift) select=0;
1952 if(em->selectmode & SCE_SELECT_FACE) {
1953 faceloop_select(em, eed, select);
1955 else if(em->selectmode & SCE_SELECT_EDGE) {
1957 edgering_select(em, eed, select);
1959 edgeloop_select(em, eed, select);
1961 else if(em->selectmode & SCE_SELECT_VERTEX) {
1963 edgering_select(em, eed, select);
1965 edgeloop_select(em, eed, select);
1968 EM_selectmode_flush(em);
1969 // if (EM_texFaceCheck())
1973 int act = (edgetag_context_check(vc->scene, eed)==0);
1976 if (alt && ctrl && em->selected.last) {
1977 EditSelection *ese = em->selected.last;
1979 if(ese && ese->type == EDITEDGE) {
1981 eed_act = (EditEdge*)ese->data;
1982 if (eed_act != eed) {
1983 /* If shift is pressed we need to use the last active edge, (if it exists) */
1984 if (edgetag_shortest_path(vc->scene, em, eed_act, eed)) {
1985 EM_remove_selection(em, eed_act, EDITEDGE);
1986 EM_select_edge(eed_act, 0);
1993 edgetag_context_set(vc->scene, eed, act); /* switch the edge option */
1997 if ((eed->f & SELECT)==0) {
1998 EM_select_edge(eed, 1);
1999 EM_selectmode_flush(em);
2001 /* even if this is selected it may not be in the selection list */
2002 EM_store_selection(em, eed, EDITEDGE);
2004 if (eed->f & SELECT) {
2005 EM_select_edge(eed, 0);
2006 /* logic is differnt from above here since if this was selected we dont know if its in the selection list or not */
2007 EM_remove_selection(em, eed, EDITEDGE);
2009 EM_selectmode_flush(em);
2013 switch (0) { // XXX scene->toolsettings->edge_mode) {
2014 case EDGE_MODE_TAG_SEAM:
2017 case EDGE_MODE_TAG_SHARP:
2020 case EDGE_MODE_TAG_CREASE:
2021 G.f |= G_DRAWCREASES;
2023 case EDGE_MODE_TAG_BEVEL:
2024 G.f |= G_DRAWBWEIGHTS;
2028 // DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
2035 /* here actual select happens */
2036 /* gets called via generic mouse select operator */
2037 void mouse_mesh(bContext *C, short mval[2], short extend)
2045 /* setup view context for argument to callbacks */
2046 em_setup_viewcontext(C, &vc);
2047 vc.mval[0]= mval[0];
2048 vc.mval[1]= mval[1];
2050 if(alt) mouse_mesh_loop(&vc);
2051 else if(unified_findnearest(&vc, &eve, &eed, &efa)) {
2053 if(extend==0) EM_clear_flag_all(vc.em, SELECT);
2056 /* set the last selected face */
2057 EM_set_actFace(vc.em, efa);
2059 if( (efa->f & SELECT)==0 ) {
2060 EM_store_selection(vc.em, efa, EDITFACE);
2061 EM_select_face_fgon(vc.em, efa, 1);
2064 EM_remove_selection(vc.em, efa, EDITFACE);
2065 EM_select_face_fgon(vc.em, efa, 0);
2069 if((eed->f & SELECT)==0) {
2070 EM_store_selection(vc.em, eed, EDITEDGE);
2071 EM_select_edge(eed, 1);
2074 EM_remove_selection(vc.em, eed, EDITEDGE);
2075 EM_select_edge(eed, 0);
2079 if((eve->f & SELECT)==0) {
2081 EM_store_selection(vc.em, eve, EDITVERT);
2084 EM_remove_selection(vc.em, eve, EDITVERT);
2089 EM_selectmode_flush(vc.em);
2091 // if (EM_texFaceCheck()) {
2093 if (efa && efa->mat_nr != vc.obedit->actcol-1) {
2094 vc.obedit->actcol= efa->mat_nr+1;
2095 vc.em->mat_nr= efa->mat_nr;
2096 // BIF_preview_changed(ID_MA);
2100 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
2102 // rightmouse_transform();
2105 // XXX should we use CTX_scene(C)->selectmode & SCE_SELECT_FACE like it was in the past ? calls selectconnected_delimit_mesh_all if true
2106 void selectconnected_mesh_all(EditMesh *em)
2110 short done=1, toggle=0;
2112 if(em->edges.first==0) return;
2118 if(toggle & 1) eed= em->edges.first;
2119 else eed= em->edges.last;
2125 if(v1->f & SELECT) {
2126 if( (v2->f & SELECT)==0 ) {
2131 else if(v2->f & SELECT) {
2132 if( (v1->f & SELECT)==0 ) {
2138 if(toggle & 1) eed= eed->next;
2139 else eed= eed->prev;
2143 /* now use vertex select flag to select rest */
2144 EM_select_flush(em);
2146 // if (EM_texFaceCheck())
2147 BIF_undo_push("Select Connected (All)");
2150 static int selectconnected_mesh_all_exec(bContext *C, wmOperator *op)
2152 Object *obedit= CTX_data_edit_object(C);
2153 EditMesh *em= ((Mesh *)obedit->data)->edit_mesh;
2155 selectconnected_mesh_all(em);
2157 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2158 return OPERATOR_FINISHED;
2161 void MESH_OT_selectconnected_mesh_all(wmOperatorType *ot)
2164 ot->name= "Select All of the Connected Mesh";
2165 ot->idname= "MESH_OT_selectconnected_mesh_all";
2168 ot->exec= selectconnected_mesh_all_exec;
2169 ot->poll= ED_operator_editmesh;
2173 /* *********** select connected ************* */
2175 // XXX should we use CTX_scene(C)->selectmode & SCE_SELECT_FACE like it was in the past ? calls selectconnected_delimit_mesh if true
2176 static int selectconnected_mesh_invoke(bContext *C, wmOperator *op, wmEvent *event)
2178 Object *obedit= CTX_data_edit_object(C);
2180 EditVert *eve, *v1, *v2;
2183 short done=1, toggle=0;
2184 int sel= !RNA_boolean_get(op->ptr, "deselect");
2186 /* unified_finednearest needs ogl */
2187 view3d_operator_needs_opengl(C);
2189 /* setup view context for argument to callbacks */
2190 em_setup_viewcontext(C, &vc);
2192 if(vc.em->edges.first==0) return OPERATOR_CANCELLED;
2194 vc.mval[0]= event->x - vc.ar->winrct.xmin;
2195 vc.mval[1]= event->y - vc.ar->winrct.ymin;
2197 if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
2198 return OPERATOR_CANCELLED;
2201 /* clear test flags */
2202 for(v1= vc.em->verts.first; v1; v1= v1->next) v1->f1= 0;
2204 /* start vertex/face/edge */
2206 else if(eed) eed->v1->f1= eed->v2->f1= 1;
2207 else efa->v1->f1= efa->v2->f1= efa->v3->f1= 1;
2209 /* set flag f1 if affected */
2214 if(toggle & 1) eed= vc.em->edges.first;
2215 else eed= vc.em->edges.last;
2222 if(v1->f1 && v2->f1==0) {
2226 else if(v1->f1==0 && v2->f1) {
2232 if(toggle & 1) eed= eed->next;
2233 else eed= eed->prev;
2237 /* now use vertex f1 flag to select/deselect */
2238 for(eed= vc.em->edges.first; eed; eed= eed->next) {
2239 if(eed->v1->f1 && eed->v2->f1)
2240 EM_select_edge(eed, sel);
2242 for(efa= vc.em->faces.first; efa; efa= efa->next) {
2243 if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1))
2244 EM_select_face(efa, sel);
2246 /* no flush needed, connected geometry is done */
2248 // if (EM_texFaceCheck())
2250 BIF_undo_push("Select Linked");
2252 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2253 return OPERATOR_FINISHED;
2256 void MESH_OT_selectconnected_mesh(wmOperatorType *ot)
2259 ot->name= "Select Connected Mesh";
2260 ot->idname= "MESH_OT_selectconnected_mesh";
2263 ot->invoke= selectconnected_mesh_invoke;
2264 ot->poll= ED_operator_editmesh;
2266 RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
2269 /* ************************* */
2271 /* for use with selectconnected_delimit_mesh only! */
2272 #define is_edge_delimit_ok(eed) ((eed->tmp.l == 1) && (eed->seam==0))
2273 #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))
2275 #define face_tag(efa)\
2276 if(efa->v4) efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;\
2277 else efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
2279 /* all - 1) use all faces for extending the selection 2) only use the mouse face
2280 * sel - 1) select 0) deselect
2282 static void selectconnected_delimit_mesh__internal(ViewContext *vc, short all, short sel)
2284 EditMesh *em= vc->em;
2287 short done=1, change=0;
2290 if(em->faces.first==0) return;
2292 /* flag all edges as off*/
2293 for(eed= em->edges.first; eed; eed= eed->next)
2297 for(efa= em->faces.first; efa; efa= efa->next) {
2298 if (efa->f & SELECT) {
2305 EditFace *efa_mouse = findnearestface(vc, &dist);
2308 /* error("Nothing indicated "); */ /* this is mostly annoying, eps with occluded geometry */
2312 for(efa= em->faces.first; efa; efa= efa->next) {
2315 efa_mouse->tmp.l = 1;
2316 face_tag(efa_mouse);
2321 /* simple algo - select all faces that have a selected edge
2322 * this intern selects the edge, repeat until nothing is left to do */
2323 for(efa= em->faces.first; efa; efa= efa->next) {
2324 if ((efa->tmp.l == 0) && (!efa->h)) {
2325 if (is_face_tag(efa)) {
2333 for(efa= em->faces.first; efa; efa= efa->next) {
2336 if (!(efa->f & SELECT)) {
2337 EM_select_face(efa, 1);
2341 if (efa->f & SELECT) {
2342 EM_select_face(efa, 0);
2352 if (!sel) /* make sure de-selecting faces didnt de-select the verts/edges connected to selected faces, this is common with boundries */
2353 for(efa= em->faces.first; efa; efa= efa->next)
2354 if (efa->f & SELECT)
2355 EM_select_face(efa, 1);
2357 // if (EM_texFaceCheck())
2359 BIF_undo_push("Select Linked Delimeted");
2363 #undef is_edge_delimit_ok
2367 void selectconnected_delimit_mesh(EditMesh *em)
2370 // XXX selectconnected_delimit_mesh__internal(em, 0, ((G.qual & LR_SHIFTKEY)==0));
2372 void selectconnected_delimit_mesh_all(ViewContext *vc)
2374 selectconnected_delimit_mesh__internal(vc, 1, 1);
2378 /* swap is 0 or 1, if 1 it hides not selected */
2379 void hide_mesh(EditMesh *em, int swap)
2386 if(em==NULL) return;
2388 /* hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
2389 /* - vertex hidden, always means edge is hidden too
2390 - edge hidden, always means face is hidden too
2391 - face hidden, only set face hide
2392 - then only flush back down what's absolute hidden
2394 if(em->selectmode & SCE_SELECT_VERTEX) {
2395 for(eve= em->verts.first; eve; eve= eve->next) {
2396 if((eve->f & SELECT)!=swap) {
2402 for(eed= em->edges.first; eed; eed= eed->next) {
2403 if(eed->v1->h || eed->v2->h) {
2409 for(efa= em->faces.first; efa; efa= efa->next) {
2410 if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
2416 else if(em->selectmode & SCE_SELECT_EDGE) {
2418 for(eed= em->edges.first; eed; eed= eed->next) {
2419 if((eed->f & SELECT)!=swap) {
2421 EM_select_edge(eed, 0);
2425 for(efa= em->faces.first; efa; efa= efa->next) {
2426 if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
2434 for(efa= em->faces.first; efa; efa= efa->next) {
2435 if((efa->f & SELECT)!=swap) {
2437 EM_select_face(efa, 0);
2442 /* flush down, only whats 100% hidden */
2443 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
2444 for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
2446 if(em->selectmode & SCE_SELECT_FACE) {
2447 for(efa= em->faces.first; efa; efa= efa->next) {
2448 if(efa->h) a= 1; else a= 2;
2452 if(efa->e4) efa->e4->f1 |= a;
2453 /* When edges are not delt with in their own loop, we need to explicitly re-selct select edges that are joined to unselected faces */
2454 if (swap && (em->selectmode == SCE_SELECT_FACE) && (efa->f & SELECT)) {
2455 EM_select_face(efa, 1);
2460 if(em->selectmode >= SCE_SELECT_EDGE) {
2461 for(eed= em->edges.first; eed; eed= eed->next) {
2462 if(eed->f1==1) eed->h |= 1;
2463 if(eed->h & 1) a= 1; else a= 2;
2469 if(em->selectmode >= SCE_SELECT_VERTEX) {
2470 for(eve= em->verts.first; eve; eve= eve->next) {
2471 if(eve->f1==1) eve->h= 1;
2475 em->totedgesel= em->totfacesel= em->totvertsel= 0;
2476 // if(EM_texFaceCheck())
2478 // DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
2479 BIF_undo_push("Hide");
2482 static int hide_mesh_exec(bContext *C, wmOperator *op)
2484 Object *obedit= CTX_data_edit_object(C);
2485 EditMesh *em= ((Mesh *)obedit->data)->edit_mesh;
2487 /* 'standard' behaviour - check if selected, then apply relevant selection */
2488 if (RNA_boolean_get(op->ptr, "swap"))
2493 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2494 return OPERATOR_FINISHED;
2497 void MESH_OT_hide_mesh(wmOperatorType *ot)
2500 ot->name= "Hide vertice or Hide All of the Mesh";
2501 ot->idname= "MESH_OT_hide_mesh";
2504 ot->exec= hide_mesh_exec;
2505 ot->poll= ED_operator_editmesh;
2508 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
2511 RNA_def_boolean(ot->srna, "swap", 0, "Swap", "");
2514 void reveal_mesh(EditMesh *em)
2520 if(em==NULL) return;
2522 for(eve= em->verts.first; eve; eve= eve->next) {
2528 for(eed= em->edges.first; eed; eed= eed->next) {
2531 if(em->selectmode & SCE_SELECT_VERTEX);
2532 else EM_select_edge(eed, 1);
2535 for(efa= em->faces.first; efa; efa= efa->next) {
2538 if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX));
2539 else EM_select_face(efa, 1);
2543 EM_fgon_flags(em); /* redo flags and indices for fgons */
2544 EM_selectmode_flush(em);
2546 // if (EM_texFaceCheck())
2547 // DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
2548 BIF_undo_push("Reveal");
2551 static int reveal_mesh_exec(bContext *C, wmOperator *op)
2553 Object *obedit= CTX_data_edit_object(C);
2554 EditMesh *em= ((Mesh *)obedit->data)->edit_mesh;
2558 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2559 return OPERATOR_FINISHED;
2562 void MESH_OT_reveal_mesh(wmOperatorType *ot)
2565 ot->name= "Reveal the Mesh";
2566 ot->idname= "MESH_OT_reveal_mesh";
2569 ot->exec= reveal_mesh_exec;
2570 ot->poll= ED_operator_editmesh;
2573 void hide_tface_uv(EditMesh *em, int swap)
2576 /* no space image here */
2580 if( is_uv_tface_editing_allowed()==0 ) return;
2582 /* call the mesh function if we are in mesh sync sel */
2583 if (G.sima->flag & SI_SYNC_UVSEL) {
2589 for (efa= em->faces.first; efa; efa= efa->next) {
2590 if(efa->f & SELECT) {
2591 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2592 if (G.sima->flag & SI_SELACTFACE) {
2593 /* Pretend face mode */
2594 if (( (efa->v4==NULL &&
2595 ( tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) ||
2596 ( tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) == (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) ) == 0) {
2598 if (em->selectmode == SCE_SELECT_FACE) {
2600 /* must re-select after */
2601 efa->e1->f &= ~SELECT;
2602 efa->e2->f &= ~SELECT;
2603 efa->e3->f &= ~SELECT;
2604 if(efa->e4) efa->e4->f &= ~SELECT;
2606 EM_select_face(efa, 0);
2609 tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2610 } else if (em->selectmode == SCE_SELECT_FACE) {
2611 if((tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))==0) {
2613 EM_select_face(efa, 0);
2614 else if(!(tface->flag & TF_SEL4))
2615 EM_select_face(efa, 0);
2616 tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2619 /* EM_deselect_flush will deselect the face */
2620 if((tface->flag & TF_SEL1)==0) efa->v1->f &= ~SELECT;
2621 if((tface->flag & TF_SEL2)==0) efa->v2->f &= ~SELECT;
2622 if((tface->flag & TF_SEL3)==0) efa->v3->f &= ~SELECT;
2623 if((efa->v4) && (tface->flag & TF_SEL4)==0) efa->v4->f &= ~SELECT;
2624 tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2629 for (efa= em->faces.first; efa; efa= efa->next) {
2630 if(efa->f & SELECT) {
2631 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2632 if (G.sima->flag & SI_SELACTFACE) {
2633 if ( (efa->v4==NULL &&
2634 ( tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) ||
2635 ( tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) == (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) ) {
2637 if (em->selectmode == SCE_SELECT_FACE) {
2639 /* must re-select after */
2640 efa->e1->f &= ~SELECT;
2641 efa->e2->f &= ~SELECT;
2642 efa->e3->f &= ~SELECT;
2643 if(efa->e4) efa->e4->f &= ~SELECT;
2645 EM_select_face(efa, 0);
2648 tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2649 } else if (em->selectmode == SCE_SELECT_FACE) {
2650 if(tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
2651 EM_select_face(efa, 0);
2652 else if(efa->v4 && tface->flag & TF_SEL4)
2653 EM_select_face(efa, 0);
2654 tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2656 /* EM_deselect_flush will deselect the face */
2657 if(tface->flag & TF_SEL1) efa->v1->f &= ~SELECT;
2658 if(tface->flag & TF_SEL2) efa->v2->f &= ~SELECT;
2659 if(tface->flag & TF_SEL3) efa->v3->f &= ~SELECT;
2660 if((efa->v4) && tface->flag & TF_SEL4) efa->v4->f &= ~SELECT;
2661 tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2668 /*deselects too many but ok for now*/
2669 if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX)) {
2670 EM_deselect_flush(em);
2673 if (em->selectmode==SCE_SELECT_FACE) {
2674 /* de-selected all edges from faces that were de-selected.
2675 * now make sure all faces that are selected also have selected edges */
2676 for (efa= em->faces.first; efa; efa= efa->next) {
2677 if (efa->f & SELECT) {
2678 EM_select_face(efa, 1);
2683 EM_validate_selections();
2685 BIF_undo_push("Hide UV");
2687 // XXX object_tface_flags_changed(OBACT, 0);
2691 void reveal_tface_uv(EditMesh *em)
2694 /* function should move away? */
2698 if( is_uv_tface_editing_allowed()==0 ) return;
2700 /* call the mesh function if we are in mesh sync sel */
2701 if (G.sima->flag & SI_SYNC_UVSEL) {
2706 if (G.sima->flag & SI_SELACTFACE) {
2707 if (em->selectmode == SCE_SELECT_FACE) {
2708 for (efa= em->faces.first; efa; efa= efa->next) {
2709 if (!(efa->h) && !(efa->f & SELECT)) {
2710 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2711 EM_select_face(efa, 1);
2712 tface->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
2716 /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
2717 if (G.sima->sticky == SI_STICKY_DISABLE) {
2718 for (efa= em->faces.first; efa; efa= efa->next) {
2719 if (!(efa->h) && !(efa->f & SELECT)) {
2720 /* All verts must be unselected for the face to be selected in the UV view */
2721 if ((efa->v1->f&SELECT)==0 && (efa->v2->f&SELECT)==0 && (efa->v3->f&SELECT)==0 && (efa->v4==0 || (efa->v4->f&SELECT)==0)) {
2722 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2723 tface->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
2724 /* Cant use EM_select_face here because it unselects the verts
2725 * and we cant tell if the face was totally unselected or not */
2726 /*EM_select_face(efa, 1);
2728 * See Loop with EM_select_face() below... */
2734 for (efa= em->faces.first; efa; efa= efa->next) {
2735 if (!(efa->h) && !(efa->f & SELECT)) {
2736 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2737 if ((efa->v1->f & SELECT)==0) {tface->flag |= TF_SEL1;}
2738 if ((efa->v2->f & SELECT)==0) {tface->flag |= TF_SEL2;}
2739 if ((efa->v3->f & SELECT)==0) {tface->flag |= TF_SEL3;}
2740 if ((efa->v4 && (efa->v4->f & SELECT)==0)) {tface->flag |= TF_SEL4;}
2746 /* Select all edges and verts now */
2747 for (efa= em->faces.first; efa; efa= efa->next) {
2748 /* we only selected the face flags, and didnt changes edges or verts, fix this now */
2749 if (!(efa->h) && (efa->f & SELECT)) {
2750 EM_select_face(efa, 1);
2753 EM_select_flush(em);
2755 } else if (em->selectmode == SCE_SELECT_FACE) {
2756 for (efa= em->faces.first; efa; efa= efa->next) {
2757 if (!(efa->h) && !(efa->f & SELECT)) {
2758 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2760 tface->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
2764 /* Select all edges and verts now */
2765 for (efa= em->faces.first; efa; efa= efa->next) {
2766 /* we only selected the face flags, and didnt changes edges or verts, fix this now */
2767 if (!(efa->h) && (efa->f & SELECT)) {
2768 EM_select_face(efa, 1);
2773 for (efa= em->faces.first; efa; efa= efa->next) {
2774 if (!(efa->h) && !(efa->f & SELECT)) {
2775 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2776 if ((efa->v1->f & SELECT)==0) {tface->flag |= TF_SEL1;}
2777 if ((efa->v2->f & SELECT)==0) {tface->flag |= TF_SEL2;}
2778 if ((efa->v3->f & SELECT)==0) {tface->flag |= TF_SEL3;}
2779 if ((efa->v4 && (efa->v4->f & SELECT)==0)) {tface->flag |= TF_SEL4;}
2784 /* Select all edges and verts now */
2785 for (efa= em->faces.first; efa; efa= efa->next) {
2786 /* we only selected the face flags, and didnt changes edges or verts, fix this now */
2787 if (!(efa->h) && (efa->f & SELECT)) {
2788 EM_select_face(efa, 1);
2793 BIF_undo_push("Reveal UV");
2795 // XXX object_tface_flags_changed(OBACT, 0);
2799 void select_faces_by_numverts(EditMesh *em, int numverts)
2803 /* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring
2807 /* for loose vertices/edges, we first select all, loop below will deselect */
2809 EM_set_flag_all(em, SELECT);
2810 else if(em->selectmode!=SCE_SELECT_FACE) {
2811 error("Only works in face selection mode");