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