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