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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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
39 #include "MEM_guardedalloc.h"
41 #include "DNA_material_types.h"
42 #include "DNA_meshdata_types.h"
43 #include "DNA_modifier_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_scene_types.h"
47 #include "BLI_blenlib.h"
49 #include "BLI_editVert.h"
51 #include "BLI_utildefines.h"
53 #include "BKE_context.h"
54 #include "BKE_displist.h"
55 #include "BKE_depsgraph.h"
57 #include "BKE_material.h"
58 #include "BKE_paint.h"
59 #include "BKE_report.h"
60 #include "BKE_texture.h"
62 #include "IMB_imbuf_types.h"
63 #include "IMB_imbuf.h"
65 #include "RE_render_ext.h" /* externtex */
71 #include "RNA_access.h"
72 #include "RNA_define.h"
75 #include "ED_screen.h"
76 #include "ED_view3d.h"
80 #include "mesh_intern.h"
82 #include "BLO_sys_types.h" // for intptr_t support
85 static void waitcursor(int UNUSED(val)) {}
86 static int pupmenu(const char *UNUSED(arg)) {return 0;}
88 /* ****************************** MIRROR **************** */
90 void EM_cache_x_mirror_vert(struct Object *ob, struct EditMesh *em)
92 EditVert *eve, *eve_mirror;
95 for(eve= em->verts.first; eve; eve= eve->next) {
99 for(eve= em->verts.first; eve; eve= eve->next, index++) {
100 if(eve->tmp.v==NULL) {
101 eve_mirror = editmesh_get_x_mirror_vert(ob, em, eve, eve->co, index);
103 eve->tmp.v= eve_mirror;
104 eve_mirror->tmp.v = eve;
110 static void EM_select_mirrored(Object *obedit, EditMesh *em, int extend)
115 EM_cache_x_mirror_vert(obedit, em);
117 for(eve= em->verts.first; eve; eve= eve->next) {
118 if(eve->f & SELECT && eve->tmp.v && (eve->tmp.v != eve->tmp.v->tmp.v)) {
119 eve->tmp.v->f |= SELECT;
124 /* remove the interference */
125 eve->tmp.v->tmp.v= NULL;
131 void EM_automerge(Scene *scene, Object *obedit, int update)
133 Mesh *me= obedit ? obedit->data : NULL; /* can be NULL */
136 if ((scene->toolsettings->automerge) &&
137 (obedit && obedit->type==OB_MESH && (obedit->mode & OB_MODE_EDIT)) &&
140 EditMesh *em= me->edit_mesh;
142 len = removedoublesflag(em, 1, 1, scene->toolsettings->doublimit);
144 em->totvert -= len; /* saves doing a countall */
146 DAG_id_tag_update(&me->id, 0);
152 /* ****************************** SELECTION ROUTINES **************** */
154 unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0; /* set in drawobject.c ... for colorindices */
156 /* facilities for border select and circle select */
157 static char *selbuf= NULL;
159 /* opengl doesn't support concave... */
160 static void draw_triangulated(short mcords[][2], short tot)
162 ListBase lb={NULL, NULL};
168 dl= MEM_callocN(sizeof(DispList), "poly disp");
172 dl->verts= fp= MEM_callocN(tot*3*sizeof(float), "poly verts");
173 BLI_addtail(&lb, dl);
175 for(a=0; a<tot; a++, fp+=3) {
176 fp[0]= (float)mcords[a][0];
177 fp[1]= (float)mcords[a][1];
181 filldisplist(&lb, &lb, 0);
184 dl= lb.first; /* filldisplist adds in head of list */
185 if(dl->type==DL_INDEX3) {
191 glBegin(GL_TRIANGLES);
193 glVertex3fv(fp+3*index[0]);
194 glVertex3fv(fp+3*index[1]);
195 glVertex3fv(fp+3*index[2]);
205 /* reads rect, and builds selection array for quick lookup */
206 /* returns if all is OK */
207 int EM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
213 if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
215 buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
216 if(buf==NULL) return 0;
217 if(em_vertoffs==0) return 0;
221 /* build selection lookup */
222 selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
224 a= (xmax-xmin+1)*(ymax-ymin+1);
226 if(*dr>0 && *dr<=em_vertoffs)
234 int EM_check_backbuf(unsigned int index)
236 if(selbuf==NULL) return 1;
237 if(index>0 && index<=em_vertoffs)
238 return selbuf[index];
242 void EM_free_backbuf(void)
244 if(selbuf) MEM_freeN(selbuf);
248 /* mcords is a polygon mask
250 - draw with black in backbuffer,
251 - grab again and compare
254 int EM_mask_init_backbuf_border(ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
256 unsigned int *dr, *drm;
257 struct ImBuf *buf, *bufmask;
261 /* method in use for face selecting too */
262 if(vc->obedit==NULL) {
263 if(paint_facesel_test(vc->obact));
266 else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
268 buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
269 if(buf==NULL) return 0;
270 if(em_vertoffs==0) return 0;
275 glDisable(GL_DEPTH_TEST);
279 /* some opengl drivers have problems with draw direction */
280 glGetBooleanv(GL_CULL_FACE, &is_cull);
281 if(is_cull) glDisable(GL_CULL_FACE);
283 /* yah, opengl doesn't do concave... tsk! */
284 ED_region_pixelspace(vc->ar);
285 draw_triangulated(mcords, tot);
287 glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */
288 for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
291 glFinish(); /* to be sure readpixels sees mask */
294 bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
296 if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
298 /* build selection lookup */
299 selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
301 a= (xmax-xmin+1)*(ymax-ymin+1);
303 if(*dr>0 && *dr<=em_vertoffs && *drm==0) selbuf[*dr]= 1;
307 IMB_freeImBuf(bufmask);
309 if(is_cull) glEnable(GL_CULL_FACE);
315 /* circle shaped sample area */
316 int EM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
320 short xmin, ymin, xmax, ymax, xc, yc;
323 /* method in use for face selecting too */
324 if(vc->obedit==NULL) {
325 if(paint_facesel_test(vc->obact));
328 else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
330 xmin= xs-rads; xmax= xs+rads;
331 ymin= ys-rads; ymax= ys+rads;
332 buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
333 if(em_vertoffs==0) return 0;
334 if(buf==NULL) return 0;
338 /* build selection lookup */
339 selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
341 for(yc= -rads; yc<=rads; yc++) {
342 for(xc= -rads; xc<=rads; xc++, dr++) {
343 if(xc*xc + yc*yc < radsq) {
344 if(*dr>0 && *dr<=em_vertoffs) selbuf[*dr]= 1;
354 static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index)
356 struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } *data = userData;
359 if (index<=data->lastIndex)
362 if (index>data->lastIndex)
367 int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
368 if ((eve->f&1) == data->select) {
369 if (data->strict == 1)
375 if (temp<data->dist) {
378 data->closestIndex = index;
386 static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
388 EditMesh *em= (EditMesh *)handle;
389 EditVert *eve = BLI_findlink(&em->verts, index-1);
391 if(eve && (eve->f & SELECT)) return 0;
397 * dist (in/out): minimal distance to the nearest and at the end, actual distance
398 * sel: selection bias
399 * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
400 * if 0, unselected vertice are given the bias
401 * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
403 EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
405 if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){
410 if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest);
411 else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL);
413 eve = BLI_findlink(&vc->em->verts, index-1);
415 if(eve && distance < *dist) {
424 struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } data;
425 static int lastSelectedIndex=0;
426 static EditVert *lastSelected=NULL;
428 if (lastSelected && BLI_findlink(&vc->em->verts, lastSelectedIndex)!=lastSelected) {
429 lastSelectedIndex = 0;
433 data.lastIndex = lastSelectedIndex;
434 data.mval[0] = vc->mval[0];
435 data.mval[1] = vc->mval[1];
438 data.strict = strict;
440 data.closestIndex = 0;
444 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
446 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
450 mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
454 lastSelected = data.closest;
455 lastSelectedIndex = data.closestIndex;
461 /* returns labda for closest distance v1 to line-piece v2-v3 */
462 static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3)
468 len= rc[0]*rc[0]+ rc[1]*rc[1];
472 return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
475 /* note; uses v3d, so needs active 3d window */
476 static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index))
478 struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } *data = userData;
482 ED_view3d_local_clipping(data->vc.rv3d, data->vc.obedit->obmat); /* for local clipping lookups */
489 distance= dist_to_line_segment_v2(data->mval, v1, v2);
492 if(eed->f & SELECT) distance+=5;
493 if(distance < data->dist) {
494 if(data->vc.rv3d->rflag & RV3D_CLIPPING) {
495 float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
498 vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
499 vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
500 vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
502 if(view3d_test_clipping(data->vc.rv3d, vec, 1)==0) {
503 data->dist = distance;
508 data->dist = distance;
513 EditEdge *findnearestedge(ViewContext *vc, int *dist)
516 if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
518 unsigned int index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_solidoffs, em_wireoffs, &distance,0, NULL, NULL);
519 EditEdge *eed = BLI_findlink(&vc->em->edges, index-1);
521 if (eed && distance<*dist) {
529 struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } data;
532 data.mval[0] = vc->mval[0];
533 data.mval[1] = vc->mval[1];
537 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
538 mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2);
545 static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int UNUSED(index))
547 struct { short mval[2]; int dist; EditFace *toFace; } *data = userData;
549 if (efa==data->toFace) {
550 int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
556 static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int y, int index)
558 struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } *data = userData;
561 if (index<=data->lastIndex)
564 if (index>data->lastIndex)
569 int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
571 if (temp<data->dist) {
574 data->closestIndex = index;
578 static EditFace *findnearestface(ViewContext *vc, int *dist)
581 if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
582 unsigned int index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
583 EditFace *efa = BLI_findlink(&vc->em->faces, index-1);
586 struct { short mval[2]; int dist; EditFace *toFace; } data;
588 data.mval[0] = vc->mval[0];
589 data.mval[1] = vc->mval[1];
590 data.dist = 0x7FFF; /* largest short */
593 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
594 mesh_foreachScreenFace(vc, findnearestface__getDistance, &data);
596 if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */
605 struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } data;
606 static int lastSelectedIndex=0;
607 static EditFace *lastSelected=NULL;
609 if (lastSelected && BLI_findlink(&vc->em->faces, lastSelectedIndex)!=lastSelected) {
610 lastSelectedIndex = 0;
614 data.lastIndex = lastSelectedIndex;
615 data.mval[0] = vc->mval[0];
616 data.mval[1] = vc->mval[1];
619 data.closestIndex = 0;
623 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
624 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
628 mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
632 lastSelected = data.closest;
633 lastSelectedIndex = data.closestIndex;
639 /* best distance based on screen coords.
640 use em->selectmode to define how to use
641 selected vertices and edges get disadvantage
642 return 1 if found one
644 static int unified_findnearest(ViewContext *vc, EditVert **eve, EditEdge **eed, EditFace **efa)
646 EditMesh *em= vc->em;
653 /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
654 view3d_validate_backbuf(vc);
656 if(em->selectmode & SCE_SELECT_VERTEX)
657 *eve= findnearestvert(vc, &dist, SELECT, 0);
658 if(em->selectmode & SCE_SELECT_FACE)
659 *efa= findnearestface(vc, &dist);
661 dist-= 20; /* since edges select lines, we give dots advantage of 20 pix */
662 if(em->selectmode & SCE_SELECT_EDGE)
663 *eed= findnearestedge(vc, &dist);
665 /* return only one of 3 pointers, for frontbuffer redraws */
667 *efa= NULL; *eve= NULL;
673 return (*eve || *eed || *efa);
677 /* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
679 /* selects new faces/edges/verts based on the existing selection */
683 #define SIMVERT_NORMAL 0
684 #define SIMVERT_FACE 1
685 #define SIMVERT_VGROUP 2
686 #define SIMVERT_TOT 3
690 #define SIMEDGE_LENGTH 101
691 #define SIMEDGE_DIR 102
692 #define SIMEDGE_FACE 103
693 #define SIMEDGE_FACE_ANGLE 104
694 #define SIMEDGE_CREASE 105
695 #define SIMEDGE_SEAM 106
696 #define SIMEDGE_SHARP 107
697 #define SIMEDGE_TOT 108
701 #define SIMFACE_MATERIAL 201
702 #define SIMFACE_IMAGE 202
703 #define SIMFACE_AREA 203
704 #define SIMFACE_PERIMETER 204
705 #define SIMFACE_NORMAL 205
706 #define SIMFACE_COPLANAR 206
707 #define SIMFACE_TOT 207
709 static EnumPropertyItem prop_similar_types[] = {
710 {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
711 {SIMVERT_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
712 {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
713 {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
714 {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
715 {SIMEDGE_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
716 {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
717 {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
718 {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
719 {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
720 {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
721 {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
722 {SIMFACE_AREA, "AREA", 0, "Area", ""},
723 {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
724 {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
725 {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
726 {0, NULL, 0, NULL, NULL}
730 /* this as a way to compare the ares, perim of 2 faces thay will scale to different sizes
731 *0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
732 #define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5) <= b))
734 static int similar_face_select__internal(EditMesh *em, int mode, float thresh)
736 EditFace *efa, *base_efa=NULL;
737 unsigned int selcount=0; /*count how many new faces we select*/
739 /*deselcount, count how many deselected faces are left, so we can bail out early
740 also means that if there are no deselected faces, we can avoid a lot of looping */
741 unsigned int deselcount=0;
744 for(efa= em->faces.first; efa; efa= efa->next) {
746 if (efa->f & SELECT) {
751 deselcount++; /* a deselected face we may select later */
756 if (!ok || !deselcount) /* no data selected OR no more data to select */
759 if (mode==SIMFACE_AREA) {
760 for(efa= em->faces.first; efa; efa= efa->next) {
761 efa->tmp.fp= EM_face_area(efa);
763 } else if (mode==SIMFACE_PERIMETER) {
764 for(efa= em->faces.first; efa; efa= efa->next) {
765 efa->tmp.fp= EM_face_perimeter(efa);
769 for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) {
770 if (base_efa->f1) { /* This was one of the faces originaly selected */
771 if (mode==SIMFACE_MATERIAL) { /* same material */
772 for(efa= em->faces.first; efa; efa= efa->next) {
774 !(efa->f & SELECT) &&
776 base_efa->mat_nr == efa->mat_nr
778 EM_select_face(efa, 1);
781 if (!deselcount) /*have we selected all posible faces?, if so return*/
785 } else if (mode==SIMFACE_IMAGE) { /* same image */
786 MTFace *tf, *base_tf;
788 base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data,
794 for(efa= em->faces.first; efa; efa= efa->next) {
795 if (!(efa->f & SELECT) && !efa->h) {
796 tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data,
799 if(base_tf->tpage == tf->tpage) {
800 EM_select_face(efa, 1);
803 if (!deselcount) /*have we selected all posible faces?, if so return*/
808 } else if (mode==SIMFACE_AREA || mode==SIMFACE_PERIMETER) { /* same area OR same perimeter, both use the same temp var */
809 for(efa= em->faces.first; efa; efa= efa->next) {
811 (!(efa->f & SELECT) && !efa->h) &&
812 SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp)
814 EM_select_face(efa, 1);
817 if (!deselcount) /*have we selected all posible faces?, if so return*/
821 } else if (mode==SIMFACE_NORMAL) {
823 for(efa= em->faces.first; efa; efa= efa->next) {
824 if (!(efa->f & SELECT) && !efa->h) {
825 angle= RAD2DEG(angle_v2v2(base_efa->n, efa->n));
826 if (angle/180.0<=thresh) {
827 EM_select_face(efa, 1);
830 if (!deselcount) /*have we selected all posible faces?, if so return*/
835 } else if (mode==SIMFACE_COPLANAR) { /* same planer */
836 float angle, base_dot, dot;
837 base_dot= dot_v3v3(base_efa->cent, base_efa->n);
838 for(efa= em->faces.first; efa; efa= efa->next) {
839 if (!(efa->f & SELECT) && !efa->h) {
840 angle= RAD2DEG(angle_v2v2(base_efa->n, efa->n));
841 if (angle/180.0<=thresh) {
842 dot=dot_v3v3(efa->cent, base_efa->n);
843 if (fabs(base_dot-dot) <= thresh) {
844 EM_select_face(efa, 1);
847 if (!deselcount) /*have we selected all posible faces?, if so return*/
855 } /* end base_efa loop */
859 static int similar_face_select_exec(bContext *C, wmOperator *op)
861 Object *obedit= CTX_data_edit_object(C);
862 Mesh *me= obedit->data;
863 EditMesh *em= BKE_mesh_get_editmesh(me);
865 int selcount = similar_face_select__internal(em, RNA_int_get(op->ptr, "type"), RNA_float_get(op->ptr, "threshold"));
868 /* here was an edge-mode only select flush case, has to be generalized */
869 EM_selectmode_flush(em);
870 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
871 BKE_mesh_end_editmesh(me, em);
872 return OPERATOR_FINISHED;
875 BKE_mesh_end_editmesh(me, em);
876 return OPERATOR_CANCELLED;
879 /* ***************************************************** */
881 static int similar_edge_select__internal(EditMesh *em, int mode, float thresh)
883 EditEdge *eed, *base_eed=NULL;
884 unsigned int selcount=0; /* count how many new edges we select*/
886 /*count how many visible selected edges there are,
887 so we can return when there are none left */
888 unsigned int deselcount=0;
892 for(eed= em->edges.first; eed; eed= eed->next) {
894 if (eed->f & SELECT) {
901 /* set all eed->tmp.l to 0 we use it later.
902 for counting face users*/
904 eed->f2=0; /* only for mode SIMEDGE_FACE_ANGLE, edge animations */
908 if (!ok || !deselcount) /* no data selected OR no more data to select*/
911 if (mode==SIMEDGE_LENGTH) { /*store length*/
912 for(eed= em->edges.first; eed; eed= eed->next) {
913 if (!eed->h) /* dont calc data for hidden edges*/
914 eed->tmp.fp= len_v3v3(eed->v1->co, eed->v2->co);
916 } else if (mode==SIMEDGE_FACE) { /*store face users*/
918 /* cound how many faces each edge uses use tmp->l */
919 for(efa= em->faces.first; efa; efa= efa->next) {
923 if (efa->e4) efa->e4->tmp.l++;
925 } else if (mode==SIMEDGE_FACE_ANGLE) { /*store edge angles */
928 /* cound how many faces each edge uses use tmp.l */
929 for(efa= em->faces.first; efa; efa= efa->next) {
930 /* here we use the edges temp data to assign a face
931 if a face has already been assigned (eed->f2==1)
932 we calculate the angle between the current face and
933 the edges previously found face.
934 store the angle in eed->tmp.fp (loosing the face eed->tmp.f)
935 but tagging eed->f2==2, so we know not to look at it again.
936 This only works for edges that connect to 2 faces. but its good enough
939 /* se we can loop through face edges*/
943 if (j==1) eed= efa->e2;
944 else if (j==2) eed= efa->e3;
951 if (!eed->h) { /* dont calc data for hidden edges*/
954 else if (eed->f2==0) /* first access, assign the face */
956 else if (eed->f2==1) /* second, we assign the angle*/
957 eed->tmp.fp= RAD2DEG(angle_v2v2(eed->tmp.f->n, efa->n))/180;
958 eed->f2++; /* f2==0 no face assigned. f2==1 one face found. f2==2 angle calculated.*/
965 for(base_eed= em->edges.first; base_eed; base_eed= base_eed->next) {
967 if (mode==SIMEDGE_LENGTH) { /* same length */
968 for(eed= em->edges.first; eed; eed= eed->next) {
970 !(eed->f & SELECT) &&
972 SCALE_CMP(base_eed->tmp.fp, eed->tmp.fp)
974 EM_select_edge(eed, 1);
977 if (!deselcount) /*have we selected all posible faces?, if so return*/
981 } else if (mode==SIMEDGE_DIR) { /* same direction */
982 float base_dir[3], dir[3], angle;
983 sub_v3_v3v3(base_dir, base_eed->v1->co, base_eed->v2->co);
984 for(eed= em->edges.first; eed; eed= eed->next) {
985 if (!(eed->f & SELECT) && !eed->h) {
986 sub_v3_v3v3(dir, eed->v1->co, eed->v2->co);
987 angle= RAD2DEG(angle_v2v2(base_dir, dir));
989 if (angle>90) /* use the smallest angle between the edges */
990 angle= fabs(angle-180.0f);
992 if (angle/90.0<=thresh) {
993 EM_select_edge(eed, 1);
996 if (!deselcount) /*have we selected all posible faces?, if so return*/
1001 } else if (mode==SIMEDGE_FACE) { /* face users */
1002 for(eed= em->edges.first; eed; eed= eed->next) {
1004 !(eed->f & SELECT) &&
1006 base_eed->tmp.l==eed->tmp.l
1008 EM_select_edge(eed, 1);
1011 if (!deselcount) /*have we selected all posible faces?, if so return*/
1015 } else if (mode==SIMEDGE_FACE_ANGLE && base_eed->f2==2) { /* edge angles, f2==2 means the edge has an angle. */
1016 for(eed= em->edges.first; eed; eed= eed->next) {
1018 !(eed->f & SELECT) &&
1021 (fabs(base_eed->tmp.fp-eed->tmp.fp)<=thresh)
1023 EM_select_edge(eed, 1);
1026 if (!deselcount) /*have we selected all posible faces?, if so return*/
1030 } else if (mode==SIMEDGE_CREASE) { /* edge crease */
1031 for(eed= em->edges.first; eed; eed= eed->next) {
1033 !(eed->f & SELECT) &&
1035 (fabs(base_eed->crease-eed->crease) <= thresh)
1037 EM_select_edge(eed, 1);
1040 if (!deselcount) /*have we selected all posible faces?, if so return*/
1044 } else if (mode==SIMEDGE_SEAM) { /* edge seam */
1045 for(eed= em->edges.first; eed; eed= eed->next) {
1047 !(eed->f & SELECT) &&
1049 (eed->seam == base_eed->seam)
1051 EM_select_edge(eed, 1);
1054 if (!deselcount) /*have we selected all posible faces?, if so return*/
1058 } else if (mode==SIMEDGE_SHARP) { /* edge sharp */
1059 for(eed= em->edges.first; eed; eed= eed->next) {
1061 !(eed->f & SELECT) &&
1063 (eed->sharp == base_eed->sharp)
1065 EM_select_edge(eed, 1);
1068 if (!deselcount) /*have we selected all posible faces?, if so return*/
1077 /* wrap the above function but do selection flushing edge to face */
1078 static int similar_edge_select_exec(bContext *C, wmOperator *op)
1080 Object *obedit= CTX_data_edit_object(C);
1081 Mesh *me= obedit->data;
1082 EditMesh *em= BKE_mesh_get_editmesh(me);
1084 int selcount = similar_edge_select__internal(em, RNA_int_get(op->ptr, "type"), RNA_float_get(op->ptr, "threshold"));
1087 /* here was an edge-mode only select flush case, has to be generalized */
1088 EM_selectmode_flush(em);
1089 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1090 BKE_mesh_end_editmesh(me, em);
1091 return OPERATOR_FINISHED;
1094 BKE_mesh_end_editmesh(me, em);
1095 return OPERATOR_CANCELLED;
1098 /* ********************************* */
1100 static int similar_vert_select_exec(bContext *C, wmOperator *op)
1102 Object *obedit= CTX_data_edit_object(C);
1103 Mesh *me= obedit->data;
1104 EditMesh *em= BKE_mesh_get_editmesh(me);
1105 EditVert *eve, *base_eve=NULL;
1106 unsigned int selcount=0; /* count how many new edges we select*/
1108 /*count how many visible selected edges there are,
1109 so we can return when there are none left */
1110 unsigned int deselcount=0;
1111 int mode= RNA_enum_get(op->ptr, "type");
1112 float thresh = RNA_float_get(op->ptr, "threshold");
1116 for(eve= em->verts.first; eve; eve= eve->next) {
1118 if (eve->f & SELECT) {
1125 /* set all eve->tmp.l to 0 we use them later.*/
1131 if (!ok || !deselcount) { /* no data selected OR no more data to select*/
1132 BKE_mesh_end_editmesh(me, em);
1136 if(mode == SIMVERT_FACE) {
1137 /* store face users */
1140 /* count how many faces each edge uses use tmp->l */
1141 for(efa= em->faces.first; efa; efa= efa->next) {
1145 if (efa->v4) efa->v4->tmp.l++;
1150 for(base_eve= em->verts.first; base_eve; base_eve= base_eve->next) {
1153 if(mode == SIMVERT_NORMAL) {
1155 for(eve= em->verts.first; eve; eve= eve->next) {
1156 if (!(eve->f & SELECT) && !eve->h) {
1157 angle= RAD2DEG(angle_v2v2(base_eve->no, eve->no));
1158 if (angle/180.0<=thresh) {
1162 if (!deselcount) {/*have we selected all posible faces?, if so return*/
1163 BKE_mesh_end_editmesh(me, em);
1170 else if(mode == SIMVERT_FACE) {
1171 for(eve= em->verts.first; eve; eve= eve->next) {
1173 !(eve->f & SELECT) &&
1175 base_eve->tmp.l==eve->tmp.l
1180 if (!deselcount) {/*have we selected all posible faces?, if so return*/
1181 BKE_mesh_end_editmesh(me, em);
1187 else if(mode == SIMVERT_VGROUP) {
1188 MDeformVert *dvert, *base_dvert;
1189 short i, j; /* weight index */
1191 base_dvert= CustomData_em_get(&em->vdata, base_eve->data,
1194 if (!base_dvert || base_dvert->totweight == 0) {
1195 BKE_mesh_end_editmesh(me, em);
1199 for(eve= em->verts.first; eve; eve= eve->next) {
1200 dvert= CustomData_em_get(&em->vdata, eve->data,
1203 if (dvert && !(eve->f & SELECT) && !eve->h && dvert->totweight) {
1204 /* do the extra check for selection in the following if, so were not
1205 checking verts that may be already selected */
1206 for (i=0; base_dvert->totweight >i && !(eve->f & SELECT); i++) {
1207 for (j=0; dvert->totweight >j; j++) {
1208 if (base_dvert->dw[i].def_nr==dvert->dw[j].def_nr) {
1212 if (!deselcount) { /*have we selected all posible faces?, if so return*/
1213 BKE_mesh_end_editmesh(me, em);
1224 } /* end basevert loop */
1227 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1228 BKE_mesh_end_editmesh(me, em);
1229 return OPERATOR_FINISHED;
1232 BKE_mesh_end_editmesh(me, em);
1233 return OPERATOR_CANCELLED;
1236 static int select_similar_exec(bContext *C, wmOperator *op)
1238 int type= RNA_enum_get(op->ptr, "type");
1241 return similar_vert_select_exec(C, op);
1243 return similar_edge_select_exec(C, op);
1245 return similar_face_select_exec(C, op);
1248 static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
1250 Object *obedit= CTX_data_edit_object(C);
1251 EnumPropertyItem *item= NULL;
1255 return prop_similar_types;
1258 if(obedit && obedit->type == OB_MESH) {
1259 EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
1261 if(em->selectmode & SCE_SELECT_VERTEX) {
1262 for(a=SIMVERT_NORMAL; a<=SIMVERT_TOT; a++)
1263 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
1265 else if(em->selectmode & SCE_SELECT_EDGE) {
1266 for(a=SIMEDGE_LENGTH; a<=SIMEDGE_TOT; a++)
1267 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
1269 else if(em->selectmode & SCE_SELECT_FACE) {
1270 for(a=SIMFACE_MATERIAL; a<=SIMFACE_TOT; a++)
1271 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
1275 RNA_enum_item_end(&item, &totitem);
1281 void MESH_OT_select_similar(wmOperatorType *ot)
1286 ot->name= "Select Similar";
1287 ot->description= "Select similar vertices, edges or faces by property types";
1288 ot->idname= "MESH_OT_select_similar";
1291 ot->invoke= WM_menu_invoke;
1292 ot->exec= select_similar_exec;
1293 ot->poll= ED_operator_editmesh;
1296 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1299 prop= RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
1300 RNA_def_enum_funcs(prop, select_similar_type_itemf);
1302 RNA_def_float(ot->srna, "threshold", 0.01f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 100.f);
1305 /* ******************************************* */
1308 int mesh_layers_menu_charlen(CustomData *data, int type)
1311 /* see if there is a duplicate */
1312 for(i=0; i<data->totlayer; i++) {
1313 if((&data->layers[i])->type == type) {
1314 /* we could count the chars here but we'll just assumeme each
1315 * is 32 chars with some room for the menu text - 40 should be fine */
1322 /* this function adds menu text into an existing string.
1323 * this string's size should be allocated with mesh_layers_menu_charlen */
1324 void mesh_layers_menu_concat(CustomData *data, int type, char *str)
1328 CustomDataLayer *layer;
1330 /* see if there is a duplicate */
1331 for(i=0; i<data->totlayer; i++) {
1332 layer = &data->layers[i];
1333 if(layer->type == type) {
1334 str_pt += sprintf(str_pt, "%s%%x%d|", layer->name, count);
1340 int mesh_layers_menu(CustomData *data, int type) {
1344 str_pt = str = MEM_mallocN(mesh_layers_menu_charlen(data, type) + 18, "layer menu");
1347 str_pt += sprintf(str_pt, "Layers%%t|");
1349 mesh_layers_menu_concat(data, type, str_pt);
1356 static void EM_mesh_copy_edge(EditMesh *em, short type)
1361 EditEdge *eed, *eed_act;
1362 float vec[3], vec_mid[3], eed_len, eed_len_act;
1366 ese = em->selected.last;
1369 eed_act = (EditEdge*)ese->data;
1372 case 1: /* copy crease */
1373 for(eed=em->edges.first; eed; eed=eed->next) {
1374 if (eed->f & SELECT && eed != eed_act && eed->crease != eed_act->crease) {
1375 eed->crease = eed_act->crease;
1380 case 2: /* copy bevel weight */
1381 for(eed=em->edges.first; eed; eed=eed->next) {
1382 if (eed->f & SELECT && eed != eed_act && eed->bweight != eed_act->bweight) {
1383 eed->bweight = eed_act->bweight;
1389 case 3: /* copy length */
1390 eed_len_act = len_v3v3(eed_act->v1->co, eed_act->v2->co);
1391 for(eed=em->edges.first; eed; eed=eed->next) {
1392 if (eed->f & SELECT && eed != eed_act) {
1394 eed_len = len_v3v3(eed->v1->co, eed->v2->co);
1396 if (eed_len == eed_len_act) continue;
1397 /* if this edge is zero length we cont do anything with it*/
1398 if (eed_len == 0.0f) continue;
1399 if (eed_len_act == 0.0f) {
1400 add_v3_v3v3(vec_mid, eed->v1->co, eed->v2->co);
1401 mul_v3_fl(vec_mid, 0.5);
1402 VECCOPY(eed->v1->co, vec_mid);
1403 VECCOPY(eed->v2->co, vec_mid);
1405 /* copy the edge length */
1406 add_v3_v3v3(vec_mid, eed->v1->co, eed->v2->co);
1407 mul_v3_fl(vec_mid, 0.5);
1410 sub_v3_v3v3(vec, eed->v1->co, vec_mid);
1411 mul_v3_fl(vec, eed_len_act/eed_len);
1412 add_v3_v3v3(eed->v1->co, vec, vec_mid);
1415 sub_v3_v3v3(vec, eed->v2->co, vec_mid);
1416 mul_v3_fl(vec, eed_len_act/eed_len);
1417 add_v3_v3v3(eed->v2->co, vec, vec_mid);
1424 recalc_editnormals(em);
1430 // DAG_id_tag_update(obedit->data, 0);
1435 static void EM_mesh_copy_face(EditMesh *em, wmOperator *op, short type)
1439 EditFace *efa, *efa_act;
1440 MTFace *tf, *tf_act = NULL;
1441 MCol *mcol, *mcol_act = NULL;
1443 efa_act = EM_get_actFace(em, 0);
1445 if (!efa_act) return;
1447 tf_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MTFACE);
1448 mcol_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MCOL);
1451 case 1: /* copy material */
1452 for(efa=em->faces.first; efa; efa=efa->next) {
1453 if (efa->f & SELECT && efa->mat_nr != efa_act->mat_nr) {
1454 efa->mat_nr = efa_act->mat_nr;
1459 case 2: /* copy image */
1461 BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
1464 for(efa=em->faces.first; efa; efa=efa->next) {
1465 if (efa->f & SELECT && efa != efa_act) {
1466 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1467 if (tf_act->tpage) {
1468 tf->tpage = tf_act->tpage;
1472 tf->mode &= ~TF_TEX;
1474 tf->tile= tf_act->tile;
1480 case 3: /* copy UV's */
1482 BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
1485 for(efa=em->faces.first; efa; efa=efa->next) {
1486 if (efa->f & SELECT && efa != efa_act) {
1487 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1488 memcpy(tf->uv, tf_act->uv, sizeof(tf->uv));
1493 case 4: /* mode's */
1495 BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
1498 for(efa=em->faces.first; efa; efa=efa->next) {
1499 if (efa->f & SELECT && efa != efa_act) {
1500 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1501 tf->mode= tf_act->mode;
1506 case 5: /* copy transp's */
1508 BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
1511 for(efa=em->faces.first; efa; efa=efa->next) {
1512 if (efa->f & SELECT && efa != efa_act) {
1513 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1514 tf->transp= tf_act->transp;
1520 case 6: /* copy vcols's */
1522 BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers.");
1525 /* guess the 4th color if needs be */
1529 /* guess the othe vale, we may need to use it
1531 * Modifying the 4th value of the mcol is ok here since its not seen
1534 val = ((float)(mcol_act->r + (mcol_act+1)->r + (mcol_act+2)->r)) / 3; CLAMP(val, 0, 255);
1535 (mcol_act+3)->r = (char)val;
1537 val = ((float)(mcol_act->g + (mcol_act+1)->g + (mcol_act+2)->g)) / 3; CLAMP(val, 0, 255);
1538 (mcol_act+3)->g = (char)val;
1540 val = ((float)(mcol_act->b + (mcol_act+1)->b + (mcol_act+2)->b)) / 3; CLAMP(val, 0, 255);
1541 (mcol_act+3)->b = (char)val;
1545 for(efa=em->faces.first; efa; efa=efa->next) {
1546 if (efa->f & SELECT && efa != efa_act) {
1547 /* TODO - make copy from tri to quad guess the 4th vert */
1548 mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
1549 memcpy(mcol, mcol_act, sizeof(MCol)*4);
1558 // DAG_id_tag_update(obedit->data, 0);
1564 static void EM_mesh_copy_face_layer(EditMesh *em, wmOperator *op, short type)
1569 MTFace *tf, *tf_from;
1570 MCol *mcol, *mcol_from;
1578 if (CustomData_number_of_layers(&em->fdata, CD_MTFACE)<2) {
1579 BKE_report(op->reports, RPT_WARNING, "mesh does not have multiple uv/image layers");
1582 int layer_orig_idx, layer_idx;
1584 layer_idx = mesh_layers_menu(&em->fdata, CD_MTFACE);
1585 if (layer_idx<0) return;
1587 /* warning, have not updated mesh pointers however this is not needed since we swicth back */
1588 layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MTFACE);
1589 if (layer_idx==layer_orig_idx)
1592 /* get the tfaces */
1593 CustomData_set_layer_active(&em->fdata, CD_MTFACE, (int)layer_idx);
1594 /* store the tfaces in our temp */
1595 for(efa=em->faces.first; efa; efa=efa->next) {
1596 if (efa->f & SELECT) {
1597 efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1600 CustomData_set_layer_active(&em->fdata, CD_MTFACE, layer_orig_idx);
1604 case 10: /* select vcol layers - make sure this stays in sync with above code */
1605 if (CustomData_number_of_layers(&em->fdata, CD_MCOL)<2) {
1606 BKE_report(op->reports, RPT_WARNING, "mesh does not have multiple color layers");
1609 int layer_orig_idx, layer_idx;
1611 layer_idx = mesh_layers_menu(&em->fdata, CD_MCOL);
1612 if (layer_idx<0) return;
1614 /* warning, have not updated mesh pointers however this is not needed since we swicth back */
1615 layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MCOL);
1616 if (layer_idx==layer_orig_idx)
1619 /* get the tfaces */
1620 CustomData_set_layer_active(&em->fdata, CD_MCOL, (int)layer_idx);
1621 /* store the tfaces in our temp */
1622 for(efa=em->faces.first; efa; efa=efa->next) {
1623 if (efa->f & SELECT) {
1624 efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
1627 CustomData_set_layer_active(&em->fdata, CD_MCOL, layer_orig_idx);
1633 /* layer copy only - sanity checks done above */
1635 case 7: /* copy UV's only */
1636 for(efa=em->faces.first; efa; efa=efa->next) {
1637 if (efa->f & SELECT) {
1638 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
1639 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1640 memcpy(tf->uv, tf_from->uv, sizeof(tf->uv));
1645 case 8: /* copy image settings only */
1646 for(efa=em->faces.first; efa; efa=efa->next) {
1647 if (efa->f & SELECT) {
1648 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
1649 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1650 if (tf_from->tpage) {
1651 tf->tpage = tf_from->tpage;
1655 tf->mode &= ~TF_TEX;
1657 tf->tile= tf_from->tile;
1662 case 9: /* copy all tface info */
1663 for(efa=em->faces.first; efa; efa=efa->next) {
1664 if (efa->f & SELECT) {
1665 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
1666 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1667 memcpy(tf->uv, ((MTFace *)efa->tmp.p)->uv, sizeof(tf->uv));
1668 tf->tpage = tf_from->tpage;
1669 tf->mode = tf_from->mode;
1670 tf->transp = tf_from->transp;
1676 for(efa=em->faces.first; efa; efa=efa->next) {
1677 if (efa->f & SELECT) {
1678 mcol_from = (MCol *)efa->tmp.p;
1679 mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
1680 memcpy(mcol, mcol_from, sizeof(MCol)*4);
1688 // DAG_id_tag_update(obedit->data, 0);
1694 /* ctrl+c in mesh editmode */
1695 static void mesh_copy_menu(EditMesh *em, wmOperator *op)
1701 ese = em->selected.last;
1703 /* Faces can have a NULL ese, so dont return on a NULL ese here */
1705 if(ese && ese->type == EDITVERT) {
1706 /* EditVert *ev, *ev_act = (EditVert*)ese->data;
1707 ret= pupmenu(""); */
1708 } else if(ese && ese->type == EDITEDGE) {
1709 ret= pupmenu("Copy Active Edge to Selected%t|Crease%x1|Bevel Weight%x2|Length%x3");
1712 EM_mesh_copy_edge(em, ret);
1714 } else if(ese==NULL || ese->type == EDITFACE) {
1716 "Copy Face Selected%t|"
1717 "Active Material%x1|Active Image%x2|Active UV Coords%x3|"
1718 "Active Mode%x4|Active Transp%x5|Active Vertex Colors%x6|%l|"
1720 "TexFace UVs from layer%x7|"
1721 "TexFace Images from layer%x8|"
1722 "TexFace All from layer%x9|"
1723 "Vertex Colors from layer%x10");
1727 EM_mesh_copy_face(em, op, ret);
1729 EM_mesh_copy_face_layer(em, op, ret);
1735 /* **************** LOOP SELECTS *************** */
1737 /* selects quads in loop direction of indicated edge */
1738 /* only flush over edges with valence <= 2 */
1739 void faceloop_select(EditMesh *em, EditEdge *startedge, int select)
1745 /* in eed->f1 we put the valence (amount of faces in edge) */
1746 /* in eed->f2 we put tagged flag as correct loop */
1747 /* in efa->f1 we put tagged flag as correct to select */
1749 for(eed= em->edges.first; eed; eed= eed->next) {
1753 for(efa= em->faces.first; efa; efa= efa->next) {
1759 if(efa->e4) efa->e4->f1++;
1763 /* tag startedge OK*/
1769 for(efa= em->faces.first; efa; efa= efa->next) {
1770 if(efa->h==0 && efa->e4 && efa->f1==0) { /* not done quad */
1771 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
1773 /* if edge tagged, select opposing edge and mark face ok */
1779 else if(efa->e2->f2) {
1799 /* (de)select the faces */
1801 for(efa= em->faces.first; efa; efa= efa->next) {
1802 if(efa->f1) EM_select_face(efa, select);
1808 /* helper for edgeloop_select, checks for eed->f2 tag in faces */
1809 static int edge_not_in_tagged_face(EditMesh *em, EditEdge *eed)
1813 for(efa= em->faces.first; efa; efa= efa->next) {
1815 if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) { /* edge is in face */
1816 if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) { /* face is tagged */
1825 /* selects or deselects edges that:
1826 - if edges has 2 faces:
1827 - has vertices with valence of 4
1828 - not shares face with previous edge
1829 - if edge has 1 face:
1830 - has vertices with valence 4
1831 - not shares face with previous edge
1832 - but also only 1 face
1834 - has vertices with valence 2
1836 static void edgeloop_select(EditMesh *em, EditEdge *starteed, int select)
1843 /* in f1 we put the valence (amount of edges in a vertex, or faces in edge) */
1844 /* in eed->f2 and efa->f1 we put tagged flag as correct loop */
1845 for(eve= em->verts.first; eve; eve= eve->next) {
1849 for(eed= em->edges.first; eed; eed= eed->next) {
1852 if((eed->h & 1)==0) { /* fgon edges add to valence too */
1853 eed->v1->f1++; eed->v2->f1++;
1856 for(efa= em->faces.first; efa; efa= efa->next) {
1862 if(efa->e4) efa->e4->f1++;
1866 /* looped edges & vertices get tagged f2 */
1868 if(starteed->v1->f1<5) starteed->v1->f2= 1;
1869 if(starteed->v2->f1<5) starteed->v2->f2= 1;
1870 /* sorry, first edge isnt even ok */
1871 if(starteed->v1->f2==0 && starteed->v2->f2==0) looking= 0;
1876 /* find correct valence edges which are not tagged yet, but connect to tagged one */
1877 for(eed= em->edges.first; eed; eed= eed->next) {
1878 if(eed->h==0 && eed->f2==0) { /* edge not hidden, not tagged */
1879 if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { /* valence of vertex OK, and is tagged */
1880 /* new edge is not allowed to be in face with tagged edge */
1881 if(edge_not_in_tagged_face(em, eed)) {
1882 if(eed->f1==starteed->f1) { /* same amount of faces */
1885 if(eed->v2->f1<5) eed->v2->f2= 1;
1886 if(eed->v1->f1<5) eed->v1->f2= 1;
1893 /* and we do the select */
1894 for(eed= em->edges.first; eed; eed= eed->next) {
1895 if(eed->f2) EM_select_edge(eed, select);
1900 Almostly exactly the same code as faceloop select
1902 static void edgering_select(EditMesh *em, EditEdge *startedge, int select)
1908 /* in eed->f1 we put the valence (amount of faces in edge) */
1909 /* in eed->f2 we put tagged flag as correct loop */
1910 /* in efa->f1 we put tagged flag as correct to select */
1912 for(eed= em->edges.first; eed; eed= eed->next) {
1916 for(efa= em->faces.first; efa; efa= efa->next) {
1922 if(efa->e4) efa->e4->f1++;
1926 /* tag startedge OK */
1932 for(efa= em->faces.first; efa; efa= efa->next) {
1933 if(efa->e4 && efa->f1==0 && !efa->h) { /* not done quad */
1934 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
1936 /* if edge tagged, select opposing edge and mark face ok */
1942 else if(efa->e2->f2) {
1962 /* (de)select the edges */
1963 for(eed= em->edges.first; eed; eed= eed->next) {
1964 if(eed->f2) EM_select_edge(eed, select);
1968 static int loop_multiselect(bContext *C, wmOperator *op)
1970 Object *obedit= CTX_data_edit_object(C);
1971 EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
1974 int edindex, edfirstcount;
1975 int looptype= RNA_boolean_get(op->ptr, "ring");
1977 /* sets em->totedgesel */
1978 EM_nedges_selected(em);
1980 edarray = MEM_mallocN(sizeof(EditEdge*)*em->totedgesel,"edge array");
1982 edfirstcount = em->totedgesel;
1984 for(eed=em->edges.first; eed; eed=eed->next){
1986 edarray[edindex] = eed;
1992 for(edindex = 0; edindex < edfirstcount; edindex +=1){
1993 eed = edarray[edindex];
1994 edgering_select(em, eed,SELECT);
1996 EM_selectmode_flush(em);
1999 for(edindex = 0; edindex < edfirstcount; edindex +=1){
2000 eed = edarray[edindex];
2001 edgeloop_select(em, eed,SELECT);
2003 EM_selectmode_flush(em);
2006 // if (EM_texFaceCheck())
2008 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2010 BKE_mesh_end_editmesh(obedit->data, em);
2011 return OPERATOR_FINISHED;
2014 void MESH_OT_loop_multi_select(wmOperatorType *ot)
2017 ot->name= "Multi Select Loops";
2018 ot->description= "Select a loop of connected edges by connection type";
2019 ot->idname= "MESH_OT_loop_multi_select";
2022 ot->exec= loop_multiselect;
2023 ot->poll= ED_operator_editmesh;
2026 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2029 RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
2033 /* ***************** MAIN MOUSE SELECTION ************** */
2036 /* ***************** loop select (non modal) ************** */
2038 static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring)
2046 em_setup_viewcontext(C, &vc);
2047 vc.mval[0]= mval[0];
2048 vc.mval[1]= mval[1];
2051 /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
2052 view3d_validate_backbuf(&vc);
2054 eed= findnearestedge(&vc, &dist);
2056 if(extend==0) EM_clear_flag_all(em, SELECT);
2058 if((eed->f & SELECT)==0) select=1;
2059 else if(extend) select=0;
2061 if(em->selectmode & SCE_SELECT_FACE) {
2062 faceloop_select(em, eed, select);
2064 else if(em->selectmode & SCE_SELECT_EDGE) {
2066 edgering_select(em, eed, select);
2068 edgeloop_select(em, eed, select);
2070 else if(em->selectmode & SCE_SELECT_VERTEX) {
2072 edgering_select(em, eed, select);
2074 edgeloop_select(em, eed, select);
2077 EM_selectmode_flush(em);
2078 // if (EM_texFaceCheck())
2080 /* sets as active, useful for other tools */
2082 if(em->selectmode & SCE_SELECT_VERTEX)
2083 EM_store_selection(em, eed->v1, EDITVERT);
2084 if(em->selectmode & SCE_SELECT_EDGE)
2085 EM_store_selection(em, eed, EDITEDGE);
2088 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
2092 static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
2095 view3d_operator_needs_opengl(C);
2097 mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
2098 RNA_boolean_get(op->ptr, "ring"));
2100 /* cannot do tweaks for as long this keymap is after transform map */
2101 return OPERATOR_FINISHED;
2104 void MESH_OT_loop_select(wmOperatorType *ot)
2107 ot->name= "Loop Select";
2108 ot->description= "Select a loop of connected edges";
2109 ot->idname= "MESH_OT_loop_select";
2112 ot->invoke= mesh_select_loop_invoke;
2113 ot->poll= ED_operator_editmesh_region_view3d;
2116 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2119 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
2120 RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
2123 /* ******************* mesh shortest path select, uses prev-selected edge ****************** */
2125 /* since you want to create paths with multiple selects, it doesn't have extend option */
2126 static void mouse_mesh_shortest_path(bContext *C, short mval[2])
2130 EditEdge *eed, *eed_act= NULL;
2133 em_setup_viewcontext(C, &vc);
2134 vc.mval[0]= mval[0];
2135 vc.mval[1]= mval[1];
2138 /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
2139 view3d_validate_backbuf(&vc);
2141 eed= findnearestedge(&vc, &dist);
2143 Mesh *me= vc.obedit->data;
2146 if (em->selected.last) {
2147 EditSelection *ese = em->selected.last;
2149 if(ese && ese->type == EDITEDGE) {
2150 eed_act = (EditEdge*)ese->data;
2151 if (eed_act != eed) {
2152 if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) { /* <- this is where the magic happens */
2153 EM_remove_selection(em, eed_act, EDITEDGE);
2160 int act = (edgetag_context_check(vc.scene, eed)==0);
2161 edgetag_context_set(vc.scene, eed, act); /* switch the edge option */
2164 /* even if this is selected it may not be in the selection list */
2165 if(edgetag_context_check(vc.scene, eed)==0) {
2166 EM_remove_selection(em, eed, EDITEDGE);
2169 /* other modes need to keep the last edge tagged */
2171 if(vc.scene->toolsettings->edge_mode!=EDGE_MODE_SELECT) {
2172 /* for non-select modes, always de-select the previous active edge */
2173 EM_select_edge(eed_act, 0);
2177 /* set the new edge active */
2178 EM_select_edge(eed, 1);
2179 EM_store_selection(em, eed, EDITEDGE);
2182 EM_selectmode_flush(em);
2184 /* force drawmode for mesh */
2185 switch (vc.scene->toolsettings->edge_mode) {
2187 case EDGE_MODE_TAG_SEAM:
2188 me->drawflag |= ME_DRAWSEAMS;
2190 case EDGE_MODE_TAG_SHARP:
2191 me->drawflag |= ME_DRAWSHARP;
2193 case EDGE_MODE_TAG_CREASE:
2194 me->drawflag |= ME_DRAWCREASES;
2196 case EDGE_MODE_TAG_BEVEL:
2197 me->drawflag |= ME_DRAWBWEIGHTS;
2201 DAG_id_tag_update(vc.obedit->data, 0);
2202 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
2207 static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
2210 view3d_operator_needs_opengl(C);
2212 mouse_mesh_shortest_path(C, event->mval);
2214 return OPERATOR_FINISHED;
2217 static int mesh_shortest_path_select_poll(bContext *C)
2219 if(ED_operator_editmesh_region_view3d(C)) {
2220 Object *obedit= CTX_data_edit_object(C);
2221 EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
2222 return (em->selectmode & SCE_SELECT_EDGE);
2227 void MESH_OT_select_shortest_path(wmOperatorType *ot)
2230 ot->name= "Shortest Path Select";
2231 ot->description= "Select shortest path between two selections";
2232 ot->idname= "MESH_OT_select_shortest_path";
2235 ot->invoke= mesh_shortest_path_select_invoke;
2236 ot->poll= mesh_shortest_path_select_poll;
2239 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2242 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
2246 /* ************************************************** */
2249 /* here actual select happens */
2250 /* gets called via generic mouse select operator */
2251 int mouse_mesh(bContext *C, short mval[2], short extend)
2258 /* setup view context for argument to callbacks */
2259 em_setup_viewcontext(C, &vc);
2260 vc.mval[0]= mval[0];
2261 vc.mval[1]= mval[1];
2263 if(unified_findnearest(&vc, &eve, &eed, &efa)) {
2265 if(extend==0) EM_clear_flag_all(vc.em, SELECT);
2268 /* set the last selected face */
2269 EM_set_actFace(vc.em, efa);
2271 if( (efa->f & SELECT)==0 ) {
2272 EM_store_selection(vc.em, efa, EDITFACE);
2273 EM_select_face_fgon(vc.em, efa, 1);
2276 EM_remove_selection(vc.em, efa, EDITFACE);
2277 EM_select_face_fgon(vc.em, efa, 0);
2281 if((eed->f & SELECT)==0) {
2282 EM_store_selection(vc.em, eed, EDITEDGE);
2283 EM_select_edge(eed, 1);
2286 EM_remove_selection(vc.em, eed, EDITEDGE);
2287 EM_select_edge(eed, 0);
2291 if((eve->f & SELECT)==0) {
2293 EM_store_selection(vc.em, eve, EDITVERT);
2296 EM_remove_selection(vc.em, eve, EDITVERT);
2301 EM_selectmode_flush(vc.em);
2303 // if (EM_texFaceCheck()) {
2305 if (efa && efa->mat_nr != vc.obedit->actcol-1) {
2306 vc.obedit->actcol= efa->mat_nr+1;
2307 vc.em->mat_nr= efa->mat_nr;
2308 // BIF_preview_changed(ID_MA);
2311 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
2319 /* *********** select linked ************* */
2321 /* for use with selectconnected_delimit_mesh only! */
2322 #define is_edge_delimit_ok(eed) ((eed->tmp.l == 1) && (eed->seam==0))
2323 #define is_face_tag(efa) is_edge_delimit_ok(efa->e1) || is_edge_delimit_ok(efa->e2) || is_edge_delimit_ok(efa->e3) || (efa->v4 && is_edge_delimit_ok(efa->e4))
2325 #define face_tag(efa)\
2326 if(efa->v4) efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;\
2327 else efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
2329 /* all - 1) use all faces for extending the selection 2) only use the mouse face
2330 * sel - 1) select 0) deselect
2333 /* legacy warning, this function combines too much :) */
2334 static int select_linked_limited_invoke(ViewContext *vc, short all, short sel)
2336 EditMesh *em= vc->em;
2340 short done=1, change=0;
2342 if(em->faces.first==0) return OPERATOR_CANCELLED;
2344 /* flag all edges+faces as off*/
2345 for(eed= em->edges.first; eed; eed= eed->next)
2348 for(efa= em->faces.first; efa; efa= efa->next) {
2354 for(eed= em->edges.first; eed; eed= eed->next) {
2358 for(efa= em->faces.first; efa; efa= efa->next) {
2360 if (efa->f & SELECT) {
2368 if( unified_findnearest(vc, &eve, &eed, &efa) ) {
2377 for(eed= em->edges.first; eed; eed= eed->next)
2378 if(eed->v1==eve || eed->v2==eve)
2384 return OPERATOR_FINISHED;
2389 /* simple algo - select all faces that have a selected edge
2390 * this intern selects the edge, repeat until nothing is left to do */
2391 for(efa= em->faces.first; efa; efa= efa->next) {
2392 if ((efa->tmp.l == 0) && (!efa->h)) {
2393 if (is_face_tag(efa)) {
2401 for(efa= em->faces.first; efa; efa= efa->next) {
2404 if (!(efa->f & SELECT)) {
2405 EM_select_face(efa, 1);
2409 if (efa->f & SELECT) {
2410 EM_select_face(efa, 0);
2418 return OPERATOR_CANCELLED;
2420 if (!sel) /* make sure de-selecting faces didnt de-select the verts/edges connected to selected faces, this is common with boundries */
2421 for(efa= em->faces.first; efa; efa= efa->next)
2422 if (efa->f & SELECT)
2423 EM_select_face(efa, 1);
2425 // if (EM_texFaceCheck())
2427 return OPERATOR_FINISHED;
2430 #undef is_edge_delimit_ok
2434 static void linked_limit_default(bContext *C, wmOperator *op) {
2435 if(!RNA_property_is_set(op->ptr, "limit")) {
2436 Object *obedit= CTX_data_edit_object(C);
2437 EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
2438 if(em->selectmode == SCE_SELECT_FACE)
2439 RNA_boolean_set(op->ptr, "limit", TRUE);
2443 static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
2445 Object *obedit= CTX_data_edit_object(C);
2447 EditVert *eve, *v1, *v2;
2450 short done=1, toggle=0;
2451 int sel= !RNA_boolean_get(op->ptr, "deselect");
2454 linked_limit_default(C, op);
2456 limit = RNA_boolean_get(op->ptr, "limit");
2458 /* unified_finednearest needs ogl */
2459 view3d_operator_needs_opengl(C);
2461 /* setup view context for argument to callbacks */
2462 em_setup_viewcontext(C, &vc);
2464 if(vc.em->edges.first==0) return OPERATOR_CANCELLED;
2466 vc.mval[0]= event->mval[0];
2467 vc.mval[1]= event->mval[1];
2469 /* return warning! */
2471 int retval= select_linked_limited_invoke(&vc, 0, sel);
2472 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2476 if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
2477 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2479 return OPERATOR_CANCELLED;
2482 /* clear test flags */
2483 for(v1= vc.em->verts.first; v1; v1= v1->next) v1->f1= 0;
2485 /* start vertex/face/edge */
2487 else if(eed) eed->v1->f1= eed->v2->f1= 1;
2488 else efa->v1->f1= efa->v2->f1= efa->v3->f1= 1;
2490 /* set flag f1 if affected */
2495 if(toggle & 1) eed= vc.em->edges.first;
2496 else eed= vc.em->edges.last;
2503 if(v1->f1 && v2->f1==0) {
2507 else if(v1->f1==0 && v2->f1) {
2513 if(toggle & 1) eed= eed->next;
2514 else eed= eed->prev;
2518 /* now use vertex f1 flag to select/deselect */
2519 for(eed= vc.em->edges.first; eed; eed= eed->next) {
2520 if(eed->v1->f1 && eed->v2->f1)
2521 EM_select_edge(eed, sel);
2523 for(efa= vc.em->faces.first; efa; efa= efa->next) {
2524 if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1))
2525 EM_select_face(efa, sel);
2527 /* no flush needed, connected geometry is done */
2529 // if (EM_texFaceCheck())
2531 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2532 return OPERATOR_FINISHED;
2535 void MESH_OT_select_linked_pick(wmOperatorType *ot)
2538 ot->name= "Select Linked";
2539 ot->description= "(un)select all vertices linked to the active mesh";
2540 ot->idname= "MESH_OT_select_linked_pick";
2543 ot->invoke= select_linked_pick_invoke;
2544 ot->poll= ED_operator_editmesh_region_view3d;
2547 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2549 RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
2550 RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "Limit selection by seam boundries (faces only)");
2554 /* ************************* */
2556 void selectconnected_mesh_all(EditMesh *em)
2560 short done=1, toggle=0;
2562 if(em->edges.first==0) return;
2568 if(toggle & 1) eed= em->edges.first;
2569 else eed= em->edges.last;
2575 if(v1->f & SELECT) {
2576 if( (v2->f & SELECT)==0 ) {
2581 else if(v2->f & SELECT) {
2582 if( (v1->f & SELECT)==0 ) {
2588 if(toggle & 1) eed= eed->next;
2589 else eed= eed->prev;
2593 /* now use vertex select flag to select rest */
2594 EM_select_flush(em);
2596 // if (EM_texFaceCheck())
2599 static int select_linked_exec(bContext *C, wmOperator *op)
2601 Object *obedit= CTX_data_edit_object(C);
2602 EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
2604 if( RNA_boolean_get(op->ptr, "limit") ) {
2606 em_setup_viewcontext(C, &vc);
2607 select_linked_limited_invoke(&vc, 1, 1);
2610 selectconnected_mesh_all(em);
2612 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2614 BKE_mesh_end_editmesh(obedit->data, em);
2615 return OPERATOR_FINISHED;
2618 static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2620 linked_limit_default(C, op);
2621 return select_linked_exec(C, op);
2624 void MESH_OT_select_linked(wmOperatorType *ot)
2627 ot->name= "Select Linked All";
2628 ot->description= "Select all vertices linked to the active mesh";
2629 ot->idname= "MESH_OT_select_linked";
2632 ot->exec= select_linked_exec;
2633 ot->invoke= select_linked_invoke;
2634 ot->poll= ED_operator_editmesh;
2637 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2639 RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "Limit selection by seam boundries (faces only)");
2643 /* ************************* */
2645 /* swap is 0 or 1, if 1 it hides not selected */
2646 void EM_hide_mesh(EditMesh *em, int swap)
2653 if(em==NULL) return;
2655 /* hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
2656 /* - vertex hidden, always means edge is hidden too
2657 - edge hidden, always means face is hidden too
2658 - face hidden, only set face hide
2659 - then only flush back down what's absolute hidden
2661 if(em->selectmode & SCE_SELECT_VERTEX) {
2662 for(eve= em->verts.first; eve; eve= eve->next) {
2663 if((eve->f & SELECT)!=swap) {
2669 for(eed= em->edges.first; eed; eed= eed->next) {
2670 if(eed->v1->h || eed->v2->h) {
2676 for(efa= em->faces.first; efa; efa= efa->next) {
2677 if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
2683 else if(em->selectmode & SCE_SELECT_EDGE) {
2685 for(eed= em->edges.first; eed; eed= eed->next) {
2686 if((eed->f & SELECT)!=swap) {
2688 EM_select_edge(eed, 0);
2692 for(efa= em->faces.first; efa; efa= efa->next) {
2693 if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
2701 for(efa= em->faces.first; efa; efa= efa->next) {
2702 if((efa->f & SELECT)!=swap) {
2704 EM_select_face(efa, 0);
2709 /* flush down, only whats 100% hidden */
2710 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
2711 for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
2713 if(em->selectmode & SCE_SELECT_FACE) {
2714 for(efa= em->faces.first; efa; efa= efa->next) {
2715 if(efa->h) a= 1; else a= 2;
2719 if(efa->e4) efa->e4->f1 |= a;
2720 /* When edges are not delt with in their own loop, we need to explicitly re-selct select edges that are joined to unselected faces */
2721 if (swap && (em->selectmode == SCE_SELECT_FACE) && (efa->f & SELECT)) {
2722 EM_select_face(efa, 1);
2727 if(em->selectmode >= SCE_SELECT_EDGE) {
2728 for(eed= em->edges.first; eed; eed= eed->next) {
2729 if(eed->f1==1) eed->h |= 1;
2730 if(eed->h & 1) a= 1; else a= 2;
2736 if(em->selectmode >= SCE_SELECT_VERTEX) {
2737 for(eve= em->verts.first; eve; eve= eve->next) {
2738 if(eve->f1==1) eve->h= 1;
2742 em->totedgesel= em->totfacesel= em->totvertsel= 0;
2743 // if(EM_texFaceCheck())
2745 // DAG_id_tag_update(obedit->data, 0);
2748 static int hide_mesh_exec(bContext *C, wmOperator *op)
2750 Object *obedit= CTX_data_edit_object(C);
2751 EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
2753 EM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
2755 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2757 BKE_mesh_end_editmesh(obedit->data, em);
2758 return OPERATOR_FINISHED;
2761 void MESH_OT_hide(wmOperatorType *ot)
2764 ot->name= "Hide Selection";
2765 ot->description= "Hide (un)selected vertices, edges or faces";
2766 ot->idname= "MESH_OT_hide";
2769 ot->exec= hide_mesh_exec;
2770 ot->poll= ED_operator_editmesh;
2773 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2776 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
2779 void EM_reveal_mesh(EditMesh *em)
2785 if(em==NULL) return;
2787 for(eve= em->verts.first; eve; eve= eve->next) {
2793 for(eed= em->edges.first; eed; eed= eed->next) {
2796 if(em->selectmode & SCE_SELECT_VERTEX);
2797 else EM_select_edge(eed, 1);
2800 for(efa= em->faces.first; efa; efa= efa->next) {
2803 if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX));
2804 else EM_select_face(efa, 1);
2808 EM_fgon_flags(em); /* redo flags and indices for fgons */
2809 EM_selectmode_flush(em);
2811 // if (EM_texFaceCheck())
2812 // DAG_id_tag_update(obedit->data, 0);
2815 static int reveal_mesh_exec(bContext *C, wmOperator *UNUSED(op))
2817 Object *obedit= CTX_data_edit_object(C);
2818 EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
2822 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2824 BKE_mesh_end_editmesh(obedit->data, em);
2825 return OPERATOR_FINISHED;
2828 void MESH_OT_reveal(wmOperatorType *ot)
2831 ot->name= "Reveal Hidden";
2832 ot->description= "Reveal all hidden vertices, edges and faces";
2833 ot->idname= "MESH_OT_reveal";
2836 ot->exec= reveal_mesh_exec;
2837 ot->poll= ED_operator_editmesh;
2840 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2843 static int select_by_number_vertices_exec(bContext *C, wmOperator *op)
2845 Object *obedit= CTX_data_edit_object(C);
2846 EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
2848 int numverts= RNA_enum_get(op->ptr, "type");
2850 /* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring
2854 /* for loose vertices/edges, we first select all, loop below will deselect */
2856 EM_set_flag_all(em, SELECT);
2858 else if(em->selectmode!=SCE_SELECT_FACE) {
2859 BKE_report(op->reports, RPT_WARNING, "Only works in face selection mode");
2860 return OPERATOR_CANCELLED;
2863 for(efa= em->faces.first; efa; efa= efa->next) {
2865 EM_select_face(efa, (numverts==4) );
2868 EM_select_face(efa, (numverts==3) );
2872 EM_selectmode_flush(em);
2874 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2876 return OPERATOR_FINISHED;
2879 void MESH_OT_select_by_number_vertices(wmOperatorType *ot)
2881 static const EnumPropertyItem type_items[]= {
2882 {3, "TRIANGLES", 0, "Triangles", NULL},
2883 {4, "QUADS", 0, "Quads", NULL},
2884 {5, "OTHER", 0, "Other", NULL},
2885 {0, NULL, 0, NULL, NULL}};
2888 ot->name= "Select by Number of Vertices";
2889 ot->description= "Select vertices or faces by vertex count";
2890 ot->idname= "MESH_OT_select_by_number_vertices";
2893 ot->exec= select_by_number_vertices_exec;
2894 ot->invoke= WM_menu_invoke;
2895 ot->poll= ED_operator_editmesh;
2898 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2901 ot->prop= RNA_def_enum(ot->srna, "type", type_items, 3, "Type", "Type of elements to select.");
2905 static int select_mirror_exec(bContext *C, wmOperator *op)
2907 Object *obedit= CTX_data_edit_object(C);
2908 EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
2910 int extend= RNA_boolean_get(op->ptr, "extend");
2912 EM_select_mirrored(obedit, em, extend);
2913 EM_selectmode_flush(em);
2914 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2916 return OPERATOR_FINISHED;
2919 void MESH_OT_select_mirror(wmOperatorType *ot)
2922 ot->name= "Select Mirror";