|
Blender
V2.59
|
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