4 * ***** BEGIN GPL/BL DUAL 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. The Blender
10 * Foundation also sells licenses for use in proprietary software under
11 * the Blender License. See http://www.blender.org/BL/ for information
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 * The Original Code is Copyright (C) 2004 by NaN Holding BV.
24 * All rights reserved.
26 * The Original Code is: all of this file.
28 * Contributor(s): none yet.
30 * ***** END GPL/BL DUAL LICENSE BLOCK *****
35 editmesh_mods.c, UI level access, no geometry changes
43 #include "MEM_guardedalloc.h"
45 #include "MTC_matrixops.h"
47 #include "DNA_mesh_types.h"
48 #include "DNA_material_types.h"
49 #include "DNA_meshdata_types.h"
50 #include "DNA_modifier_types.h"
51 #include "DNA_object_types.h"
52 #include "DNA_texture_types.h"
53 #include "DNA_scene_types.h"
54 #include "DNA_screen_types.h"
55 #include "DNA_view3d_types.h"
57 #include "BLI_blenlib.h"
58 #include "BLI_arithb.h"
59 #include "BLI_editVert.h"
62 #include "BKE_displist.h"
63 #include "BKE_depsgraph.h"
64 #include "BKE_DerivedMesh.h"
65 #include "BKE_global.h"
67 #include "BKE_material.h"
68 #include "BKE_texture.h"
69 #include "BKE_utildefines.h"
71 #include "BIF_editmesh.h"
72 #include "BIF_resources.h"
74 #include "BIF_glutil.h"
75 #include "BIF_graphics.h"
76 #include "BIF_interface.h"
77 #include "BIF_meshtools.h"
78 #include "BIF_mywindow.h"
79 #include "BIF_resources.h"
80 #include "BIF_screen.h"
81 #include "BIF_space.h"
82 #include "BIF_toolbox.h"
84 #include "BDR_drawobject.h"
85 #include "BDR_editobject.h"
87 #include "BSE_drawview.h"
91 #include "IMB_imbuf_types.h"
92 #include "IMB_imbuf.h"
94 #include "RE_render_ext.h" // externtex
102 /* ****************************** MIRROR **************** */
104 void EM_select_mirrored(void)
106 if(G.scene->selectmode & SCE_SELECT_VERTEX) {
107 EditMesh *em = G.editMesh;
110 for(eve= em->verts.first; eve; eve= eve->next) {
111 if(eve->f & SELECT) {
112 v1= editmesh_get_x_mirror_vert(G.obedit, eve->co);
122 /* ****************************** SELECTION ROUTINES **************** */
124 unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0; // set in drawobject.c ... for colorindices
126 /* facilities for border select and circle select */
127 static char *selbuf= NULL;
129 /* opengl doesn't support concave... */
130 static void draw_triangulated(short mcords[][2], short tot)
132 ListBase lb={NULL, NULL};
138 dl= MEM_callocN(sizeof(DispList), "poly disp");
142 dl->verts= fp= MEM_callocN(tot*3*sizeof(float), "poly verts");
143 BLI_addtail(&lb, dl);
145 for(a=0; a<tot; a++, fp+=3) {
146 fp[0]= (float)mcords[a][0];
147 fp[1]= (float)mcords[a][1];
151 filldisplist(&lb, &lb);
154 dl= lb.first; // filldisplist adds in head of list
155 if(dl->type==DL_INDEX3) {
161 glBegin(GL_TRIANGLES);
163 glVertex3fv(fp+3*index[0]);
164 glVertex3fv(fp+3*index[1]);
165 glVertex3fv(fp+3*index[2]);
175 /* reads rect, and builds selection array for quick lookup */
176 /* returns if all is OK */
177 int EM_init_backbuf_border(short xmin, short ymin, short xmax, short ymax)
183 if(G.obedit==NULL || G.vd->drawtype<OB_SOLID || (G.vd->flag & V3D_ZBUF_SELECT)==0) return 0;
184 if(em_vertoffs==0) return 0;
186 buf= read_backbuf(xmin, ymin, xmax, ymax);
187 if(buf==NULL) return 0;
191 /* build selection lookup */
192 selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
194 a= (xmax-xmin+1)*(ymax-ymin+1);
196 if(*dr>0 && *dr<=em_vertoffs)
204 int EM_check_backbuf(unsigned int index)
206 if(selbuf==NULL) return 1;
207 if(index>0 && index<=em_vertoffs)
208 return selbuf[index];
212 void EM_free_backbuf(void)
214 if(selbuf) MEM_freeN(selbuf);
218 /* mcords is a polygon mask
220 - draw with black in backbuffer,
221 - grab again and compare
224 int EM_mask_init_backbuf_border(short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
226 unsigned int *dr, *drm;
227 struct ImBuf *buf, *bufmask;
230 /* method in use for face selecting too */
232 if(G.f & G_FACESELECT);
235 else if(G.vd->drawtype<OB_SOLID || (G.vd->flag & V3D_ZBUF_SELECT)==0) return 0;
237 if(em_vertoffs==0) return 0;
239 buf= read_backbuf(xmin, ymin, xmax, ymax);
240 if(buf==NULL) return 0;
246 glDrawBuffer(GL_AUX0);
248 glDisable(GL_DEPTH_TEST);
253 /* yah, opengl doesn't do concave... tsk! */
254 draw_triangulated(mcords, tot);
256 glBegin(GL_LINE_LOOP); // for zero sized masks, lines
257 for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
261 glFinish(); // to be sure readpixels sees mask
263 glDrawBuffer(GL_BACK);
266 bufmask= read_backbuf(xmin, ymin, xmax, ymax);
268 if(bufmask==NULL) return 0; // only when mem alloc fails, go crash somewhere else!
270 /* build selection lookup */
271 selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
273 a= (xmax-xmin+1)*(ymax-ymin+1);
275 if(*dr>0 && *dr<=em_vertoffs && *drm==0) selbuf[*dr]= 1;
279 IMB_freeImBuf(bufmask);
284 /* circle shaped sample area */
285 int EM_init_backbuf_circle(short xs, short ys, short rads)
289 short xmin, ymin, xmax, ymax, xc, yc;
292 /* method in use for face selecting too */
294 if(G.f & G_FACESELECT);
297 else if(G.vd->drawtype<OB_SOLID || (G.vd->flag & V3D_ZBUF_SELECT)==0) return 0;
298 if(em_vertoffs==0) return 0;
300 xmin= xs-rads; xmax= xs+rads;
301 ymin= ys-rads; ymax= ys+rads;
302 buf= read_backbuf(xmin, ymin, xmax, ymax);
303 if(buf==NULL) return 0;
307 /* build selection lookup */
308 selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
310 for(yc= -rads; yc<=rads; yc++) {
311 for(xc= -rads; xc<=rads; xc++, dr++) {
312 if(xc*xc + yc*yc < radsq) {
313 if(*dr>0 && *dr<=em_vertoffs) selbuf[*dr]= 1;
323 static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index)
325 struct { short mval[2], pass, select; int dist, lastIndex, closestIndex; EditVert *closest; } *data = userData;
328 if (index<=data->lastIndex)
331 if (index>data->lastIndex)
336 int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
337 if ((eve->f&1)==data->select) temp += 5;
339 if (temp<data->dist) {
342 data->closestIndex = index;
346 static EditVert *findnearestvert(short *dist, short sel)
350 getmouseco_areawin(mval);
352 if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
354 unsigned int index = sample_backbuf_rect(mval, 50, em_wireoffs, 0xFFFFFF, &distance);
355 EditVert *eve = BLI_findlink(&G.editMesh->verts, index-1);
357 if (eve && distance < *dist) {
365 struct { short mval[2], pass, select; int dist, lastIndex, closestIndex; EditVert *closest; } data;
366 static int lastSelectedIndex=0;
367 static EditVert *lastSelected=NULL;
369 if (lastSelected && BLI_findlink(&G.editMesh->verts, lastSelectedIndex)!=lastSelected) {
370 lastSelectedIndex = 0;
374 data.lastIndex = lastSelectedIndex;
375 data.mval[0] = mval[0];
376 data.mval[1] = mval[1];
380 data.closestIndex = 0;
383 mesh_foreachScreenVert(findnearestvert__doClosest, &data, 1);
387 mesh_foreachScreenVert(findnearestvert__doClosest, &data, 1);
391 lastSelected = data.closest;
392 lastSelectedIndex = data.closestIndex;
398 /* returns labda for closest distance v1 to line-piece v2-v3 */
399 static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3)
405 len= rc[0]*rc[0]+ rc[1]*rc[1];
409 return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
412 /* note; uses G.vd, so needs active 3d window */
413 static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
415 struct { float mval[2]; short dist; EditEdge *closest; } *data = userData;
424 distance= PdistVL2Dfl(data->mval, v1, v2);
426 if(eed->f & SELECT) distance+=5;
427 if(distance < data->dist) {
428 if(G.vd->flag & V3D_CLIPPING) {
429 float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
432 vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
433 vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
434 vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
435 Mat4MulVecfl(G.obedit->obmat, vec);
437 if(view3d_test_clipping(G.vd, vec)==0) {
438 data->dist = distance;
443 data->dist = distance;
448 EditEdge *findnearestedge(short *dist)
452 getmouseco_areawin(mval);
454 if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
456 unsigned int index = sample_backbuf_rect(mval, 50, em_solidoffs, em_wireoffs, &distance);
457 EditEdge *eed = BLI_findlink(&G.editMesh->edges, index-1);
459 if (eed && distance<*dist) {
467 struct { float mval[2]; short dist; EditEdge *closest; } data;
469 data.mval[0] = mval[0];
470 data.mval[1] = mval[1];
474 mesh_foreachScreenEdge(findnearestedge__doClosest, &data, 2);
481 static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int index)
483 struct { short mval[2], dist; EditFace *toFace; } *data = userData;
485 if (efa==data->toFace) {
486 short temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
492 static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int y, int index)
494 struct { short mval[2], pass, dist; int lastIndex, closestIndex; EditFace *closest; } *data = userData;
497 if (index<=data->lastIndex)
500 if (index>data->lastIndex)
505 short temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
507 if (temp<data->dist) {
510 data->closestIndex = index;
514 static EditFace *findnearestface(short *dist)
518 getmouseco_areawin(mval);
520 if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
521 unsigned int index = sample_backbuf(mval[0], mval[1]);
522 EditFace *efa = BLI_findlink(&G.editMesh->faces, index-1);
525 struct { short mval[2], dist; EditFace *toFace; } data;
527 data.mval[0] = mval[0];
528 data.mval[1] = mval[1];
529 data.dist = 0x7FFF; // largest short
532 mesh_foreachScreenFace(findnearestface__getDistance, &data);
534 if(G.scene->selectmode == SCE_SELECT_FACE || data.dist<*dist) { // only faces, no dist check
543 struct { short mval[2], pass, dist; int lastIndex, closestIndex; EditFace *closest; } data;
544 static int lastSelectedIndex=0;
545 static EditFace *lastSelected=NULL;
547 if (lastSelected && BLI_findlink(&G.editMesh->faces, lastSelectedIndex)!=lastSelected) {
548 lastSelectedIndex = 0;
552 data.lastIndex = lastSelectedIndex;
553 data.mval[0] = mval[0];
554 data.mval[1] = mval[1];
557 data.closestIndex = 0;
560 mesh_foreachScreenFace(findnearestface__doClosest, &data);
564 mesh_foreachScreenFace(findnearestface__doClosest, &data);
568 lastSelected = data.closest;
569 lastSelectedIndex = data.closestIndex;
575 /* for interactivity, frontbuffer draw in current window */
576 static void draw_dm_mapped_vert__mapFunc(void *theVert, int index, float *co, float *no_f, short *no_s)
578 if (EM_get_vert_for_index(index)==theVert) {
582 static void draw_dm_mapped_vert(DerivedMesh *dm, EditVert *eve)
584 EM_init_index_arrays(1, 0, 0);
586 dm->foreachMappedVert(dm, draw_dm_mapped_vert__mapFunc, eve);
588 EM_free_index_arrays();
591 static int draw_dm_mapped_edge__setDrawOptions(void *theEdge, int index)
593 return EM_get_edge_for_index(index)==theEdge;
595 static void draw_dm_mapped_edge(DerivedMesh *dm, EditEdge *eed)
597 EM_init_index_arrays(0, 1, 0);
598 dm->drawMappedEdges(dm, draw_dm_mapped_edge__setDrawOptions, eed);
599 EM_free_index_arrays();
602 static void draw_dm_mapped_face_center__mapFunc(void *theFace, int index, float *cent, float *no)
604 if (EM_get_face_for_index(index)==theFace) {
608 static void draw_dm_mapped_face_center(DerivedMesh *dm, EditFace *efa)
610 EM_init_index_arrays(0, 0, 1);
612 dm->foreachMappedFaceCenter(dm, draw_dm_mapped_face_center__mapFunc, efa);
614 EM_free_index_arrays();
617 static void unified_select_draw(EditVert *eve, EditEdge *eed, EditFace *efa)
620 DerivedMesh *dm = editmesh_get_derived_cage(&dmNeedsFree);
622 glDrawBuffer(GL_FRONT);
626 if(G.vd->flag & V3D_CLIPPING)
627 view3d_set_clipping(G.vd);
630 mymultmatrix(G.obedit->obmat);
634 if(G.scene->selectmode & SCE_SELECT_VERTEX) {
635 glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
637 if(efa->f & SELECT) BIF_ThemeColor(TH_VERTEX_SELECT);
638 else BIF_ThemeColor(TH_VERTEX);
641 bglVertex3fv(efa->v1->co);
642 bglVertex3fv(efa->v2->co);
643 bglVertex3fv(efa->v3->co);
644 if(efa->v4) bglVertex3fv(efa->v4->co);
648 if(G.scene->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_FACE)) {
650 BIF_ThemeColor((efa->f & SELECT)?TH_EDGE_SELECT:TH_WIRE);
652 draw_dm_mapped_edge(dm, efa->e1);
653 draw_dm_mapped_edge(dm, efa->e2);
654 draw_dm_mapped_edge(dm, efa->e3);
656 draw_dm_mapped_edge(dm, efa->e4);
661 if(G.scene->selectmode & SCE_SELECT_FACE) {
663 glPointSize(BIF_GetThemeValuef(TH_FACEDOT_SIZE));
664 BIF_ThemeColor((efa->f & SELECT)?TH_FACE_DOT:TH_WIRE);
666 draw_dm_mapped_face_center(dm, efa);
672 if(G.scene->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_FACE)) {
673 BIF_ThemeColor((eed->f & SELECT)?TH_EDGE_SELECT:TH_WIRE);
675 draw_dm_mapped_edge(dm, eed);
677 if(G.scene->selectmode & SCE_SELECT_VERTEX) {
678 glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
680 BIF_ThemeColor((eed->f & SELECT)?TH_VERTEX_SELECT:TH_VERTEX);
682 draw_dm_mapped_vert(dm, eed->v1);
683 draw_dm_mapped_vert(dm, eed->v2);
687 if(G.scene->selectmode & SCE_SELECT_VERTEX) {
688 glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
690 BIF_ThemeColor((eve->f & SELECT)?TH_VERTEX_SELECT:TH_VERTEX);
692 draw_dm_mapped_vert(dm, eve);
700 glDrawBuffer(GL_BACK);
702 if(G.vd->flag & V3D_CLIPPING)
703 view3d_clr_clipping();
705 /* signal that frontbuf differs from back */
706 curarea->win_swap= WIN_FRONT_OK;
714 /* best distance based on screen coords.
715 use g.scene->selectmode to define how to use
716 selected vertices and edges get disadvantage
717 return 1 if found one
719 static int unified_findnearest(EditVert **eve, EditEdge **eed, EditFace **efa)
727 if(G.scene->selectmode & SCE_SELECT_VERTEX)
728 *eve= findnearestvert(&dist, SELECT);
729 if(G.scene->selectmode & SCE_SELECT_FACE)
730 *efa= findnearestface(&dist);
732 dist-= 20; // since edges select lines, we give dots advantage of 20 pix
733 if(G.scene->selectmode & SCE_SELECT_EDGE)
734 *eed= findnearestedge(&dist);
736 /* return only one of 3 pointers, for frontbuffer redraws */
738 *efa= NULL; *eve= NULL;
744 return (*eve || *eed || *efa);
747 /* **************** LOOP SELECTS *************** */
749 /* selects quads in loop direction of indicated edge */
750 /* only flush over edges with valence <= 2 */
751 void faceloop_select(EditEdge *startedge, int select)
753 EditMesh *em = G.editMesh;
758 /* in eed->f1 we put the valence (amount of faces in edge) */
759 /* in eed->f2 we put tagged flag as correct loop */
760 /* in efa->f1 we put tagged flag as correct to select */
762 for(eed= em->edges.first; eed; eed= eed->next) {
766 for(efa= em->faces.first; efa; efa= efa->next) {
772 if(efa->e4) efa->e4->f1++;
782 for(efa= em->faces.first; efa; efa= efa->next) {
783 if(efa->e4 && efa->f1==0) { // not done quad
784 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok
786 // if edge tagged, select opposing edge and mark face ok
792 else if(efa->e2->f2) {
812 /* (de)select the faces */
814 for(efa= em->faces.first; efa; efa= efa->next) {
815 if(efa->f1) EM_select_face(efa, select);
821 /* helper for edgeloop_select, checks for eed->f2 tag in faces */
822 static int edge_not_in_tagged_face(EditEdge *eed)
824 EditMesh *em = G.editMesh;
827 for(efa= em->faces.first; efa; efa= efa->next) {
829 if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) { // edge is in face
830 if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) { // face is tagged
839 /* selects or deselects edges that:
840 - if edges has 2 faces:
841 - has vertices with valence of 4
842 - not shares face with previous edge
843 - if edge has 1 face:
844 - has vertices with valence 4
845 - not shares face with previous edge
846 - but also only 1 face
848 - has vertices with valence 2
850 static void edgeloop_select(EditEdge *starteed, int select)
852 EditMesh *em = G.editMesh;
858 /* in f1 we put the valence (amount of edges in a vertex, or faces in edge) */
859 /* in eed->f2 and efa->f1 we put tagged flag as correct loop */
860 for(eve= em->verts.first; eve; eve= eve->next) {
864 for(eed= em->edges.first; eed; eed= eed->next) {
867 if((eed->h & 1)==0) { // fgon edges add to valence too
868 eed->v1->f1++; eed->v2->f1++;
871 for(efa= em->faces.first; efa; efa= efa->next) {
877 if(efa->e4) efa->e4->f1++;
881 /* looped edges & vertices get tagged f2 */
883 if(starteed->v1->f1<5) starteed->v1->f2= 1;
884 if(starteed->v2->f1<5) starteed->v2->f2= 1;
885 /* sorry, first edge isnt even ok */
886 if(starteed->v1->f2==0 && starteed->v2->f2==0) looking= 0;
891 /* find correct valence edges which are not tagged yet, but connect to tagged one */
892 for(eed= em->edges.first; eed; eed= eed->next) {
893 if(eed->h==0 && eed->f2==0) { // edge not hidden, not tagged
894 if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { // valence of vertex OK, and is tagged
895 /* new edge is not allowed to be in face with tagged edge */
896 if(edge_not_in_tagged_face(eed)) {
897 if(eed->f1==starteed->f1) { // same amount of faces
900 if(eed->v2->f1<5) eed->v2->f2= 1;
901 if(eed->v1->f1<5) eed->v1->f2= 1;
908 /* and we do the select */
909 for(eed= em->edges.first; eed; eed= eed->next) {
910 if(eed->f2) EM_select_edge(eed, select);
915 Almostly exactly the same code as faceloop select
917 static void edgering_select(EditEdge *startedge, int select){
918 EditMesh *em = G.editMesh;
923 /* in eed->f1 we put the valence (amount of faces in edge) */
924 /* in eed->f2 we put tagged flag as correct loop */
925 /* in efa->f1 we put tagged flag as correct to select */
927 for(eed= em->edges.first; eed; eed= eed->next) {
931 for(efa= em->faces.first; efa; efa= efa->next) {
937 if(efa->e4) efa->e4->f1++;
947 for(efa= em->faces.first; efa; efa= efa->next) {
948 if(efa->e4 && efa->f1==0) { // not done quad
949 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok
951 // if edge tagged, select opposing edge and mark face ok
957 else if(efa->e2->f2) {
977 /* (de)select the edges */
978 for(eed= em->edges.first; eed; eed= eed->next) {
979 if(eed->f2) EM_select_edge(eed, select);
982 /* ***************** MAIN MOUSE SELECTION ************** */
984 // just to have the functions nice together
985 static void mouse_mesh_loop(void)
990 eed= findnearestedge(&dist);
993 if((G.qual & LR_SHIFTKEY)==0) EM_clear_flag_all(SELECT);
995 if((eed->f & SELECT)==0) EM_select_edge(eed, 1);
996 else if(G.qual & LR_SHIFTKEY) EM_select_edge(eed, 0);
998 if(G.scene->selectmode & SCE_SELECT_FACE) {
999 faceloop_select(eed, eed->f & SELECT);
1001 else if(G.scene->selectmode & SCE_SELECT_EDGE) {
1002 if(G.qual == (LR_CTRLKEY | LR_ALTKEY) || G.qual == (LR_CTRLKEY | LR_ALTKEY |LR_SHIFTKEY))
1003 edgering_select(eed, eed->f & SELECT);
1004 else if(G.qual & LR_ALTKEY)
1005 edgeloop_select(eed, eed->f & SELECT);
1007 else if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1008 if(G.qual == (LR_CTRLKEY | LR_ALTKEY) || G.qual == (LR_CTRLKEY | LR_ALTKEY |LR_SHIFTKEY))
1009 edgering_select(eed, eed->f & SELECT);
1010 else if(G.qual & LR_ALTKEY)
1011 edgeloop_select(eed, eed->f & SELECT);
1014 /* frontbuffer draw of last selected only */
1015 unified_select_draw(NULL, eed, NULL);
1017 EM_selectmode_flush();
1020 allqueue(REDRAWVIEW3D, 0);
1025 /* here actual select happens */
1026 void mouse_mesh(void)
1032 if(G.qual & LR_ALTKEY) mouse_mesh_loop();
1033 else if(unified_findnearest(&eve, &eed, &efa)) {
1035 if((G.qual & LR_SHIFTKEY)==0) EM_clear_flag_all(SELECT);
1039 if( (efa->f & SELECT)==0 ) {
1040 EM_select_face_fgon(efa, 1);
1042 else if(G.qual & LR_SHIFTKEY) {
1043 EM_select_face_fgon(efa, 0);
1047 if((eed->f & SELECT)==0) {
1048 EM_select_edge(eed, 1);
1050 else if(G.qual & LR_SHIFTKEY) {
1051 EM_select_edge(eed, 0);
1055 if((eve->f & SELECT)==0) eve->f |= SELECT;
1056 else if(G.qual & LR_SHIFTKEY) eve->f &= ~SELECT;
1059 /* frontbuffer draw of last selected only */
1060 unified_select_draw(eve, eed, efa);
1062 EM_selectmode_flush();
1065 allqueue(REDRAWVIEW3D, 0);
1068 rightmouse_transform();
1072 static void selectconnectedAll(void)
1074 EditMesh *em = G.editMesh;
1077 short done=1, toggle=0;
1079 if(em->edges.first==0) return;
1085 if(toggle & 1) eed= em->edges.first;
1086 else eed= em->edges.last;
1092 if(v1->f & SELECT) {
1093 if( (v2->f & SELECT)==0 ) {
1098 else if(v2->f & SELECT) {
1099 if( (v1->f & SELECT)==0 ) {
1105 if(toggle & 1) eed= eed->next;
1106 else eed= eed->prev;
1110 /* now use vertex select flag to select rest */
1115 allqueue(REDRAWVIEW3D, 0);
1116 BIF_undo_push("Select Connected (All)");
1119 void selectconnected_mesh(int qual)
1121 EditMesh *em = G.editMesh;
1122 EditVert *eve, *v1, *v2;
1125 short done=1, sel, toggle=0;
1127 if(em->edges.first==0) return;
1129 if(qual & LR_CTRLKEY) {
1130 selectconnectedAll();
1135 if( unified_findnearest(&eve, &eed, &efa)==0 ) {
1136 error("Nothing indicated ");
1141 if(qual & LR_SHIFTKEY) sel=0;
1143 /* clear test flags */
1144 for(v1= em->verts.first; v1; v1= v1->next) v1->f1= 0;
1146 /* start vertex/face/edge */
1148 else if(eed) eed->v1->f1= eed->v2->f1= 1;
1149 else efa->v1->f1= efa->v2->f1= efa->v3->f1= 1;
1151 /* set flag f1 if affected */
1156 if(toggle & 1) eed= em->edges.first;
1157 else eed= em->edges.last;
1164 if(v1->f1 && v2->f1==0) {
1168 else if(v1->f1==0 && v2->f1) {
1174 if(toggle & 1) eed= eed->next;
1175 else eed= eed->prev;
1179 /* now use vertex f1 flag to select/deselect */
1180 for(eed= em->edges.first; eed; eed= eed->next) {
1181 if(eed->v1->f1 && eed->v2->f1)
1182 EM_select_edge(eed, sel);
1184 for(efa= em->faces.first; efa; efa= efa->next) {
1185 if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1))
1186 EM_select_face(efa, sel);
1188 /* no flush needed, connected geometry is done */
1192 allqueue(REDRAWVIEW3D, 0);
1193 BIF_undo_push("Select Linked");
1197 /* swap is 0 or 1, if 1 it hides not selected */
1198 void hide_mesh(int swap)
1200 EditMesh *em = G.editMesh;
1206 if(G.obedit==0) return;
1208 /* hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
1209 /* - vertex hidden, always means edge is hidden too
1210 - edge hidden, always means face is hidden too
1211 - face hidden, only set face hide
1212 - then only flush back down what's absolute hidden
1214 if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1215 for(eve= em->verts.first; eve; eve= eve->next) {
1216 if((eve->f & SELECT)!=swap) {
1222 for(eed= em->edges.first; eed; eed= eed->next) {
1223 if(eed->v1->h || eed->v2->h) {
1229 for(efa= em->faces.first; efa; efa= efa->next) {
1230 if(efa->e1->h || efa->e2->h || efa->e3->h || (efa->e4 && efa->e4->h)) {
1236 else if(G.scene->selectmode & SCE_SELECT_EDGE) {
1238 for(eed= em->edges.first; eed; eed= eed->next) {
1239 if((eed->f & SELECT)!=swap) {
1241 EM_select_edge(eed, 0);
1245 for(efa= em->faces.first; efa; efa= efa->next) {
1246 if(efa->e1->h || efa->e2->h || efa->e3->h || (efa->e4 && efa->e4->h)) {
1254 for(efa= em->faces.first; efa; efa= efa->next) {
1255 if((efa->f & SELECT)!=swap) {
1257 EM_select_face(efa, 0);
1262 /* flush down, only whats 100% hidden */
1263 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
1264 for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
1266 if(G.scene->selectmode & SCE_SELECT_FACE) {
1267 for(efa= em->faces.first; efa; efa= efa->next) {
1268 if(efa->h) a= 1; else a= 2;
1272 if(efa->e4) efa->e4->f1 |= a;
1276 if(G.scene->selectmode >= SCE_SELECT_EDGE) {
1277 for(eed= em->edges.first; eed; eed= eed->next) {
1278 if(eed->f1==1) eed->h |= 1;
1279 if(eed->h & 1) a= 1; else a= 2;
1285 if(G.scene->selectmode >= SCE_SELECT_VERTEX) {
1286 for(eve= em->verts.first; eve; eve= eve->next) {
1287 if(eve->f1==1) eve->h= 1;
1291 allqueue(REDRAWVIEW3D, 0);
1292 DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
1293 BIF_undo_push("Hide");
1297 void reveal_mesh(void)
1299 EditMesh *em = G.editMesh;
1304 if(G.obedit==0) return;
1306 for(eve= em->verts.first; eve; eve= eve->next) {
1312 for(eed= em->edges.first; eed; eed= eed->next) {
1315 if(G.scene->selectmode & SCE_SELECT_VERTEX);
1316 else EM_select_edge(eed, 1);
1319 for(efa= em->faces.first; efa; efa= efa->next) {
1322 if(G.scene->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX));
1323 else EM_select_face(efa, 1);
1327 EM_fgon_flags(); // redo flags and indices for fgons
1328 EM_selectmode_flush();
1331 allqueue(REDRAWVIEW3D, 0);
1332 DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
1333 BIF_undo_push("Reveal");
1336 void select_faces_by_numverts(int numverts)
1338 EditMesh *em = G.editMesh;
1341 /* Selects isolated verts, and edges that do not have 2 neighboring
1345 if(G.scene->selectmode!=SCE_SELECT_FACE) {
1346 error("Only works in face selection mode");
1350 efa= em->faces.first;
1353 EM_select_face(efa, (numverts==4) );
1356 EM_select_face(efa, (numverts==3) );
1359 EM_select_face(efa, (numverts!=3) && (numverts!=4) );
1364 addqueue(curarea->win, REDRAW, 0);
1367 BIF_undo_push("Select Triangles");
1368 else if (numverts==4)
1369 BIF_undo_push("Select Quads");
1371 BIF_undo_push("Select non-Triangles/Quads");
1374 void select_sharp_edges(void)
1376 /* Find edges that have exactly two neighboring faces,
1377 * check the angle between those faces, and if angle is
1378 * small enough, select the edge
1380 EditMesh *em = G.editMesh;
1385 long edgecount = 0, i;
1386 static short sharpness = 135;
1389 if(G.scene->selectmode==SCE_SELECT_FACE) {
1390 error("Doesn't work in face selection mode");
1394 if(button(&sharpness,0, 180,"Max Angle:")==0) return;
1395 /* if faces are at angle 'sharpness', then the face normals
1396 * are at angle 180.0 - 'sharpness' (convert to radians too)
1398 fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
1401 /* count edges, use tmp.l */
1402 eed= em->edges.first;
1410 /* for each edge, we want a pointer to two adjacent faces */
1411 efa1 = MEM_callocN(edgecount*sizeof(EditFace *),
1412 "pairs of edit face pointers");
1413 efa2 = MEM_callocN(edgecount*sizeof(EditFace *),
1414 "pairs of edit face pointers");
1416 #define face_table_edge(eed) { \
1421 /* invalidate, edge has more than two neighbors */ \
1434 /* find the adjacent faces of each edge, we want only two */
1435 efa= em->faces.first;
1437 face_table_edge(efa->e1);
1438 face_table_edge(efa->e2);
1439 face_table_edge(efa->e3);
1441 face_table_edge(efa->e4);
1446 #undef face_table_edge
1448 eed = em->edges.first;
1452 /* edge has two or less neighboring faces */
1453 if ( (efa1[i]) && (efa2[i]) ) {
1454 /* edge has exactly two neighboring faces, check angle */
1456 angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
1457 efa1[i]->n[1]*efa2[i]->n[1] +
1458 efa1[i]->n[2]*efa2[i]->n[2]);
1459 if (fabs(angle) >= fsharpness)
1460 EM_select_edge(eed, 1);
1471 addqueue(curarea->win, REDRAW, 0);
1472 BIF_undo_push("Select Sharp Edges");
1475 void select_linked_flat_faces(void)
1477 /* Find faces that are linked to selected faces that are
1478 * relatively flat (angle between faces is higher than
1481 EditMesh *em = G.editMesh;
1486 long edgecount = 0, i, faceselcount=0, faceselcountold=0;
1487 static short sharpness = 135;
1490 if(G.scene->selectmode!=SCE_SELECT_FACE) {
1491 error("Only works in face selection mode");
1495 if(button(&sharpness,0, 180,"Min Angle:")==0) return;
1496 /* if faces are at angle 'sharpness', then the face normals
1497 * are at angle 180.0 - 'sharpness' (convert to radians too)
1499 fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
1502 /* count edges, use tmp.l */
1503 eed= em->edges.first;
1511 /* for each edge, we want a pointer to two adjacent faces */
1512 efa1 = MEM_callocN(edgecount*sizeof(EditFace *),
1513 "pairs of edit face pointers");
1514 efa2 = MEM_callocN(edgecount*sizeof(EditFace *),
1515 "pairs of edit face pointers");
1517 #define face_table_edge(eed) { \
1522 /* invalidate, edge has more than two neighbors */ \
1535 /* find the adjacent faces of each edge, we want only two */
1536 efa= em->faces.first;
1538 face_table_edge(efa->e1);
1539 face_table_edge(efa->e2);
1540 face_table_edge(efa->e3);
1542 face_table_edge(efa->e4);
1545 /* while were at it, count the selected faces */
1546 if (efa->f & SELECT) ++faceselcount;
1551 #undef face_table_edge
1553 eed= em->edges.first;
1557 /* edge has two or less neighboring faces */
1558 if ( (efa1[i]) && (efa2[i]) ) {
1559 /* edge has exactly two neighboring faces, check angle */
1561 angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
1562 efa1[i]->n[1]*efa2[i]->n[1] +
1563 efa1[i]->n[2]*efa2[i]->n[2]);
1564 /* invalidate: edge too sharp */
1565 if (fabs(angle) >= fsharpness)
1569 /* invalidate: less than two neighbors */
1577 #define select_flat_neighbor(eed) { \
1580 if (! (efa1[i]->f & SELECT) ) { \
1581 EM_select_face(efa1[i], 1); \
1584 if (! (efa2[i]->f & SELECT) ) { \
1585 EM_select_face(efa2[i], 1); \
1591 while (faceselcount != faceselcountold) {
1592 faceselcountold = faceselcount;
1594 efa= em->faces.first;
1596 if (efa->f & SELECT) {
1597 select_flat_neighbor(efa->e1);
1598 select_flat_neighbor(efa->e2);
1599 select_flat_neighbor(efa->e3);
1601 select_flat_neighbor(efa->e4);
1608 #undef select_flat_neighbor
1614 addqueue(curarea->win, REDRAW, 0);
1615 BIF_undo_push("Select Linked Flat Faces");
1618 void select_non_manifold(void)
1620 EditMesh *em = G.editMesh;
1625 /* Selects isolated verts, and edges that do not have 2 neighboring
1629 if(G.scene->selectmode==SCE_SELECT_FACE) {
1630 error("Doesn't work in face selection mode");
1634 eve= em->verts.first;
1636 /* this will count how many edges are connected
1642 eed= em->edges.first;
1644 /* this will count how many faces are connected to
1647 /* increase edge count for verts */
1653 efa= em->faces.first;
1655 /* increase face count for edges */
1664 /* select verts that are attached to an edge that does not
1665 * have 2 neighboring faces */
1666 eed= em->edges.first;
1668 if (eed->h==0 && eed->f1 != 2) {
1669 EM_select_edge(eed, 1);
1674 /* select isolated verts */
1675 eve= em->verts.first;
1678 if (!eve->h) eve->f |= SELECT;
1684 addqueue(curarea->win, REDRAW, 0);
1685 BIF_undo_push("Select Non Manifold");
1688 void selectswap_mesh(void) /* UI level */
1690 EditMesh *em = G.editMesh;
1695 if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1697 for(eve= em->verts.first; eve; eve= eve->next) {
1699 if(eve->f & SELECT) eve->f &= ~SELECT;
1700 else eve->f|= SELECT;
1704 else if(G.scene->selectmode & SCE_SELECT_EDGE) {
1705 for(eed= em->edges.first; eed; eed= eed->next) {
1707 EM_select_edge(eed, !(eed->f & SELECT));
1712 for(efa= em->faces.first; efa; efa= efa->next) {
1714 EM_select_face(efa, !(efa->f & SELECT));
1719 EM_selectmode_flush();
1722 allqueue(REDRAWVIEW3D, 0);
1724 BIF_undo_push("Select Swap");
1728 void deselectall_mesh(void) /* this toggles!!!, UI level */
1731 if(G.obedit->lay & G.vd->lay) {
1733 if( EM_nvertices_selected() ) {
1734 EM_clear_flag_all(SELECT);
1735 BIF_undo_push("Deselect All");
1738 EM_set_flag_all(SELECT);
1739 BIF_undo_push("Select All");
1743 allqueue(REDRAWVIEW3D, 0);
1747 void select_more(void)
1749 EditMesh *em = G.editMesh;
1754 for(eve= em->verts.first; eve; eve= eve->next) {
1755 if(eve->f & SELECT) eve->f1= 1;
1759 /* set f1 flags in vertices to select 'more' */
1760 for(eed= em->edges.first; eed; eed= eed->next) {
1762 if (eed->v1->f & SELECT)
1764 if (eed->v2->f & SELECT)
1769 /* new selected edges, but not in facemode */
1770 if(G.scene->selectmode <= SCE_SELECT_EDGE) {
1772 for(eed= em->edges.first; eed; eed= eed->next) {
1774 if(eed->v1->f1 && eed->v2->f1) EM_select_edge(eed, 1);
1778 /* new selected faces */
1779 for(efa= em->faces.first; efa; efa= efa->next) {
1781 if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1))
1782 EM_select_face(efa, 1);
1787 addqueue(curarea->win, REDRAW, 0);
1788 BIF_undo_push("Select More");
1791 void select_less(void)
1793 EditMesh *em = G.editMesh;
1797 if(G.scene->selectmode <= SCE_SELECT_EDGE) {
1798 /* eed->f1 == 1: edge with a selected and deselected vert */
1800 for(eed= em->edges.first; eed; eed= eed->next) {
1804 if ( !(eed->v1->f & SELECT) && (eed->v2->f & SELECT) )
1806 if ( (eed->v1->f & SELECT) && !(eed->v2->f & SELECT) )
1811 /* deselect edges with flag set */
1812 for(eed= em->edges.first; eed; eed= eed->next) {
1813 if (eed->h==0 && eed->f1 == 1) {
1814 EM_select_edge(eed, 0);
1817 EM_deselect_flush();
1821 /* deselect faces with 1 or more deselect edges */
1822 /* eed->f1 == mixed selection edge */
1823 for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
1825 for(efa= em->faces.first; efa; efa= efa->next) {
1827 if(efa->f & SELECT) {
1831 if(efa->e4) efa->e4->f1 |= 1;
1837 if(efa->e4) efa->e4->f1 |= 2;
1841 for(efa= em->faces.first; efa; efa= efa->next) {
1843 if(efa->e1->f1==3 || efa->e2->f1==3 || efa->e3->f1==3 || (efa->e4 && efa->e4->f1==3)) {
1844 EM_select_face(efa, 0);
1848 EM_selectmode_flush();
1853 allqueue(REDRAWVIEW3D, 0);
1857 void selectrandom_mesh(void) /* randomly selects a user-set % of vertices/edges/faces */
1859 EditMesh *em = G.editMesh;
1865 if(G.obedit==NULL || (G.obedit->lay & G.vd->lay)==0) return;
1867 /* Get the percentage of vertices to randomly select as 'randfac' */
1868 if(button(&randfac,0, 100,"Percentage:")==0) return;
1870 BLI_srand( BLI_rand() ); /* random seed */
1872 if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1873 for(eve= em->verts.first; eve; eve= eve->next) {
1875 if ( (BLI_frand() * 100) < randfac)
1880 else if(G.scene->selectmode & SCE_SELECT_EDGE) {
1881 for(eed= em->edges.first; eed; eed= eed->next) {
1883 if ( (BLI_frand() * 100) < randfac)
1884 EM_select_edge(eed, 1);
1889 for(efa= em->faces.first; efa; efa= efa->next) {
1891 if ( (BLI_frand() * 100) < randfac)
1892 EM_select_face(efa, 1);
1897 EM_selectmode_flush();
1900 allqueue(REDRAWVIEW3D, 0);
1903 void editmesh_select_by_material(int index)
1905 EditMesh *em = G.editMesh;
1908 for (efa=em->faces.first; efa; efa= efa->next) {
1909 if (efa->mat_nr==index) {
1910 EM_select_face(efa, 1);
1914 EM_selectmode_flush();
1917 void editmesh_deselect_by_material(int index)
1919 EditMesh *em = G.editMesh;
1922 for (efa=em->faces.first; efa; efa= efa->next) {
1923 if (efa->mat_nr==index) {
1924 EM_select_face(efa, 0);
1928 EM_selectmode_flush();
1931 void EM_selectmode_menu(void)
1935 if(G.scene->selectmode & SCE_SELECT_VERTEX) pupmenu_set_active(1);
1936 else if(G.scene->selectmode & SCE_SELECT_EDGE) pupmenu_set_active(2);
1937 else pupmenu_set_active(3);
1939 val= pupmenu("Select Mode%t|Vertices|Edges|Faces");
1941 if(val==1) G.scene->selectmode= SCE_SELECT_VERTEX;
1942 else if(val==2) G.scene->selectmode= SCE_SELECT_EDGE;
1943 else G.scene->selectmode= SCE_SELECT_FACE;
1945 EM_selectmode_set(); // when mode changes
1946 allqueue(REDRAWVIEW3D, 1);
1950 /* ************************* SEAMS AND EDGES **************** */
1952 void editmesh_mark_seam(int clear)
1954 EditMesh *em= G.editMesh;
1957 /* auto-enable seams drawing */
1959 if(!(G.f & G_DRAWSEAMS)) {
1961 allqueue(REDRAWBUTSEDIT, 0);
1966 eed= em->edges.first;
1968 if((eed->h==0) && (eed->f & SELECT)) {
1973 BIF_undo_push("Mark Seam");
1976 eed= em->edges.first;
1978 if((eed->h==0) && (eed->f & SELECT)) {
1983 BIF_undo_push("Clear Seam");
1986 allqueue(REDRAWVIEW3D, 0);
1992 ret= pupmenu("Edge Specials%t|Mark Seam %x1|Clear Seam %x2|Rotate Edge CW%x3|Rotate Edge CCW%x4|Loopcut%x6|Edge Slide%x5");
1997 editmesh_mark_seam(0);
2000 editmesh_mark_seam(1);
2003 edge_rotate_selected(2);
2006 edge_rotate_selected(1);
2010 BIF_undo_push("EdgeSlide");
2014 BIF_undo_push("Loopcut New");
2020 /* **************** NORMALS ************** */
2022 void righthandfaces(int select) /* makes faces righthand turning */
2024 EditMesh *em = G.editMesh;
2025 EditEdge *eed, *ed1, *ed2, *ed3, *ed4;
2026 EditFace *efa, *startvl;
2027 float maxx, nor[3], cent[3];
2028 int totsel, found, foundone, direct, turn, tria_nr;
2030 /* based at a select-connected to witness loose objects */
2032 /* count per edge the amount of faces */
2034 /* find the ultimate left, front, upper face (not manhattan dist!!) */
2035 /* also evaluate both triangle cases in quad, since these can be non-flat */
2037 /* put normal to the outside, and set the first direction flags in edges */
2039 /* then check the object, and set directions / direction-flags: but only for edges with 1 or 2 faces */
2040 /* this is in fact the 'select connected' */
2042 /* in case (selected) faces were not done: start over with 'find the ultimate ...' */
2046 eed= em->edges.first;
2048 eed->f2= 0; // edge direction
2049 eed->f1= 0; // counter
2053 /* count faces and edges */
2055 efa= em->faces.first;
2057 if(select==0 || (efa->f & SELECT) ) {
2063 if(efa->v4) efa->e4->f1++;
2071 /* from the outside to the inside */
2073 efa= em->faces.first;
2080 CalcCent3f(cent, efa->v1->co, efa->v2->co, efa->v3->co);
2081 cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
2089 CalcCent3f(cent, efa->v1->co, efa->v3->co, efa->v4->co);
2090 cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
2102 /* set first face correct: calc normal */
2105 CalcNormFloat(startvl->v1->co, startvl->v3->co, startvl->v4->co, nor);
2106 CalcCent3f(cent, startvl->v1->co, startvl->v3->co, startvl->v4->co);
2108 CalcNormFloat(startvl->v1->co, startvl->v2->co, startvl->v3->co, nor);
2109 CalcCent3f(cent, startvl->v1->co, startvl->v2->co, startvl->v3->co);
2111 /* first normal is oriented this way or the other */
2114 if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] > 0.0) flipface(startvl);
2117 if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipface(startvl);
2120 else if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipface(startvl);
2124 if(eed->v1==startvl->v1) eed->f2= 1;
2128 if(eed->v1==startvl->v2) eed->f2= 1;
2132 if(eed->v1==startvl->v3) eed->f2= 1;
2137 if(eed->v1==startvl->v4) eed->f2= 1;
2149 if(direct) efa= em->faces.first;
2150 else efa= em->faces.last;
2162 if(ed1->v1==efa->v1 && ed1->f2==1) turn= 1;
2163 if(ed1->v2==efa->v1 && ed1->f2==2) turn= 1;
2167 if(ed2->v1==efa->v2 && ed2->f2==1) turn= 1;
2168 if(ed2->v2==efa->v2 && ed2->f2==2) turn= 1;
2172 if(ed3->v1==efa->v3 && ed3->f2==1) turn= 1;
2173 if(ed3->v2==efa->v3 && ed3->f2==2) turn= 1;
2176 else if(ed4 && ed4->f2) {
2177 if(ed4->v1==efa->v4 && ed4->f2==1) turn= 1;
2178 if(ed4->v2==efa->v4 && ed4->f2==2) turn= 1;
2188 if(ed1->v1==efa->v1) ed1->f2= 2;
2190 if(ed2->v1==efa->v2) ed2->f2= 2;
2192 if(ed3->v1==efa->v3) ed3->f2= 2;
2195 if(ed4->v1==efa->v4) ed4->f2= 2;
2203 if(ed1->v1== efa->v1) ed1->f2= 1;
2205 if(ed2->v1==efa->v2) ed2->f2= 1;
2207 if(ed3->v1==efa->v3) ed3->f2= 1;
2210 if(ed4->v1==efa->v4) ed4->f2= 1;
2216 if(direct) efa= efa->next;
2217 else efa= efa->prev;
2223 recalc_editnormals();
2225 DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
2231 /* ********** ALIGN WITH VIEW **************** */
2234 static void editmesh_calc_selvert_center(float cent_r[3])
2236 EditMesh *em = G.editMesh;
2240 cent_r[0]= cent_r[1]= cent_r[0]= 0.0;
2242 for (eve= em->verts.first; eve; eve= eve->next) {
2243 if (eve->f & SELECT) {
2244 cent_r[0]+= eve->co[0];
2245 cent_r[1]+= eve->co[1];
2246 cent_r[2]+= eve->co[2];
2258 static int tface_is_selected(TFace *tf)
2260 return (!(tf->flag & TF_HIDE) && (tf->flag & TF_SELECT));
2263 static int faceselect_nfaces_selected(Mesh *me)
2267 for (i=0; i<me->totface; i++)
2268 if (tface_is_selected(&me->tface[i]))
2274 /* XXX, code for both these functions should be abstract,
2275 * then unified, then written for other things (like objects,
2276 * which would use same as vertices method), then added
2277 * to interface! Hoera! - zr
2279 void faceselect_align_view_to_selected(View3D *v3d, Mesh *me, int axis)
2281 if (!faceselect_nfaces_selected(me)) {
2282 error("No faces selected.");
2287 norm[0]= norm[1]= norm[2]= 0.0;
2288 for (i=0; i<me->totface; i++) {
2289 MFace *mf= ((MFace*) me->mface) + i;
2290 TFace *tf= ((TFace*) me->tface) + i;
2292 if (tface_is_selected(tf)) {
2293 float *v1, *v2, *v3, fno[3];
2295 v1= me->mvert[mf->v1].co;
2296 v2= me->mvert[mf->v2].co;
2297 v3= me->mvert[mf->v3].co;
2299 float *v4= me->mvert[mf->v4].co;
2300 CalcNormFloat4(v1, v2, v3, v4, fno);
2302 CalcNormFloat(v1, v2, v3, fno);
2311 view3d_align_axis_to_vector(v3d, axis, norm);
2315 void editmesh_align_view_to_selected(View3D *v3d, int axis)
2317 EditMesh *em = G.editMesh;
2318 int nselverts= EM_nvertices_selected();
2319 float norm[3]={0.0, 0.0, 0.0}; /* used for storing the mesh normal */
2322 error("No faces or vertices selected.");
2323 } else if (EM_nfaces_selected()) {
2325 for (efa= em->faces.first; efa; efa= efa->next) {
2326 if (faceselectedAND(efa, SELECT)) {
2328 if (efa->v4) CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, fno);
2329 else CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, fno);
2330 /* XXX, fixme, should be flipped intp a
2331 * consistent direction. -zr
2339 Mat4Mul3Vecfl(G.obedit->obmat, norm);
2340 view3d_align_axis_to_vector(v3d, axis, norm);
2341 } else if (nselverts>2) {
2343 EditVert *eve, *leve= NULL;
2345 editmesh_calc_selvert_center(cent);
2346 for (eve= em->verts.first; eve; eve= eve->next) {
2347 if (eve->f & SELECT) {
2350 CalcNormFloat(cent, leve->co, eve->co, tno);
2352 /* XXX, fixme, should be flipped intp a
2353 * consistent direction. -zr
2363 Mat4Mul3Vecfl(G.obedit->obmat, norm);
2364 view3d_align_axis_to_vector(v3d, axis, norm);
2365 } else if (nselverts==2) { /* Align view to edge (or 2 verts) */
2366 EditVert *eve, *leve= NULL;
2368 for (eve= em->verts.first; eve; eve= eve->next) {
2369 if (eve->f & SELECT) {
2371 norm[0]= leve->co[0] - eve->co[0];
2372 norm[1]= leve->co[1] - eve->co[1];
2373 norm[2]= leve->co[2] - eve->co[2];
2374 break; /* we know there are only 2 verts so no need to keep looking */
2379 Mat4Mul3Vecfl(G.obedit->obmat, norm);
2380 view3d_align_axis_to_vector(v3d, axis, norm);
2381 } else if (nselverts==1) { /* Align view to vert normal */
2384 for (eve= em->verts.first; eve; eve= eve->next) {
2385 if (eve->f & SELECT) {
2386 norm[0]= eve->no[0];
2387 norm[1]= eve->no[1];
2388 norm[2]= eve->no[2];
2389 break; /* we know this is the only selected vert, so no need to keep looking */
2392 Mat4Mul3Vecfl(G.obedit->obmat, norm);
2393 view3d_align_axis_to_vector(v3d, axis, norm);
2397 /* **************** VERTEX DEFORMS *************** */
2399 void vertexsmooth(void)
2401 EditMesh *em = G.editMesh;
2404 float *adror, *adr, fac;
2407 ModifierData *md= G.obedit->modifiers.first;
2409 if(G.obedit==0) return;
2412 eve= em->verts.first;
2414 if(eve->f & SELECT) teller++;
2417 if(teller==0) return;
2419 adr=adror= (float *)MEM_callocN(3*sizeof(float *)*teller, "vertsmooth");
2420 eve= em->verts.first;
2422 if(eve->f & SELECT) {
2431 /* if there is a mirror modifier with clipping, flag the verts that
2432 * are within tolerance of the plane(s) of reflection
2434 for (; md; md=md->next) {
2435 if (md->type==eModifierType_Mirror) {
2436 MirrorModifierData *mmd = (MirrorModifierData*) md;
2438 if(mmd->flag & MOD_MIR_CLIPPING) {
2439 for (eve= em->verts.first; eve; eve= eve->next) {
2440 if(eve->f & SELECT) {
2444 if (fabs(eve->co[0]) < mmd->tolerance)
2448 if (fabs(eve->co[1]) < mmd->tolerance)
2452 if (fabs(eve->co[2]) < mmd->tolerance)
2462 eed= em->edges.first;
2464 if( (eed->v1->f & SELECT) || (eed->v2->f & SELECT) ) {
2465 fvec[0]= (eed->v1->co[0]+eed->v2->co[0])/2.0;
2466 fvec[1]= (eed->v1->co[1]+eed->v2->co[1])/2.0;
2467 fvec[2]= (eed->v1->co[2]+eed->v2->co[2])/2.0;
2469 if((eed->v1->f & SELECT) && eed->v1->f1<255) {
2471 VecAddf(eed->v1->tmp.fp, eed->v1->tmp.fp, fvec);
2473 if((eed->v2->f & SELECT) && eed->v2->f1<255) {
2475 VecAddf(eed->v2->tmp.fp, eed->v2->tmp.fp, fvec);
2481 eve= em->verts.first;
2483 if(eve->f & SELECT) {
2486 fac= 0.5/(float)eve->f1;
2488 eve->co[0]= 0.5*eve->co[0]+fac*adr[0];
2489 eve->co[1]= 0.5*eve->co[1]+fac*adr[1];
2490 eve->co[2]= 0.5*eve->co[2]+fac*adr[2];
2492 /* clip if needed by mirror modifier */
2511 recalc_editnormals();
2513 allqueue(REDRAWVIEW3D, 0);
2514 DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
2515 BIF_undo_push("Vertex Smooth");
2518 void vertexnoise(void)
2520 EditMesh *em = G.editMesh;
2524 float b2, ofs, vec[3];
2526 if(G.obedit==0) return;
2528 ma= give_current_material(G.obedit, G.obedit->actcol);
2529 if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) {
2532 tex= ma->mtex[0]->tex;
2534 ofs= tex->turbul/200.0;
2536 eve= (struct EditVert *)em->verts.first;
2538 if(eve->f & SELECT) {
2540 if(tex->type==TEX_STUCCI) {
2542 b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]);
2543 if(tex->stype) ofs*=(b2*b2);
2544 vec[0]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2]));
2545 vec[1]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2]));
2546 vec[2]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs));
2548 VecAddf(eve->co, eve->co, vec);
2552 externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum);
2553 eve->co[2]+= 0.05*tin;
2559 recalc_editnormals();
2560 allqueue(REDRAWVIEW3D, 0);
2561 DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
2562 BIF_undo_push("Vertex Noise");
2565 void vertices_to_sphere(void)
2567 EditMesh *em = G.editMesh;
2570 float *curs, len, vec[3], cent[3], fac, facm, imat[3][3], bmat[3][3];
2577 if(button(&perc, 1, 100, "Percentage:")==0) return;
2582 Mat3CpyMat4(bmat, ob->obmat);
2583 Mat3Inv(imat, bmat);
2586 curs= give_cursor();
2587 cent[0]= curs[0]-ob->obmat[3][0];
2588 cent[1]= curs[1]-ob->obmat[3][1];
2589 cent[2]= curs[2]-ob->obmat[3][2];
2590 Mat3MulVecfl(imat, cent);
2594 eve= em->verts.first;
2596 if(eve->f & SELECT) {
2598 len+= VecLenf(cent, eve->co);
2604 if(len==0.0) len= 10.0;
2606 eve= em->verts.first;
2608 if(eve->f & SELECT) {
2609 vec[0]= eve->co[0]-cent[0];
2610 vec[1]= eve->co[1]-cent[1];
2611 vec[2]= eve->co[2]-cent[2];
2615 eve->co[0]= fac*(cent[0]+vec[0]*len) + facm*eve->co[0];
2616 eve->co[1]= fac*(cent[1]+vec[1]*len) + facm*eve->co[1];
2617 eve->co[2]= fac*(cent[2]+vec[2]*len) + facm*eve->co[2];
2623 recalc_editnormals();
2624 allqueue(REDRAWVIEW3D, 0);
2625 DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
2626 BIF_undo_push("To Sphere");