Blender V2.61 - r43446

editmesh_mods.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2004 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 /*
00034 
00035 editmesh_mods.c, UI level access, no geometry changes 
00036 
00037 */
00038 
00039 #include <stdlib.h>
00040 #include <string.h>
00041 
00042 #include "MEM_guardedalloc.h"
00043 
00044 #include "DNA_material_types.h"
00045 #include "DNA_meshdata_types.h"
00046 #include "DNA_modifier_types.h"
00047 #include "DNA_object_types.h"
00048 #include "DNA_scene_types.h"
00049 
00050 #include "BLI_blenlib.h"
00051 #include "BLI_math.h"
00052 #include "BLI_editVert.h"
00053 #include "BLI_rand.h"
00054 #include "BLI_utildefines.h"
00055 
00056 #include "BKE_context.h"
00057 #include "BKE_displist.h"
00058 #include "BKE_depsgraph.h"
00059 #include "BKE_mesh.h"
00060 #include "BKE_material.h"
00061 #include "BKE_paint.h"
00062 #include "BKE_report.h"
00063 #include "BKE_texture.h"
00064 
00065 #include "IMB_imbuf_types.h"
00066 #include "IMB_imbuf.h"
00067 
00068 #include "RE_render_ext.h"  /* externtex */
00069 
00070 #include "WM_api.h"
00071 #include "WM_types.h"
00072 
00073 
00074 #include "RNA_access.h"
00075 #include "RNA_define.h"
00076 
00077 #include "ED_mesh.h"
00078 #include "ED_screen.h"
00079 #include "ED_view3d.h"
00080 #include "ED_uvedit.h"
00081 
00082 #include "BIF_gl.h"
00083 
00084 #include "mesh_intern.h"
00085 
00086 #include "BLO_sys_types.h" // for intptr_t support
00087 
00088 /* XXX */
00089 static void waitcursor(int UNUSED(val)) {}
00090 static int pupmenu(const char *UNUSED(arg)) {return 0;}
00091 
00092 /* ****************************** MIRROR **************** */
00093 
00094 void EM_cache_x_mirror_vert(struct Object *ob, struct EditMesh *em)
00095 {
00096     EditVert *eve, *eve_mirror;
00097     int index= 0;
00098 
00099     for(eve= em->verts.first; eve; eve= eve->next) {
00100         eve->tmp.v= NULL;
00101     }
00102 
00103     for(eve= em->verts.first; eve; eve= eve->next, index++) {
00104         if(eve->tmp.v==NULL) {
00105             eve_mirror = editmesh_get_x_mirror_vert(ob, em, eve, eve->co, index);
00106             if(eve_mirror) {
00107                 eve->tmp.v= eve_mirror;
00108                 eve_mirror->tmp.v = eve;
00109             }
00110         }
00111     }
00112 }
00113 
00114 static void EM_select_mirrored(Object *obedit, EditMesh *em, int extend)
00115 {
00116 
00117     EditVert *eve;
00118 
00119     EM_cache_x_mirror_vert(obedit, em);
00120 
00121     for(eve= em->verts.first; eve; eve= eve->next) {
00122         if(eve->f & SELECT && eve->tmp.v && (eve->tmp.v != eve->tmp.v->tmp.v)) {
00123             eve->tmp.v->f |= SELECT;
00124 
00125             if(extend==FALSE)
00126                 eve->f &= ~SELECT;
00127 
00128             /* remove the interference */
00129             eve->tmp.v->tmp.v= NULL;
00130             eve->tmp.v= NULL;
00131         }
00132     }
00133 }
00134 
00135 void EM_automerge(Scene *scene, Object *obedit, int update)
00136 {
00137     Mesh *me= obedit ? obedit->data : NULL; /* can be NULL */
00138     /* int len; */ /* UNUSED */
00139 
00140     if ((scene->toolsettings->automerge) &&
00141         (obedit && obedit->type==OB_MESH && (obedit->mode & OB_MODE_EDIT))
00142       ) {
00143         EditMesh *em= me->edit_mesh;
00144         int totvert= em->totvert, totedge= em->totedge, totface= em->totface;
00145 
00146         /* len = */ /* UNUSED */ removedoublesflag(em, 1, 1, scene->toolsettings->doublimit);
00147         if (totvert != em->totvert || totedge != em->totedge || totface != em->totface) {
00148             if (update) {
00149                 DAG_id_tag_update(&me->id, 0);
00150             }
00151         }
00152     }
00153 }
00154 
00155 /* ****************************** SELECTION ROUTINES **************** */
00156 
00157 unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0;  /* set in drawobject.c ... for colorindices */
00158 
00159 /* facilities for border select and circle select */
00160 static char *selbuf= NULL;
00161 
00162 /* opengl doesn't support concave... */
00163 static void draw_triangulated(int mcords[][2], short tot)
00164 {
00165     ListBase lb={NULL, NULL};
00166     DispList *dl;
00167     float *fp;
00168     int a;
00169     
00170     /* make displist */
00171     dl= MEM_callocN(sizeof(DispList), "poly disp");
00172     dl->type= DL_POLY;
00173     dl->parts= 1;
00174     dl->nr= tot;
00175     dl->verts= fp=  MEM_callocN(tot*3*sizeof(float), "poly verts");
00176     BLI_addtail(&lb, dl);
00177     
00178     for(a=0; a<tot; a++, fp+=3) {
00179         fp[0]= (float)mcords[a][0];
00180         fp[1]= (float)mcords[a][1];
00181     }
00182     
00183     /* do the fill */
00184     filldisplist(&lb, &lb, 0);
00185 
00186     /* do the draw */
00187     dl= lb.first;   /* filldisplist adds in head of list */
00188     if(dl->type==DL_INDEX3) {
00189         int *index;
00190         
00191         a= dl->parts;
00192         fp= dl->verts;
00193         index= dl->index;
00194         glBegin(GL_TRIANGLES);
00195         while(a--) {
00196             glVertex3fv(fp+3*index[0]);
00197             glVertex3fv(fp+3*index[1]);
00198             glVertex3fv(fp+3*index[2]);
00199             index+= 3;
00200         }
00201         glEnd();
00202     }
00203     
00204     freedisplist(&lb);
00205 }
00206 
00207 
00208 /* reads rect, and builds selection array for quick lookup */
00209 /* returns if all is OK */
00210 int EM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
00211 {
00212     struct ImBuf *buf;
00213     unsigned int *dr;
00214     int a;
00215     
00216     if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
00217     
00218     buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
00219     if(buf==NULL) return 0;
00220     if(em_vertoffs==0) return 0;
00221 
00222     dr = buf->rect;
00223     
00224     /* build selection lookup */
00225     selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
00226     
00227     a= (xmax-xmin+1)*(ymax-ymin+1);
00228     while(a--) {
00229         if(*dr>0 && *dr<=em_vertoffs) 
00230             selbuf[*dr]= 1;
00231         dr++;
00232     }
00233     IMB_freeImBuf(buf);
00234     return 1;
00235 }
00236 
00237 int EM_check_backbuf(unsigned int index)
00238 {
00239     if(selbuf==NULL) return 1;
00240     if(index>0 && index<=em_vertoffs)
00241         return selbuf[index];
00242     return 0;
00243 }
00244 
00245 void EM_free_backbuf(void)
00246 {
00247     if(selbuf) MEM_freeN(selbuf);
00248     selbuf= NULL;
00249 }
00250 
00251 /* mcords is a polygon mask
00252    - grab backbuffer,
00253    - draw with black in backbuffer, 
00254    - grab again and compare
00255    returns 'OK' 
00256 */
00257 int EM_mask_init_backbuf_border(ViewContext *vc, int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
00258 {
00259     unsigned int *dr, *drm;
00260     struct ImBuf *buf, *bufmask;
00261     int a;
00262     GLboolean is_cull;
00263     
00264     /* method in use for face selecting too */
00265     if(vc->obedit==NULL) {
00266         if(paint_facesel_test(vc->obact));
00267         else if(paint_vertsel_test(vc->obact));
00268         else return 0;
00269     }
00270     else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
00271 
00272     buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
00273     if(buf==NULL) return 0;
00274     if(em_vertoffs==0) return 0;
00275 
00276     dr = buf->rect;
00277 
00278     /* draw the mask */
00279     glDisable(GL_DEPTH_TEST);
00280     
00281     glColor3ub(0, 0, 0);
00282 
00283     /* some opengl drivers have problems with draw direction */
00284     glGetBooleanv(GL_CULL_FACE, &is_cull);
00285     if(is_cull) glDisable(GL_CULL_FACE);
00286     
00287     /* yah, opengl doesn't do concave... tsk! */
00288     ED_region_pixelspace(vc->ar);
00289     draw_triangulated(mcords, tot);
00290     
00291     glBegin(GL_LINE_LOOP);  /* for zero sized masks, lines */
00292     for(a=0; a<tot; a++) glVertex2iv(mcords[a]);
00293     glEnd();
00294     
00295     glFinish(); /* to be sure readpixels sees mask */
00296     
00297     /* grab mask */
00298     bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
00299     drm = bufmask->rect;
00300     if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
00301     
00302     /* build selection lookup */
00303     selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
00304     
00305     a= (xmax-xmin+1)*(ymax-ymin+1);
00306     while(a--) {
00307         if(*dr>0 && *dr<=em_vertoffs && *drm==0) selbuf[*dr]= 1;
00308         dr++; drm++;
00309     }
00310     IMB_freeImBuf(buf);
00311     IMB_freeImBuf(bufmask);
00312     
00313     if(is_cull) glEnable(GL_CULL_FACE);
00314 
00315     return 1;
00316     
00317 }
00318 
00319 /* circle shaped sample area */
00320 int EM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
00321 {
00322     struct ImBuf *buf;
00323     unsigned int *dr;
00324     short xmin, ymin, xmax, ymax, xc, yc;
00325     int radsq;
00326     
00327     /* method in use for face selecting too */
00328     if(vc->obedit==NULL) {
00329         if(paint_facesel_test(vc->obact));
00330         else if (paint_vertsel_test(vc->obact));
00331         else return 0;
00332     }
00333     else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
00334     
00335     xmin= xs-rads; xmax= xs+rads;
00336     ymin= ys-rads; ymax= ys+rads;
00337     buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
00338     if(em_vertoffs==0) return 0;
00339     if(buf==NULL) return 0;
00340 
00341     dr = buf->rect;
00342     
00343     /* build selection lookup */
00344     selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
00345     radsq= rads*rads;
00346     for(yc= -rads; yc<=rads; yc++) {
00347         for(xc= -rads; xc<=rads; xc++, dr++) {
00348             if(xc*xc + yc*yc < radsq) {
00349                 if(*dr>0 && *dr<=em_vertoffs) selbuf[*dr]= 1;
00350             }
00351         }
00352     }
00353 
00354     IMB_freeImBuf(buf);
00355     return 1;
00356     
00357 }
00358 
00359 static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index)
00360 {
00361     struct { int mval[2]; short pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } *data = userData;
00362 
00363     if (data->pass==0) {
00364         if (index<=data->lastIndex)
00365             return;
00366     } else {
00367         if (index>data->lastIndex)
00368             return;
00369     }
00370 
00371     if (data->dist>3) {
00372         int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
00373         if ((eve->f&1) == data->select) {
00374             if (data->strict == 1)
00375                 return;
00376             else
00377                 temp += 5;
00378         }
00379 
00380         if (temp<data->dist) {
00381             data->dist = temp;
00382             data->closest = eve;
00383             data->closestIndex = index;
00384         }
00385     }
00386 }
00387 
00388 
00389 
00390 
00391 static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
00392 {
00393     EditMesh *em= (EditMesh *)handle;
00394     EditVert *eve = BLI_findlink(&em->verts, index-1);
00395 
00396     if(eve && (eve->f & SELECT)) return 0;
00397     return 1; 
00398 }
00408 EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
00409 {
00410     if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){
00411         int distance;
00412         unsigned int index;
00413         EditVert *eve;
00414         
00415         if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest); 
00416         else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL); 
00417         
00418         eve = BLI_findlink(&vc->em->verts, index-1);
00419         
00420         if(eve && distance < *dist) {
00421             *dist = distance;
00422             return eve;
00423         } else {
00424             return NULL;
00425         }
00426             
00427     }
00428     else {
00429         struct { int mval[2]; short pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } data;
00430         static int lastSelectedIndex=0;
00431         static EditVert *lastSelected=NULL;
00432 
00433         if (lastSelected && BLI_findlink(&vc->em->verts, lastSelectedIndex)!=lastSelected) {
00434             lastSelectedIndex = 0;
00435             lastSelected = NULL;
00436         }
00437 
00438         data.lastIndex = lastSelectedIndex;
00439         data.mval[0] = vc->mval[0];
00440         data.mval[1] = vc->mval[1];
00441         data.select = sel;
00442         data.dist = *dist;
00443         data.strict = strict;
00444         data.closest = NULL;
00445         data.closestIndex = 0;
00446 
00447         data.pass = 0;
00448 
00449         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
00450 
00451         mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_CLIP_TEST_RV3D_CLIPPING);
00452 
00453         if (data.dist>3) {
00454             data.pass = 1;
00455             mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_CLIP_TEST_RV3D_CLIPPING);
00456         }
00457 
00458         *dist = data.dist;
00459         lastSelected = data.closest;
00460         lastSelectedIndex = data.closestIndex;
00461 
00462         return data.closest;
00463     }
00464 }
00465 
00466 /* returns labda for closest distance v1 to line-piece v2-v3 */
00467 static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3) 
00468 {
00469     float rc[2], len;
00470     
00471     rc[0]= v3[0]-v2[0];
00472     rc[1]= v3[1]-v2[1];
00473     len= rc[0]*rc[0]+ rc[1]*rc[1];
00474     if(len==0.0f)
00475         return 0.0f;
00476     
00477     return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
00478 }
00479 
00480 /* note; uses v3d, so needs active 3d window */
00481 static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index))
00482 {
00483     struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } *data = userData;
00484     float v1[2], v2[2];
00485     int distance;
00486 
00487     ED_view3d_local_clipping(data->vc.rv3d, data->vc.obedit->obmat); /* for local clipping lookups */
00488 
00489     v1[0] = x0;
00490     v1[1] = y0;
00491     v2[0] = x1;
00492     v2[1] = y1;
00493 
00494     distance= dist_to_line_segment_v2(data->mval, v1, v2);
00495 
00496 
00497     if(eed->f & SELECT) distance+=5;
00498     if(distance < data->dist) {
00499         if(data->vc.rv3d->rflag & RV3D_CLIPPING) {
00500             float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
00501             float vec[3];
00502 
00503             vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
00504             vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
00505             vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
00506 
00507             if(ED_view3d_test_clipping(data->vc.rv3d, vec, 1)==0) {
00508                 data->dist = distance;
00509                 data->closest = eed;
00510             }
00511         }
00512         else {
00513             data->dist = distance;
00514             data->closest = eed;
00515         }
00516     }
00517 }
00518 EditEdge *findnearestedge(ViewContext *vc, int *dist)
00519 {
00520 
00521     if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
00522         int distance;
00523         unsigned int index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_solidoffs, em_wireoffs, &distance,0, NULL, NULL);
00524         EditEdge *eed = BLI_findlink(&vc->em->edges, index-1);
00525 
00526         if (eed && distance<*dist) {
00527             *dist = distance;
00528             return eed;
00529         } else {
00530             return NULL;
00531         }
00532     }
00533     else {
00534         struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } data;
00535 
00536         data.vc= *vc;
00537         data.mval[0] = vc->mval[0];
00538         data.mval[1] = vc->mval[1];
00539         data.dist = *dist;
00540         data.closest = NULL;
00541 
00542         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
00543         mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, V3D_CLIP_TEST_REGION);
00544 
00545         *dist = data.dist;
00546         return data.closest;
00547     }
00548 }
00549 
00550 static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int UNUSED(index))
00551 {
00552     struct { int mval[2]; int dist; EditFace *toFace; } *data = userData;
00553 
00554     if (efa==data->toFace) {
00555         int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
00556 
00557         if (temp<data->dist)
00558             data->dist = temp;
00559     }
00560 }
00561 static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int y, int index)
00562 {
00563     struct { int mval[2]; short pass; int dist, lastIndex, closestIndex; EditFace *closest; } *data = userData;
00564 
00565     if (data->pass==0) {
00566         if (index<=data->lastIndex)
00567             return;
00568     } else {
00569         if (index>data->lastIndex)
00570             return;
00571     }
00572 
00573     if (data->dist>3) {
00574         int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
00575 
00576         if (temp<data->dist) {
00577             data->dist = temp;
00578             data->closest = efa;
00579             data->closestIndex = index;
00580         }
00581     }
00582 }
00583 static EditFace *findnearestface(ViewContext *vc, int *dist)
00584 {
00585 
00586     if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
00587         unsigned int index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
00588         EditFace *efa = BLI_findlink(&vc->em->faces, index-1);
00589 
00590         if (efa) {
00591             struct { int mval[2]; int dist; EditFace *toFace; } data;
00592 
00593             data.mval[0] = vc->mval[0];
00594             data.mval[1] = vc->mval[1];
00595             data.dist = 0x7FFF;     /* largest short */
00596             data.toFace = efa;
00597 
00598             ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
00599             mesh_foreachScreenFace(vc, findnearestface__getDistance, &data);
00600 
00601             if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) {  /* only faces, no dist check */
00602                 *dist= data.dist;
00603                 return efa;
00604             }
00605         }
00606         
00607         return NULL;
00608     }
00609     else {
00610         struct { int mval[2]; short pass; int dist, lastIndex, closestIndex; EditFace *closest; } data;
00611         static int lastSelectedIndex=0;
00612         static EditFace *lastSelected=NULL;
00613 
00614         if (lastSelected && BLI_findlink(&vc->em->faces, lastSelectedIndex)!=lastSelected) {
00615             lastSelectedIndex = 0;
00616             lastSelected = NULL;
00617         }
00618 
00619         data.lastIndex = lastSelectedIndex;
00620         data.mval[0] = vc->mval[0];
00621         data.mval[1] = vc->mval[1];
00622         data.dist = *dist;
00623         data.closest = NULL;
00624         data.closestIndex = 0;
00625 
00626         data.pass = 0;
00627 
00628         ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
00629         mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
00630 
00631         if (data.dist>3) {
00632             data.pass = 1;
00633             mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
00634         }
00635 
00636         *dist = data.dist;
00637         lastSelected = data.closest;
00638         lastSelectedIndex = data.closestIndex;
00639 
00640         return data.closest;
00641     }
00642 }
00643 
00644 /* best distance based on screen coords. 
00645    use em->selectmode to define how to use 
00646    selected vertices and edges get disadvantage
00647    return 1 if found one
00648 */
00649 static int unified_findnearest(ViewContext *vc, EditVert **eve, EditEdge **eed, EditFace **efa) 
00650 {
00651     EditMesh *em= vc->em;
00652     int dist= 75;
00653     
00654     *eve= NULL;
00655     *eed= NULL;
00656     *efa= NULL;
00657     
00658     /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
00659     view3d_validate_backbuf(vc);
00660     
00661     if(em->selectmode & SCE_SELECT_VERTEX)
00662         *eve= findnearestvert(vc, &dist, SELECT, 0);
00663     if(em->selectmode & SCE_SELECT_FACE)
00664         *efa= findnearestface(vc, &dist);
00665 
00666     dist-= 20;  /* since edges select lines, we give dots advantage of 20 pix */
00667     if(em->selectmode & SCE_SELECT_EDGE)
00668         *eed= findnearestedge(vc, &dist);
00669 
00670     /* return only one of 3 pointers, for frontbuffer redraws */
00671     if(*eed) {
00672         *efa= NULL; *eve= NULL;
00673     }
00674     else if(*efa) {
00675         *eve= NULL;
00676     }
00677     
00678     return (*eve || *eed || *efa);
00679 }
00680 
00681 
00682 /* ****************  SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
00683 
00684 /* selects new faces/edges/verts based on the existing selection */
00685 
00686 /* VERT GROUP */
00687 
00688 #define SIMVERT_NORMAL  0
00689 #define SIMVERT_FACE    1
00690 #define SIMVERT_VGROUP  2
00691 #define SIMVERT_TOT     3
00692 
00693 /* EDGE GROUP */
00694 
00695 #define SIMEDGE_LENGTH      101
00696 #define SIMEDGE_DIR         102
00697 #define SIMEDGE_FACE        103
00698 #define SIMEDGE_FACE_ANGLE  104
00699 #define SIMEDGE_CREASE      105
00700 #define SIMEDGE_SEAM        106
00701 #define SIMEDGE_SHARP       107
00702 #define SIMEDGE_TOT         108
00703 
00704 /* FACE GROUP */
00705 
00706 #define SIMFACE_MATERIAL    201
00707 #define SIMFACE_IMAGE       202
00708 #define SIMFACE_AREA        203
00709 #define SIMFACE_PERIMETER   204
00710 #define SIMFACE_NORMAL      205
00711 #define SIMFACE_COPLANAR    206
00712 #define SIMFACE_TOT         207
00713 
00714 static EnumPropertyItem prop_similar_types[] = {
00715     {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
00716     {SIMVERT_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
00717     {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
00718     {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
00719     {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
00720     {SIMEDGE_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
00721     {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
00722     {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
00723     {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
00724     {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
00725     {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
00726     {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
00727     {SIMFACE_AREA, "AREA", 0, "Area", ""},
00728     {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
00729     {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
00730     {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
00731     {0, NULL, 0, NULL, NULL}
00732 };
00733 
00734 
00735 /* this as a way to compare the ares, perim  of 2 faces thay will scale to different sizes
00736 *0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
00737 #define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5f) <= b))
00738 
00739 static int similar_face_select__internal(EditMesh *em, int mode, float thresh)
00740 {
00741     EditFace *efa, *base_efa=NULL;
00742     unsigned int selcount=0; /*count how many new faces we select*/
00743     
00744     /*deselcount, count how many deselected faces are left, so we can bail out early
00745     also means that if there are no deselected faces, we can avoid a lot of looping */
00746     unsigned int deselcount=0; 
00747     short ok=0;
00748     
00749     for(efa= em->faces.first; efa; efa= efa->next) {
00750         if (!efa->h) {
00751             if (efa->f & SELECT) {
00752                 efa->f1=1;
00753                 ok=1;
00754             } else {
00755                 efa->f1=0;
00756                 deselcount++; /* a deselected face we may select later */
00757             }
00758         }
00759     }
00760     
00761     if (!ok || !deselcount) /* no data selected OR no more data to select */
00762         return 0;
00763     
00764     if (mode==SIMFACE_AREA) {
00765         for(efa= em->faces.first; efa; efa= efa->next) {
00766             efa->tmp.fp= EM_face_area(efa);
00767         }
00768     } else if (mode==SIMFACE_PERIMETER) {
00769         for(efa= em->faces.first; efa; efa= efa->next) {
00770             efa->tmp.fp= EM_face_perimeter(efa);
00771         }
00772     }
00773     
00774     for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) {
00775         if (base_efa->f1) { /* This was one of the faces originaly selected */
00776             if (mode==SIMFACE_MATERIAL) { /* same material */
00777                 for(efa= em->faces.first; efa; efa= efa->next) {
00778                     if (
00779                         !(efa->f & SELECT) &&
00780                         !efa->h &&
00781                         base_efa->mat_nr == efa->mat_nr
00782                     ) {
00783                         EM_select_face(efa, 1);
00784                         selcount++;
00785                         deselcount--;
00786                         if (!deselcount) /*have we selected all posible faces?, if so return*/
00787                             return selcount;
00788                     }
00789                 }
00790             } else if (mode==SIMFACE_IMAGE) { /* same image */
00791                 MTFace *tf, *base_tf;
00792 
00793                 base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data,
00794                                                      CD_MTFACE);
00795 
00796                 if(!base_tf)
00797                     return selcount;
00798 
00799                 for(efa= em->faces.first; efa; efa= efa->next) {
00800                     if (!(efa->f & SELECT) && !efa->h) {
00801                         tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data,
00802                                                         CD_MTFACE);
00803 
00804                         if(base_tf->tpage == tf->tpage) {
00805                             EM_select_face(efa, 1);
00806                             selcount++;
00807                             deselcount--;
00808                             if (!deselcount) /*have we selected all posible faces?, if so return*/
00809                                 return selcount;
00810                         }
00811                     }
00812                 }
00813             } else if (mode==SIMFACE_AREA || mode==SIMFACE_PERIMETER) { /* same area OR same perimeter, both use the same temp var */
00814                 for(efa= em->faces.first; efa; efa= efa->next) {
00815                     if (
00816                         (!(efa->f & SELECT) && !efa->h) &&
00817                         SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp)
00818                     ) {
00819                         EM_select_face(efa, 1);
00820                         selcount++;
00821                         deselcount--;
00822                         if (!deselcount) /*have we selected all posible faces?, if so return*/
00823                             return selcount;
00824                     }
00825                 }
00826             } else if (mode==SIMFACE_NORMAL) {
00827                 float angle;
00828                 for(efa= em->faces.first; efa; efa= efa->next) {
00829                     if (!(efa->f & SELECT) && !efa->h) {
00830                         angle= RAD2DEGF(angle_v3v3(base_efa->n, efa->n));
00831                         if (angle/180.0f<=thresh) {
00832                             EM_select_face(efa, 1);
00833                             selcount++;
00834                             deselcount--;
00835                             if (!deselcount) /*have we selected all posible faces?, if so return*/
00836                                 return selcount;
00837                         }
00838                     }
00839                 }
00840             } else if (mode==SIMFACE_COPLANAR) { /* same planer */
00841                 float angle, base_dot, dot;
00842                 base_dot= dot_v3v3(base_efa->cent, base_efa->n);
00843                 for(efa= em->faces.first; efa; efa= efa->next) {
00844                     if (!(efa->f & SELECT) && !efa->h) {
00845                         angle= RAD2DEGF(angle_v3v3(base_efa->n, efa->n));
00846                         if (angle/180.0f<=thresh) {
00847                             dot=dot_v3v3(efa->cent, base_efa->n);
00848                             if (fabsf(base_dot-dot) <= thresh) {
00849                                 EM_select_face(efa, 1);
00850                                 selcount++;
00851                                 deselcount--;
00852                                 if (!deselcount) /*have we selected all posible faces?, if so return*/
00853                                     return selcount;
00854                             }
00855                         }
00856                     }
00857                 }
00858             }
00859         }
00860     } /* end base_efa loop */
00861     return selcount;
00862 }
00863 
00864 static int similar_face_select_exec(bContext *C, wmOperator *op)
00865 {
00866     Object *obedit= CTX_data_edit_object(C);
00867     Mesh *me= obedit->data;
00868     EditMesh *em= BKE_mesh_get_editmesh(me); 
00869 
00870     int selcount = similar_face_select__internal(em, RNA_enum_get(op->ptr, "type"), RNA_float_get(op->ptr, "threshold"));
00871     
00872     if (selcount) {
00873         /* here was an edge-mode only select flush case, has to be generalized */
00874         EM_selectmode_flush(em);
00875         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
00876     }
00877     
00878     BKE_mesh_end_editmesh(me, em);
00879     return OPERATOR_FINISHED;
00880 }   
00881 
00882 /* ***************************************************** */
00883 
00884 static int similar_edge_select__internal(EditMesh *em, int mode, float thresh)
00885 {
00886     EditEdge *eed, *base_eed=NULL;
00887     unsigned int selcount=0; /* count how many new edges we select*/
00888     
00889     /*count how many visible selected edges there are,
00890     so we can return when there are none left */
00891     unsigned int deselcount=0;
00892     
00893     short ok=0;
00894     
00895     for(eed= em->edges.first; eed; eed= eed->next) {
00896         if (!eed->h) {
00897             if (eed->f & SELECT) {
00898                 eed->f1=1;
00899                 ok=1;
00900             } else {
00901                 eed->f1=0;
00902                 deselcount++;
00903             }
00904             /* set all eed->tmp.l to 0 we use it later.
00905             for counting face users*/
00906             eed->tmp.l=0;
00907             eed->f2=0; /* only for mode SIMEDGE_FACE_ANGLE, edge animations */
00908         }
00909     }
00910     
00911     if (!ok || !deselcount) /* no data selected OR no more data to select*/
00912         return 0;
00913     
00914     if (mode==SIMEDGE_LENGTH) { /*store length*/
00915         for(eed= em->edges.first; eed; eed= eed->next) {
00916             if (!eed->h) /* dont calc data for hidden edges*/
00917                 eed->tmp.fp= len_v3v3(eed->v1->co, eed->v2->co);
00918         }
00919     } else if (mode==SIMEDGE_FACE) { /*store face users*/
00920         EditFace *efa;
00921         /* cound how many faces each edge uses use tmp->l */
00922         for(efa= em->faces.first; efa; efa= efa->next) {
00923             efa->e1->tmp.l++;
00924             efa->e2->tmp.l++;
00925             efa->e3->tmp.l++;
00926             if (efa->e4) efa->e4->tmp.l++;
00927         }
00928     } else if (mode==SIMEDGE_FACE_ANGLE) { /*store edge angles */
00929         EditFace *efa;
00930         int j;
00931         /* cound how many faces each edge uses use tmp.l */
00932         for(efa= em->faces.first; efa; efa= efa->next) {
00933             /* here we use the edges temp data to assign a face
00934             if a face has already been assigned (eed->f2==1)
00935             we calculate the angle between the current face and
00936             the edges previously found face.
00937             store the angle in eed->tmp.fp (loosing the face eed->tmp.f)
00938             but tagging eed->f2==2, so we know not to look at it again.
00939             This only works for edges that connect to 2 faces. but its good enough
00940             */
00941             
00942             /* se we can loop through face edges*/
00943             j=0;
00944             eed= efa->e1;
00945             while (j<4) {
00946                 if (j==1) eed= efa->e2;
00947                 else if (j==2) eed= efa->e3;
00948                 else if (j==3) {
00949                     eed= efa->e4;
00950                     if (!eed)
00951                         break;
00952                 } /* done looping */
00953                 
00954                 if (!eed->h) { /* dont calc data for hidden edges*/
00955                     if (eed->f2==2)
00956                         break;
00957                     else if (eed->f2==0) /* first access, assign the face */
00958                         eed->tmp.f= efa;
00959                     else if (eed->f2==1) /* second, we assign the angle*/
00960                         eed->tmp.fp= RAD2DEGF(angle_v3v3(eed->tmp.f->n, efa->n))/180;
00961                     eed->f2++; /* f2==0 no face assigned. f2==1 one face found. f2==2 angle calculated.*/
00962                 }
00963                 j++;
00964             }
00965         }
00966     }
00967     
00968     for(base_eed= em->edges.first; base_eed; base_eed= base_eed->next) {
00969         if (base_eed->f1) {
00970             if (mode==SIMEDGE_LENGTH) { /* same length */
00971                 for(eed= em->edges.first; eed; eed= eed->next) {
00972                     if (
00973                         !(eed->f & SELECT) &&
00974                         !eed->h &&
00975                         SCALE_CMP(base_eed->tmp.fp, eed->tmp.fp)
00976                     ) {
00977                         EM_select_edge(eed, 1);
00978                         selcount++;
00979                         deselcount--;
00980                         if (!deselcount) /*have we selected all posible faces?, if so return*/
00981                             return selcount;
00982                     }
00983                 }
00984             } else if (mode==SIMEDGE_DIR) { /* same direction */
00985                 float base_dir[3], dir[3], angle;
00986                 sub_v3_v3v3(base_dir, base_eed->v1->co, base_eed->v2->co);
00987                 for(eed= em->edges.first; eed; eed= eed->next) {
00988                     if (!(eed->f & SELECT) && !eed->h) {
00989                         sub_v3_v3v3(dir, eed->v1->co, eed->v2->co);
00990                         angle= RAD2DEGF(angle_v3v3(base_dir, dir));
00991                         
00992                         if (angle>90.0f) /* use the smallest angle between the edges */
00993                             angle= fabsf(angle-180.0f);
00994                         
00995                         if (angle / 90.0f<=thresh) {
00996                             EM_select_edge(eed, 1);
00997                             selcount++;
00998                             deselcount--;
00999                             if (!deselcount) /*have we selected all posible faces?, if so return*/
01000                                 return selcount;
01001                         }
01002                     }
01003                 }
01004             } else if (mode==SIMEDGE_FACE) { /* face users */               
01005                 for(eed= em->edges.first; eed; eed= eed->next) {
01006                     if (
01007                         !(eed->f & SELECT) &&
01008                         !eed->h &&
01009                         base_eed->tmp.l==eed->tmp.l
01010                     ) {
01011                         EM_select_edge(eed, 1);
01012                         selcount++;
01013                         deselcount--;
01014                         if (!deselcount) /*have we selected all posible faces?, if so return*/
01015                             return selcount;
01016                     }
01017                 }
01018             } else if (mode==SIMEDGE_FACE_ANGLE && base_eed->f2==2) { /* edge angles, f2==2 means the edge has an angle. */             
01019                 for(eed= em->edges.first; eed; eed= eed->next) {
01020                     if (
01021                         !(eed->f & SELECT) &&
01022                         !eed->h &&
01023                         eed->f2==2 &&
01024                         (fabsf(base_eed->tmp.fp-eed->tmp.fp)<=thresh)
01025                     ) {
01026                         EM_select_edge(eed, 1);
01027                         selcount++;
01028                         deselcount--;
01029                         if (!deselcount) /*have we selected all posible faces?, if so return*/
01030                             return selcount;
01031                     }
01032                 }
01033             } else if (mode==SIMEDGE_CREASE) { /* edge crease */
01034                 for(eed= em->edges.first; eed; eed= eed->next) {
01035                     if (
01036                         !(eed->f & SELECT) &&
01037                         !eed->h &&
01038                         (fabsf(base_eed->crease-eed->crease) <= thresh)
01039                     ) {
01040                         EM_select_edge(eed, 1);
01041                         selcount++;
01042                         deselcount--;
01043                         if (!deselcount) /*have we selected all posible faces?, if so return*/
01044                             return selcount;
01045                     }
01046                 }
01047             } else if (mode==SIMEDGE_SEAM) { /* edge seam */
01048                 for(eed= em->edges.first; eed; eed= eed->next) {
01049                     if (
01050                         !(eed->f & SELECT) &&
01051                         !eed->h &&
01052                         (eed->seam == base_eed->seam)
01053                     ) {
01054                         EM_select_edge(eed, 1);
01055                         selcount++;
01056                         deselcount--;
01057                         if (!deselcount) /*have we selected all posible faces?, if so return*/
01058                             return selcount;
01059                     }
01060                 }
01061             } else if (mode==SIMEDGE_SHARP) { /* edge sharp */
01062                 for(eed= em->edges.first; eed; eed= eed->next) {
01063                     if (
01064                         !(eed->f & SELECT) &&
01065                         !eed->h &&
01066                         (eed->sharp == base_eed->sharp)
01067                     ) {
01068                         EM_select_edge(eed, 1);
01069                         selcount++;
01070                         deselcount--;
01071                         if (!deselcount) /*have we selected all posible faces?, if so return*/
01072                             return selcount;
01073                     }
01074                 }
01075             }
01076         }
01077     }   
01078     return selcount;
01079 }
01080 /* wrap the above function but do selection flushing edge to face */
01081 static int similar_edge_select_exec(bContext *C, wmOperator *op)
01082 {
01083     Object *obedit= CTX_data_edit_object(C);
01084     Mesh *me= obedit->data;
01085     EditMesh *em= BKE_mesh_get_editmesh(me); 
01086 
01087     int selcount = similar_edge_select__internal(em, RNA_enum_get(op->ptr, "type"), RNA_float_get(op->ptr, "threshold"));
01088     
01089     if (selcount) {
01090         /* here was an edge-mode only select flush case, has to be generalized */
01091         EM_selectmode_flush(em);
01092         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
01093     }
01094 
01095     BKE_mesh_end_editmesh(me, em);
01096     return OPERATOR_FINISHED;
01097 }
01098 
01099 /* ********************************* */
01100 
01101 static int similar_vert_select_exec(bContext *C, wmOperator *op)
01102 {
01103     Object *obedit= CTX_data_edit_object(C);
01104     Mesh *me= obedit->data;
01105     EditMesh *em= BKE_mesh_get_editmesh(me); 
01106     EditVert *eve, *base_eve=NULL;
01107     unsigned int selcount=0; /* count how many new edges we select*/
01108     
01109     /*count how many visible selected edges there are,
01110     so we can return when there are none left */
01111     unsigned int deselcount=0;
01112     int mode= RNA_enum_get(op->ptr, "type");
01113     float thresh = RNA_float_get(op->ptr, "threshold");
01114     
01115     short ok=0;
01116     
01117     for(eve= em->verts.first; eve; eve= eve->next) {
01118         if (!eve->h) {
01119             if (eve->f & SELECT) {
01120                 eve->f1=1;
01121                 ok=1;
01122             } else {
01123                 eve->f1=0;
01124                 deselcount++;
01125             }
01126             /* set all eve->tmp.l to 0 we use them later.*/
01127             eve->tmp.l=0;
01128         }
01129         
01130     }
01131     
01132     if (!ok || !deselcount) { /* no data selected OR no more data to select*/
01133         BKE_mesh_end_editmesh(me, em);
01134         return OPERATOR_CANCELLED;
01135     }
01136     
01137     if(mode == SIMVERT_FACE) {
01138         /* store face users */
01139         EditFace *efa;
01140         
01141         /* count how many faces each edge uses use tmp->l */
01142         for(efa= em->faces.first; efa; efa= efa->next) {
01143             efa->v1->tmp.l++;
01144             efa->v2->tmp.l++;
01145             efa->v3->tmp.l++;
01146             if (efa->v4) efa->v4->tmp.l++;
01147         }
01148     }
01149     
01150     
01151     for(base_eve= em->verts.first; base_eve; base_eve= base_eve->next) {
01152         if (base_eve->f1) {
01153                 
01154             if(mode == SIMVERT_NORMAL) {
01155                 float angle;
01156                 for(eve= em->verts.first; eve; eve= eve->next) {
01157                     if (!(eve->f & SELECT) && !eve->h) {
01158                         angle= RAD2DEGF(angle_v3v3(base_eve->no, eve->no));
01159                         if (angle/180.0f<=thresh) {
01160                             eve->f |= SELECT;
01161                             selcount++;
01162                             deselcount--;
01163                             if (!deselcount) {/*have we selected all posible faces?, if so return*/
01164                                 BKE_mesh_end_editmesh(me, em);
01165                                 return OPERATOR_FINISHED;
01166                             }
01167                         }
01168                     }
01169                 }
01170             }
01171             else if(mode == SIMVERT_FACE) {
01172                 for(eve= em->verts.first; eve; eve= eve->next) {
01173                     if (
01174                         !(eve->f & SELECT) &&
01175                         !eve->h &&
01176                         base_eve->tmp.l==eve->tmp.l
01177                     ) {
01178                         eve->f |= SELECT;
01179                         selcount++;
01180                         deselcount--;
01181                         if (!deselcount) {/*have we selected all posible faces?, if so return*/
01182                             BKE_mesh_end_editmesh(me, em);
01183                             return OPERATOR_FINISHED;
01184                         }
01185                     }
01186                 }
01187             } 
01188             else if(mode == SIMVERT_VGROUP) {
01189                 MDeformVert *dvert, *base_dvert;
01190                 short i, j; /* weight index */
01191 
01192                 base_dvert= CustomData_em_get(&em->vdata, base_eve->data,
01193                     CD_MDEFORMVERT);
01194 
01195                 if (!base_dvert || base_dvert->totweight == 0) {
01196                     BKE_mesh_end_editmesh(me, em);
01197                     return OPERATOR_FINISHED;
01198                 }
01199                 
01200                 for(eve= em->verts.first; eve; eve= eve->next) {
01201                     dvert= CustomData_em_get(&em->vdata, eve->data,
01202                         CD_MDEFORMVERT);
01203 
01204                     if (dvert && !(eve->f & SELECT) && !eve->h && dvert->totweight) {
01205                         /* do the extra check for selection in the following if, so were not
01206                         checking verts that may be already selected */
01207                         for (i=0; base_dvert->totweight >i && !(eve->f & SELECT); i++) { 
01208                             for (j=0; dvert->totweight >j; j++) {
01209                                 if (base_dvert->dw[i].def_nr==dvert->dw[j].def_nr) {
01210                                     eve->f |= SELECT;
01211                                     selcount++;
01212                                     deselcount--;
01213                                     if (!deselcount) { /*have we selected all posible faces?, if so return*/
01214                                         BKE_mesh_end_editmesh(me, em);
01215                                         return OPERATOR_FINISHED;
01216                                     }
01217                                     break;
01218                                 }
01219                             }
01220                         }
01221                     }
01222                 }
01223             }
01224         }
01225     } /* end basevert loop */
01226 
01227     if(selcount) {
01228         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
01229     }
01230 
01231     BKE_mesh_end_editmesh(me, em);
01232     return OPERATOR_FINISHED;
01233 }
01234 
01235 static int select_similar_exec(bContext *C, wmOperator *op)
01236 {
01237     int type= RNA_enum_get(op->ptr, "type");
01238 
01239     if(type < 100)
01240         return similar_vert_select_exec(C, op);
01241     else if(type < 200)
01242         return similar_edge_select_exec(C, op);
01243     else
01244         return similar_face_select_exec(C, op);
01245 }
01246 
01247 static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
01248 {
01249     Object *obedit= CTX_data_edit_object(C);
01250     EnumPropertyItem *item= NULL;
01251     int a, totitem= 0;
01252 
01253     if (C == NULL) {
01254         return prop_similar_types;
01255     }
01256         
01257     if(obedit && obedit->type == OB_MESH) {
01258         EditMesh *em= BKE_mesh_get_editmesh(obedit->data); 
01259 
01260         if(em->selectmode & SCE_SELECT_VERTEX) {
01261             for(a=SIMVERT_NORMAL; a<=SIMVERT_TOT; a++)
01262                 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
01263         }
01264         else if(em->selectmode & SCE_SELECT_EDGE) {
01265             for(a=SIMEDGE_LENGTH; a<=SIMEDGE_TOT; a++)
01266                 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
01267         }
01268         else if(em->selectmode & SCE_SELECT_FACE) {
01269             for(a=SIMFACE_MATERIAL; a<=SIMFACE_TOT; a++)
01270                 RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
01271         }
01272     }
01273 
01274     RNA_enum_item_end(&item, &totitem);
01275     *free= 1;
01276 
01277     return item;
01278 }
01279 
01280 void MESH_OT_select_similar(wmOperatorType *ot)
01281 {
01282     PropertyRNA *prop;
01283 
01284     /* identifiers */
01285     ot->name= "Select Similar";
01286     ot->description= "Select similar vertices, edges or faces by property types";
01287     ot->idname= "MESH_OT_select_similar";
01288     
01289     /* api callbacks */
01290     ot->invoke= WM_menu_invoke;
01291     ot->exec= select_similar_exec;
01292     ot->poll= ED_operator_editmesh;
01293     
01294     /* flags */
01295     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01296     
01297     /* properties */
01298     prop= RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
01299     RNA_def_enum_funcs(prop, select_similar_type_itemf);
01300     ot->prop= prop;
01301     RNA_def_float(ot->srna, "threshold", 0.01f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 100.f);
01302 }
01303 
01304 /* ******************************************* */
01305 
01306 
01307 int mesh_layers_menu_charlen(CustomData *data, int type)
01308 {
01309     int i, len = 0;
01310     /* see if there is a duplicate */
01311     for(i=0; i<data->totlayer; i++) {
01312         if((&data->layers[i])->type == type) {
01313             /* we could count the chars here but we'll just assumeme each
01314              * is 32 chars with some room for the menu text - 40 should be fine */
01315             len+=40; 
01316         }
01317     }
01318     return len;
01319 }
01320 
01321 /* this function adds menu text into an existing string.
01322  * this string's size should be allocated with mesh_layers_menu_charlen */
01323 void mesh_layers_menu_concat(CustomData *data, int type, char *str) 
01324 {
01325     int i, count = 0;
01326     char *str_pt = str;
01327     CustomDataLayer *layer;
01328     
01329     /* see if there is a duplicate */
01330     for(i=0; i<data->totlayer; i++) {
01331         layer = &data->layers[i];
01332         if(layer->type == type) {
01333             str_pt += sprintf(str_pt, "%s%%x%d|", layer->name, count);
01334             count++;
01335         }
01336     }
01337 }
01338 
01339 int mesh_layers_menu(CustomData *data, int type)
01340 {
01341     int ret;
01342     char *str_pt, *str;
01343     
01344     str_pt = str = MEM_mallocN(mesh_layers_menu_charlen(data, type) + 18, "layer menu");
01345     str[0] = '\0';
01346     
01347     str_pt += sprintf(str_pt, "Layers%%t|");
01348     
01349     mesh_layers_menu_concat(data, type, str_pt);
01350     
01351     ret = pupmenu(str);
01352     MEM_freeN(str);
01353     return ret;
01354 }
01355 
01356 static void EM_mesh_copy_edge(EditMesh *em, short type) 
01357 {
01358     EditSelection *ese;
01359     short change=0;
01360     
01361     EditEdge *eed, *eed_act;
01362     float vec[3], vec_mid[3], eed_len, eed_len_act;
01363     
01364     if (!em) return;
01365     
01366     ese = em->selected.last;
01367     if (!ese) return;
01368     
01369     eed_act = (EditEdge*)ese->data;
01370     
01371     switch (type) {
01372     case 1: /* copy crease */
01373         for(eed=em->edges.first; eed; eed=eed->next) {
01374             if (eed->f & SELECT && eed != eed_act && eed->crease != eed_act->crease) {
01375                 eed->crease = eed_act->crease;
01376                 change = 1;
01377             }
01378         }
01379         break;
01380     case 2: /* copy bevel weight */
01381         for(eed=em->edges.first; eed; eed=eed->next) {
01382             if (eed->f & SELECT && eed != eed_act && eed->bweight != eed_act->bweight) {
01383                 eed->bweight = eed_act->bweight;
01384                 change = 1;
01385             }
01386         }
01387         break;
01388 
01389     case 3: /* copy length */
01390         eed_len_act = len_v3v3(eed_act->v1->co, eed_act->v2->co);
01391         for(eed=em->edges.first; eed; eed=eed->next) {
01392             if (eed->f & SELECT && eed != eed_act) {
01393 
01394                 eed_len = len_v3v3(eed->v1->co, eed->v2->co);
01395 
01396                 if (eed_len == eed_len_act) continue;
01397                 /* if this edge is zero length we cont do anything with it*/
01398                 if (eed_len == 0.0f) continue;
01399                 if (eed_len_act == 0.0f) {
01400                     add_v3_v3v3(vec_mid, eed->v1->co, eed->v2->co);
01401                     mul_v3_fl(vec_mid, 0.5);
01402                     VECCOPY(eed->v1->co, vec_mid);
01403                     VECCOPY(eed->v2->co, vec_mid);
01404                 } else {
01405                     /* copy the edge length */
01406                     add_v3_v3v3(vec_mid, eed->v1->co, eed->v2->co);
01407                     mul_v3_fl(vec_mid, 0.5);
01408 
01409                     /* SCALE 1 */
01410                     sub_v3_v3v3(vec, eed->v1->co, vec_mid);
01411                     mul_v3_fl(vec, eed_len_act/eed_len);
01412                     add_v3_v3v3(eed->v1->co, vec, vec_mid);
01413 
01414                     /* SCALE 2 */
01415                     sub_v3_v3v3(vec, eed->v2->co, vec_mid);
01416                     mul_v3_fl(vec, eed_len_act/eed_len);
01417                     add_v3_v3v3(eed->v2->co, vec, vec_mid);
01418                 }
01419                 change = 1;
01420             }
01421         }
01422 
01423         if (change)
01424             recalc_editnormals(em);
01425 
01426         break;
01427     }
01428     
01429     if (change) {
01430 //      DAG_id_tag_update(obedit->data, 0);
01431         
01432     }
01433 }
01434 
01435 static void EM_mesh_copy_face(EditMesh *em, wmOperator *op, short type)
01436 {
01437     short change=0;
01438     
01439     EditFace *efa, *efa_act;
01440     MTFace *tf, *tf_act = NULL;
01441     MCol *mcol, *mcol_act = NULL;
01442     if (!em) return;
01443     efa_act = EM_get_actFace(em, 0);
01444     
01445     if (!efa_act) return;
01446     
01447     tf_act =    CustomData_em_get(&em->fdata, efa_act->data, CD_MTFACE);
01448     mcol_act =  CustomData_em_get(&em->fdata, efa_act->data, CD_MCOL);
01449     
01450     switch (type) {
01451     case 1: /* copy material */
01452         for(efa=em->faces.first; efa; efa=efa->next) {
01453             if (efa->f & SELECT && efa->mat_nr != efa_act->mat_nr) {
01454                 efa->mat_nr = efa_act->mat_nr;
01455                 change = 1;
01456             }
01457         }
01458         break;
01459     case 2: /* copy image */
01460         if (!tf_act) {
01461             BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers");
01462             return;
01463         }
01464         for(efa=em->faces.first; efa; efa=efa->next) {
01465             if (efa->f & SELECT && efa != efa_act) {
01466                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01467                 if (tf_act->tpage) {
01468                     tf->tpage = tf_act->tpage;
01469                 } else {
01470                     tf->tpage = NULL;
01471                 }
01472                 tf->tile= tf_act->tile;
01473                 change = 1;
01474             }
01475         }
01476         break;
01477 
01478     case 3: /* copy UV's */
01479         if (!tf_act) {
01480             BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers");
01481             return;
01482         }
01483         for(efa=em->faces.first; efa; efa=efa->next) {
01484             if (efa->f & SELECT && efa != efa_act) {
01485                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01486                 memcpy(tf->uv, tf_act->uv, sizeof(tf->uv));
01487                 change = 1;
01488             }
01489         }
01490         break;
01491     case 4: /* mode's */
01492         if (!tf_act) {
01493             BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers");
01494             return;
01495         }
01496         for(efa=em->faces.first; efa; efa=efa->next) {
01497             if (efa->f & SELECT && efa != efa_act) {
01498                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01499                 tf->mode= tf_act->mode;
01500                 change = 1;
01501             }
01502         }
01503         break;
01504     case 5: /* copy transp's */
01505         if (!tf_act) {
01506             BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers");
01507             return;
01508         }
01509         for(efa=em->faces.first; efa; efa=efa->next) {
01510             if (efa->f & SELECT && efa != efa_act) {
01511                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01512                 tf->transp= tf_act->transp;
01513                 change = 1;
01514             }
01515         }
01516         break;
01517 
01518     case 6: /* copy vcols's */
01519         if (!mcol_act) {
01520             BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers");
01521             return;
01522         } else {
01523             /* guess the 4th color if needs be */
01524             float val =- 1;
01525 
01526             if (!efa_act->v4) {
01527                 /* guess the othe vale, we may need to use it
01528                  * 
01529                  * Modifying the 4th value of the mcol is ok here since its not seen
01530                  * on a triangle
01531                  * */
01532                 val = ((float)(mcol_act->r +  (mcol_act+1)->r + (mcol_act+2)->r)) / 3; CLAMP(val, 0, 255);
01533                 (mcol_act+3)->r = (char)val;
01534 
01535                 val = ((float)(mcol_act->g +  (mcol_act+1)->g + (mcol_act+2)->g)) / 3; CLAMP(val, 0, 255);
01536                 (mcol_act+3)->g = (char)val;
01537 
01538                 val = ((float)(mcol_act->b +  (mcol_act+1)->b + (mcol_act+2)->b)) / 3; CLAMP(val, 0, 255);
01539                 (mcol_act+3)->b = (char)val;
01540             } 
01541 
01542 
01543             for(efa=em->faces.first; efa; efa=efa->next) {
01544                 if (efa->f & SELECT && efa != efa_act) {
01545                     /* TODO - make copy from tri to quad guess the 4th vert */
01546                     mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
01547                     memcpy(mcol, mcol_act, sizeof(MCol)*4); 
01548                     change = 1;
01549                 }
01550             }
01551         }
01552         break;
01553     }
01554     
01555     if (change) {
01556 //      DAG_id_tag_update(obedit->data, 0);
01557         
01558     }
01559 }
01560 
01561 
01562 void EM_mesh_copy_face_layer(EditMesh *em, wmOperator *op, short type) 
01563 {
01564     short change=0;
01565     
01566     EditFace *efa;
01567     MTFace *tf, *tf_from;
01568     MCol *mcol, *mcol_from;
01569     
01570     if (!em) return;
01571     
01572     switch(type) {
01573     case 7:
01574     case 8:
01575     case 9:
01576         if (CustomData_number_of_layers(&em->fdata, CD_MTFACE)<2) {
01577             BKE_report(op->reports, RPT_WARNING, "mesh does not have multiple uv/image layers");
01578             return;
01579         } else {
01580             int layer_orig_idx, layer_idx;
01581 
01582             layer_idx = mesh_layers_menu(&em->fdata, CD_MTFACE);
01583             if (layer_idx<0) return;
01584 
01585             /* warning, have not updated mesh pointers however this is not needed since we swicth back */
01586             layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MTFACE);
01587             if (layer_idx==layer_orig_idx)
01588                 return;
01589 
01590             /* get the tfaces */
01591             CustomData_set_layer_active(&em->fdata, CD_MTFACE, (int)layer_idx);
01592             /* store the tfaces in our temp */
01593             for(efa=em->faces.first; efa; efa=efa->next) {
01594                 if (efa->f & SELECT) {
01595                     efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01596                 }   
01597             }
01598             CustomData_set_layer_active(&em->fdata, CD_MTFACE, layer_orig_idx);
01599         }
01600         break;
01601 
01602     case 10: /* select vcol layers - make sure this stays in sync with above code */
01603         if (CustomData_number_of_layers(&em->fdata, CD_MCOL)<2) {
01604             BKE_report(op->reports, RPT_WARNING, "mesh does not have multiple color layers");
01605             return;
01606         } else {
01607             int layer_orig_idx, layer_idx;
01608 
01609             layer_idx = mesh_layers_menu(&em->fdata, CD_MCOL);
01610             if (layer_idx<0) return;
01611 
01612             /* warning, have not updated mesh pointers however this is not needed since we swicth back */
01613             layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MCOL);
01614             if (layer_idx==layer_orig_idx)
01615                 return;
01616 
01617             /* get the tfaces */
01618             CustomData_set_layer_active(&em->fdata, CD_MCOL, (int)layer_idx);
01619             /* store the tfaces in our temp */
01620             for(efa=em->faces.first; efa; efa=efa->next) {
01621                 if (efa->f & SELECT) {
01622                     efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
01623                 }   
01624             }
01625             CustomData_set_layer_active(&em->fdata, CD_MCOL, layer_orig_idx);
01626 
01627         }
01628         break;
01629     }
01630 
01631     /* layer copy only - sanity checks done above */
01632     switch (type) {
01633     case 7: /* copy UV's only */
01634         for(efa=em->faces.first; efa; efa=efa->next) {
01635             if (efa->f & SELECT) {
01636                 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
01637                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01638                 memcpy(tf->uv, tf_from->uv, sizeof(tf->uv));
01639                 change = 1;
01640             }
01641         }
01642         break;
01643     case 8: /* copy image settings only */
01644         for(efa=em->faces.first; efa; efa=efa->next) {
01645             if (efa->f & SELECT) {
01646                 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
01647                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01648                 if (tf_from->tpage) {
01649                     tf->tpage = tf_from->tpage;
01650                 } else {
01651                     tf->tpage = NULL;
01652                 }
01653                 tf->tile= tf_from->tile;
01654                 change = 1;
01655             }
01656         }
01657         break;
01658     case 9: /* copy all tface info */
01659         for(efa=em->faces.first; efa; efa=efa->next) {
01660             if (efa->f & SELECT) {
01661                 tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
01662                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01663                 memcpy(tf->uv, ((MTFace *)efa->tmp.p)->uv, sizeof(tf->uv));
01664                 tf->tpage = tf_from->tpage;
01665                 tf->mode = tf_from->mode;
01666                 tf->transp = tf_from->transp;
01667                 change = 1;
01668             }
01669         }
01670         break;
01671     case 10:
01672         for(efa=em->faces.first; efa; efa=efa->next) {
01673             if (efa->f & SELECT) {
01674                 mcol_from = (MCol *)efa->tmp.p; 
01675                 mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
01676                 memcpy(mcol, mcol_from, sizeof(MCol)*4);    
01677                 change = 1;
01678             }
01679         }
01680         break;
01681     }
01682 
01683     if (change) {
01684 //      DAG_id_tag_update(obedit->data, 0);
01685         
01686     }
01687 }
01688 
01689 
01690 /* ctrl+c in mesh editmode */
01691 static void UNUSED_FUNCTION(mesh_copy_menu)(EditMesh *em, wmOperator *op)
01692 {
01693     EditSelection *ese;
01694     int ret;
01695     if (!em) return;
01696     
01697     ese = em->selected.last;
01698     
01699     /* Faces can have a NULL ese, so dont return on a NULL ese here */
01700     
01701     if(ese && ese->type == EDITVERT) {
01702         /* EditVert *ev, *ev_act = (EditVert*)ese->data;
01703         ret= pupmenu(""); */
01704     } else if(ese && ese->type == EDITEDGE) {
01705         ret= pupmenu("Copy Active Edge to Selected%t|Crease%x1|Bevel Weight%x2|Length%x3");
01706         if (ret<1) return;
01707         
01708         EM_mesh_copy_edge(em, ret);
01709         
01710     } else if(ese==NULL || ese->type == EDITFACE) {
01711         ret= pupmenu(
01712             "Copy Face Selected%t|"
01713             "Active Material%x1|Active Image%x2|Active UV Coords%x3|"
01714             "Active Mode%x4|Active Transp%x5|Active Vertex Colors%x6|%l|"
01715 
01716             "TexFace UVs from layer%x7|"
01717             "TexFace Images from layer%x8|"
01718             "TexFace All from layer%x9|"
01719             "Vertex Colors from layer%x10");
01720         if (ret<1) return;
01721         
01722         if (ret<=6) {
01723             EM_mesh_copy_face(em, op, ret);
01724         } else {
01725             EM_mesh_copy_face_layer(em, op, ret);
01726         }
01727     }
01728 }
01729 
01730 /* ****************  LOOP SELECTS *************** */
01731 
01732 /* selects quads in loop direction of indicated edge */
01733 /* only flush over edges with valence <= 2 */
01734 void faceloop_select(EditMesh *em, EditEdge *startedge, int select)
01735 {
01736     EditEdge *eed;
01737     EditFace *efa;
01738     int looking= 1;
01739     
01740     /* in eed->f1 we put the valence (amount of faces in edge) */
01741     /* in eed->f2 we put tagged flag as correct loop */
01742     /* in efa->f1 we put tagged flag as correct to select */
01743 
01744     for(eed= em->edges.first; eed; eed= eed->next) {
01745         eed->f1= 0;
01746         eed->f2= 0;
01747     }
01748     for(efa= em->faces.first; efa; efa= efa->next) {
01749         efa->f1= 0;
01750         if(efa->h==0) {
01751             efa->e1->f1++;
01752             efa->e2->f1++;
01753             efa->e3->f1++;
01754             if(efa->e4) efa->e4->f1++;
01755         }
01756     }
01757     
01758     /* tag startedge OK*/
01759     startedge->f2= 1;
01760     
01761     while(looking) {
01762         looking= 0;
01763         
01764         for(efa= em->faces.first; efa; efa= efa->next) {
01765             if(efa->h==0 && efa->e4 && efa->f1==0) {    /* not done quad */
01766                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
01767 
01768                     /* if edge tagged, select opposing edge and mark face ok */
01769                     if(efa->e1->f2) {
01770                         efa->e3->f2= 1;
01771                         efa->f1= 1;
01772                         looking= 1;
01773                     }
01774                     else if(efa->e2->f2) {
01775                         efa->e4->f2= 1;
01776                         efa->f1= 1;
01777                         looking= 1;
01778                     }
01779                     if(efa->e3->f2) {
01780                         efa->e1->f2= 1;
01781                         efa->f1= 1;
01782                         looking= 1;
01783                     }
01784                     if(efa->e4->f2) {
01785                         efa->e2->f2= 1;
01786                         efa->f1= 1;
01787                         looking= 1;
01788                     }
01789                 }
01790             }
01791         }
01792     }
01793     
01794     /* (de)select the faces */
01795     if(select!=2) {
01796         for(efa= em->faces.first; efa; efa= efa->next) {
01797             if(efa->f1) EM_select_face(efa, select);
01798         }
01799     }
01800 }
01801 
01802 
01803 /* helper for edgeloop_select, checks for eed->f2 tag in faces */
01804 static int edge_not_in_tagged_face(EditMesh *em, EditEdge *eed)
01805 {
01806     EditFace *efa;
01807     
01808     for(efa= em->faces.first; efa; efa= efa->next) {
01809         if(efa->h==0) {
01810             if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) {  /* edge is in face */
01811                 if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) { /* face is tagged */
01812                     return 0;
01813                 }
01814             }
01815         }
01816     }
01817     return 1;
01818 }
01819 
01820 static void ensure_ed_vert_sel(EditMesh *em)
01821 {
01822     EditEdge *eed;
01823 
01824     /* EM_selectmode_flush() doesnt take into account that deselected edges
01825      * may be still connected to selected edges [#26885] */
01826     for(eed= em->edges.first; eed; eed= eed->next) {
01827         if(eed->f & SELECT) {
01828             eed->v1->f |= SELECT;
01829             eed->v2->f |= SELECT;
01830         }
01831     }
01832 }
01833 
01834 /* selects or deselects edges that:
01835 - if edges has 2 faces:
01836     - has vertices with valence of 4
01837     - not shares face with previous edge
01838 - if edge has 1 face:
01839     - has vertices with valence 4
01840     - not shares face with previous edge
01841     - but also only 1 face
01842 - if edge no face:
01843     - has vertices with valence 2
01844 */
01845 static void edgeloop_select(EditMesh *em, EditEdge *starteed, int select)
01846 {
01847     EditVert *eve;
01848     EditEdge *eed;
01849     EditFace *efa;
01850     int looking= 1;
01851     
01852     /* in f1 we put the valence (amount of edges in a vertex, or faces in edge) */
01853     /* in eed->f2 and efa->f1 we put tagged flag as correct loop */
01854     for(eve= em->verts.first; eve; eve= eve->next) {
01855         eve->f1= 0;
01856         eve->f2= 0;
01857     }
01858     for(eed= em->edges.first; eed; eed= eed->next) {
01859         eed->f1= 0;
01860         eed->f2= 0;
01861         if((eed->h & 1)==0) {   /* fgon edges add to valence too */
01862             eed->v1->f1++; eed->v2->f1++;
01863         }
01864     }
01865     for(efa= em->faces.first; efa; efa= efa->next) {
01866         efa->f1= 0;
01867         if(efa->h==0) {
01868             efa->e1->f1++;
01869             efa->e2->f1++;
01870             efa->e3->f1++;
01871             if(efa->e4) efa->e4->f1++;
01872         }
01873     }
01874     
01875     /* looped edges & vertices get tagged f2 */
01876     starteed->f2= 1;
01877     if(starteed->v1->f1<5) starteed->v1->f2= 1;
01878     if(starteed->v2->f1<5) starteed->v2->f2= 1;
01879     /* sorry, first edge isnt even ok */
01880     if(starteed->v1->f2==0 && starteed->v2->f2==0) looking= 0;
01881     
01882     while(looking) {
01883         looking= 0;
01884         
01885         /* find correct valence edges which are not tagged yet, but connect to tagged one */
01886         for(eed= em->edges.first; eed; eed= eed->next) {
01887             if(eed->h==0 && eed->f2==0) { /* edge not hidden, not tagged */
01888                 if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { /* valence of vertex OK, and is tagged */
01889                     /* new edge is not allowed to be in face with tagged edge */
01890                     if(edge_not_in_tagged_face(em, eed)) {
01891                         if(eed->f1==starteed->f1) { /* same amount of faces */
01892                             looking= 1;
01893                             eed->f2= 1;
01894                             if(eed->v2->f1<5) eed->v2->f2= 1;
01895                             if(eed->v1->f1<5) eed->v1->f2= 1;
01896                         }
01897                     }
01898                 }
01899             }
01900         }
01901     }
01902     /* and we do the select */
01903     for(eed= em->edges.first; eed; eed= eed->next) {
01904         if(eed->f2) EM_select_edge(eed, select);
01905     }
01906 
01907     if(select == FALSE && !(em->selectmode & SCE_SELECT_VERTEX)) { /* only when not in vert sel [#26931] */
01908         ensure_ed_vert_sel(em);
01909     }
01910 }
01911 
01912 /* 
01913    Almostly exactly the same code as faceloop select
01914 */
01915 static void edgering_select(EditMesh *em, EditEdge *startedge, int select)
01916 {
01917     EditEdge *eed;
01918     EditFace *efa;
01919     int looking= 1;
01920     
01921     /* in eed->f1 we put the valence (amount of faces in edge) */
01922     /* in eed->f2 we put tagged flag as correct loop */
01923     /* in efa->f1 we put tagged flag as correct to select */
01924 
01925     for(eed= em->edges.first; eed; eed= eed->next) {
01926         eed->f1= 0;
01927         eed->f2= 0;
01928     }
01929     for(efa= em->faces.first; efa; efa= efa->next) {
01930         efa->f1= 0;
01931         if(efa->h==0) {
01932             efa->e1->f1++;
01933             efa->e2->f1++;
01934             efa->e3->f1++;
01935             if(efa->e4) efa->e4->f1++;
01936         }
01937     }
01938     
01939     /* tag startedge OK */
01940     startedge->f2= 1;
01941     
01942     while(looking) {
01943         looking= 0;
01944         
01945         for(efa= em->faces.first; efa; efa= efa->next) {
01946             if(efa->e4 && efa->f1==0 && !efa->h) {  /* not done quad */
01947                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
01948 
01949                     /* if edge tagged, select opposing edge and mark face ok */
01950                     if(efa->e1->f2) {
01951                         efa->e3->f2= 1;
01952                         efa->f1= 1;
01953                         looking= 1;
01954                     }
01955                     else if(efa->e2->f2) {
01956                         efa->e4->f2= 1;
01957                         efa->f1= 1;
01958                         looking= 1;
01959                     }
01960                     if(efa->e3->f2) {
01961                         efa->e1->f2= 1;
01962                         efa->f1= 1;
01963                         looking= 1;
01964                     }
01965                     if(efa->e4->f2) {
01966                         efa->e2->f2= 1;
01967                         efa->f1= 1;
01968                         looking= 1;
01969                     }
01970                 }
01971             }
01972         }
01973     }
01974     
01975     /* (de)select the edges */
01976     for(eed= em->edges.first; eed; eed= eed->next) {
01977             if(eed->f2) EM_select_edge(eed, select);
01978     }
01979 
01980     if(select == FALSE && !(em->selectmode & SCE_SELECT_VERTEX)) { /* only when not in vert sel [#26931] */
01981         ensure_ed_vert_sel(em);
01982     }
01983 }
01984 
01985 static int loop_multiselect(bContext *C, wmOperator *op)
01986 {
01987     Object *obedit= CTX_data_edit_object(C);
01988     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
01989     EditEdge *eed;
01990     EditEdge **edarray;
01991     int edindex, edfirstcount;
01992     int looptype= RNA_boolean_get(op->ptr, "ring");
01993     
01994     /* sets em->totedgesel */
01995     EM_nedges_selected(em);
01996     
01997     edarray = MEM_mallocN(sizeof(EditEdge*)*em->totedgesel,"edge array");
01998     edindex = 0;
01999     edfirstcount = em->totedgesel;
02000     
02001     for(eed=em->edges.first; eed; eed=eed->next){
02002         if(eed->f&SELECT){
02003             edarray[edindex] = eed;
02004             edindex += 1;
02005         }
02006     }
02007     
02008     if(looptype){
02009         for(edindex = 0; edindex < edfirstcount; edindex +=1){
02010             eed = edarray[edindex];
02011             edgering_select(em, eed,SELECT);
02012         }
02013         EM_selectmode_flush(em);
02014     }
02015     else{
02016         for(edindex = 0; edindex < edfirstcount; edindex +=1){
02017             eed = edarray[edindex];
02018             edgeloop_select(em, eed,SELECT);
02019         }
02020         EM_selectmode_flush(em);
02021     }
02022     MEM_freeN(edarray);
02023 //  if (EM_texFaceCheck())
02024     
02025     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02026 
02027     BKE_mesh_end_editmesh(obedit->data, em);
02028     return OPERATOR_FINISHED;   
02029 }
02030 
02031 void MESH_OT_loop_multi_select(wmOperatorType *ot)
02032 {
02033     /* identifiers */
02034     ot->name= "Multi Select Loops";
02035     ot->description= "Select a loop of connected edges by connection type";
02036     ot->idname= "MESH_OT_loop_multi_select";
02037     
02038     /* api callbacks */
02039     ot->exec= loop_multiselect;
02040     ot->poll= ED_operator_editmesh;
02041     
02042     /* flags */
02043     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02044     
02045     /* properties */
02046     RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
02047 }
02048 
02049         
02050 /* ***************** MAIN MOUSE SELECTION ************** */
02051 
02052 
02053 /* ***************** loop select (non modal) ************** */
02054 
02055 static void mouse_mesh_loop(bContext *C, const int mval[2], short extend, short ring)
02056 {
02057     ViewContext vc;
02058     EditMesh *em;
02059     EditEdge *eed;
02060     int select= 1;
02061     int dist= 50;
02062     
02063     em_setup_viewcontext(C, &vc);
02064     vc.mval[0]= mval[0];
02065     vc.mval[1]= mval[1];
02066     em= vc.em;
02067 
02068     /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
02069     view3d_validate_backbuf(&vc);
02070     
02071     eed= findnearestedge(&vc, &dist);
02072     if(eed) {
02073         if(extend==0) EM_clear_flag_all(em, SELECT);
02074     
02075         if((eed->f & SELECT)==0) select=1;
02076         else if(extend) select=0;
02077 
02078         if(em->selectmode & SCE_SELECT_FACE) {
02079             faceloop_select(em, eed, select);
02080         }
02081         else if(em->selectmode & SCE_SELECT_EDGE) {
02082             if(ring)
02083                 edgering_select(em, eed, select);
02084             else
02085                 edgeloop_select(em, eed, select);
02086         }
02087         else if(em->selectmode & SCE_SELECT_VERTEX) {
02088             if(ring)
02089                 edgering_select(em, eed, select);
02090             else 
02091                 edgeloop_select(em, eed, select);
02092         }
02093 
02094         EM_selectmode_flush(em);
02095 //          if (EM_texFaceCheck())
02096         
02097         /* sets as active, useful for other tools */
02098         if(select) {
02099             if(em->selectmode & SCE_SELECT_VERTEX)
02100                 EM_store_selection(em, eed->v1, EDITVERT);
02101             if(em->selectmode & SCE_SELECT_EDGE)
02102                 EM_store_selection(em, eed, EDITEDGE);
02103         }
02104 
02105         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
02106     }
02107 }
02108 
02109 static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
02110 {
02111     
02112     view3d_operator_needs_opengl(C);
02113     
02114     mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
02115                     RNA_boolean_get(op->ptr, "ring"));
02116     
02117     /* cannot do tweaks for as long this keymap is after transform map */
02118     return OPERATOR_FINISHED;
02119 }
02120 
02121 void MESH_OT_loop_select(wmOperatorType *ot)
02122 {
02123     /* identifiers */
02124     ot->name= "Loop Select";
02125     ot->description= "Select a loop of connected edges";
02126     ot->idname= "MESH_OT_loop_select";
02127     
02128     /* api callbacks */
02129     ot->invoke= mesh_select_loop_invoke;
02130     ot->poll= ED_operator_editmesh_region_view3d;
02131     
02132     /* flags */
02133     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02134     
02135     /* properties */
02136     RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
02137     RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
02138 }
02139 
02140 /* ******************* mesh shortest path select, uses prev-selected edge ****************** */
02141 
02142 /* since you want to create paths with multiple selects, it doesn't have extend option */
02143 static void mouse_mesh_shortest_path(bContext *C, const int mval[2])
02144 {
02145     ViewContext vc;
02146     EditMesh *em;
02147     EditEdge *eed, *eed_act= NULL;
02148     int dist= 50;
02149     
02150     em_setup_viewcontext(C, &vc);
02151     vc.mval[0]= mval[0];
02152     vc.mval[1]= mval[1];
02153     em= vc.em;
02154     
02155     /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
02156     view3d_validate_backbuf(&vc);
02157     
02158     eed= findnearestedge(&vc, &dist);
02159     if(eed) {
02160         Mesh *me= vc.obedit->data;
02161         int path = 0;
02162         
02163         if (em->selected.last) {
02164             EditSelection *ese = em->selected.last;
02165             
02166             if(ese && ese->type == EDITEDGE) {
02167                 eed_act = (EditEdge*)ese->data;
02168                 if (eed_act != eed) {
02169                     if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) { /* <- this is where the magic happens */
02170                         EM_remove_selection(em, eed_act, EDITEDGE);
02171                         path = 1;
02172                     }
02173                 }
02174             }
02175         }
02176         if (path==0) {
02177             int act = (edgetag_context_check(vc.scene, eed)==0);
02178             edgetag_context_set(vc.scene, eed, act); /* switch the edge option */
02179         }
02180 
02181         /* even if this is selected it may not be in the selection list */
02182         if(edgetag_context_check(vc.scene, eed)==0) {
02183             EM_remove_selection(em, eed, EDITEDGE);
02184         }
02185         else {
02186             /* other modes need to keep the last edge tagged */
02187             if(eed_act) {
02188                 if(vc.scene->toolsettings->edge_mode!=EDGE_MODE_SELECT) {
02189                     /* for non-select modes, always de-select the previous active edge */
02190                     EM_select_edge(eed_act, 0);
02191                 }
02192             }
02193 
02194             /* set the new edge active */
02195             EM_select_edge(eed, 1);
02196             EM_store_selection(em, eed, EDITEDGE);
02197         }
02198 
02199         EM_selectmode_flush(em);
02200     
02201         /* force drawmode for mesh */
02202         switch (vc.scene->toolsettings->edge_mode) {
02203             
02204             case EDGE_MODE_TAG_SEAM:
02205                 me->drawflag |= ME_DRAWSEAMS;
02206                 break;
02207             case EDGE_MODE_TAG_SHARP:
02208                 me->drawflag |= ME_DRAWSHARP;
02209                 break;
02210             case EDGE_MODE_TAG_CREASE:  
02211                 me->drawflag |= ME_DRAWCREASES;
02212                 break;
02213             case EDGE_MODE_TAG_BEVEL:
02214                 me->drawflag |= ME_DRAWBWEIGHTS;
02215                 break;
02216         }
02217 
02218         /* live unwrap while tagging */
02219         if( (vc.scene->toolsettings->edge_mode_live_unwrap) &&
02220             (vc.scene->toolsettings->edge_mode == EDGE_MODE_TAG_SEAM) &&
02221             (CustomData_has_layer(&em->fdata, CD_MTFACE))
02222         ) {
02223             ED_unwrap_lscm(vc.scene, vc.obedit, FALSE); /* unwrap all not just sel */
02224         }
02225 
02226         DAG_id_tag_update(vc.obedit->data, 0);
02227         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
02228     }
02229 }
02230 
02231 
02232 static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
02233 {
02234     
02235     view3d_operator_needs_opengl(C);
02236 
02237     mouse_mesh_shortest_path(C, event->mval);
02238     
02239     return OPERATOR_FINISHED;
02240 }
02241 
02242 static int mesh_shortest_path_select_poll(bContext *C)
02243 {
02244     if(ED_operator_editmesh_region_view3d(C)) {
02245         Object *obedit= CTX_data_edit_object(C);
02246         EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
02247         return (em->selectmode & SCE_SELECT_EDGE);
02248     }
02249     return 0;
02250 }
02251     
02252 void MESH_OT_select_shortest_path(wmOperatorType *ot)
02253 {
02254     /* identifiers */
02255     ot->name= "Shortest Path Select";
02256     ot->description= "Select shortest path between two selections";
02257     ot->idname= "MESH_OT_select_shortest_path";
02258     
02259     /* api callbacks */
02260     ot->invoke= mesh_shortest_path_select_invoke;
02261     ot->poll= mesh_shortest_path_select_poll;
02262     
02263     /* flags */
02264     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02265     
02266     /* properties */
02267     RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
02268 }
02269 
02270 
02271 /* ************************************************** */
02272 
02273 
02274 /* here actual select happens */
02275 /* gets called via generic mouse select operator */
02276 int mouse_mesh(bContext *C, const int mval[2], short extend)
02277 {
02278     ViewContext vc;
02279     EditVert *eve;
02280     EditEdge *eed;
02281     EditFace *efa;
02282     
02283     /* setup view context for argument to callbacks */
02284     em_setup_viewcontext(C, &vc);
02285     vc.mval[0]= mval[0];
02286     vc.mval[1]= mval[1];
02287     
02288     if(unified_findnearest(&vc, &eve, &eed, &efa)) {
02289         
02290         if(extend==0) EM_clear_flag_all(vc.em, SELECT);
02291         
02292         if(efa) {
02293             /* set the last selected face */
02294             EM_set_actFace(vc.em, efa);
02295             
02296             if( (efa->f & SELECT)==0 ) {
02297                 EM_store_selection(vc.em, efa, EDITFACE);
02298                 EM_select_face_fgon(vc.em, efa, 1);
02299             }
02300             else if(extend) {
02301                 EM_remove_selection(vc.em, efa, EDITFACE);
02302                 EM_select_face_fgon(vc.em, efa, 0);
02303             }
02304         }
02305         else if(eed) {
02306             if((eed->f & SELECT)==0) {
02307                 EM_store_selection(vc.em, eed, EDITEDGE);
02308                 EM_select_edge(eed, 1);
02309             }
02310             else if(extend) {
02311                 EM_remove_selection(vc.em, eed, EDITEDGE);
02312                 EM_select_edge(eed, 0);
02313             }
02314         }
02315         else if(eve) {
02316             if((eve->f & SELECT)==0) {
02317                 eve->f |= SELECT;
02318                 EM_store_selection(vc.em, eve, EDITVERT);
02319             }
02320             else if(extend){ 
02321                 EM_remove_selection(vc.em, eve, EDITVERT);
02322                 eve->f &= ~SELECT;
02323             }
02324         }
02325         
02326         EM_selectmode_flush(vc.em);
02327           
02328 //      if (EM_texFaceCheck()) {
02329 
02330         if (efa && efa->mat_nr != vc.obedit->actcol-1) {
02331             vc.obedit->actcol= efa->mat_nr+1;
02332             vc.em->mat_nr= efa->mat_nr;
02333             WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, NULL);
02334         }
02335 
02336         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
02337 
02338         return 1;
02339     }
02340     
02341     return 0;
02342 }
02343 
02344 /* *********** select linked ************* */
02345 
02346 /* for use with selectconnected_delimit_mesh only! */
02347 #define is_edge_delimit_ok(eed) ((eed->tmp.l == 1) && (eed->seam==0))
02348 #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))
02349 
02350 #define face_tag(efa)\
02351 if(efa->v4) efa->tmp.l=     efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;\
02352 else        efa->tmp.l=     efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
02353 
02354 /* all - 1) use all faces for extending the selection  2) only use the mouse face
02355 * sel - 1) select  0) deselect 
02356 * */
02357 
02358 /* legacy warning, this function combines too much :) */
02359 static int select_linked_limited_invoke(ViewContext *vc, short all, short sel)
02360 {
02361     EditMesh *em= vc->em;
02362     EditFace *efa;
02363     EditEdge *eed;
02364     EditVert *eve;
02365     short done=1, change=0;
02366     
02367     if(em->faces.first==0) return OPERATOR_CANCELLED;
02368     
02369     /* flag all edges+faces as off*/
02370     for(eed= em->edges.first; eed; eed= eed->next)
02371         eed->tmp.l=0;
02372     
02373     for(efa= em->faces.first; efa; efa= efa->next) {
02374         efa->tmp.l = 0;
02375     }
02376     
02377     if (all) {
02378         // XXX verts?
02379         for(eed= em->edges.first; eed; eed= eed->next) {
02380             if(eed->f & SELECT)
02381                 eed->tmp.l= 1;
02382         }
02383         for(efa= em->faces.first; efa; efa= efa->next) {
02384             
02385             if (efa->f & SELECT) {
02386                 face_tag(efa);
02387             } else {
02388                 efa->tmp.l = 0;
02389             }
02390         }
02391     } 
02392     else {
02393         if( unified_findnearest(vc, &eve, &eed, &efa) ) {
02394             
02395             if(efa) {
02396                 efa->tmp.l = 1;
02397                 face_tag(efa);
02398             }
02399             else if(eed)
02400                 eed->tmp.l= 1;
02401             else {
02402                 for(eed= em->edges.first; eed; eed= eed->next)
02403                     if(eed->v1==eve || eed->v2==eve)
02404                         break;
02405                 eed->tmp.l= 1;
02406             }
02407         }
02408         else
02409             return OPERATOR_FINISHED;
02410     }
02411     
02412     while(done==1) {
02413         done= 0;
02414         /* simple algo - select all faces that have a selected edge
02415         * this intern selects the edge, repeat until nothing is left to do */
02416         for(efa= em->faces.first; efa; efa= efa->next) {
02417             if ((efa->tmp.l == 0) && (!efa->h)) {
02418                 if (is_face_tag(efa)) {
02419                     face_tag(efa);
02420                     done= 1;
02421                 }
02422             }
02423         }
02424     }
02425     
02426     for(efa= em->faces.first; efa; efa= efa->next) {
02427         if (efa->tmp.l) {
02428             if (sel) {
02429                 if (!(efa->f & SELECT)) {
02430                     EM_select_face(efa, 1);
02431                     change = 1;
02432                 }
02433             } else {
02434                 if (efa->f & SELECT) {
02435                     EM_select_face(efa, 0);
02436                     change = 1;
02437                 }
02438             }
02439         }
02440     }
02441     
02442     if (!change)
02443         return OPERATOR_CANCELLED;
02444     
02445     if (!sel) /* make sure de-selecting faces didnt de-select the verts/edges connected to selected faces, this is common with boundaries */
02446         for(efa= em->faces.first; efa; efa= efa->next)
02447             if (efa->f & SELECT)
02448                 EM_select_face(efa, 1);
02449     
02450     //  if (EM_texFaceCheck())
02451     
02452     return OPERATOR_FINISHED;
02453 }
02454 
02455 #undef is_edge_delimit_ok
02456 #undef is_face_tag
02457 #undef face_tag
02458 
02459 static void linked_limit_default(bContext *C, wmOperator *op)
02460 {
02461     if(!RNA_struct_property_is_set(op->ptr, "limit")) {
02462         Object *obedit= CTX_data_edit_object(C);
02463         EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
02464         if(em->selectmode == SCE_SELECT_FACE)
02465             RNA_boolean_set(op->ptr, "limit", TRUE);
02466     }
02467 }
02468 
02469 static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
02470 {
02471     Object *obedit= CTX_data_edit_object(C);
02472     ViewContext vc;
02473     EditVert *eve, *v1, *v2;
02474     EditEdge *eed;
02475     EditFace *efa;
02476     short done=1, toggle=0;
02477     int sel= !RNA_boolean_get(op->ptr, "deselect");
02478     int limit;
02479     
02480     linked_limit_default(C, op);
02481 
02482     limit = RNA_boolean_get(op->ptr, "limit");
02483 
02484     /* unified_finednearest needs ogl */
02485     view3d_operator_needs_opengl(C);
02486     
02487     /* setup view context for argument to callbacks */
02488     em_setup_viewcontext(C, &vc);
02489     
02490     if(vc.em->edges.first==0) return OPERATOR_CANCELLED;
02491     
02492     vc.mval[0]= event->mval[0];
02493     vc.mval[1]= event->mval[1];
02494     
02495     /* return warning! */
02496     if(limit) {
02497         int retval= select_linked_limited_invoke(&vc, 0, sel);
02498         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02499         return retval;
02500     }
02501     
02502     if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
02503         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02504     
02505         return OPERATOR_CANCELLED;
02506     }
02507 
02508     /* clear test flags */
02509     for(v1= vc.em->verts.first; v1; v1= v1->next) v1->f1= 0;
02510     
02511     /* start vertex/face/edge */
02512     if(eve) eve->f1= 1;
02513     else if(eed) eed->v1->f1= eed->v2->f1= 1;
02514     else efa->v1->f1= efa->v2->f1= efa->v3->f1= 1;
02515     
02516     /* set flag f1 if affected */
02517     while(done==1) {
02518         done= 0;
02519         toggle++;
02520         
02521         if(toggle & 1) eed= vc.em->edges.first;
02522         else eed= vc.em->edges.last;
02523         
02524         while(eed) {
02525             v1= eed->v1;
02526             v2= eed->v2;
02527             
02528             if(eed->h==0) {
02529                 if(v1->f1 && v2->f1==0) {
02530                     v2->f1= 1;
02531                     done= 1;
02532                 }
02533                 else if(v1->f1==0 && v2->f1) {
02534                     v1->f1= 1;
02535                     done= 1;
02536                 }
02537             }
02538             
02539             if(toggle & 1) eed= eed->next;
02540             else eed= eed->prev;
02541         }
02542     }
02543     
02544     /* now use vertex f1 flag to select/deselect */
02545     for(eed= vc.em->edges.first; eed; eed= eed->next) {
02546         if(eed->v1->f1 && eed->v2->f1) 
02547             EM_select_edge(eed, sel);
02548     }
02549     for(efa= vc.em->faces.first; efa; efa= efa->next) {
02550         if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1)) 
02551             EM_select_face(efa, sel);
02552     }
02553     /* no flush needed, connected geometry is done */
02554     
02555 //  if (EM_texFaceCheck())
02556     
02557     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02558     return OPERATOR_FINISHED;   
02559 }
02560 
02561 void MESH_OT_select_linked_pick(wmOperatorType *ot)
02562 {
02563     /* identifiers */
02564     ot->name= "Select Linked";
02565     ot->description= "(un)select all vertices linked to the active mesh";
02566     ot->idname= "MESH_OT_select_linked_pick";
02567     
02568     /* api callbacks */
02569     ot->invoke= select_linked_pick_invoke;
02570     ot->poll= ED_operator_editmesh_region_view3d;
02571     
02572     /* flags */
02573     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02574     
02575     RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
02576     RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "Limit selection by seam boundaries (faces only)");
02577 }
02578 
02579 
02580 /* ************************* */
02581 
02582 void selectconnected_mesh_all(EditMesh *em)
02583 {
02584     EditVert *v1,*v2;
02585     EditEdge *eed;
02586     short done=1, toggle=0;
02587     
02588     if(em->edges.first==0) return;
02589     
02590     while(done==1) {
02591         done= 0;
02592         
02593         toggle++;
02594         if(toggle & 1) eed= em->edges.first;
02595         else eed= em->edges.last;
02596         
02597         while(eed) {
02598             v1= eed->v1;
02599             v2= eed->v2;
02600             if(eed->h==0) {
02601                 if(v1->f & SELECT) {
02602                     if( (v2->f & SELECT)==0 ) {
02603                         v2->f |= SELECT;
02604                         done= 1;
02605                     }
02606                 }
02607                 else if(v2->f & SELECT) {
02608                     if( (v1->f & SELECT)==0 ) {
02609                         v1->f |= SELECT;
02610                         done= 1;
02611                     }
02612                 }
02613             }
02614             if(toggle & 1) eed= eed->next;
02615             else eed= eed->prev;
02616         }
02617     }
02618     
02619     /* now use vertex select flag to select rest */
02620     EM_select_flush(em);
02621     
02622     //  if (EM_texFaceCheck())
02623 }
02624 
02625 static int select_linked_exec(bContext *C, wmOperator *op)
02626 {
02627     Object *obedit= CTX_data_edit_object(C);
02628     EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
02629     
02630     if( RNA_boolean_get(op->ptr, "limit") ) {
02631         ViewContext vc;
02632         em_setup_viewcontext(C, &vc);
02633         select_linked_limited_invoke(&vc, 1, 1);
02634     }
02635     else
02636         selectconnected_mesh_all(em);
02637     
02638     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02639 
02640     BKE_mesh_end_editmesh(obedit->data, em);
02641     return OPERATOR_FINISHED;   
02642 }
02643 
02644 static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
02645 {
02646     linked_limit_default(C, op);
02647     return select_linked_exec(C, op);
02648 }
02649 
02650 void MESH_OT_select_linked(wmOperatorType *ot)
02651 {
02652     /* identifiers */
02653     ot->name= "Select Linked All";
02654     ot->description= "Select all vertices linked to the active mesh";
02655     ot->idname= "MESH_OT_select_linked";
02656     
02657     /* api callbacks */
02658     ot->exec= select_linked_exec;
02659     ot->invoke= select_linked_invoke;
02660     ot->poll= ED_operator_editmesh;
02661     
02662     /* flags */
02663     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02664     
02665     RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "Limit selection by seam boundaries (faces only)");
02666 }
02667 
02668 
02669 /* ************************* */
02670 
02671 /* swap is 0 or 1, if 1 it hides not selected */
02672 void EM_hide_mesh(EditMesh *em, int swap)
02673 {
02674     EditVert *eve;
02675     EditEdge *eed;
02676     EditFace *efa;
02677     int a;
02678     
02679     if(em==NULL) return;
02680 
02681     /* hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
02682     /*  - vertex hidden, always means edge is hidden too
02683         - edge hidden, always means face is hidden too
02684         - face hidden, only set face hide
02685         - then only flush back down what's absolute hidden
02686     */
02687     if(em->selectmode & SCE_SELECT_VERTEX) {
02688         for(eve= em->verts.first; eve; eve= eve->next) {
02689             if((eve->f & SELECT)!=swap) {
02690                 eve->f &= ~SELECT;
02691                 eve->h= 1;
02692             }
02693         }
02694     
02695         for(eed= em->edges.first; eed; eed= eed->next) {
02696             if(eed->v1->h || eed->v2->h) {
02697                 eed->h |= 1;
02698                 eed->f &= ~SELECT;
02699             }
02700         }
02701     
02702         for(efa= em->faces.first; efa; efa= efa->next) {
02703             if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
02704                 efa->h= 1;
02705                 efa->f &= ~SELECT;
02706             }
02707         }
02708     }
02709     else if(em->selectmode & SCE_SELECT_EDGE) {
02710 
02711         for(eed= em->edges.first; eed; eed= eed->next) {
02712             if((eed->f & SELECT)!=swap) {
02713                 eed->h |= 1;
02714                 EM_select_edge(eed, 0);
02715             }
02716         }
02717 
02718         for(efa= em->faces.first; efa; efa= efa->next) {
02719             if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
02720                 efa->h= 1;
02721                 efa->f &= ~SELECT;
02722             }
02723         }
02724     }
02725     else {
02726 
02727         for(efa= em->faces.first; efa; efa= efa->next) {
02728             if((efa->f & SELECT)!=swap) {
02729                 efa->h= 1;
02730                 EM_select_face(efa, 0);
02731             }
02732         }
02733     }
02734     
02735     /* flush down, only whats 100% hidden */
02736     for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
02737     for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
02738     
02739     if(em->selectmode & SCE_SELECT_FACE) {
02740         for(efa= em->faces.first; efa; efa= efa->next) {
02741             if(efa->h) a= 1; else a= 2;
02742             efa->e1->f1 |= a;
02743             efa->e2->f1 |= a;
02744             efa->e3->f1 |= a;
02745             if(efa->e4) efa->e4->f1 |= a;
02746             /* When edges are not delt with in their own loop, we need to explicitly re-selct select edges that are joined to unselected faces */
02747             if (swap && (em->selectmode == SCE_SELECT_FACE) && (efa->f & SELECT)) {
02748                 EM_select_face(efa, 1);
02749             }
02750         }
02751     }
02752     
02753     if(em->selectmode >= SCE_SELECT_EDGE) {
02754         for(eed= em->edges.first; eed; eed= eed->next) {
02755             if(eed->f1==1) eed->h |= 1;
02756             if(eed->h & 1) a= 1; else a= 2;
02757             eed->v1->f1 |= a;
02758             eed->v2->f1 |= a;
02759         }
02760     }
02761 
02762     if(em->selectmode >= SCE_SELECT_VERTEX) {
02763         for(eve= em->verts.first; eve; eve= eve->next) {
02764             if(eve->f1==1) eve->h= 1;
02765         }
02766     }
02767     
02768     em->totedgesel= em->totfacesel= em->totvertsel= 0;
02769 //  if(EM_texFaceCheck())
02770 
02771     //  DAG_id_tag_update(obedit->data, 0);
02772 }
02773 
02774 static int hide_mesh_exec(bContext *C, wmOperator *op)
02775 {
02776     Object *obedit= CTX_data_edit_object(C);
02777     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
02778     
02779     EM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
02780         
02781     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02782 
02783     BKE_mesh_end_editmesh(obedit->data, em);
02784     return OPERATOR_FINISHED;   
02785 }
02786 
02787 void MESH_OT_hide(wmOperatorType *ot)
02788 {
02789     /* identifiers */
02790     ot->name= "Hide Selection";
02791     ot->description= "Hide (un)selected vertices, edges or faces";
02792     ot->idname= "MESH_OT_hide";
02793     
02794     /* api callbacks */
02795     ot->exec= hide_mesh_exec;
02796     ot->poll= ED_operator_editmesh;
02797     
02798     /* flags */
02799     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02800     
02801     /* props */
02802     RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
02803 }
02804 
02805 void EM_reveal_mesh(EditMesh *em)
02806 {
02807     EditVert *eve;
02808     EditEdge *eed;
02809     EditFace *efa;
02810     
02811     if(em==NULL) return;
02812 
02813     for(eve= em->verts.first; eve; eve= eve->next) {
02814         if(eve->h) {
02815             eve->h= 0;
02816             eve->f |= SELECT;
02817         }
02818     }
02819     for(eed= em->edges.first; eed; eed= eed->next) {
02820         if(eed->h & 1) {
02821             eed->h &= ~1;
02822             if(em->selectmode & SCE_SELECT_VERTEX); 
02823             else EM_select_edge(eed, 1);
02824         }
02825     }
02826     for(efa= em->faces.first; efa; efa= efa->next) {
02827         if(efa->h) {
02828             efa->h= 0;
02829             if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX)); 
02830             else EM_select_face(efa, 1);
02831         }
02832     }
02833 
02834     EM_fgon_flags(em);  /* redo flags and indices for fgons */
02835     EM_selectmode_flush(em);
02836 
02837 //  if (EM_texFaceCheck())
02838 //  DAG_id_tag_update(obedit->data, 0);
02839 }
02840 
02841 static int reveal_mesh_exec(bContext *C, wmOperator *UNUSED(op))
02842 {
02843     Object *obedit= CTX_data_edit_object(C);
02844     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
02845     
02846     EM_reveal_mesh(em);
02847 
02848     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02849 
02850     BKE_mesh_end_editmesh(obedit->data, em);
02851     return OPERATOR_FINISHED;   
02852 }
02853 
02854 void MESH_OT_reveal(wmOperatorType *ot)
02855 {
02856     /* identifiers */
02857     ot->name= "Reveal Hidden";
02858     ot->description= "Reveal all hidden vertices, edges and faces";
02859     ot->idname= "MESH_OT_reveal";
02860     
02861     /* api callbacks */
02862     ot->exec= reveal_mesh_exec;
02863     ot->poll= ED_operator_editmesh;
02864     
02865     /* flags */
02866     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02867 }
02868 
02869 static int select_by_number_vertices_exec(bContext *C, wmOperator *op)
02870 {
02871     Object *obedit= CTX_data_edit_object(C);
02872     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
02873     EditFace *efa;
02874     int numverts= RNA_enum_get(op->ptr, "type");
02875 
02876     /* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring
02877      * faces
02878      */
02879 
02880     /* for loose vertices/edges, we first select all, loop below will deselect */
02881     if(numverts==5) {
02882         EM_set_flag_all(em, SELECT);
02883     }
02884     else if(em->selectmode!=SCE_SELECT_FACE) {
02885         BKE_report(op->reports, RPT_WARNING, "Only works in face selection mode");
02886         return OPERATOR_CANCELLED;
02887     }
02888     
02889     for(efa= em->faces.first; efa; efa= efa->next) {
02890         if (efa->e4) {
02891             EM_select_face(efa, (numverts==4) );
02892         }
02893         else {
02894             EM_select_face(efa, (numverts==3) );
02895         }
02896     }
02897     
02898     EM_selectmode_flush(em);
02899 
02900     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02901     
02902     return OPERATOR_FINISHED;
02903 }
02904 
02905 void MESH_OT_select_by_number_vertices(wmOperatorType *ot)
02906 {
02907     static const EnumPropertyItem type_items[]= {
02908         {3, "TRIANGLES", 0, "Triangles", NULL},
02909         {4, "QUADS", 0, "Quads", NULL},
02910         {5, "OTHER", 0, "Other", NULL},
02911         {0, NULL, 0, NULL, NULL}};
02912 
02913     /* identifiers */
02914     ot->name= "Select by Number of Vertices";
02915     ot->description= "Select vertices or faces by vertex count";
02916     ot->idname= "MESH_OT_select_by_number_vertices";
02917     
02918     /* api callbacks */
02919     ot->exec= select_by_number_vertices_exec;
02920     ot->invoke= WM_menu_invoke;
02921     ot->poll= ED_operator_editmesh;
02922     
02923     /* flags */
02924     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02925     
02926     /* props */
02927     ot->prop= RNA_def_enum(ot->srna, "type", type_items, 3, "Type", "Type of elements to select");
02928 }
02929 
02930 
02931 static int select_mirror_exec(bContext *C, wmOperator *op)
02932 {
02933     Object *obedit= CTX_data_edit_object(C);
02934     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
02935 
02936     int extend= RNA_boolean_get(op->ptr, "extend");
02937 
02938     EM_select_mirrored(obedit, em, extend);
02939     EM_selectmode_flush(em);
02940     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02941 
02942     return OPERATOR_FINISHED;
02943 }
02944 
02945 void MESH_OT_select_mirror(wmOperatorType *ot)
02946 {
02947     /* identifiers */
02948     ot->name= "Select Mirror";
02949     ot->description= "Select mesh items at mirrored locations";
02950     ot->idname= "MESH_OT_select_mirror";
02951 
02952     /* api callbacks */
02953     ot->exec= select_mirror_exec;
02954     ot->poll= ED_operator_editmesh;
02955 
02956     /* flags */
02957     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02958 
02959     /* props */
02960     RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
02961 }
02962 
02963 static int select_sharp_edges_exec(bContext *C, wmOperator *op)
02964 {
02965     /* Find edges that have exactly two neighboring faces,
02966     * check the angle between those faces, and if angle is
02967     * small enough, select the edge
02968     */
02969     Object *obedit= CTX_data_edit_object(C);
02970     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
02971     EditEdge *eed;
02972     EditFace *efa;
02973     EditFace **efa1;
02974     EditFace **efa2;
02975     intptr_t edgecount = 0, i = 0;
02976     float sharpness, fsharpness;
02977     
02978     /* 'standard' behaviour - check if selected, then apply relevant selection */
02979     
02980     if(em->selectmode==SCE_SELECT_FACE) {
02981         BKE_report(op->reports, RPT_WARNING, "Doesn't work in face selection mode");
02982         BKE_mesh_end_editmesh(obedit->data, em);
02983         return OPERATOR_CANCELLED;
02984     }
02985 
02986     sharpness= RNA_float_get(op->ptr, "sharpness");
02987     fsharpness = ((180.0f - sharpness) * (float)M_PI) / 180.0f;
02988 
02989     /* count edges, use tmp.l  */
02990     eed= em->edges.first;
02991     while(eed) {
02992         edgecount++;
02993         eed->tmp.l = i;
02994         eed= eed->next;
02995         ++i;
02996     }
02997 
02998     /* for each edge, we want a pointer to two adjacent faces */
02999     efa1 = MEM_callocN(edgecount*sizeof(EditFace *), 
03000                        "pairs of edit face pointers");
03001     efa2 = MEM_callocN(edgecount*sizeof(EditFace *), 
03002                        "pairs of edit face pointers");
03003 
03004 #define face_table_edge(eed) { \
03005         i = eed->tmp.l; \
03006         if (i != -1) { \
03007             if (efa1[i]) { \
03008                 if (efa2[i]) { \
03009                     /* invalidate, edge has more than two neighbors */ \
03010                     eed->tmp.l = -1; \
03011                 } \
03012                 else { \
03013                     efa2[i] = efa; \
03014                 } \
03015             } \
03016             else { \
03017                 efa1[i] = efa; \
03018             } \
03019         } \
03020     }
03021 
03022     /* find the adjacent faces of each edge, we want only two */
03023     efa= em->faces.first;
03024     while(efa) {
03025         face_table_edge(efa->e1);
03026         face_table_edge(efa->e2);
03027         face_table_edge(efa->e3);
03028         if (efa->e4) {
03029             face_table_edge(efa->e4);
03030         }
03031         efa= efa->next;
03032     }
03033 
03034 #undef face_table_edge
03035 
03036     eed = em->edges.first;
03037     while(eed) {
03038         i = eed->tmp.l;
03039         if (i != -1) { 
03040             /* edge has two or less neighboring faces */
03041             if ( (efa1[i]) && (efa2[i]) ) { 
03042                 /* edge has exactly two neighboring faces, check angle */
03043                 float angle;
03044                 angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
03045                                efa1[i]->n[1]*efa2[i]->n[1] +
03046                                efa1[i]->n[2]*efa2[i]->n[2]);
03047                 if (fabsf(angle) >= fsharpness)
03048                     EM_select_edge(eed, 1);
03049             }
03050         }
03051 
03052         eed= eed->next;
03053     }
03054 
03055     MEM_freeN(efa1);
03056     MEM_freeN(efa2);
03057 
03058 //  if (EM_texFaceCheck())
03059     
03060     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); //TODO is this needed ?
03061 
03062     BKE_mesh_end_editmesh(obedit->data, em);
03063     return OPERATOR_FINISHED;   
03064 }
03065 
03066 void MESH_OT_edges_select_sharp(wmOperatorType *ot)
03067 {
03068     /* identifiers */
03069     ot->name= "Select Sharp Edges";
03070     ot->description= "Marked selected edges as sharp";
03071     ot->idname= "MESH_OT_edges_select_sharp";
03072     
03073     /* api callbacks */
03074     ot->exec= select_sharp_edges_exec;
03075     ot->poll= ED_operator_editmesh;
03076     
03077     /* flags */
03078     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03079     
03080     /* props */
03081     RNA_def_float(ot->srna, "sharpness", 0.01f, 0.0f, FLT_MAX, "sharpness", "", 0.0f, 180.0f);
03082 }
03083 
03084 
03085 static void select_linked_flat_faces(EditMesh *em, wmOperator *op, float sharpness)
03086 {
03087     /* Find faces that are linked to selected faces that are 
03088      * relatively flat (angle between faces is higher than
03089      * specified angle)
03090      */
03091     EditEdge *eed;
03092     EditFace *efa;
03093     EditFace **efa1;
03094     EditFace **efa2;
03095     intptr_t edgecount = 0, i, faceselcount=0, faceselcountold=0;
03096     float fsharpness;
03097     
03098     if(em->selectmode!=SCE_SELECT_FACE) {
03099         BKE_report(op->reports, RPT_WARNING, "Only works in face selection mode");
03100         return;
03101     }
03102 
03103     fsharpness = ((180.0f - sharpness) * (float)M_PI) / 180.0f;
03104 
03105     i=0;
03106     /* count edges, use tmp.l */
03107     eed= em->edges.first;
03108     while(eed) {
03109         edgecount++;
03110         eed->tmp.l = i;
03111         eed= eed->next;
03112         ++i;
03113     }
03114 
03115     /* for each edge, we want a pointer to two adjacent faces */
03116     efa1 = MEM_callocN(edgecount*sizeof(EditFace *), 
03117                        "pairs of edit face pointers");
03118     efa2 = MEM_callocN(edgecount*sizeof(EditFace *), 
03119                        "pairs of edit face pointers");
03120 
03121 #define face_table_edge(eed) { \
03122         i = eed->tmp.l; \
03123         if (i != -1) { \
03124             if (efa1[i]) { \
03125                 if (efa2[i]) { \
03126                     /* invalidate, edge has more than two neighbors */ \
03127                     eed->tmp.l = -1; \
03128                 } \
03129                 else { \
03130                     efa2[i] = efa; \
03131                 } \
03132             } \
03133             else { \
03134                 efa1[i] = efa; \
03135             } \
03136         } \
03137     }
03138 
03139     /* find the adjacent faces of each edge, we want only two */
03140     efa= em->faces.first;
03141     while(efa) {
03142         face_table_edge(efa->e1);
03143         face_table_edge(efa->e2);
03144         face_table_edge(efa->e3);
03145         if (efa->e4) {
03146             face_table_edge(efa->e4);
03147         }
03148 
03149         /* while were at it, count the selected faces */
03150         if (efa->f & SELECT) ++faceselcount;
03151 
03152         efa= efa->next;
03153     }
03154 
03155 #undef face_table_edge
03156 
03157     eed= em->edges.first;
03158     while(eed) {
03159         i = eed->tmp.l;
03160         if (i != -1) { 
03161             /* edge has two or less neighboring faces */
03162             if ( (efa1[i]) && (efa2[i]) ) { 
03163                 /* edge has exactly two neighboring faces, check angle */
03164                 float angle;
03165                 angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
03166                                efa1[i]->n[1]*efa2[i]->n[1] +
03167                                efa1[i]->n[2]*efa2[i]->n[2]);
03168                 /* invalidate: edge too sharp */
03169                 if (fabsf(angle) >= fsharpness)
03170                     eed->tmp.l = -1;
03171             }
03172             else {
03173                 /* invalidate: less than two neighbors */
03174                 eed->tmp.l = -1;
03175             }
03176         }
03177 
03178         eed= eed->next;
03179     }
03180 
03181 #define select_flat_neighbor(eed) { \
03182                 i = eed->tmp.l; \
03183                 if (i!=-1) { \
03184                     if (! (efa1[i]->f & SELECT) ) { \
03185                         EM_select_face(efa1[i], 1); \
03186                         ++faceselcount; \
03187                     } \
03188                     if (! (efa2[i]->f & SELECT) ) { \
03189                         EM_select_face(efa2[i], 1); \
03190                         ++faceselcount; \
03191                     } \
03192                 } \
03193     }
03194 
03195     while (faceselcount != faceselcountold) {
03196         faceselcountold = faceselcount;
03197 
03198         efa= em->faces.first;
03199         while(efa) {
03200             if (efa->f & SELECT) {
03201                 select_flat_neighbor(efa->e1);
03202                 select_flat_neighbor(efa->e2);
03203                 select_flat_neighbor(efa->e3);
03204                 if (efa->e4) {
03205                     select_flat_neighbor(efa->e4);
03206                 }
03207             }
03208             efa= efa->next;
03209         }
03210     }
03211 
03212 #undef select_flat_neighbor
03213 
03214     MEM_freeN(efa1);
03215     MEM_freeN(efa2);
03216 
03217 //  if (EM_texFaceCheck())
03218 
03219 }
03220 
03221 static int select_linked_flat_faces_exec(bContext *C, wmOperator *op)
03222 {
03223     Object *obedit= CTX_data_edit_object(C);
03224     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
03225     
03226     select_linked_flat_faces(em, op, RNA_float_get(op->ptr, "sharpness"));
03227     
03228     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
03229 
03230     BKE_mesh_end_editmesh(obedit->data, em);
03231     return OPERATOR_FINISHED;   
03232 }
03233 
03234 void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
03235 {
03236     /* identifiers */
03237     ot->name= "Select Linked Flat Faces";
03238     ot->description= "Select linked faces by angle";
03239     ot->idname= "MESH_OT_faces_select_linked_flat";
03240     
03241     /* api callbacks */
03242     ot->exec= select_linked_flat_faces_exec;
03243     ot->poll= ED_operator_editmesh;
03244     
03245     /* flags */
03246     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03247     
03248     /* props */
03249     RNA_def_float(ot->srna, "sharpness", 135.0f, 0.0f, FLT_MAX, "sharpness", "", 0.0f, 180.0f);
03250 }
03251 
03252 static void select_non_manifold(EditMesh *em, wmOperator *op )
03253 {
03254     EditVert *eve;
03255     EditEdge *eed;
03256     EditFace *efa;
03257 
03258     /* Selects isolated verts, and edges that do not have 2 neighboring
03259      * faces
03260      */
03261     
03262     if(em->selectmode==SCE_SELECT_FACE) {
03263         BKE_report(op->reports, RPT_WARNING, "Doesn't work in face selection mode");
03264         return;
03265     }
03266 
03267     eve= em->verts.first;
03268     while(eve) {
03269         /* this will count how many edges are connected
03270          * to this vert */
03271         eve->f1= 0;
03272         eve= eve->next;
03273     }
03274 
03275     eed= em->edges.first;
03276     while(eed) {
03277         /* this will count how many faces are connected to
03278          * this edge */
03279         eed->f1= 0;
03280         /* increase edge count for verts */
03281         ++eed->v1->f1;
03282         ++eed->v2->f1;
03283         eed= eed->next;
03284     }
03285 
03286     efa= em->faces.first;
03287     while(efa) {
03288         /* increase face count for edges */
03289         ++efa->e1->f1;
03290         ++efa->e2->f1;
03291         ++efa->e3->f1;
03292         if (efa->e4)
03293             ++efa->e4->f1;          
03294         efa= efa->next;
03295     }
03296 
03297     /* select verts that are attached to an edge that does not
03298      * have 2 neighboring faces */
03299     eed= em->edges.first;
03300     while(eed) {
03301         if (eed->h==0 && eed->f1 != 2) {
03302             EM_select_edge(eed, 1);
03303         }
03304         eed= eed->next;
03305     }
03306 
03307     /* select isolated verts */
03308     if(em->selectmode & SCE_SELECT_VERTEX) {
03309         eve= em->verts.first;
03310         while(eve) {
03311             if (eve->f1 == 0) {
03312                 if (!eve->h) eve->f |= SELECT;
03313             }
03314             eve= eve->next;
03315         }
03316     }
03317 
03318 //  if (EM_texFaceCheck())
03319 
03320 }
03321 
03322 static int select_non_manifold_exec(bContext *C, wmOperator *op)
03323 {
03324     Object *obedit= CTX_data_edit_object(C);
03325     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
03326     
03327     select_non_manifold(em, op);
03328     
03329     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
03330 
03331     BKE_mesh_end_editmesh(obedit->data, em);
03332     return OPERATOR_FINISHED;   
03333 }
03334 
03335 void MESH_OT_select_non_manifold(wmOperatorType *ot)
03336 {
03337     /* identifiers */
03338     ot->name= "Select Non Manifold";
03339     ot->description= "Select all non-manifold vertices or edges";
03340     ot->idname= "MESH_OT_select_non_manifold";
03341     
03342     /* api callbacks */
03343     ot->exec= select_non_manifold_exec;
03344     ot->poll= ED_operator_editmesh;
03345     
03346     /* flags */
03347     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03348 }
03349 
03350 void EM_select_swap(EditMesh *em) /* exported for UV */
03351 {
03352     EditVert *eve;
03353     EditEdge *eed;
03354     EditFace *efa;
03355     
03356     if(em->selectmode & SCE_SELECT_VERTEX) {
03357 
03358         for(eve= em->verts.first; eve; eve= eve->next) {
03359             if(eve->h==0) {
03360                 if(eve->f & SELECT) eve->f &= ~SELECT;
03361                 else eve->f|= SELECT;
03362             }
03363         }
03364     }
03365     else if(em->selectmode & SCE_SELECT_EDGE) {
03366         for(eed= em->edges.first; eed; eed= eed->next) {
03367             if(eed->h==0) {
03368                 EM_select_edge(eed, !(eed->f & SELECT));
03369             }
03370         }
03371     }
03372     else {
03373         for(efa= em->faces.first; efa; efa= efa->next) {
03374             if(efa->h==0) {
03375                 EM_select_face(efa, !(efa->f & SELECT));
03376             }
03377         }
03378     }
03379 
03380     EM_selectmode_flush(em);
03381     
03382 //  if (EM_texFaceCheck())
03383 
03384 }
03385     
03386 /* ******************** (de)select all operator **************** */
03387 
03388 void EM_toggle_select_all(EditMesh *em) /* exported for UV */
03389 {
03390     if(EM_nvertices_selected(em))
03391         EM_clear_flag_all(em, SELECT);
03392     else 
03393         EM_set_flag_all_selectmode(em, SELECT);
03394 }
03395 
03396 void EM_select_all(EditMesh *em)
03397 {
03398     EM_set_flag_all_selectmode(em, SELECT);
03399 }
03400 
03401 void EM_deselect_all(EditMesh *em)
03402 {
03403     EM_clear_flag_all(em, SELECT);
03404 }
03405 
03406 static int editmesh_select_all_exec(bContext *C, wmOperator *op)
03407 {
03408     Object *obedit= CTX_data_edit_object(C);
03409     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
03410     int action = RNA_enum_get(op->ptr, "action");
03411     
03412     switch (action) {
03413     case SEL_TOGGLE:
03414         EM_toggle_select_all(em);
03415         break;
03416     case SEL_SELECT:
03417         EM_select_all(em);
03418         break;
03419     case SEL_DESELECT:
03420         EM_deselect_all(em);
03421         break;
03422     case SEL_INVERT:
03423         EM_select_swap(em);
03424         break;
03425     }
03426     
03427     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);  
03428     BKE_mesh_end_editmesh(obedit->data, em);
03429 
03430     return OPERATOR_FINISHED;
03431 }
03432 
03433 void MESH_OT_select_all(wmOperatorType *ot)
03434 {
03435     /* identifiers */
03436     ot->name= "Select or Deselect All";
03437     ot->description= "Change selection of all vertices, edges or faces";
03438     ot->idname= "MESH_OT_select_all";
03439     
03440     /* api callbacks */
03441     ot->exec= editmesh_select_all_exec;
03442     ot->poll= ED_operator_editmesh;
03443     
03444     /* flags */
03445     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03446 
03447     WM_operator_properties_select_all(ot);
03448 }
03449 
03450 /* ******************** **************** */
03451 
03452 void EM_select_more(EditMesh *em)
03453 {
03454     EditVert *eve;
03455     EditEdge *eed;
03456     EditFace *efa;
03457     
03458     for(eve= em->verts.first; eve; eve= eve->next) {
03459         if(eve->f & SELECT) eve->f1= 1;
03460         else eve->f1 = 0;
03461     }
03462     
03463     /* set f1 flags in vertices to select 'more' */
03464     for(eed= em->edges.first; eed; eed= eed->next) {
03465         if(eed->h==0) {
03466             if (eed->v1->f & SELECT)
03467                 eed->v2->f1 = 1;
03468             if (eed->v2->f & SELECT)
03469                 eed->v1->f1 = 1;
03470         }
03471     }
03472 
03473     /* new selected edges, but not in facemode */
03474     if(em->selectmode <= SCE_SELECT_EDGE) {
03475         
03476         for(eed= em->edges.first; eed; eed= eed->next) {
03477             if(eed->h==0) {
03478                 if(eed->v1->f1 && eed->v2->f1) EM_select_edge(eed, 1);
03479             }
03480         }
03481     }
03482     /* new selected faces */
03483     for(efa= em->faces.first; efa; efa= efa->next) {
03484         if(efa->h==0) {
03485             if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1)) 
03486                 EM_select_face(efa, 1);
03487         }
03488     }
03489 }
03490 
03491 static int select_more(bContext *C, wmOperator *UNUSED(op))
03492 {
03493     Object *obedit= CTX_data_edit_object(C);
03494     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)) ;
03495 
03496     EM_select_more(em);
03497 
03498 //  if (EM_texFaceCheck(em))
03499 
03500     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
03501 
03502     BKE_mesh_end_editmesh(obedit->data, em);
03503     return OPERATOR_FINISHED;
03504 }
03505 
03506 void MESH_OT_select_more(wmOperatorType *ot)
03507 {
03508     /* identifiers */
03509     ot->name= "Select More";
03510     ot->description= "Select more vertices, edges or faces connected to initial selection";
03511     ot->idname= "MESH_OT_select_more";
03512 
03513     /* api callbacks */
03514     ot->exec= select_more;
03515     ot->poll= ED_operator_editmesh;
03516     
03517     /* flags */
03518     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03519 }
03520 
03521 static void EM_select_less(EditMesh *em)
03522 {
03523     EditEdge *eed;
03524     EditFace *efa;
03525 
03526     if(em->selectmode <= SCE_SELECT_EDGE) {
03527         /* eed->f1 == 1:  edge with a selected and deselected vert */ 
03528 
03529         for(eed= em->edges.first; eed; eed= eed->next) {
03530             eed->f1= 0;
03531             if(eed->h==0) {
03532                 
03533                 if ( !(eed->v1->f & SELECT) && (eed->v2->f & SELECT) ) 
03534                     eed->f1= 1;
03535                 if ( (eed->v1->f & SELECT) && !(eed->v2->f & SELECT) ) 
03536                     eed->f1= 1;
03537             }
03538         }
03539         
03540         /* deselect edges with flag set */
03541         for(eed= em->edges.first; eed; eed= eed->next) {
03542             if (eed->h==0 && eed->f1 == 1) {
03543                 EM_select_edge(eed, 0);
03544             }
03545         }
03546         EM_deselect_flush(em);
03547         
03548     }
03549     else {
03550         /* deselect faces with 1 or more deselect edges */
03551         /* eed->f1 == mixed selection edge */
03552         for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
03553 
03554         for(efa= em->faces.first; efa; efa= efa->next) {
03555             if(efa->h==0) {
03556                 if(efa->f & SELECT) {
03557                     efa->e1->f1 |= 1;
03558                     efa->e2->f1 |= 1;
03559                     efa->e3->f1 |= 1;
03560                     if(efa->e4) efa->e4->f1 |= 1;
03561                 }
03562                 else {
03563                     efa->e1->f1 |= 2;
03564                     efa->e2->f1 |= 2;
03565                     efa->e3->f1 |= 2;
03566                     if(efa->e4) efa->e4->f1 |= 2;
03567                 }
03568             }
03569         }
03570         for(efa= em->faces.first; efa; efa= efa->next) {
03571             if(efa->h==0) {
03572                 if(efa->e1->f1==3 || efa->e2->f1==3 || efa->e3->f1==3 || (efa->e4 && efa->e4->f1==3)) { 
03573                     EM_select_face(efa, 0);
03574                 }
03575             }
03576         }
03577         EM_selectmode_flush(em);
03578         
03579     }
03580 }
03581 
03582 static int select_less(bContext *C, wmOperator *UNUSED(op))
03583 {
03584     Object *obedit= CTX_data_edit_object(C);
03585     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
03586 
03587     EM_select_less(em);
03588 
03589 //  if (EM_texFaceCheck(em))
03590     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
03591 
03592     BKE_mesh_end_editmesh(obedit->data, em);
03593     return OPERATOR_FINISHED;
03594 }
03595 
03596 void MESH_OT_select_less(wmOperatorType *ot)
03597 {
03598     /* identifiers */
03599     ot->name= "Select Less";
03600     ot->description= "Select less vertices, edges or faces connected to initial selection";
03601     ot->idname= "MESH_OT_select_less";
03602 
03603     /* api callbacks */
03604     ot->exec= select_less;
03605     ot->poll= ED_operator_editmesh;
03606     
03607     /* flags */
03608     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03609 }
03610 
03611 static void selectrandom_mesh(EditMesh *em, float randfac) /* randomly selects a user-set % of vertices/edges/faces */
03612 {
03613     EditVert *eve;
03614     EditEdge *eed;
03615     EditFace *efa;
03616 
03617     BLI_srand( BLI_rand() ); /* random seed */
03618     
03619     if(em->selectmode & SCE_SELECT_VERTEX) {
03620         for(eve= em->verts.first; eve; eve= eve->next) {
03621             if(eve->h==0) {
03622                 if (BLI_frand() < randfac) 
03623                     eve->f |= SELECT;
03624             }
03625         }
03626         EM_selectmode_flush(em);
03627     }
03628     else if(em->selectmode & SCE_SELECT_EDGE) {
03629         for(eed= em->edges.first; eed; eed= eed->next) {
03630             if(eed->h==0) {
03631                 if (BLI_frand() < randfac) 
03632                     EM_select_edge(eed, 1);
03633             }
03634         }
03635         EM_selectmode_flush(em);
03636     }
03637     else {
03638         for(efa= em->faces.first; efa; efa= efa->next) {
03639             if(efa->h==0) {
03640                 if (BLI_frand() < randfac) 
03641                     EM_select_face(efa, 1);
03642             }
03643         }
03644         
03645         EM_selectmode_flush(em);
03646     }
03647 //  if (EM_texFaceCheck())
03648 }
03649 
03650 static int mesh_select_random_exec(bContext *C, wmOperator *op)
03651 {
03652     Object *obedit= CTX_data_edit_object(C);
03653     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
03654     
03655     if(!RNA_boolean_get(op->ptr, "extend"))
03656         EM_deselect_all(em);
03657     
03658     selectrandom_mesh(em, RNA_float_get(op->ptr, "percent")/100.0f);
03659         
03660     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
03661     
03662     BKE_mesh_end_editmesh(obedit->data, em);
03663     return OPERATOR_FINISHED;   
03664 }
03665 
03666 void MESH_OT_select_random(wmOperatorType *ot)
03667 {
03668     /* identifiers */
03669     ot->name= "Select Random";
03670     ot->description= "Randomly select vertices";
03671     ot->idname= "MESH_OT_select_random";
03672 
03673     /* api callbacks */
03674     ot->exec= mesh_select_random_exec;
03675     ot->poll= ED_operator_editmesh;
03676 
03677     /* flags */
03678     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03679     
03680     /* props */
03681     RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
03682     RNA_def_boolean(ot->srna, "extend", FALSE, "Extend Selection", "Extend selection instead of deselecting everything first");
03683 }
03684 
03685 void EM_select_by_material(EditMesh *em, int index) 
03686 {
03687     EditFace *efa;
03688     
03689     for (efa=em->faces.first; efa; efa= efa->next) {
03690         if (efa->mat_nr==index) {
03691             EM_select_face(efa, 1);
03692         }
03693     }
03694 
03695     EM_selectmode_flush(em);
03696 }
03697 
03698 void EM_deselect_by_material(EditMesh *em, int index) 
03699 {
03700     EditFace *efa;
03701     
03702     for (efa=em->faces.first; efa; efa= efa->next) {
03703         if (efa->mat_nr==index) {
03704             EM_select_face(efa, 0);
03705         }
03706     }
03707 
03708     EM_selectmode_flush(em);
03709 }
03710 
03711 /* ************************* SEAMS AND EDGES **************** */
03712 
03713 static int editmesh_mark_seam(bContext *C, wmOperator *op)
03714 {
03715     Scene *scene= CTX_data_scene(C);
03716     Object *obedit= CTX_data_edit_object(C);
03717     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
03718     Mesh *me= ((Mesh *)obedit->data);
03719     EditEdge *eed;
03720     int clear = RNA_boolean_get(op->ptr, "clear");
03721     
03722     /* auto-enable seams drawing */
03723     if(clear==0) {
03724         me->drawflag |= ME_DRAWSEAMS;
03725     }
03726 
03727     if(clear) {
03728         eed= em->edges.first;
03729         while(eed) {
03730             if((eed->h==0) && (eed->f & SELECT)) {
03731                 eed->seam = 0;
03732             }
03733             eed= eed->next;
03734         }
03735     }
03736     else {
03737         eed= em->edges.first;
03738         while(eed) {
03739             if((eed->h==0) && (eed->f & SELECT)) {
03740                 eed->seam = 1;
03741             }
03742             eed= eed->next;
03743         }
03744     }
03745 
03746     /* live unwrap while tagging */
03747     if( (scene->toolsettings->edge_mode_live_unwrap) &&
03748         (CustomData_has_layer(&em->fdata, CD_MTFACE))
03749     ) {
03750         ED_unwrap_lscm(scene, obedit, FALSE); /* unwrap all not just sel */
03751     }
03752 
03753     BKE_mesh_end_editmesh(obedit->data, em);
03754 
03755     DAG_id_tag_update(obedit->data, 0);
03756     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
03757 
03758     return OPERATOR_FINISHED;
03759 }
03760 
03761 void MESH_OT_mark_seam(wmOperatorType *ot)
03762 {
03763     /* identifiers */
03764     ot->name= "Mark Seam";
03765     ot->description= "(un)mark selected edges as a seam";
03766     ot->idname= "MESH_OT_mark_seam";
03767     
03768     /* api callbacks */
03769     ot->exec= editmesh_mark_seam;
03770     ot->poll= ED_operator_editmesh;
03771     
03772     /* flags */
03773     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03774     
03775     RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
03776 }
03777 
03778 static int editmesh_mark_sharp(bContext *C, wmOperator *op)
03779 {
03780     Object *obedit= CTX_data_edit_object(C);
03781     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
03782     Mesh *me= ((Mesh *)obedit->data);
03783     int clear = RNA_boolean_get(op->ptr, "clear");
03784     EditEdge *eed;
03785 
03786     /* auto-enable sharp edge drawing */
03787     if(clear == 0) {
03788         me->drawflag |= ME_DRAWSHARP;
03789     }
03790 
03791     if(!clear) {
03792         eed= em->edges.first;
03793         while(eed) {
03794             if(!eed->h && (eed->f & SELECT)) eed->sharp = 1;
03795             eed = eed->next;
03796         }
03797     } else {
03798         eed= em->edges.first;
03799         while(eed) {
03800             if(!eed->h && (eed->f & SELECT)) eed->sharp = 0;
03801             eed = eed->next;
03802         }
03803     }
03804 
03805     BKE_mesh_end_editmesh(obedit->data, em);
03806 
03807     DAG_id_tag_update(obedit->data, 0);
03808     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
03809 
03810     return OPERATOR_FINISHED;
03811 }
03812 
03813 void MESH_OT_mark_sharp(wmOperatorType *ot)
03814 {
03815     /* identifiers */
03816     ot->name= "Mark Sharp";
03817     ot->description= "(un)mark selected edges as sharp";
03818     ot->idname= "MESH_OT_mark_sharp";
03819     
03820     /* api callbacks */
03821     ot->exec= editmesh_mark_sharp;
03822     ot->poll= ED_operator_editmesh;
03823     
03824     /* flags */
03825     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03826     
03827     RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
03828 }
03829 
03830 /* **************** NORMALS ************** */
03831 
03832 void EM_recalc_normal_direction(EditMesh *em, int inside, int select)   /* makes faces righthand turning */
03833 {
03834     EditEdge *eed, *ed1, *ed2, *ed3, *ed4;
03835     EditFace *efa, *startvl;
03836     float maxx, nor[3], cent[3];
03837     int totsel, found, foundone, direct, turn, tria_nr;
03838 
03839    /* based at a select-connected to witness loose objects */
03840 
03841     /* count per edge the amount of faces */
03842 
03843     /* find the ultimate left, front, upper face (not manhattan dist!!) */
03844     /* also evaluate both triangle cases in quad, since these can be non-flat */
03845 
03846     /* put normal to the outside, and set the first direction flags in edges */
03847 
03848     /* then check the object, and set directions / direction-flags: but only for edges with 1 or 2 faces */
03849     /* this is in fact the 'select connected' */
03850     
03851     /* in case (selected) faces were not done: start over with 'find the ultimate ...' */
03852 
03853     waitcursor(1);
03854     
03855     eed= em->edges.first;
03856     while(eed) {
03857         eed->f2= 0;     /* edge direction */
03858         eed->f1= 0;     /* counter */
03859         eed= eed->next;
03860     }
03861 
03862     /* count faces and edges */
03863     totsel= 0;
03864     efa= em->faces.first;
03865     while(efa) {
03866         if(select==0 || (efa->f & SELECT) ) {
03867             efa->f1= 1;
03868             totsel++;
03869             efa->e1->f1++;
03870             efa->e2->f1++;
03871             efa->e3->f1++;
03872             if(efa->v4) efa->e4->f1++;
03873         }
03874         else efa->f1= 0;
03875 
03876         efa= efa->next;
03877     }
03878 
03879     while(totsel>0) {
03880         /* from the outside to the inside */
03881 
03882         efa= em->faces.first;
03883         startvl= NULL;
03884         maxx= -1.0e10;
03885         tria_nr= 0;
03886 
03887         while(efa) {
03888             if(efa->f1) {
03889                 cent_tri_v3(cent, efa->v1->co, efa->v2->co, efa->v3->co);
03890                 cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
03891                 
03892                 if(cent[0]>maxx) {
03893                     maxx= cent[0];
03894                     startvl= efa;
03895                     tria_nr= 0;
03896                 }
03897                 if(efa->v4) {
03898                     cent_tri_v3(cent, efa->v1->co, efa->v3->co, efa->v4->co);
03899                     cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
03900                     
03901                     if(cent[0]>maxx) {
03902                         maxx= cent[0];
03903                         startvl= efa;
03904                         tria_nr= 1;
03905                     }
03906                 }
03907             }
03908             efa= efa->next;
03909         }
03910 
03911         if (startvl==NULL)
03912             startvl= em->faces.first;
03913         
03914         /* set first face correct: calc normal */
03915         
03916         if(tria_nr==1) {
03917             normal_tri_v3( nor,startvl->v1->co, startvl->v3->co, startvl->v4->co);
03918             cent_tri_v3(cent, startvl->v1->co, startvl->v3->co, startvl->v4->co);
03919         } else {
03920             normal_tri_v3( nor,startvl->v1->co, startvl->v2->co, startvl->v3->co);
03921             cent_tri_v3(cent, startvl->v1->co, startvl->v2->co, startvl->v3->co);
03922         }
03923         /* first normal is oriented this way or the other */
03924         if(inside) {
03925             if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] > 0.0f) flipface(em, startvl);
03926         }
03927         else {
03928             if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0f) flipface(em, startvl);
03929         }
03930 
03931         eed= startvl->e1;
03932         if(eed->v1==startvl->v1) eed->f2= 1; 
03933         else eed->f2= 2;
03934         
03935         eed= startvl->e2;
03936         if(eed->v1==startvl->v2) eed->f2= 1; 
03937         else eed->f2= 2;
03938         
03939         eed= startvl->e3;
03940         if(eed->v1==startvl->v3) eed->f2= 1; 
03941         else eed->f2= 2;
03942         
03943         eed= startvl->e4;
03944         if(eed) {
03945             if(eed->v1==startvl->v4) eed->f2= 1; 
03946             else eed->f2= 2;
03947         }
03948         
03949         startvl->f1= 0;
03950         totsel--;
03951 
03952         /* test normals */
03953         found= 1;
03954         direct= 1;
03955         while(found) {
03956             found= 0;
03957             if(direct) efa= em->faces.first;
03958             else efa= em->faces.last;
03959             while(efa) {
03960                 if(efa->f1) {
03961                     turn= 0;
03962                     foundone= 0;
03963 
03964                     ed1= efa->e1;
03965                     ed2= efa->e2;
03966                     ed3= efa->e3;
03967                     ed4= efa->e4;
03968 
03969                     if(ed1->f2) {
03970                         if(ed1->v1==efa->v1 && ed1->f2==1) turn= 1;
03971                         if(ed1->v2==efa->v1 && ed1->f2==2) turn= 1;
03972                         foundone= 1;
03973                     }
03974                     else if(ed2->f2) {
03975                         if(ed2->v1==efa->v2 && ed2->f2==1) turn= 1;
03976                         if(ed2->v2==efa->v2 && ed2->f2==2) turn= 1;
03977                         foundone= 1;
03978                     }
03979                     else if(ed3->f2) {
03980                         if(ed3->v1==efa->v3 && ed3->f2==1) turn= 1;
03981                         if(ed3->v2==efa->v3 && ed3->f2==2) turn= 1;
03982                         foundone= 1;
03983                     }
03984                     else if(ed4 && ed4->f2) {
03985                         if(ed4->v1==efa->v4 && ed4->f2==1) turn= 1;
03986                         if(ed4->v2==efa->v4 && ed4->f2==2) turn= 1;
03987                         foundone= 1;
03988                     }
03989 
03990                     if(foundone) {
03991                         found= 1;
03992                         totsel--;
03993                         efa->f1= 0;
03994 
03995                         if(turn) {
03996                             if(ed1->v1==efa->v1) ed1->f2= 2; 
03997                             else ed1->f2= 1;
03998                             if(ed2->v1==efa->v2) ed2->f2= 2; 
03999                             else ed2->f2= 1;
04000                             if(ed3->v1==efa->v3) ed3->f2= 2; 
04001                             else ed3->f2= 1;
04002                             if(ed4) {
04003                                 if(ed4->v1==efa->v4) ed4->f2= 2; 
04004                                 else ed4->f2= 1;
04005                             }
04006 
04007                             flipface(em, efa);
04008 
04009                         }
04010                         else {
04011                             if(ed1->v1== efa->v1) ed1->f2= 1; 
04012                             else ed1->f2= 2;
04013                             if(ed2->v1==efa->v2) ed2->f2= 1; 
04014                             else ed2->f2= 2;
04015                             if(ed3->v1==efa->v3) ed3->f2= 1; 
04016                             else ed3->f2= 2;
04017                             if(ed4) {
04018                                 if(ed4->v1==efa->v4) ed4->f2= 1; 
04019                                 else ed4->f2= 2;
04020                             }
04021                         }
04022                     }
04023                 }
04024                 if(direct) efa= efa->next;
04025                 else efa= efa->prev;
04026             }
04027             direct= 1-direct;
04028         }
04029     }
04030 
04031     recalc_editnormals(em);
04032     
04033 //  DAG_id_tag_update(obedit->data, 0);
04034 
04035     waitcursor(0);
04036 }
04037 
04038 
04039 static int normals_make_consistent_exec(bContext *C, wmOperator *op)
04040 {
04041     Object *obedit= CTX_data_edit_object(C);
04042     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
04043     
04044     /* 'standard' behaviour - check if selected, then apply relevant selection */
04045     
04046     // XXX  need other args
04047     EM_recalc_normal_direction(em, RNA_boolean_get(op->ptr, "inside"), 1);
04048     
04049     BKE_mesh_end_editmesh(obedit->data, em);
04050 
04051     DAG_id_tag_update(obedit->data, 0);
04052     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); //TODO is this needed ?
04053 
04054     return OPERATOR_FINISHED;   
04055 }
04056 
04057 void MESH_OT_normals_make_consistent(wmOperatorType *ot)
04058 {
04059     /* identifiers */
04060     ot->name= "Make Normals Consistent";
04061     ot->description= "Flip all selected vertex and face normals in a consistent direction";
04062     ot->idname= "MESH_OT_normals_make_consistent";
04063     
04064     /* api callbacks */
04065     ot->exec= normals_make_consistent_exec;
04066     ot->poll= ED_operator_editmesh;
04067     
04068     /* flags */
04069     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
04070     
04071     RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
04072 }
04073 
04074 /* **************** VERTEX DEFORMS *************** */
04075 
04076 static int smooth_vertex(bContext *C, wmOperator *op)
04077 {
04078     Object *obedit= CTX_data_edit_object(C);
04079     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
04080     EditVert *eve, *eve_mir = NULL;
04081     EditEdge *eed;
04082     float *adror, *adr, fac;
04083     float fvec[3];
04084     int teller=0;
04085     ModifierData *md;
04086     int index;
04087 
04088     /* count */
04089     eve= em->verts.first;
04090     while(eve) {
04091         if(eve->f & SELECT) teller++;
04092         eve= eve->next;
04093     }
04094     if(teller==0) {
04095         BKE_mesh_end_editmesh(obedit->data, em);
04096         return OPERATOR_CANCELLED;
04097     }
04098     
04099     adr=adror= (float *)MEM_callocN(3*sizeof(float *)*teller, "vertsmooth");
04100     eve= em->verts.first;
04101     while(eve) {
04102         if(eve->f & SELECT) {
04103             eve->tmp.p = (void*)adr;
04104             eve->f1= 0;
04105             eve->f2= 0;
04106             adr+= 3;
04107         }
04108         eve= eve->next;
04109     }
04110 
04111     /* if there is a mirror modifier with clipping, flag the verts that
04112      * are within tolerance of the plane(s) of reflection 
04113      */
04114     for(md=obedit->modifiers.first; md; md=md->next) {
04115         if((md->type==eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
04116             MirrorModifierData *mmd = (MirrorModifierData*) md; 
04117         
04118             if(mmd->flag & MOD_MIR_CLIPPING) {
04119                 for (eve= em->verts.first; eve; eve= eve->next) {
04120                     if(eve->f & SELECT) {
04121 
04122                         if (mmd->flag & MOD_MIR_AXIS_X && fabsf(eve->co[0]) < mmd->tolerance) eve->f2 |= 1;
04123                         if (mmd->flag & MOD_MIR_AXIS_Y && fabsf(eve->co[1]) < mmd->tolerance) eve->f2 |= 2;
04124                         if (mmd->flag & MOD_MIR_AXIS_Z && fabsf(eve->co[2]) < mmd->tolerance) eve->f2 |= 4;
04125 
04126                     }
04127                 }
04128             }
04129         }
04130     }
04131     
04132     eed= em->edges.first;
04133     while(eed) {
04134         if( (eed->v1->f & SELECT) || (eed->v2->f & SELECT) ) {
04135             mid_v3_v3v3(fvec, eed->v1->co, eed->v2->co);
04136             
04137             if((eed->v1->f & SELECT) && eed->v1->f1<255) {
04138                 eed->v1->f1++;
04139                 add_v3_v3(eed->v1->tmp.p, fvec);
04140             }
04141             if((eed->v2->f & SELECT) && eed->v2->f1<255) {
04142                 eed->v2->f1++;
04143                 add_v3_v3(eed->v2->tmp.p, fvec);
04144             }
04145         }
04146         eed= eed->next;
04147     }
04148 
04149     index= 0;
04150     eve= em->verts.first;
04151     while(eve) {
04152         if(eve->f & SELECT) {
04153             if(eve->f1) {
04154                 
04155                 int xaxis= RNA_boolean_get(op->ptr, "xaxis");
04156                 int yaxis= RNA_boolean_get(op->ptr, "yaxis");
04157                 int zaxis= RNA_boolean_get(op->ptr, "zaxis");
04158                 
04159                 if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
04160                     eve_mir= editmesh_get_x_mirror_vert(obedit, em, eve, eve->co, index);
04161                 }
04162                 
04163                 adr = eve->tmp.p;
04164                 fac= 0.5f/(float)eve->f1;
04165                 
04166                 if(xaxis)
04167                     eve->co[0]= 0.5f*eve->co[0]+fac*adr[0];
04168                 if(yaxis)
04169                     eve->co[1]= 0.5f*eve->co[1]+fac*adr[1];
04170                 if(zaxis)
04171                     eve->co[2]= 0.5f*eve->co[2]+fac*adr[2];
04172                 
04173                 
04174                 /* clip if needed by mirror modifier */
04175                 if (eve->f2) {
04176                     if (eve->f2 & 1) {
04177                         eve->co[0]= 0.0f;
04178                     }
04179                     if (eve->f2 & 2) {
04180                         eve->co[1]= 0.0f;
04181                     }
04182                     if (eve->f2 & 4) {
04183                         eve->co[2]= 0.0f;
04184                     }
04185                 }
04186                 
04187                 if (eve_mir) {
04188                     eve_mir->co[0]=-eve->co[0];
04189                     eve_mir->co[1]= eve->co[1];
04190                     eve_mir->co[2]= eve->co[2];
04191                 }
04192                 
04193             }
04194             eve->tmp.p= NULL;
04195         }
04196         index++;
04197         eve= eve->next;
04198     }
04199     MEM_freeN(adror);
04200 
04201     recalc_editnormals(em);
04202 
04203     BKE_mesh_end_editmesh(obedit->data, em);
04204 
04205     DAG_id_tag_update(obedit->data, 0);
04206     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
04207 
04208     return OPERATOR_FINISHED;
04209 }
04210 
04211 static int smooth_vertex_exec(bContext *C, wmOperator *op)
04212 {
04213     int repeat = RNA_int_get(op->ptr, "repeat");
04214     int i;
04215 
04216     if (!repeat) repeat = 1;
04217 
04218     for (i=0; i<repeat; i++) {
04219         smooth_vertex(C, op);
04220     }
04221 
04222     return OPERATOR_FINISHED;
04223 }
04224 
04225 void MESH_OT_vertices_smooth(wmOperatorType *ot)
04226 {
04227     /* identifiers */
04228     ot->name= "Smooth Vertex";
04229     ot->description= "Flatten angles of selected vertices";
04230     ot->idname= "MESH_OT_vertices_smooth";
04231     
04232     /* api callbacks */
04233     ot->exec= smooth_vertex_exec;
04234     ot->poll= ED_operator_editmesh;
04235     
04236     /* flags */
04237     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
04238 
04239     RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Smooth Iterations", "", 1, INT_MAX);
04240     RNA_def_boolean(ot->srna, "xaxis", 1, "X-Axis", "Smooth along the X axis");
04241     RNA_def_boolean(ot->srna, "yaxis", 1, "Y-Axis", "Smooth along the Y axis");
04242     RNA_def_boolean(ot->srna, "zaxis", 1, "Z-Axis", "Smooth along the Z axis");
04243 }
04244 
04245 static int mesh_noise_exec(bContext *C, wmOperator *op)
04246 {
04247     Object *obedit= CTX_data_edit_object(C);
04248     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
04249     Material *ma;
04250     Tex *tex;
04251     EditVert *eve;
04252     float fac= RNA_float_get(op->ptr, "factor");
04253 
04254     if(em==NULL) return OPERATOR_FINISHED;
04255 
04256     ma= give_current_material(obedit, obedit->actcol);
04257     if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) {
04258         BKE_report(op->reports, RPT_WARNING, "Mesh has no material or texture assigned");
04259         return OPERATOR_FINISHED;
04260     }
04261     tex= give_current_material_texture(ma);
04262 
04263 
04264     if(tex->type==TEX_STUCCI) {
04265         float b2, vec[3];
04266         float ofs= tex->turbul/200.0f;
04267         for(eve= em->verts.first; eve; eve= eve->next) {
04268             if(eve->f & SELECT) {
04269                 b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]);
04270                 if(tex->stype) ofs*=(b2*b2);
04271                 vec[0]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2]));
04272                 vec[1]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2]));
04273                 vec[2]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs));
04274                 
04275                 add_v3_v3(eve->co, vec);
04276             }
04277         }
04278     }
04279     else {
04280         for(eve= em->verts.first; eve; eve= eve->next) {
04281             if(eve->f & SELECT) {
04282                 float tin, dum;
04283                 externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0);
04284                 eve->co[2]+= fac*tin;
04285             }
04286         }
04287     }
04288 
04289     recalc_editnormals(em);
04290 
04291     BKE_mesh_end_editmesh(obedit->data, em);
04292 
04293     DAG_id_tag_update(obedit->data, 0);
04294     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
04295 
04296     return OPERATOR_FINISHED;
04297 }
04298 
04299 void MESH_OT_noise(wmOperatorType *ot)
04300 {
04301     /* identifiers */
04302     ot->name= "Noise";
04303     ot->description= "Use vertex coordinate as texture coordinate";
04304     ot->idname= "MESH_OT_noise";
04305 
04306     /* api callbacks */
04307     ot->exec= mesh_noise_exec;
04308     ot->poll= ED_operator_editmesh;
04309 
04310     /* flags */
04311     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
04312 
04313     RNA_def_float(ot->srna, "factor", 0.1f, -FLT_MAX, FLT_MAX, "Factor", "", 0.0f, 1.0f);
04314 }
04315 
04316 void flipface(EditMesh *em, EditFace *efa)
04317 {
04318     if(efa->v4) {
04319         SWAP(EditVert *, efa->v2, efa->v4);
04320         SWAP(EditEdge *, efa->e1, efa->e4);
04321         SWAP(EditEdge *, efa->e2, efa->e3);
04322         EM_data_interp_from_faces(em, efa, NULL, efa, 0, 3, 2, 1);
04323     }
04324     else {
04325         SWAP(EditVert *, efa->v2, efa->v3);
04326         SWAP(EditEdge *, efa->e1, efa->e3);
04327         efa->e2->dir= 1-efa->e2->dir;
04328         EM_data_interp_from_faces(em, efa, NULL, efa, 0, 2, 1, 3);
04329     }
04330 
04331     if(efa->v4) normal_quad_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
04332     else normal_tri_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co);
04333 }
04334 
04335 
04336 static int flip_normals(bContext *C, wmOperator *UNUSED(op))
04337 {
04338     Object *obedit= CTX_data_edit_object(C);
04339     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
04340     EditFace *efa;
04341     
04342     efa= em->faces.first;
04343     while(efa) {
04344         if( efa->f & SELECT ){
04345             flipface(em, efa);
04346         }
04347         efa= efa->next;
04348     }
04349     
04350     /* update vertex normals too */
04351     recalc_editnormals(em);
04352 
04353     BKE_mesh_end_editmesh(obedit->data, em);
04354 
04355     DAG_id_tag_update(obedit->data, 0);
04356     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
04357 
04358     return OPERATOR_FINISHED;
04359 }
04360 
04361 void MESH_OT_flip_normals(wmOperatorType *ot)
04362 {
04363     /* identifiers */
04364     ot->name= "Flip Normals";
04365     ot->description= "Toggle the direction of selected face's vertex and face normals";
04366     ot->idname= "MESH_OT_flip_normals";
04367     
04368     /* api callbacks */
04369     ot->exec= flip_normals;
04370     ot->poll= ED_operator_editmesh;
04371     
04372     /* flags */
04373     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
04374 }
04375 
04376 
04377 static int solidify_exec(bContext *C, wmOperator *op)
04378 {
04379     Object *obedit= CTX_data_edit_object(C);
04380     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
04381     float nor[3] = {0,0,1};
04382 
04383     float thickness= RNA_float_get(op->ptr, "thickness");
04384 
04385     extrudeflag(obedit, em, SELECT, nor, 1);
04386     EM_make_hq_normals(em);
04387     EM_solidify(em, thickness);
04388 
04389 
04390     /* update vertex normals too */
04391     recalc_editnormals(em);
04392 
04393     BKE_mesh_end_editmesh(obedit->data, em);
04394 
04395     DAG_id_tag_update(obedit->data, 0);
04396     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
04397 
04398     return OPERATOR_FINISHED;
04399 }
04400 
04401 
04402 void MESH_OT_solidify(wmOperatorType *ot)
04403 {
04404     PropertyRNA *prop;
04405     /* identifiers */
04406     ot->name= "Solidify";
04407     ot->description= "Create a solid skin by extruding, compensating for sharp angles";
04408     ot->idname= "MESH_OT_solidify";
04409 
04410     /* api callbacks */
04411     ot->exec= solidify_exec;
04412     ot->poll= ED_operator_editmesh;
04413 
04414     /* flags */
04415     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
04416 
04417     prop= RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "Thickness", "", -10.0f, 10.0f);
04418     RNA_def_property_ui_range(prop, -10, 10, 0.1, 4);
04419 }
04420 
04421 static int mesh_select_nth_exec(bContext *C, wmOperator *op)
04422 {
04423     Object *obedit= CTX_data_edit_object(C);
04424     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
04425     int nth = RNA_int_get(op->ptr, "nth");
04426 
04427     EM_deselect_nth(em, nth);
04428 
04429     BKE_mesh_end_editmesh(obedit->data, em);
04430 
04431     DAG_id_tag_update(obedit->data, 0);
04432     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
04433 
04434     return OPERATOR_FINISHED;
04435 }
04436 
04437 
04438 void MESH_OT_select_nth(wmOperatorType *ot)
04439 {
04440     /* identifiers */
04441     ot->name= "Select Nth";
04442     ot->description= "";
04443     ot->idname= "MESH_OT_select_nth";
04444 
04445     /* api callbacks */
04446     ot->exec= mesh_select_nth_exec;
04447     ot->poll= ED_operator_editmesh;
04448 
04449     /* flags */
04450     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
04451 
04452     RNA_def_int(ot->srna, "nth", 2, 2, 100, "Nth Selection", "", 1, INT_MAX);
04453 }
04454