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 by Blender Foundation. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): Johnny Matthews, Geoffrey Bantle. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 /* 00034 00035 editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise in mods.c 00036 00037 */ 00038 00039 #include <stdlib.h> 00040 #include <string.h> 00041 #include <math.h> 00042 #include <float.h> 00043 00044 #include "BLO_sys_types.h" // for intptr_t support 00045 00046 #include "DNA_meshdata_types.h" 00047 #include "DNA_modifier_types.h" 00048 #include "DNA_object_types.h" 00049 #include "DNA_scene_types.h" 00050 #include "DNA_key_types.h" 00051 00052 #include "MEM_guardedalloc.h" 00053 00054 #include "RNA_define.h" 00055 #include "RNA_access.h" 00056 00057 #include "BLI_blenlib.h" 00058 #include "BLI_math.h" 00059 #include "BLI_utildefines.h" 00060 #include "BLI_editVert.h" 00061 #include "BLI_rand.h" 00062 #include "BLI_ghash.h" 00063 #include "BLI_linklist.h" 00064 #include "BLI_heap.h" 00065 #include "BLI_scanfill.h" 00066 00067 #include "BKE_context.h" 00068 #include "BKE_depsgraph.h" 00069 #include "BKE_global.h" 00070 #include "BKE_key.h" 00071 #include "BKE_mesh.h" 00072 #include "BKE_bmesh.h" 00073 #include "BKE_report.h" 00074 00075 00076 #include "WM_api.h" 00077 #include "WM_types.h" 00078 00079 #include "ED_mesh.h" 00080 #include "ED_screen.h" 00081 #include "ED_transform.h" 00082 #include "ED_view3d.h" 00083 #include "ED_object.h" 00084 00085 00086 #include "mesh_intern.h" 00087 00088 /* XXX */ 00089 static void waitcursor(int UNUSED(val)) {} 00090 #define add_numbut(a, b, c, d, e, f, g) {} 00091 00092 /* XXX */ 00093 00094 /* RNA corner cut enum property - used in multiple files for tools 00095 * that need this property for esubdivideflag() */ 00096 EnumPropertyItem corner_type_items[] = { 00097 {SUBDIV_CORNER_PATH, "PATH", 0, "Path", ""}, 00098 {SUBDIV_CORNER_INNERVERT, "INNER_VERTEX", 0, "Inner Vertex", ""}, 00099 {SUBDIV_CORNER_FAN, "FAN", 0, "Fan", ""}, 00100 {0, NULL, 0, NULL, NULL}}; 00101 00102 00103 /* local prototypes ---------------*/ 00104 static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa); 00105 int EdgeLoopDelete(EditMesh *em, wmOperator *op); 00106 00107 /********* qsort routines *********/ 00108 00109 00110 typedef struct xvertsort { 00111 float x; 00112 EditVert *v1; 00113 } xvertsort; 00114 00115 static int vergxco(const void *v1, const void *v2) 00116 { 00117 const xvertsort *x1=v1, *x2=v2; 00118 00119 if( x1->x > x2->x ) return 1; 00120 else if( x1->x < x2->x) return -1; 00121 return 0; 00122 } 00123 00124 struct facesort { 00125 uintptr_t x; 00126 struct EditFace *efa; 00127 }; 00128 00129 00130 static int vergface(const void *v1, const void *v2) 00131 { 00132 const struct facesort *x1=v1, *x2=v2; 00133 00134 if( x1->x > x2->x ) return 1; 00135 else if( x1->x < x2->x) return -1; 00136 return 0; 00137 } 00138 00139 00140 /* *********************************** */ 00141 00142 static void convert_to_triface(EditMesh *em, int direction) 00143 { 00144 EditFace *efa, *efan, *next; 00145 float fac; 00146 00147 efa= em->faces.last; 00148 while(efa) { 00149 next= efa->prev; 00150 if(efa->v4) { 00151 if(efa->f & SELECT) { 00152 /* choose shortest diagonal for split */ 00153 fac= len_v3v3(efa->v1->co, efa->v3->co) - len_v3v3(efa->v2->co, efa->v4->co); 00154 /* this makes sure exact squares get split different in both cases */ 00155 if( (direction==0 && fac<FLT_EPSILON) || (direction && fac>0.0f) ) { 00156 efan= EM_face_from_faces(em, efa, NULL, 0, 1, 2, -1); 00157 if(efa->f & SELECT) EM_select_face(efan, 1); 00158 efan= EM_face_from_faces(em, efa, NULL, 0, 2, 3, -1); 00159 if(efa->f & SELECT) EM_select_face(efan, 1); 00160 } 00161 else { 00162 efan= EM_face_from_faces(em, efa, NULL, 0, 1, 3, -1); 00163 if(efa->f & SELECT) EM_select_face(efan, 1); 00164 efan= EM_face_from_faces(em, efa, NULL, 1, 2, 3, -1); 00165 if(efa->f & SELECT) EM_select_face(efan, 1); 00166 } 00167 00168 BLI_remlink(&em->faces, efa); 00169 free_editface(em, efa); 00170 } 00171 } 00172 efa= next; 00173 } 00174 00175 EM_fgon_flags(em); // redo flags and indices for fgons 00176 00177 00178 } 00179 00180 int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /* return amount */ 00181 { 00182 /* 00183 flag - Test with vert->flags 00184 automerge - Alternative operation, merge unselected into selected. 00185 Used for "Auto Weld" mode. warning. 00186 limit - Quick manhattan distance between verts. 00187 */ 00188 00189 /* all verts with (flag & 'flag') are being evaluated */ 00190 EditVert *eve, *v1, *nextve; 00191 EditEdge *eed, *e1, *nexted; 00192 EditFace *efa, *nextvl; 00193 xvertsort *sortblock, *sb, *sb1; 00194 struct facesort *vlsortblock, *vsb, *vsb1; 00195 int a, b, test, amount; 00196 00197 00198 /* flag 128 is cleared, count */ 00199 00200 /* Normal non weld operation */ 00201 eve= em->verts.first; 00202 amount= 0; 00203 while(eve) { 00204 eve->f &= ~128; 00205 if(eve->h==0 && (automerge || (eve->f & flag))) amount++; 00206 eve= eve->next; 00207 } 00208 if(amount==0) return 0; 00209 00210 /* allocate memory and qsort */ 00211 sb= sortblock= MEM_mallocN(sizeof(xvertsort)*amount,"sortremovedoub"); 00212 eve= em->verts.first; 00213 while(eve) { 00214 if(eve->h==0 && (automerge || (eve->f & flag))) { 00215 sb->x= eve->co[0]+eve->co[1]+eve->co[2]; 00216 sb->v1= eve; 00217 sb++; 00218 } 00219 eve= eve->next; 00220 } 00221 qsort(sortblock, amount, sizeof(xvertsort), vergxco); 00222 00223 00224 /* test for doubles */ 00225 sb= sortblock; 00226 if (automerge) { 00227 for(a=0; a<amount; a++, sb++) { 00228 eve= sb->v1; 00229 if( (eve->f & 128)==0 ) { 00230 sb1= sb+1; 00231 for(b=a+1; b<amount && (eve->f & 128)==0; b++, sb1++) { 00232 if(sb1->x - sb->x > limit) break; 00233 00234 /* when automarge, only allow unselected->selected */ 00235 v1= sb1->v1; 00236 if( (v1->f & 128)==0 ) { 00237 if ((eve->f & flag)==0 && (v1->f & flag)==1) { 00238 if( (float)fabs(v1->co[0]-eve->co[0])<=limit && 00239 (float)fabs(v1->co[1]-eve->co[1])<=limit && 00240 (float)fabs(v1->co[2]-eve->co[2])<=limit) 00241 { /* unique bit */ 00242 eve->f|= 128; 00243 eve->tmp.v = v1; 00244 } 00245 } else if( (eve->f & flag)==1 && (v1->f & flag)==0 ) { 00246 if( (float)fabs(v1->co[0]-eve->co[0])<=limit && 00247 (float)fabs(v1->co[1]-eve->co[1])<=limit && 00248 (float)fabs(v1->co[2]-eve->co[2])<=limit) 00249 { /* unique bit */ 00250 v1->f|= 128; 00251 v1->tmp.v = eve; 00252 } 00253 } 00254 } 00255 } 00256 } 00257 } 00258 } else { 00259 for(a=0; a<amount; a++, sb++) { 00260 eve= sb->v1; 00261 if( (eve->f & 128)==0 ) { 00262 sb1= sb+1; 00263 for(b=a+1; b<amount; b++, sb1++) { 00264 /* first test: simpel dist */ 00265 if(sb1->x - sb->x > limit) break; 00266 v1= sb1->v1; 00267 00268 /* second test: is vertex allowed */ 00269 if( (v1->f & 128)==0 ) { 00270 if( (float)fabs(v1->co[0]-eve->co[0])<=limit && 00271 (float)fabs(v1->co[1]-eve->co[1])<=limit && 00272 (float)fabs(v1->co[2]-eve->co[2])<=limit) 00273 { 00274 v1->f|= 128; 00275 v1->tmp.v = eve; 00276 } 00277 } 00278 } 00279 } 00280 } 00281 } 00282 MEM_freeN(sortblock); 00283 00284 if (!automerge) 00285 for(eve = em->verts.first; eve; eve=eve->next) 00286 if((eve->f & flag) && (eve->f & 128)) 00287 EM_data_interp_from_verts(em, eve, eve->tmp.v, eve->tmp.v, 0.5f); 00288 00289 /* test edges and insert again */ 00290 eed= em->edges.first; 00291 while(eed) { 00292 eed->f2= 0; 00293 eed= eed->next; 00294 } 00295 eed= em->edges.last; 00296 while(eed) { 00297 nexted= eed->prev; 00298 00299 if(eed->f2==0) { 00300 if( (eed->v1->f & 128) || (eed->v2->f & 128) ) { 00301 remedge(em, eed); 00302 00303 if(eed->v1->f & 128) eed->v1 = eed->v1->tmp.v; 00304 if(eed->v2->f & 128) eed->v2 = eed->v2->tmp.v; 00305 e1= addedgelist(em, eed->v1, eed->v2, eed); 00306 00307 if(e1) { 00308 e1->f2= 1; 00309 if(eed->f & SELECT) 00310 e1->f |= SELECT; 00311 } 00312 if(e1!=eed) free_editedge(em, eed); 00313 } 00314 } 00315 eed= nexted; 00316 } 00317 00318 /* first count amount of test faces */ 00319 efa= (struct EditFace *)em->faces.first; 00320 amount= 0; 00321 while(efa) { 00322 efa->f1= 0; 00323 if(efa->v1->f & 128) efa->f1= 1; 00324 else if(efa->v2->f & 128) efa->f1= 1; 00325 else if(efa->v3->f & 128) efa->f1= 1; 00326 else if(efa->v4 && (efa->v4->f & 128)) efa->f1= 1; 00327 00328 if(efa->f1==1) amount++; 00329 efa= efa->next; 00330 } 00331 00332 /* test faces for double vertices, and if needed remove them */ 00333 efa= (struct EditFace *)em->faces.first; 00334 while(efa) { 00335 nextvl= efa->next; 00336 if(efa->f1==1) { 00337 00338 if(efa->v1->f & 128) efa->v1= efa->v1->tmp.v; 00339 if(efa->v2->f & 128) efa->v2= efa->v2->tmp.v; 00340 if(efa->v3->f & 128) efa->v3= efa->v3->tmp.v; 00341 if(efa->v4 && (efa->v4->f & 128)) efa->v4= efa->v4->tmp.v; 00342 00343 test= 0; 00344 if(efa->v1==efa->v2) test+=1; 00345 if(efa->v2==efa->v3) test+=2; 00346 if(efa->v3==efa->v1) test+=4; 00347 if(efa->v4==efa->v1) test+=8; 00348 if(efa->v3==efa->v4) test+=16; 00349 if(efa->v2==efa->v4) test+=32; 00350 00351 if(test) { 00352 if(efa->v4) { 00353 if(test==1 || test==2) { 00354 efa->v2= efa->v3; 00355 efa->v3= efa->v4; 00356 efa->v4= 0; 00357 00358 EM_data_interp_from_faces(em, efa, NULL, efa, 0, 2, 3, 3); 00359 00360 test= 0; 00361 } 00362 else if(test==8 || test==16) { 00363 efa->v4= 0; 00364 test= 0; 00365 } 00366 else { 00367 BLI_remlink(&em->faces, efa); 00368 free_editface(em, efa); 00369 amount--; 00370 } 00371 } 00372 else { 00373 BLI_remlink(&em->faces, efa); 00374 free_editface(em, efa); 00375 amount--; 00376 } 00377 } 00378 00379 if(test==0) { 00380 /* set edge pointers */ 00381 efa->e1= findedgelist(em, efa->v1, efa->v2); 00382 efa->e2= findedgelist(em, efa->v2, efa->v3); 00383 if(efa->v4==0) { 00384 efa->e3= findedgelist(em, efa->v3, efa->v1); 00385 efa->e4= 0; 00386 } 00387 else { 00388 efa->e3= findedgelist(em, efa->v3, efa->v4); 00389 efa->e4= findedgelist(em, efa->v4, efa->v1); 00390 } 00391 } 00392 } 00393 efa= nextvl; 00394 } 00395 00396 /* double faces: sort block */ 00397 /* count again, now all selected faces */ 00398 amount= 0; 00399 efa= em->faces.first; 00400 while(efa) { 00401 efa->f1= 0; 00402 if(faceselectedOR(efa, 1)) { 00403 efa->f1= 1; 00404 amount++; 00405 } 00406 efa= efa->next; 00407 } 00408 00409 if(amount) { 00410 /* double faces: sort block */ 00411 vsb= vlsortblock= MEM_mallocN(sizeof(struct facesort)*amount, "sortremovedoub"); 00412 efa= em->faces.first; 00413 while(efa) { 00414 if(efa->f1 & 1) { 00415 if(efa->v4) vsb->x= (uintptr_t) MIN4( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3, (uintptr_t)efa->v4); 00416 else vsb->x= (uintptr_t) MIN3( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3); 00417 00418 vsb->efa= efa; 00419 vsb++; 00420 } 00421 efa= efa->next; 00422 } 00423 00424 qsort(vlsortblock, amount, sizeof(struct facesort), vergface); 00425 00426 vsb= vlsortblock; 00427 for(a=0; a<amount; a++) { 00428 efa= vsb->efa; 00429 if( (efa->f1 & 128)==0 ) { 00430 vsb1= vsb+1; 00431 00432 for(b=a+1; b<amount; b++) { 00433 00434 /* first test: same pointer? */ 00435 if(vsb->x != vsb1->x) break; 00436 00437 /* second test: is test permitted? */ 00438 efa= vsb1->efa; 00439 if( (efa->f1 & 128)==0 ) { 00440 if( compareface(efa, vsb->efa)) efa->f1 |= 128; 00441 00442 } 00443 vsb1++; 00444 } 00445 } 00446 vsb++; 00447 } 00448 00449 MEM_freeN(vlsortblock); 00450 00451 /* remove double faces */ 00452 efa= (struct EditFace *)em->faces.first; 00453 while(efa) { 00454 nextvl= efa->next; 00455 if(efa->f1 & 128) { 00456 BLI_remlink(&em->faces, efa); 00457 free_editface(em, efa); 00458 } 00459 efa= nextvl; 00460 } 00461 } 00462 00463 /* remove double vertices */ 00464 a= 0; 00465 eve= (struct EditVert *)em->verts.first; 00466 while(eve) { 00467 nextve= eve->next; 00468 if(automerge || eve->f & flag) { 00469 if(eve->f & 128) { 00470 a++; 00471 BLI_remlink(&em->verts, eve); 00472 free_editvert(em, eve); 00473 } 00474 } 00475 eve= nextve; 00476 } 00477 00478 return a; /* amount */ 00479 } 00480 00481 static int removedoublesflag_exec(bContext *C, wmOperator *op) 00482 { 00483 Object *obedit= CTX_data_edit_object(C); 00484 EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); 00485 int totvert= em->totvert, totedge= em->totedge, totface= em->totface; 00486 00487 int count = removedoublesflag(em,1,0,RNA_float_get(op->ptr, "limit")); 00488 00489 if (totvert != em->totvert || totedge != em->totedge || totface != em->totface) { 00490 recalc_editnormals(em); 00491 00492 DAG_id_tag_update(obedit->data, 0); 00493 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 00494 } 00495 00496 BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s", count, (count==1)?"ex":"ices"); 00497 00498 BKE_mesh_end_editmesh(obedit->data, em); 00499 00500 return OPERATOR_FINISHED; 00501 } 00502 00503 void MESH_OT_remove_doubles(wmOperatorType *ot) 00504 { 00505 PropertyRNA *prop; 00506 00507 /* identifiers */ 00508 ot->name= "Remove Doubles"; 00509 ot->description= "Remove duplicate vertices"; 00510 ot->idname= "MESH_OT_remove_doubles"; 00511 00512 /* api callbacks */ 00513 ot->exec= removedoublesflag_exec; 00514 ot->poll= ED_operator_editmesh; 00515 00516 /* flags */ 00517 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00518 00519 prop= RNA_def_float(ot->srna, "limit", 0.0001f, 0.000001f, 50.0f, "Merge Threshold", "Minimum distance between merged verts", 0.00001f, 2.0f); 00520 RNA_def_property_ui_range(prop, 0.000001f, 50.0f, 0.001, 5); 00521 } 00522 00523 // XXX is this needed? 00524 /* called from buttons */ 00525 static void xsortvert_flag__doSetX(void *userData, EditVert *UNUSED(eve), int x, int UNUSED(y), int index) 00526 { 00527 xvertsort *sortblock = userData; 00528 00529 sortblock[index].x = x; 00530 } 00531 00532 /* all verts with (flag & 'flag') are sorted */ 00533 static void xsortvert_flag(bContext *C, int flag) 00534 { 00535 ViewContext vc; 00536 EditVert *eve; 00537 xvertsort *sortblock; 00538 ListBase tbase; 00539 int i, amount; 00540 00541 em_setup_viewcontext(C, &vc); 00542 00543 amount = BLI_countlist(&vc.em->verts); 00544 sortblock = MEM_callocN(sizeof(xvertsort)*amount,"xsort"); 00545 for (i=0,eve= vc.em->verts.first; eve; i++,eve=eve->next) 00546 if(eve->f & flag) 00547 sortblock[i].v1 = eve; 00548 00549 ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); 00550 mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, V3D_CLIP_TEST_OFF); 00551 00552 qsort(sortblock, amount, sizeof(xvertsort), vergxco); 00553 00554 /* make temporal listbase */ 00555 tbase.first= tbase.last= 0; 00556 for (i=0; i<amount; i++) { 00557 eve = sortblock[i].v1; 00558 00559 if (eve) { 00560 BLI_remlink(&vc.em->verts, eve); 00561 BLI_addtail(&tbase, eve); 00562 } 00563 } 00564 00565 BLI_movelisttolist(&vc.em->verts, &tbase); 00566 00567 MEM_freeN(sortblock); 00568 00569 } 00570 00571 static int mesh_vertices_sort_exec(bContext *C, wmOperator *UNUSED(op)) 00572 { 00573 xsortvert_flag(C, SELECT); 00574 return OPERATOR_FINISHED; 00575 } 00576 00577 void MESH_OT_vertices_sort(wmOperatorType *ot) 00578 { 00579 /* identifiers */ 00580 ot->name= "Vertex Sort"; 00581 ot->description= "Sort vertex order"; 00582 ot->idname= "MESH_OT_vertices_sort"; 00583 00584 /* api callbacks */ 00585 ot->exec= mesh_vertices_sort_exec; 00586 00587 ot->poll= EM_view3d_poll; /* uses view relative X axis to sort verts */ 00588 00589 /* flags */ 00590 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00591 } 00592 00593 00594 /* called from buttons */ 00595 static void hashvert_flag(EditMesh *em, int flag) 00596 { 00597 /* switch vertex order using hash table */ 00598 EditVert *eve; 00599 struct xvertsort *sortblock, *sb, onth, *newsort; 00600 ListBase tbase; 00601 int amount, a, b; 00602 00603 /* count */ 00604 eve= em->verts.first; 00605 amount= 0; 00606 while(eve) { 00607 if(eve->f & flag) amount++; 00608 eve= eve->next; 00609 } 00610 if(amount==0) return; 00611 00612 /* allocate memory */ 00613 sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*amount,"sortremovedoub"); 00614 eve= em->verts.first; 00615 while(eve) { 00616 if(eve->f & flag) { 00617 sb->v1= eve; 00618 sb++; 00619 } 00620 eve= eve->next; 00621 } 00622 00623 BLI_srand(1); 00624 00625 sb= sortblock; 00626 for(a=0; a<amount; a++, sb++) { 00627 b= (int)(amount*BLI_drand()); 00628 if(b>=0 && b<amount) { 00629 newsort= sortblock+b; 00630 onth= *sb; 00631 *sb= *newsort; 00632 *newsort= onth; 00633 } 00634 } 00635 00636 /* make temporal listbase */ 00637 tbase.first= tbase.last= 0; 00638 sb= sortblock; 00639 while(amount--) { 00640 eve= sb->v1; 00641 BLI_remlink(&em->verts, eve); 00642 BLI_addtail(&tbase, eve); 00643 sb++; 00644 } 00645 00646 BLI_movelisttolist(&em->verts, &tbase); 00647 00648 MEM_freeN(sortblock); 00649 00650 } 00651 00652 static int mesh_vertices_randomize_exec(bContext *C, wmOperator *UNUSED(op)) 00653 { 00654 Object *obedit= CTX_data_edit_object(C); 00655 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 00656 hashvert_flag(em, SELECT); 00657 return OPERATOR_FINISHED; 00658 } 00659 00660 void MESH_OT_vertices_randomize(wmOperatorType *ot) 00661 { 00662 /* identifiers */ 00663 ot->name= "Vertex Randomize"; 00664 ot->description= "Randomize vertex order"; 00665 ot->idname= "MESH_OT_vertices_randomize"; 00666 00667 /* api callbacks */ 00668 ot->exec= mesh_vertices_randomize_exec; 00669 00670 ot->poll= ED_operator_editmesh; 00671 00672 /* flags */ 00673 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00674 } 00675 00676 00677 /* generic extern called extruder */ 00678 static void extrude_mesh(Object *obedit, EditMesh *em, wmOperator *op, short type) 00679 { 00680 float nor[3]= {0.0, 0.0, 0.0}; 00681 short transmode= 0; 00682 00683 if(type<1) return; 00684 00685 if(type==1) transmode= extrudeflag(obedit, em, SELECT, nor, 0); 00686 else if(type==4) transmode= extrudeflag_verts_indiv(em, SELECT, nor); 00687 else if(type==3) transmode= extrudeflag_edges_indiv(em, SELECT, nor); 00688 else transmode= extrudeflag_face_indiv(em, SELECT, nor); 00689 00690 EM_stats_update(em); 00691 00692 if(transmode==0) { 00693 BKE_report(op->reports, RPT_WARNING, "Not a valid selection for extrude"); 00694 } 00695 else { 00696 EM_fgon_flags(em); 00697 00698 /* We need to force immediate calculation here because 00699 * transform may use derived objects (which are now stale). 00700 * 00701 * This shouldn't be necessary, derived queries should be 00702 * automatically building this data if invalid. Or something. 00703 */ 00704 DAG_id_tag_update(obedit->data, 0); 00705 00706 /* individual faces? */ 00707 // BIF_TransformSetUndo("Extrude"); 00708 if(type==2) { 00709 // initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR); 00710 // Transform(); 00711 } 00712 else { 00713 // initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR); 00714 if(transmode=='n') { 00715 mul_m4_v3(obedit->obmat, nor); 00716 sub_v3_v3(nor, obedit->obmat[3]); 00717 // BIF_setSingleAxisConstraint(nor, "along normal"); 00718 } 00719 // Transform(); 00720 } 00721 } 00722 00723 } 00724 00725 // XXX should be a menu item 00726 static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 00727 { 00728 Object *obedit= CTX_data_edit_object(C); 00729 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 00730 00731 extrude_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type")); 00732 00733 BKE_mesh_end_editmesh(obedit->data, em); 00734 00735 DAG_id_tag_update(obedit->data, 0); 00736 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 00737 00738 return OPERATOR_FINISHED; 00739 } 00740 00741 /* extrude without transform */ 00742 static int mesh_extrude_exec(bContext *C, wmOperator *op) 00743 { 00744 Object *obedit= CTX_data_edit_object(C); 00745 EditMesh *em= BKE_mesh_get_editmesh(obedit->data); 00746 00747 extrude_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type")); 00748 00749 DAG_id_tag_update(obedit->data, 0); 00750 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 00751 00752 BKE_mesh_end_editmesh(obedit->data, em); 00753 return OPERATOR_FINISHED; 00754 } 00755 00756 static EnumPropertyItem extrude_items[] = { 00757 {1, "REGION", 0, "Region", ""}, 00758 {2, "FACES", 0, "Individual Faces", ""}, 00759 {3, "EDGES", 0, "Only Edges", ""}, 00760 {4, "VERTS", 0, "Only Vertices", ""}, 00761 {0, NULL, 0, NULL, NULL}}; 00762 00763 00764 static EnumPropertyItem *mesh_extrude_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) 00765 { 00766 EnumPropertyItem *item= NULL; 00767 Object *obedit= CTX_data_edit_object(C); 00768 EditMesh *em; 00769 00770 int totitem= 0; 00771 00772 if(obedit==NULL || obedit->type != OB_MESH) 00773 return extrude_items; 00774 00775 em = BKE_mesh_get_editmesh(obedit->data); 00776 00777 EM_stats_update(em); 00778 00779 if(em->selectmode & SCE_SELECT_VERTEX) { 00780 if(em->totvertsel==0) {} 00781 else if(em->totvertsel==1) { RNA_enum_item_add(&item, &totitem, &extrude_items[3]); } 00782 else if(em->totedgesel==0) { RNA_enum_item_add(&item, &totitem, &extrude_items[3]); } 00783 else if(em->totfacesel==0) { 00784 RNA_enum_item_add(&item, &totitem, &extrude_items[2]); 00785 RNA_enum_item_add(&item, &totitem, &extrude_items[3]); 00786 } 00787 else if(em->totfacesel==1) { 00788 RNA_enum_item_add(&item, &totitem, &extrude_items[0]); 00789 RNA_enum_item_add(&item, &totitem, &extrude_items[2]); 00790 RNA_enum_item_add(&item, &totitem, &extrude_items[3]); 00791 } 00792 else { 00793 RNA_enum_item_add(&item, &totitem, &extrude_items[0]); 00794 RNA_enum_item_add(&item, &totitem, &extrude_items[1]); 00795 RNA_enum_item_add(&item, &totitem, &extrude_items[2]); 00796 RNA_enum_item_add(&item, &totitem, &extrude_items[3]); 00797 } 00798 } 00799 else if(em->selectmode & SCE_SELECT_EDGE) { 00800 if (em->totedgesel==0) {} 00801 else if (em->totedgesel==1) { RNA_enum_item_add(&item, &totitem, &extrude_items[2]); } 00802 else if(em->totfacesel==0) { RNA_enum_item_add(&item, &totitem, &extrude_items[2]); } 00803 else if(em->totfacesel==1) { 00804 RNA_enum_item_add(&item, &totitem, &extrude_items[0]); 00805 RNA_enum_item_add(&item, &totitem, &extrude_items[2]); 00806 } 00807 else { 00808 RNA_enum_item_add(&item, &totitem, &extrude_items[0]); 00809 RNA_enum_item_add(&item, &totitem, &extrude_items[1]); 00810 RNA_enum_item_add(&item, &totitem, &extrude_items[2]); 00811 } 00812 } 00813 else { 00814 if (em->totfacesel == 0) {} 00815 else if (em->totfacesel == 1) { RNA_enum_item_add(&item, &totitem, &extrude_items[0]); } 00816 else { 00817 RNA_enum_item_add(&item, &totitem, &extrude_items[0]); 00818 RNA_enum_item_add(&item, &totitem, &extrude_items[1]); 00819 } 00820 } 00821 00822 if(item) { 00823 RNA_enum_item_end(&item, &totitem); 00824 *free= 1; 00825 return item; 00826 } 00827 else { 00828 return NULL; 00829 } 00830 } 00831 00832 void MESH_OT_extrude(wmOperatorType *ot) 00833 { 00834 PropertyRNA *prop; 00835 00836 /* identifiers */ 00837 ot->name= "Extrude"; 00838 ot->description= "Extrude selected vertices, edges or faces"; 00839 ot->idname= "MESH_OT_extrude"; 00840 00841 /* api callbacks */ 00842 ot->invoke= mesh_extrude_invoke; 00843 ot->exec= mesh_extrude_exec; 00844 ot->poll= ED_operator_editmesh; 00845 00846 /* flags */ 00847 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00848 00849 /* properties */ 00850 prop= RNA_def_enum(ot->srna, "type", extrude_items, 0, "Type", ""); 00851 RNA_def_property_flag(prop, PROP_HIDDEN); 00852 RNA_def_enum_funcs(prop, mesh_extrude_itemf); 00853 ot->prop= prop; 00854 } 00855 00856 static int split_mesh(bContext *C, wmOperator *UNUSED(op)) 00857 { 00858 Object *obedit= CTX_data_edit_object(C); 00859 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 00860 00861 WM_cursor_wait(1); 00862 00863 /* make duplicate first */ 00864 adduplicateflag(em, SELECT); 00865 /* old faces have flag 128 set, delete them */ 00866 delfaceflag(em, 128); 00867 recalc_editnormals(em); 00868 00869 WM_cursor_wait(0); 00870 00871 DAG_id_tag_update(obedit->data, 0); 00872 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 00873 00874 BKE_mesh_end_editmesh(obedit->data, em); 00875 return OPERATOR_FINISHED; 00876 } 00877 00878 void MESH_OT_split(wmOperatorType *ot) 00879 { 00880 /* identifiers */ 00881 ot->name= "Split"; 00882 ot->description= "Split selected geometry into separate disconnected mesh"; 00883 ot->idname= "MESH_OT_split"; 00884 00885 /* api callbacks */ 00886 ot->exec= split_mesh; 00887 ot->poll= ED_operator_editmesh; 00888 00889 /* flags */ 00890 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00891 } 00892 00893 00894 static int extrude_repeat_mesh_exec(bContext *C, wmOperator *op) 00895 { 00896 Object *obedit= CTX_data_edit_object(C); 00897 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 00898 00899 int steps = RNA_int_get(op->ptr,"steps"); 00900 00901 float offs = RNA_float_get(op->ptr,"offset"); 00902 00903 float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0}; 00904 short a; 00905 00906 /* dvec */ 00907 RNA_float_get_array(op->ptr, "direction", dvec); 00908 normalize_v3(dvec); 00909 dvec[0]*= offs; 00910 dvec[1]*= offs; 00911 dvec[2]*= offs; 00912 00913 /* base correction */ 00914 copy_m3_m4(bmat, obedit->obmat); 00915 invert_m3_m3(tmat, bmat); 00916 mul_m3_v3(tmat, dvec); 00917 00918 for(a=0; a<steps; a++) { 00919 extrudeflag(obedit, em, SELECT, nor, 0); 00920 translateflag(em, SELECT, dvec); 00921 } 00922 00923 recalc_editnormals(em); 00924 00925 EM_fgon_flags(em); 00926 00927 DAG_id_tag_update(obedit->data, 0); 00928 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 00929 00930 BKE_mesh_end_editmesh(obedit->data, em); 00931 return OPERATOR_FINISHED; 00932 } 00933 00934 /* get center and axis, in global coords */ 00935 static int extrude_repeat_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 00936 { 00937 RegionView3D *rv3d= ED_view3d_context_rv3d(C); 00938 00939 if(rv3d) 00940 RNA_float_set_array(op->ptr, "direction", rv3d->persinv[2]); 00941 00942 return extrude_repeat_mesh_exec(C, op); 00943 } 00944 00945 void MESH_OT_extrude_repeat(wmOperatorType *ot) 00946 { 00947 /* identifiers */ 00948 ot->name= "Extrude Repeat Mesh"; 00949 ot->description= "Extrude selected vertices, edges or faces repeatedly"; 00950 ot->idname= "MESH_OT_extrude_repeat"; 00951 00952 /* api callbacks */ 00953 ot->invoke= extrude_repeat_mesh_invoke; 00954 ot->exec= extrude_repeat_mesh_exec; 00955 ot->poll= ED_operator_editmesh; 00956 00957 /* flags */ 00958 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00959 00960 /* props */ 00961 RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, 100.0f); 00962 RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, 180); 00963 RNA_def_float_vector(ot->srna, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "Direction", "Direction of extrude", -FLT_MAX, FLT_MAX); 00964 } 00965 00966 /* ************************** spin operator ******************** */ 00967 00968 00969 static int spin_mesh(bContext *C, wmOperator *op, float *dvec, int steps, float degr, int dupli ) 00970 { 00971 Object *obedit= CTX_data_edit_object(C); 00972 ToolSettings *ts= CTX_data_tool_settings(C); 00973 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 00974 EditVert *eve,*nextve; 00975 float nor[3]= {0.0f, 0.0f, 0.0f}; 00976 float si, n[3], q[4], cmat[3][3], imat[3][3], tmat[3][3]; 00977 float cent[3], bmat[3][3]; 00978 float phi; 00979 short a, ok= 1; 00980 00981 RNA_float_get_array(op->ptr, "center", cent); 00982 00983 /* imat and center and size */ 00984 copy_m3_m4(bmat, obedit->obmat); 00985 invert_m3_m3(imat,bmat); 00986 00987 cent[0]-= obedit->obmat[3][0]; 00988 cent[1]-= obedit->obmat[3][1]; 00989 cent[2]-= obedit->obmat[3][2]; 00990 mul_m3_v3(imat, cent); 00991 00992 phi= degr*(float)M_PI/360.0f; 00993 phi/= steps; 00994 if(ts->editbutflag & B_CLOCKWISE) phi= -phi; 00995 00996 RNA_float_get_array(op->ptr, "axis", n); 00997 normalize_v3(n); 00998 00999 q[0]= (float)cos(phi); 01000 si= (float)sin(phi); 01001 q[1]= n[0]*si; 01002 q[2]= n[1]*si; 01003 q[3]= n[2]*si; 01004 quat_to_mat3( cmat,q); 01005 01006 mul_m3_m3m3(tmat,cmat,bmat); 01007 mul_m3_m3m3(bmat,imat,tmat); 01008 01009 if(dupli==0) 01010 if(ts->editbutflag & B_KEEPORIG) 01011 adduplicateflag(em, 1); 01012 01013 for(a=0; a<steps; a++) { 01014 if(dupli==0) ok= extrudeflag(obedit, em, SELECT, nor, 0); 01015 else adduplicateflag(em, SELECT); 01016 01017 if(ok==0) 01018 break; 01019 01020 rotateflag(em, SELECT, cent, bmat); 01021 if(dvec) { 01022 mul_m3_v3(bmat,dvec); 01023 translateflag(em, SELECT, dvec); 01024 } 01025 } 01026 01027 if(ok==0) { 01028 /* no vertices or only loose ones selected, remove duplicates */ 01029 eve= em->verts.first; 01030 while(eve) { 01031 nextve= eve->next; 01032 if(eve->f & SELECT) { 01033 BLI_remlink(&em->verts,eve); 01034 free_editvert(em, eve); 01035 } 01036 eve= nextve; 01037 } 01038 } 01039 else { 01040 recalc_editnormals(em); 01041 01042 EM_fgon_flags(em); 01043 01044 DAG_id_tag_update(obedit->data, 0); 01045 } 01046 01047 BKE_mesh_end_editmesh(obedit->data, em); 01048 return ok; 01049 } 01050 01051 static int spin_mesh_exec(bContext *C, wmOperator *op) 01052 { 01053 Object *obedit= CTX_data_edit_object(C); 01054 int ok; 01055 01056 ok= spin_mesh(C, op, NULL, RNA_int_get(op->ptr,"steps"), RNA_float_get(op->ptr,"degrees"), RNA_boolean_get(op->ptr,"dupli")); 01057 if(ok==0) { 01058 BKE_report(op->reports, RPT_WARNING, "No valid vertices are selected"); 01059 return OPERATOR_CANCELLED; 01060 } 01061 01062 DAG_id_tag_update(obedit->data, 0); 01063 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 01064 01065 return OPERATOR_FINISHED; 01066 } 01067 01068 /* get center and axis, in global coords */ 01069 static int spin_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01070 { 01071 Scene *scene = CTX_data_scene(C); 01072 View3D *v3d = CTX_wm_view3d(C); 01073 RegionView3D *rv3d= ED_view3d_context_rv3d(C); 01074 01075 RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d)); 01076 RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[2]); 01077 01078 return spin_mesh_exec(C, op); 01079 } 01080 01081 void MESH_OT_spin(wmOperatorType *ot) 01082 { 01083 /* identifiers */ 01084 ot->name= "Spin"; 01085 ot->description= "Extrude selected vertices in a circle around the cursor in indicated viewport"; 01086 ot->idname= "MESH_OT_spin"; 01087 01088 /* api callbacks */ 01089 ot->invoke= spin_mesh_invoke; 01090 ot->exec= spin_mesh_exec; 01091 ot->poll= EM_view3d_poll; 01092 01093 /* flags */ 01094 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01095 01096 /* props */ 01097 RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 128); 01098 RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates"); 01099 RNA_def_float(ot->srna, "degrees", 90.0f, -FLT_MAX, FLT_MAX, "Degrees", "Degrees", -360.0f, 360.0f); 01100 01101 RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX); 01102 RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX); 01103 01104 } 01105 01106 static int screw_mesh_exec(bContext *C, wmOperator *op) 01107 { 01108 Object *obedit= CTX_data_edit_object(C); 01109 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 01110 EditVert *eve,*v1=0,*v2=0; 01111 EditEdge *eed; 01112 float dvec[3], nor[3]; 01113 int steps, turns; 01114 01115 turns= RNA_int_get(op->ptr, "turns"); 01116 steps= RNA_int_get(op->ptr, "steps"); 01117 01118 /* clear flags */ 01119 for(eve= em->verts.first; eve; eve= eve->next) 01120 eve->f1= 0; 01121 01122 /* edges set flags in verts */ 01123 for(eed= em->edges.first; eed; eed= eed->next) { 01124 if(eed->v1->f & SELECT) { 01125 if(eed->v2->f & SELECT) { 01126 /* watch: f1 is a byte */ 01127 if(eed->v1->f1<2) eed->v1->f1++; 01128 if(eed->v2->f1<2) eed->v2->f1++; 01129 } 01130 } 01131 } 01132 /* find two vertices with eve->f1==1, more or less is wrong */ 01133 for(eve= em->verts.first; eve; eve= eve->next) { 01134 if(eve->f1==1) { 01135 if(v1==NULL) v1= eve; 01136 else if(v2==NULL) v2= eve; 01137 else { 01138 v1= NULL; 01139 break; 01140 } 01141 } 01142 } 01143 if(v1==NULL || v2==NULL) { 01144 BKE_report(op->reports, RPT_WARNING, "You have to select a string of connected vertices too"); 01145 BKE_mesh_end_editmesh(obedit->data, em); 01146 return OPERATOR_CANCELLED; 01147 } 01148 01149 /* calculate dvec */ 01150 dvec[0]= ( v1->co[0]- v2->co[0] )/steps; 01151 dvec[1]= ( v1->co[1]- v2->co[1] )/steps; 01152 dvec[2]= ( v1->co[2]- v2->co[2] )/steps; 01153 01154 VECCOPY(nor, obedit->obmat[2]); 01155 01156 if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.0f) { 01157 negate_v3(dvec); 01158 } 01159 01160 if(spin_mesh(C, op, dvec, turns*steps, 360.0f*turns, 0)) { 01161 DAG_id_tag_update(obedit->data, 0); 01162 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 01163 01164 BKE_mesh_end_editmesh(obedit->data, em); 01165 return OPERATOR_FINISHED; 01166 } 01167 else { 01168 BKE_report(op->reports, RPT_WARNING, "No valid vertices are selected"); 01169 BKE_mesh_end_editmesh(obedit->data, em); 01170 return OPERATOR_CANCELLED; 01171 } 01172 } 01173 01174 /* get center and axis, in global coords */ 01175 static int screw_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01176 { 01177 Scene *scene = CTX_data_scene(C); 01178 View3D *v3d = CTX_wm_view3d(C); 01179 RegionView3D *rv3d= ED_view3d_context_rv3d(C); 01180 01181 RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d)); 01182 RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[1]); 01183 01184 return screw_mesh_exec(C, op); 01185 } 01186 01187 void MESH_OT_screw(wmOperatorType *ot) 01188 { 01189 /* identifiers */ 01190 ot->name= "Screw"; 01191 ot->description= "Extrude selected vertices in screw-shaped rotation around the cursor in indicated viewport"; 01192 ot->idname= "MESH_OT_screw"; 01193 01194 /* api callbacks */ 01195 ot->invoke= screw_mesh_invoke; 01196 ot->exec= screw_mesh_exec; 01197 ot->poll= EM_view3d_poll; 01198 01199 /* flags */ 01200 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01201 01202 /*props */ 01203 RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 256); 01204 RNA_def_int(ot->srna, "turns", 1, 0, INT_MAX, "Turns", "Turns", 0, 256); 01205 01206 RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX); 01207 RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX); 01208 } 01209 01210 static void erase_edges(EditMesh *em, ListBase *l) 01211 { 01212 EditEdge *ed, *nexted; 01213 01214 ed = (EditEdge *) l->first; 01215 while(ed) { 01216 nexted= ed->next; 01217 if( (ed->v1->f & SELECT) || (ed->v2->f & SELECT) ) { 01218 remedge(em, ed); 01219 free_editedge(em, ed); 01220 } 01221 ed= nexted; 01222 } 01223 } 01224 01225 static void erase_faces(EditMesh *em, ListBase *l) 01226 { 01227 EditFace *f, *nextf; 01228 01229 f = (EditFace *) l->first; 01230 01231 while(f) { 01232 nextf= f->next; 01233 if( faceselectedOR(f, SELECT) ) { 01234 BLI_remlink(l, f); 01235 free_editface(em, f); 01236 } 01237 f = nextf; 01238 } 01239 } 01240 01241 static void erase_vertices(EditMesh *em, ListBase *l) 01242 { 01243 EditVert *v, *nextv; 01244 01245 v = (EditVert *) l->first; 01246 while(v) { 01247 nextv= v->next; 01248 if(v->f & 1) { 01249 BLI_remlink(l, v); 01250 free_editvert(em, v); 01251 } 01252 v = nextv; 01253 } 01254 } 01255 01256 static void delete_mesh(EditMesh *em, wmOperator *op, int event) 01257 { 01258 EditFace *efa, *nextvl; 01259 EditVert *eve,*nextve; 01260 EditEdge *eed,*nexted; 01261 int count; 01262 /* const char *str="Erase"; */ 01263 01264 01265 if(event<1) return; 01266 01267 if(event==10 ) { 01268 /* str= "Erase Vertices"; */ 01269 erase_edges(em, &em->edges); 01270 erase_faces(em, &em->faces); 01271 erase_vertices(em, &em->verts); 01272 } 01273 else if(event==6) { 01274 if(!EdgeLoopDelete(em, op)) 01275 return; 01276 01277 /* str= "Erase Edge Loop"; */ 01278 } 01279 else if(event==4) { 01280 /* str= "Erase Edges & Faces"; */ 01281 efa= em->faces.first; 01282 while(efa) { 01283 nextvl= efa->next; 01284 /* delete only faces with 1 or more edges selected */ 01285 count= 0; 01286 if(efa->e1->f & SELECT) count++; 01287 if(efa->e2->f & SELECT) count++; 01288 if(efa->e3->f & SELECT) count++; 01289 if(efa->e4 && (efa->e4->f & SELECT)) count++; 01290 if(count) { 01291 BLI_remlink(&em->faces, efa); 01292 free_editface(em, efa); 01293 } 01294 efa= nextvl; 01295 } 01296 eed= em->edges.first; 01297 while(eed) { 01298 nexted= eed->next; 01299 if(eed->f & SELECT) { 01300 remedge(em, eed); 01301 free_editedge(em, eed); 01302 } 01303 eed= nexted; 01304 } 01305 efa= em->faces.first; 01306 while(efa) { 01307 nextvl= efa->next; 01308 event=0; 01309 if( efa->v1->f & SELECT) event++; 01310 if( efa->v2->f & SELECT) event++; 01311 if( efa->v3->f & SELECT) event++; 01312 if(efa->v4 && (efa->v4->f & SELECT)) event++; 01313 01314 if(event>1) { 01315 BLI_remlink(&em->faces, efa); 01316 free_editface(em, efa); 01317 } 01318 efa= nextvl; 01319 } 01320 } 01321 else if(event==1) { 01322 /* str= "Erase Edges"; */ 01323 // faces first 01324 efa= em->faces.first; 01325 while(efa) { 01326 nextvl= efa->next; 01327 event=0; 01328 if( efa->e1->f & SELECT) event++; 01329 if( efa->e2->f & SELECT) event++; 01330 if( efa->e3->f & SELECT) event++; 01331 if(efa->e4 && (efa->e4->f & SELECT)) event++; 01332 01333 if(event) { 01334 BLI_remlink(&em->faces, efa); 01335 free_editface(em, efa); 01336 } 01337 efa= nextvl; 01338 } 01339 eed= em->edges.first; 01340 while(eed) { 01341 nexted= eed->next; 01342 if(eed->f & SELECT) { 01343 remedge(em, eed); 01344 free_editedge(em, eed); 01345 } 01346 eed= nexted; 01347 } 01348 /* to remove loose vertices: */ 01349 eed= em->edges.first; 01350 while(eed) { 01351 if( eed->v1->f & SELECT) eed->v1->f-=SELECT; 01352 if( eed->v2->f & SELECT) eed->v2->f-=SELECT; 01353 eed= eed->next; 01354 } 01355 eve= em->verts.first; 01356 while(eve) { 01357 nextve= eve->next; 01358 if(eve->f & SELECT) { 01359 BLI_remlink(&em->verts,eve); 01360 free_editvert(em, eve); 01361 } 01362 eve= nextve; 01363 } 01364 01365 } 01366 else if(event==2) { 01367 /* str="Erase Faces"; */ 01368 delfaceflag(em, SELECT); 01369 } 01370 else if(event==3) { 01371 /* str= "Erase All"; */ 01372 if(em->verts.first) free_vertlist(em, &em->verts); 01373 if(em->edges.first) free_edgelist(em, &em->edges); 01374 if(em->faces.first) free_facelist(em, &em->faces); 01375 if(em->selected.first) BLI_freelistN(&(em->selected)); 01376 } 01377 else if(event==5) { 01378 /* str= "Erase Only Faces"; */ 01379 efa= em->faces.first; 01380 while(efa) { 01381 nextvl= efa->next; 01382 if(efa->f & SELECT) { 01383 BLI_remlink(&em->faces, efa); 01384 free_editface(em, efa); 01385 } 01386 efa= nextvl; 01387 } 01388 } 01389 01390 recalc_editnormals(em); 01391 01392 EM_fgon_flags(em); // redo flags and indices for fgons 01393 } 01394 01395 /* Note, these values must match delete_mesh() event values */ 01396 static EnumPropertyItem prop_mesh_delete_types[] = { 01397 {10,"VERT", 0, "Vertices", ""}, 01398 {1, "EDGE", 0, "Edges", ""}, 01399 {2, "FACE", 0, "Faces", ""}, 01400 {3, "ALL", 0, "All", ""}, 01401 {4, "EDGE_FACE",0, "Edges & Faces", ""}, 01402 {5, "ONLY_FACE",0, "Only Faces", ""}, 01403 {6, "EDGE_LOOP",0, "Edge Loop", ""}, 01404 {0, NULL, 0, NULL, NULL} 01405 }; 01406 01407 static int delete_mesh_exec(bContext *C, wmOperator *op) 01408 { 01409 Object *obedit= CTX_data_edit_object(C); 01410 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 01411 int type= RNA_enum_get(op->ptr, "type"); 01412 01413 if(type==6) 01414 return WM_operator_name_call(C, "MESH_OT_delete_edgeloop", WM_OP_EXEC_DEFAULT, NULL); 01415 01416 delete_mesh(em, op, type); 01417 01418 DAG_id_tag_update(obedit->data, 0); 01419 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 01420 01421 BKE_mesh_end_editmesh(obedit->data, em); 01422 return OPERATOR_FINISHED; 01423 } 01424 01425 void MESH_OT_delete(wmOperatorType *ot) 01426 { 01427 /* identifiers */ 01428 ot->name= "Delete"; 01429 ot->description= "Delete selected vertices, edges or faces"; 01430 ot->idname= "MESH_OT_delete"; 01431 01432 /* api callbacks */ 01433 ot->invoke= WM_menu_invoke; 01434 ot->exec= delete_mesh_exec; 01435 01436 ot->poll= ED_operator_editmesh; 01437 01438 /* flags */ 01439 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01440 01441 /*props */ 01442 ot->prop= RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data"); 01443 } 01444 01445 01446 /*GB*/ 01447 /*-------------------------------------------------------------------------------*/ 01448 /*--------------------------- Edge Based Subdivide ------------------------------*/ 01449 01450 #define EDGENEW 2 01451 #define FACENEW 2 01452 #define EDGEINNER 4 01453 #define EDGEOLD 8 01454 01455 /*used by faceloop cut to select only edges valid for edge slide*/ 01456 #define DOUBLEOPFILL 16 01457 01458 /* calculates offset for co, based on fractal, sphere or smooth settings */ 01459 static void alter_co(float *co, EditEdge *edge, float smooth, float fractal, int beauty, float perc) 01460 { 01461 float tvec[3], fac; 01462 01463 if(beauty & B_SMOOTH) { 01464 /* we calculate an offset vector tvec[], to be added to *co */ 01465 float len, nor[3], nor1[3], nor2[3]; 01466 01467 sub_v3_v3v3(nor, edge->v1->co, edge->v2->co); 01468 len= 0.5f*normalize_v3(nor); 01469 01470 copy_v3_v3(nor1, edge->v1->no); 01471 copy_v3_v3(nor2, edge->v2->no); 01472 01473 /* cosine angle */ 01474 fac= dot_v3v3(nor, nor1); 01475 mul_v3_v3fl(tvec, nor1, fac); 01476 01477 /* cosine angle */ 01478 fac= -dot_v3v3(nor, nor2); 01479 madd_v3_v3fl(tvec, nor2, fac); 01480 01481 /* falloff for multi subdivide */ 01482 smooth *= sqrtf(fabs(1.0f - 2.0f*fabsf(0.5f-perc))); 01483 01484 mul_v3_fl(tvec, smooth * len); 01485 01486 add_v3_v3(co, tvec); 01487 } 01488 else if(beauty & B_SPHERE) { /* subdivide sphere */ 01489 normalize_v3(co); 01490 mul_v3_fl(co, smooth); 01491 } 01492 01493 if(beauty & B_FRACTAL) { 01494 fac= fractal*len_v3v3(edge->v1->co, edge->v2->co); 01495 tvec[0]= fac*(float)(0.5-BLI_drand()); 01496 tvec[1]= fac*(float)(0.5-BLI_drand()); 01497 tvec[2]= fac*(float)(0.5-BLI_drand()); 01498 add_v3_v3(co, tvec); 01499 } 01500 } 01501 01502 /* assumes in the edge is the correct interpolated vertices already */ 01503 /* percent defines the interpolation, smooth, fractal and beauty are for special options */ 01504 /* results in new vertex with correct coordinate, vertex normal and weight group info */ 01505 static EditVert *subdivide_edge_addvert(EditMesh *em, EditEdge *edge, float smooth, float fractal, int beauty, float percent) 01506 { 01507 EditVert *ev; 01508 float co[3]; 01509 01510 interp_v3_v3v3(co, edge->v1->co, edge->v2->co, percent); 01511 01512 /* offset for smooth or sphere or fractal */ 01513 alter_co(co, edge, smooth, fractal, beauty, percent); 01514 01515 /* clip if needed by mirror modifier */ 01516 if (edge->v1->f2) { 01517 if ( edge->v1->f2 & edge->v2->f2 & 1) { 01518 co[0]= 0.0f; 01519 } 01520 if ( edge->v1->f2 & edge->v2->f2 & 2) { 01521 co[1]= 0.0f; 01522 } 01523 if ( edge->v1->f2 & edge->v2->f2 & 4) { 01524 co[2]= 0.0f; 01525 } 01526 } 01527 01528 ev = addvertlist(em, co, NULL); 01529 01530 /* vert data (vgroups, ..) */ 01531 EM_data_interp_from_verts(em, edge->v1, edge->v2, ev, percent); 01532 01533 /* normal */ 01534 interp_v3_v3v3(ev->no, edge->v1->no, edge->v2->no, percent); 01535 normalize_v3(ev->no); 01536 01537 return ev; 01538 } 01539 01540 static void flipvertarray(EditVert** arr, short size) 01541 { 01542 EditVert *hold; 01543 int i; 01544 01545 for(i=0; i<size/2; i++) { 01546 hold = arr[i]; 01547 arr[i] = arr[size-i-1]; 01548 arr[size-i-1] = hold; 01549 } 01550 } 01551 01552 static void facecopy(EditMesh *em, EditFace *source, EditFace *target) 01553 { 01554 float *v1 = source->v1->co, *v2 = source->v2->co, *v3 = source->v3->co; 01555 float *v4 = source->v4? source->v4->co: NULL; 01556 float w[4][4]; 01557 01558 CustomData_em_copy_data(&em->fdata, &em->fdata, source->data, &target->data); 01559 01560 target->mat_nr = source->mat_nr; 01561 target->flag = source->flag; 01562 target->h = source->h; 01563 01564 interp_weights_face_v3( w[0],v1, v2, v3, v4, target->v1->co); 01565 interp_weights_face_v3( w[1],v1, v2, v3, v4, target->v2->co); 01566 interp_weights_face_v3( w[2],v1, v2, v3, v4, target->v3->co); 01567 if (target->v4) 01568 interp_weights_face_v3( w[3],v1, v2, v3, v4, target->v4->co); 01569 01570 CustomData_em_validate_data(&em->fdata, target->data, target->v4 ? 4 : 3); 01571 CustomData_em_interp(&em->fdata, &source->data, NULL, (float*)w, 1, target->data); 01572 } 01573 01574 static void fill_quad_single(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, int seltype) 01575 { 01576 EditEdge *cedge=NULL; 01577 EditVert *v[4], **verts; 01578 EditFace *hold; 01579 short start=0, /* end, */ /* UNUSED */ left, right, vertsize,i; 01580 01581 v[0] = efa->v1; 01582 v[1] = efa->v2; 01583 v[2] = efa->v3; 01584 v[3] = efa->v4; 01585 01586 if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;} 01587 else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;} 01588 else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;} 01589 else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;} 01590 01591 // Point verts to the array of new verts for cedge 01592 verts = BLI_ghash_lookup(gh, cedge); 01593 //This is the index size of the verts array 01594 vertsize = numcuts+2; 01595 01596 // Is the original v1 the same as the first vert on the selected edge? 01597 // if not, the edge is running the opposite direction in this face so flip 01598 // the array to the correct direction 01599 01600 if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);} 01601 /* end = (start+1)%4; */ /* UNUSED */ 01602 left = (start+2)%4; 01603 right = (start+3)%4; 01604 01605 /* 01606 We should have something like this now 01607 01608 end start 01609 3 2 1 0 01610 |---*---*---| 01611 | | 01612 | | 01613 | | 01614 ------------- 01615 left right 01616 01617 where start,end,left, right are indexes of EditFace->v1, etc (stored in v) 01618 and 0,1,2... are the indexes of the new verts stored in verts 01619 01620 We will fill this case like this or this depending on even or odd cuts 01621 01622 |---*---*---| |---*---| 01623 | / \ | | / \ | 01624 | / \ | | / \ | 01625 |/ \| |/ \| 01626 ------------- --------- 01627 */ 01628 01629 // Make center face 01630 if(vertsize % 2 == 0) { 01631 hold = addfacelist(em, verts[(vertsize-1)/2],verts[((vertsize-1)/2)+1],v[left],v[right], NULL,NULL); 01632 hold->e2->f2 |= EDGEINNER; 01633 hold->e4->f2 |= EDGEINNER; 01634 }else{ 01635 hold = addfacelist(em, verts[(vertsize-1)/2],v[left],v[right],NULL, NULL,NULL); 01636 hold->e1->f2 |= EDGEINNER; 01637 hold->e3->f2 |= EDGEINNER; 01638 } 01639 facecopy(em, efa,hold); 01640 01641 // Make side faces 01642 for(i=0;i<(vertsize-1)/2;i++) { 01643 hold = addfacelist(em, verts[i],verts[i+1],v[right],NULL,NULL,NULL); 01644 facecopy(em, efa,hold); 01645 if(i+1 != (vertsize-1)/2) { 01646 if(seltype == SUBDIV_SELECT_INNER) { 01647 hold->e2->f2 |= EDGEINNER; 01648 } 01649 } 01650 hold = addfacelist(em, verts[vertsize-2-i],verts[vertsize-1-i],v[left],NULL,NULL,NULL); 01651 facecopy(em, efa,hold); 01652 if(i+1 != (vertsize-1)/2) { 01653 if(seltype == SUBDIV_SELECT_INNER) { 01654 hold->e3->f2 |= EDGEINNER; 01655 } 01656 } 01657 } 01658 } 01659 01660 static void fill_tri_single(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, int seltype) 01661 { 01662 EditEdge *cedge=NULL; 01663 EditVert *v[3], **verts; 01664 EditFace *hold; 01665 short start=0, /* end, */ /* UNUSED */ op, vertsize,i; 01666 01667 v[0] = efa->v1; 01668 v[1] = efa->v2; 01669 v[2] = efa->v3; 01670 01671 if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;} 01672 else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;} 01673 else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;} 01674 01675 // Point verts to the array of new verts for cedge 01676 verts = BLI_ghash_lookup(gh, cedge); 01677 //This is the index size of the verts array 01678 vertsize = numcuts+2; 01679 01680 // Is the original v1 the same as the first vert on the selected edge? 01681 // if not, the edge is running the opposite direction in this face so flip 01682 // the array to the correct direction 01683 01684 if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);} 01685 /* end = (start+1)%3; */ /* UNUSED */ 01686 op = (start+2)%3; 01687 01688 /* 01689 We should have something like this now 01690 01691 end start 01692 3 2 1 0 01693 |---*---*---| 01694 \ | 01695 \ | 01696 \ | 01697 \ | 01698 \ | 01699 \ | 01700 |op 01701 01702 where start,end,op are indexes of EditFace->v1, etc (stored in v) 01703 and 0,1,2... are the indexes of the new verts stored in verts 01704 01705 We will fill this case like this or this depending on even or odd cuts 01706 01707 3 2 1 0 01708 |---*---*---| 01709 \ \ \ | 01710 \ \ \ | 01711 \ \ \ | 01712 \ \ \| 01713 \ \\| 01714 \ | 01715 |op 01716 */ 01717 01718 // Make side faces 01719 for(i=0;i<(vertsize-1);i++) { 01720 hold = addfacelist(em, verts[i],verts[i+1],v[op],NULL,NULL,NULL); 01721 if(i+1 != vertsize-1) { 01722 if(seltype == SUBDIV_SELECT_INNER) { 01723 hold->e2->f2 |= EDGEINNER; 01724 } 01725 } 01726 facecopy(em, efa,hold); 01727 } 01728 } 01729 01730 static void fill_quad_double_op(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts) 01731 { 01732 EditEdge *cedge[2]={NULL, NULL}; 01733 EditVert *v[4], **verts[2]; 01734 EditFace *hold; 01735 short start=0, /*end,*/ left, /* right,*/ vertsize,i; 01736 01737 v[0] = efa->v1; 01738 v[1] = efa->v2; 01739 v[2] = efa->v3; 01740 v[3] = efa->v4; 01741 01742 if(efa->e1->f & SELECT) { cedge[0] = efa->e1; cedge[1] = efa->e3; start = 0;} 01743 else if(efa->e2->f & SELECT) { cedge[0] = efa->e2; cedge[1] = efa->e4; start = 1;} 01744 01745 // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] 01746 verts[0] = BLI_ghash_lookup(gh, cedge[0]); 01747 verts[1] = BLI_ghash_lookup(gh, cedge[1]); 01748 //This is the index size of the verts array 01749 vertsize = numcuts+2; 01750 01751 // Is the original v1 the same as the first vert on the selected edge? 01752 // if not, the edge is running the opposite direction in this face so flip 01753 // the array to the correct direction 01754 01755 if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} 01756 /* end = (start+1)%4; */ /* UNUSED */ 01757 left = (start+2)%4; 01758 /* right = (start+3)%4; */ /* UNUSED */ 01759 if(verts[1][0] != v[left]) {flipvertarray(verts[1],numcuts+2);} 01760 /* 01761 We should have something like this now 01762 01763 end start 01764 3 2 1 0 01765 |---*---*---| 01766 | | 01767 | | 01768 | | 01769 |---*---*---| 01770 0 1 2 3 01771 left right 01772 01773 We will fill this case like this or this depending on even or odd cuts 01774 01775 |---*---*---| 01776 | | | | 01777 | | | | 01778 | | | | 01779 |---*---*---| 01780 */ 01781 01782 // Make side faces 01783 for(i=0;i<vertsize-1;i++) { 01784 hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-2-i],verts[1][vertsize-1-i],NULL,NULL); 01785 if(i < vertsize-2) { 01786 hold->e2->f2 |= EDGEINNER; 01787 hold->e2->f2 |= DOUBLEOPFILL; 01788 } 01789 facecopy(em, efa,hold); 01790 } 01791 } 01792 01793 static void fill_quad_double_adj_path(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts) 01794 { 01795 EditEdge *cedge[2]={NULL, NULL}; 01796 EditVert *v[4], **verts[2]; 01797 EditFace *hold; 01798 short start=0, start2=0, vertsize,i; 01799 int ctrl= 0; // XXX 01800 01801 v[0] = efa->v1; 01802 v[1] = efa->v2; 01803 v[2] = efa->v3; 01804 v[3] = efa->v4; 01805 01806 if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1;} 01807 if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2;} 01808 if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3;} 01809 if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0;} 01810 01811 // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] 01812 verts[0] = BLI_ghash_lookup(gh, cedge[0]); 01813 verts[1] = BLI_ghash_lookup(gh, cedge[1]); 01814 //This is the index size of the verts array 01815 vertsize = numcuts+2; 01816 01817 // Is the original v1 the same as the first vert on the selected edge? 01818 // if not, the edge is running the opposite direction in this face so flip 01819 // the array to the correct direction 01820 01821 if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} 01822 if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} 01823 /* 01824 We should have something like this now 01825 01826 end start 01827 3 2 1 0 01828 start2 0|---*---*---| 01829 | | 01830 1* | 01831 | | 01832 2* | 01833 | | 01834 end2 3|-----------| 01835 01836 We will fill this case like this or this depending on even or odd cuts 01837 |---*---*---| 01838 | / / / | 01839 * / / | 01840 | / / | 01841 * / | 01842 | / | 01843 |-----------| 01844 */ 01845 01846 // Make outside tris 01847 hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL); 01848 /* when ctrl is depressed, only want verts on the cutline selected */ 01849 if (ctrl) 01850 hold->e3->f2 |= EDGEINNER; 01851 facecopy(em, efa,hold); 01852 hold = addfacelist(em, verts[0][0],verts[1][vertsize-1],v[(start2+2)%4],NULL,NULL,NULL); 01853 /* when ctrl is depressed, only want verts on the cutline selected */ 01854 if (ctrl) 01855 hold->e1->f2 |= EDGEINNER; 01856 facecopy(em, efa,hold); 01857 //if(scene->toolsettings->editbutflag & B_AUTOFGON) { 01858 // hold->e1->h |= EM_FGON; 01859 //} 01860 // Make side faces 01861 01862 for(i=0;i<numcuts;i++) { 01863 hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL); 01864 hold->e2->f2 |= EDGEINNER; 01865 facecopy(em, efa,hold); 01866 } 01867 //EM_fgon_flags(em); 01868 01869 } 01870 01871 static void fill_quad_double_adj_fan(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts) 01872 { 01873 EditEdge *cedge[2]={NULL, NULL}; 01874 EditVert *v[4], *op=NULL, **verts[2]; 01875 EditFace *hold; 01876 short start=0, start2=0, /* vertsize, */ /* UNUSED */ i; 01877 01878 v[0] = efa->v1; 01879 v[1] = efa->v2; 01880 v[2] = efa->v3; 01881 v[3] = efa->v4; 01882 01883 if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;} 01884 if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;} 01885 if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;} 01886 if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;} 01887 01888 01889 // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] 01890 verts[0] = BLI_ghash_lookup(gh, cedge[0]); 01891 verts[1] = BLI_ghash_lookup(gh, cedge[1]); 01892 //This is the index size of the verts array 01893 /* vertsize = numcuts+2; */ /* UNUSED */ 01894 01895 // Is the original v1 the same as the first vert on the selected edge? 01896 // if not, the edge is running the opposite direction in this face so flip 01897 // the array to the correct direction 01898 01899 if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} 01900 if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} 01901 /* 01902 We should have something like this now 01903 01904 end start 01905 3 2 1 0 01906 start2 0|---*---*---| 01907 | | 01908 1* | 01909 | | 01910 2* | 01911 | | 01912 end2 3|-----------|op 01913 01914 We will fill this case like this or this (warning horrible ascii art follows) 01915 |---*---*---| 01916 | \ \ \ | 01917 *---\ \ \ | 01918 | \ \ \ \| 01919 *---- \ \ \ | 01920 | --- \\\| 01921 |-----------| 01922 */ 01923 01924 for(i=0;i<=numcuts;i++) { 01925 hold = addfacelist(em, op,verts[1][numcuts-i],verts[1][numcuts-i+1],NULL,NULL,NULL); 01926 hold->e1->f2 |= EDGEINNER; 01927 facecopy(em, efa,hold); 01928 01929 hold = addfacelist(em, op,verts[0][i],verts[0][i+1],NULL,NULL,NULL); 01930 hold->e3->f2 |= EDGEINNER; 01931 facecopy(em, efa,hold); 01932 } 01933 } 01934 01935 static void fill_quad_double_adj_inner(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts) 01936 { 01937 EditEdge *cedge[2]={NULL, NULL}; 01938 EditVert *v[4], *op=NULL, **verts[2],**inner; 01939 EditFace *hold; 01940 short start=0, start2=0, /* vertsize, */ /* UNUSED */ i; 01941 float co[3]; 01942 01943 v[0] = efa->v1; 01944 v[1] = efa->v2; 01945 v[2] = efa->v3; 01946 v[3] = efa->v4; 01947 01948 if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;} 01949 if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;} 01950 if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;} 01951 if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;} 01952 01953 01954 // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] 01955 verts[0] = BLI_ghash_lookup(gh, cedge[0]); 01956 verts[1] = BLI_ghash_lookup(gh, cedge[1]); 01957 //This is the index size of the verts array 01958 /* vertsize = numcuts+2; */ /* UNUSED */ 01959 01960 // Is the original v1 the same as the first vert on the selected edge? 01961 // if not, the edge is running the opposite direction in this face so flip 01962 // the array to the correct direction 01963 01964 if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} 01965 if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} 01966 /* 01967 We should have something like this now 01968 01969 end start 01970 3 2 1 0 01971 start2 0|---*---*---| 01972 | | 01973 1* | 01974 | | 01975 2* | 01976 | | 01977 end2 3|-----------|op 01978 01979 We will fill this case like this or this (warning horrible ascii art follows) 01980 |---*-----*---| 01981 | * / | 01982 * \ / | 01983 | * | 01984 | / \ | 01985 * \ | 01986 | \ | 01987 |-------------| 01988 */ 01989 01990 // Add Inner Vert(s) 01991 inner = MEM_mallocN(sizeof(EditVert*)*numcuts,"New inner verts"); 01992 01993 for(i=0;i<numcuts;i++) { 01994 co[0] = (verts[0][numcuts-i]->co[0] + verts[1][i+1]->co[0] ) / 2 ; 01995 co[1] = (verts[0][numcuts-i]->co[1] + verts[1][i+1]->co[1] ) / 2 ; 01996 co[2] = (verts[0][numcuts-i]->co[2] + verts[1][i+1]->co[2] ) / 2 ; 01997 inner[i] = addvertlist(em, co, NULL); 01998 inner[i]->f2 |= EDGEINNER; 01999 02000 EM_data_interp_from_verts(em, verts[0][numcuts-i], verts[1][i+1], inner[i], 0.5f); 02001 } 02002 02003 // Add Corner Quad 02004 hold = addfacelist(em, verts[0][numcuts+1],verts[1][1],inner[0],verts[0][numcuts],NULL,NULL); 02005 hold->e2->f2 |= EDGEINNER; 02006 hold->e3->f2 |= EDGEINNER; 02007 facecopy(em, efa,hold); 02008 // Add Bottom Quads 02009 hold = addfacelist(em, verts[0][0],verts[0][1],inner[numcuts-1],op,NULL,NULL); 02010 hold->e2->f2 |= EDGEINNER; 02011 facecopy(em, efa,hold); 02012 02013 hold = addfacelist(em, op,inner[numcuts-1],verts[1][numcuts],verts[1][numcuts+1],NULL,NULL); 02014 hold->e2->f2 |= EDGEINNER; 02015 facecopy(em, efa,hold); 02016 02017 //if(scene->toolsettings->editbutflag & B_AUTOFGON) { 02018 // hold->e1->h |= EM_FGON; 02019 //} 02020 // Add Fill Quads (if # cuts > 1) 02021 02022 for(i=0;i<numcuts-1;i++) { 02023 hold = addfacelist(em, inner[i],verts[1][i+1],verts[1][i+2],inner[i+1],NULL,NULL); 02024 hold->e1->f2 |= EDGEINNER; 02025 hold->e3->f2 |= EDGEINNER; 02026 facecopy(em, efa,hold); 02027 02028 hold = addfacelist(em, inner[i],inner[i+1],verts[0][numcuts-1-i],verts[0][numcuts-i],NULL,NULL); 02029 hold->e2->f2 |= EDGEINNER; 02030 hold->e4->f2 |= EDGEINNER; 02031 facecopy(em, efa,hold); 02032 02033 //if(scene->toolsettings->editbutflag & B_AUTOFGON) { 02034 // hold->e1->h |= EM_FGON; 02035 //} 02036 } 02037 02038 //EM_fgon_flags(em); 02039 02040 MEM_freeN(inner); 02041 } 02042 02043 static void fill_tri_double(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts) 02044 { 02045 EditEdge *cedge[2]={NULL, NULL}; 02046 EditVert *v[3], **verts[2]; 02047 EditFace *hold; 02048 short start=0, start2=0, vertsize,i; 02049 02050 v[0] = efa->v1; 02051 v[1] = efa->v2; 02052 v[2] = efa->v3; 02053 02054 if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1;} 02055 if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2;} 02056 if(efa->e3->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e1; start = 2; start2 = 0;} 02057 02058 // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] 02059 verts[0] = BLI_ghash_lookup(gh, cedge[0]); 02060 verts[1] = BLI_ghash_lookup(gh, cedge[1]); 02061 //This is the index size of the verts array 02062 vertsize = numcuts+2; 02063 02064 // Is the original v1 the same as the first vert on the selected edge? 02065 // if not, the edge is running the opposite direction in this face so flip 02066 // the array to the correct direction 02067 02068 if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} 02069 if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} 02070 /* 02071 We should have something like this now 02072 02073 end start 02074 3 2 1 0 02075 start2 0|---*---*---| 02076 | / 02077 1* / 02078 | / 02079 2* / 02080 | / 02081 end2 3| 02082 02083 We will fill this case like this or this depending on even or odd cuts 02084 |---*---*---| 02085 | / / / 02086 * / / 02087 | / / 02088 * / 02089 | / 02090 | 02091 */ 02092 02093 // Make outside tri 02094 hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL); 02095 hold->e3->f2 |= EDGEINNER; 02096 facecopy(em, efa,hold); 02097 // Make side faces 02098 02099 for(i=0;i<numcuts;i++) { 02100 hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL); 02101 hold->e2->f2 |= EDGEINNER; 02102 facecopy(em, efa,hold); 02103 } 02104 } 02105 02106 static void fill_quad_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts) 02107 { 02108 EditEdge *cedge[3]={0}; 02109 EditVert *v[4], **verts[3]; 02110 EditFace *hold; 02111 short start=0, start2=0, start3=0, vertsize, i, repeats; 02112 02113 v[0] = efa->v1; 02114 v[1] = efa->v2; 02115 v[2] = efa->v3; 02116 v[3] = efa->v4; 02117 02118 if(!(efa->e1->f & SELECT)) { 02119 cedge[0] = efa->e2; 02120 cedge[1] = efa->e3; 02121 cedge[2] = efa->e4; 02122 start = 1;start2 = 2;start3 = 3; 02123 } 02124 if(!(efa->e2->f & SELECT)) { 02125 cedge[0] = efa->e3; 02126 cedge[1] = efa->e4; 02127 cedge[2] = efa->e1; 02128 start = 2;start2 = 3;start3 = 0; 02129 } 02130 if(!(efa->e3->f & SELECT)) { 02131 cedge[0] = efa->e4; 02132 cedge[1] = efa->e1; 02133 cedge[2] = efa->e2; 02134 start = 3;start2 = 0;start3 = 1; 02135 } 02136 if(!(efa->e4->f & SELECT)) { 02137 cedge[0] = efa->e1; 02138 cedge[1] = efa->e2; 02139 cedge[2] = efa->e3; 02140 start = 0;start2 = 1;start3 = 2; 02141 } 02142 // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] 02143 verts[0] = BLI_ghash_lookup(gh, cedge[0]); 02144 verts[1] = BLI_ghash_lookup(gh, cedge[1]); 02145 verts[2] = BLI_ghash_lookup(gh, cedge[2]); 02146 //This is the index size of the verts array 02147 vertsize = numcuts+2; 02148 02149 // Is the original v1 the same as the first vert on the selected edge? 02150 // if not, the edge is running the opposite direction in this face so flip 02151 // the array to the correct direction 02152 02153 if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} 02154 if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} 02155 if(verts[2][0] != v[start3]) {flipvertarray(verts[2],numcuts+2);} 02156 /* 02157 We should have something like this now 02158 02159 start2 02160 3 2 1 0 02161 start3 0|---*---*---|3 02162 | | 02163 1* *2 02164 | | 02165 2* *1 02166 | | 02167 3|-----------|0 start 02168 02169 We will fill this case like this or this depending on even or odd cuts 02170 there are a couple of differences. For odd cuts, there is a tri in the 02171 middle as well as 1 quad at the bottom (not including the extra quads 02172 for odd cuts > 1 02173 02174 For even cuts, there is a quad in the middle and 2 quads on the bottom 02175 02176 they are numbered here for clarity 02177 02178 1 outer tris and bottom quads 02179 2 inner tri or quad 02180 3 repeating quads 02181 02182 |---*---*---*---| 02183 |1/ / \ \ 1| 02184 |/ 3 / \ 3 \| 02185 * / 2 \ * 02186 | / \ | 02187 |/ \ | 02188 *---------------* 02189 | 3 | 02190 | | 02191 *---------------* 02192 | | 02193 | 1 | 02194 | | 02195 |---------------| 02196 02197 |---*---*---*---*---| 02198 | 1/ / \ \ 1| 02199 | / / \ \ | 02200 |/ 3 / \ 3 \| 02201 * / \ * 02202 | / \ | 02203 | / 2 \ | 02204 |/ \| 02205 *-------------------* 02206 | | 02207 | 3 | 02208 | | 02209 *-------------------* 02210 | | 02211 | 1 | 02212 | | 02213 *-------------------* 02214 | | 02215 | 1 | 02216 | | 02217 |-------------------| 02218 02219 */ 02220 02221 // Make outside tris 02222 hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL); 02223 hold->e3->f2 |= EDGEINNER; 02224 facecopy(em, efa,hold); 02225 hold = addfacelist(em, verts[1][vertsize-2],verts[1][vertsize-1],verts[2][1],NULL,NULL,NULL); 02226 hold->e3->f2 |= EDGEINNER; 02227 facecopy(em, efa,hold); 02228 // Make bottom quad 02229 hold = addfacelist(em, verts[0][0],verts[0][1],verts[2][vertsize-2],verts[2][vertsize-1],NULL,NULL); 02230 hold->e2->f2 |= EDGEINNER; 02231 facecopy(em, efa,hold); 02232 //If it is even cuts, add the 2nd lower quad 02233 if(numcuts % 2 == 0) { 02234 hold = addfacelist(em, verts[0][1],verts[0][2],verts[2][vertsize-3],verts[2][vertsize-2],NULL,NULL); 02235 hold->e2->f2 |= EDGEINNER; 02236 facecopy(em, efa,hold); 02237 // Also Make inner quad 02238 hold = addfacelist(em, verts[1][numcuts/2],verts[1][(numcuts/2)+1],verts[2][numcuts/2],verts[0][(numcuts/2)+1],NULL,NULL); 02239 hold->e3->f2 |= EDGEINNER; 02240 //if(scene->toolsettings->editbutflag & B_AUTOFGON) { 02241 // hold->e3->h |= EM_FGON; 02242 //} 02243 facecopy(em, efa,hold); 02244 repeats = (numcuts / 2) -1; 02245 } else { 02246 // Make inner tri 02247 hold = addfacelist(em, verts[1][(numcuts/2)+1],verts[2][(numcuts/2)+1],verts[0][(numcuts/2)+1],NULL,NULL,NULL); 02248 hold->e2->f2 |= EDGEINNER; 02249 //if(scene->toolsettings->editbutflag & B_AUTOFGON) { 02250 // hold->e2->h |= EM_FGON; 02251 //} 02252 facecopy(em, efa,hold); 02253 repeats = ((numcuts+1) / 2)-1; 02254 } 02255 02256 // cuts for 1 and 2 do not have the repeating quads 02257 if(numcuts < 3) {repeats = 0;} 02258 for(i=0;i<repeats;i++) { 02259 //Make side repeating Quads 02260 hold = addfacelist(em, verts[1][i+1],verts[1][i+2],verts[0][vertsize-i-3],verts[0][vertsize-i-2],NULL,NULL); 02261 hold->e2->f2 |= EDGEINNER; 02262 facecopy(em, efa,hold); 02263 hold = addfacelist(em, verts[1][vertsize-i-3],verts[1][vertsize-i-2],verts[2][i+1],verts[2][i+2],NULL,NULL); 02264 hold->e4->f2 |= EDGEINNER; 02265 facecopy(em, efa,hold); 02266 } 02267 // Do repeating bottom quads 02268 for(i=0;i<repeats;i++) { 02269 if(numcuts % 2 == 1) { 02270 hold = addfacelist(em, verts[0][1+i],verts[0][2+i],verts[2][vertsize-3-i],verts[2][vertsize-2-i],NULL,NULL); 02271 } else { 02272 hold = addfacelist(em, verts[0][2+i],verts[0][3+i],verts[2][vertsize-4-i],verts[2][vertsize-3-i],NULL,NULL); 02273 } 02274 hold->e2->f2 |= EDGEINNER; 02275 facecopy(em, efa,hold); 02276 } 02277 //EM_fgon_flags(em); 02278 } 02279 02280 static void fill_quad_quadruple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, float smooth, float fractal, int beauty) 02281 { 02282 EditVert **verts[4], ***innerverts; 02283 EditFace *hold; 02284 EditEdge temp; 02285 short /* vertsize, */ /* UNUSED */ i, j; 02286 02287 // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] 02288 verts[0] = BLI_ghash_lookup(gh, efa->e1); 02289 verts[1] = BLI_ghash_lookup(gh, efa->e2); 02290 verts[2] = BLI_ghash_lookup(gh, efa->e3); 02291 verts[3] = BLI_ghash_lookup(gh, efa->e4); 02292 02293 //This is the index size of the verts array 02294 /* vertsize = numcuts+2; */ /* UNUSED */ 02295 02296 // Is the original v1 the same as the first vert on the selected edge? 02297 // if not, the edge is running the opposite direction in this face so flip 02298 // the array to the correct direction 02299 02300 if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);} 02301 if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);} 02302 if(verts[2][0] == efa->v3) {flipvertarray(verts[2],numcuts+2);} 02303 if(verts[3][0] == efa->v4) {flipvertarray(verts[3],numcuts+2);} 02304 /* 02305 We should have something like this now 02306 1 02307 02308 3 2 1 0 02309 0|---*---*---|0 02310 | | 02311 1* *1 02312 2 | | 4 02313 2* *2 02314 | | 02315 3|---*---*---|3 02316 3 2 1 0 02317 02318 3 02319 // we will fill a 2 dim array of editvert*s to make filling easier 02320 // the innervert order is shown 02321 02322 0 0---1---2---3 02323 | | | | 02324 1 0---1---2---3 02325 | | | | 02326 2 0---1---2---3 02327 | | | | 02328 3 0---1---2---3 02329 02330 */ 02331 innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts outer array"); 02332 for(i=0;i<numcuts+2;i++) { 02333 innerverts[i] = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts inner array"); 02334 } 02335 02336 // first row is e1 last row is e3 02337 for(i=0;i<numcuts+2;i++) { 02338 innerverts[0][i] = verts[0][(numcuts+1)-i]; 02339 innerverts[numcuts+1][i] = verts[2][(numcuts+1)-i]; 02340 } 02341 02342 for(i=1;i<=numcuts;i++) { 02343 /* we create a fake edge for the next loop */ 02344 temp.v2 = innerverts[i][0] = verts[1][i]; 02345 temp.v1 = innerverts[i][numcuts+1] = verts[3][i]; 02346 02347 for(j=1;j<=numcuts;j++) { 02348 float percent= (float)j/(float)(numcuts+1); 02349 02350 innerverts[i][(numcuts+1)-j]= subdivide_edge_addvert(em, &temp, smooth, fractal, beauty, percent); 02351 } 02352 } 02353 // Fill with faces 02354 for(i=0;i<numcuts+1;i++) { 02355 for(j=0;j<numcuts+1;j++) { 02356 hold = addfacelist(em, innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],innerverts[i+1][j+1],NULL,NULL); 02357 hold->e1->f2 = EDGENEW; 02358 hold->e2->f2 = EDGENEW; 02359 hold->e3->f2 = EDGENEW; 02360 hold->e4->f2 = EDGENEW; 02361 02362 if(i != 0) { hold->e1->f2 |= EDGEINNER; } 02363 if(j != 0) { hold->e2->f2 |= EDGEINNER; } 02364 if(i != numcuts) { hold->e3->f2 |= EDGEINNER; } 02365 if(j != numcuts) { hold->e4->f2 |= EDGEINNER; } 02366 02367 facecopy(em, efa,hold); 02368 } 02369 } 02370 // Clean up our dynamic multi-dim array 02371 for(i=0;i<numcuts+2;i++) { 02372 MEM_freeN(innerverts[i]); 02373 } 02374 MEM_freeN(innerverts); 02375 } 02376 02377 static void fill_tri_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, float smooth, float fractal, int beauty) 02378 { 02379 EditVert **verts[3], ***innerverts; 02380 short /* vertsize, */ /* UNUSED */ i, j; 02381 EditFace *hold; 02382 EditEdge temp; 02383 02384 // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] 02385 verts[0] = BLI_ghash_lookup(gh, efa->e1); 02386 verts[1] = BLI_ghash_lookup(gh, efa->e2); 02387 verts[2] = BLI_ghash_lookup(gh, efa->e3); 02388 02389 //This is the index size of the verts array 02390 /* vertsize = numcuts+2; */ /* UNUSED */ 02391 02392 // Is the original v1 the same as the first vert on the selected edge? 02393 // if not, the edge is running the opposite direction in this face so flip 02394 // the array to the correct direction 02395 02396 if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);} 02397 if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);} 02398 if(verts[2][0] != efa->v3) {flipvertarray(verts[2],numcuts+2);} 02399 /* 02400 We should have something like this now 02401 3 02402 02403 3 2 1 0 02404 0|---*---*---|3 02405 | / 02406 1 1* *2 02407 | / 02408 2* *1 2 02409 | / 02410 3|/ 02411 0 02412 02413 we will fill a 2 dim array of editvert*s to make filling easier 02414 02415 3 02416 02417 0 0---1---2---3---4 02418 | / | / |/ | / 02419 1 0---1----2---3 02420 1 | / | / | / 02421 2 0----1---2 2 02422 | / | / 02423 |/ |/ 02424 3 0---1 02425 | / 02426 |/ 02427 4 0 02428 02429 */ 02430 02431 innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"tri-tri subdiv inner verts outer array"); 02432 for(i=0;i<numcuts+2;i++) { 02433 innerverts[i] = MEM_mallocN(sizeof(EditVert*)*((numcuts+2)-i),"tri-tri subdiv inner verts inner array"); 02434 } 02435 //top row is e3 backwards 02436 for(i=0;i<numcuts+2;i++) { 02437 innerverts[0][i] = verts[2][(numcuts+1)-i]; 02438 } 02439 02440 for(i=1;i<=numcuts+1;i++) { 02441 //fake edge, first vert is from e1, last is from e2 02442 temp.v1= innerverts[i][0] = verts[0][i]; 02443 temp.v2= innerverts[i][(numcuts+1)-i] = verts[1][(numcuts+1)-i]; 02444 02445 for(j=1;j<(numcuts+1)-i;j++) { 02446 float percent= (float)j/(float)((numcuts+1)-i); 02447 02448 innerverts[i][((numcuts+1)-i)-j]= subdivide_edge_addvert(em, &temp, smooth, fractal, beauty, 1-percent); 02449 } 02450 } 02451 02452 // Now fill the verts with happy little tris :) 02453 for(i=0;i<=numcuts+1;i++) { 02454 for(j=0;j<(numcuts+1)-i;j++) { 02455 //We always do the first tri 02456 hold = addfacelist(em, innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],NULL,NULL,NULL); 02457 hold->e1->f2 |= EDGENEW; 02458 hold->e2->f2 |= EDGENEW; 02459 hold->e3->f2 |= EDGENEW; 02460 if(i != 0) { hold->e1->f2 |= EDGEINNER; } 02461 if(j != 0) { hold->e2->f2 |= EDGEINNER; } 02462 if(j+1 != (numcuts+1)-i) {hold->e3->f2 |= EDGEINNER;} 02463 02464 facecopy(em, efa,hold); 02465 //if there are more to come, we do the 2nd 02466 if(j+1 <= numcuts-i) { 02467 hold = addfacelist(em, innerverts[i+1][j],innerverts[i+1][j+1],innerverts[i][j+1],NULL,NULL,NULL); 02468 facecopy(em, efa,hold); 02469 hold->e1->f2 |= EDGENEW; 02470 hold->e2->f2 |= EDGENEW; 02471 hold->e3->f2 |= EDGENEW; 02472 } 02473 } 02474 } 02475 02476 // Clean up our dynamic multi-dim array 02477 for(i=0;i<numcuts+2;i++) { 02478 MEM_freeN(innerverts[i]); 02479 } 02480 MEM_freeN(innerverts); 02481 } 02482 02483 //Next two fill types are for knife exact only and are provided to allow for knifing through vertices 02484 //This means there is no multicut! 02485 static void fill_quad_doublevert(EditMesh *em, EditFace *efa, int v1, int v2) 02486 { 02487 EditFace *hold; 02488 /* 02489 Depending on which two vertices have been knifed through (v1 and v2), we 02490 triangulate like the patterns below. 02491 X-------| |-------X 02492 | \ | | / | 02493 | \ | | / | 02494 | \ | | / | 02495 --------X X-------- 02496 */ 02497 02498 if(v1 == 1 && v2 == 3){ 02499 hold= addfacelist(em, efa->v1, efa->v2, efa->v3, 0, efa, NULL); 02500 hold->e1->f2 |= EDGENEW; 02501 hold->e2->f2 |= EDGENEW; 02502 hold->e3->f2 |= EDGENEW; 02503 hold->e3->f2 |= EDGEINNER; 02504 facecopy(em, efa, hold); 02505 02506 hold= addfacelist(em, efa->v1, efa->v3, efa->v4, 0, efa, NULL); 02507 hold->e1->f2 |= EDGENEW; 02508 hold->e2->f2 |= EDGENEW; 02509 hold->e3->f2 |= EDGENEW; 02510 hold->e1->f2 |= EDGEINNER; 02511 facecopy(em, efa, hold); 02512 } 02513 else{ 02514 hold= addfacelist(em, efa->v1, efa->v2, efa->v4, 0, efa, NULL); 02515 hold->e1->f2 |= EDGENEW; 02516 hold->e2->f2 |= EDGENEW; 02517 hold->e3->f2 |= EDGENEW; 02518 hold->e2->f2 |= EDGEINNER; 02519 facecopy(em, efa, hold); 02520 02521 hold= addfacelist(em, efa->v2, efa->v3, efa->v4, 0, efa, NULL); 02522 hold->e1->f2 |= EDGENEW; 02523 hold->e2->f2 |= EDGENEW; 02524 hold->e3->f2 |= EDGENEW; 02525 hold->e3->f2 |= EDGEINNER; 02526 facecopy(em, efa, hold); 02527 } 02528 } 02529 02530 static void fill_quad_singlevert(EditMesh *em, EditFace *efa, struct GHash *gh) 02531 { 02532 EditEdge *cedge=NULL; 02533 EditVert *v[4], **verts; 02534 EditFace *hold; 02535 short start=0, end, left, right /* , vertsize */ /* UNUSED */; 02536 02537 v[0] = efa->v1; 02538 v[1] = efa->v2; 02539 v[2] = efa->v3; 02540 v[3] = efa->v4; 02541 02542 if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;} 02543 else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;} 02544 else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;} 02545 else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;} 02546 02547 // Point verts to the array of new verts for cedge 02548 verts = BLI_ghash_lookup(gh, cedge); 02549 //This is the index size of the verts array 02550 /* vertsize = 3; */ /* UNUSED */ 02551 02552 // Is the original v1 the same as the first vert on the selected edge? 02553 // if not, the edge is running the opposite direction in this face so flip 02554 // the array to the correct direction 02555 02556 if(verts[0] != v[start]) {flipvertarray(verts,3);} 02557 end = (start+1)%4; 02558 left = (start+2)%4; 02559 right = (start+3)%4; 02560 02561 /* 02562 We should have something like this now 02563 02564 end start 02565 2 1 0 02566 |-----*-----| 02567 | | 02568 | | 02569 | | 02570 ------------- 02571 left right 02572 02573 where start,end,left, right are indexes of EditFace->v1, etc (stored in v) 02574 and 0,1,2 are the indexes of the new verts stored in verts. We fill like 02575 this, depending on whether its vertex 'left' or vertex 'right' thats 02576 been knifed through... 02577 02578 |---*---| |---*---| 02579 | / | | \ | 02580 | / | | \ | 02581 |/ | | \| 02582 X-------- --------X 02583 */ 02584 02585 if(v[left]->f1){ 02586 //triangle is composed of cutvert, end and left 02587 hold = addfacelist(em, verts[1],v[end],v[left],NULL, NULL,NULL); 02588 hold->e1->f2 |= EDGENEW; 02589 hold->e2->f2 |= EDGENEW; 02590 hold->e3->f2 |= EDGENEW; 02591 hold->e3->f2 |= EDGEINNER; 02592 facecopy(em, efa, hold); 02593 02594 //quad is composed of cutvert, left, right and start 02595 hold = addfacelist(em, verts[1],v[left],v[right],v[start], NULL, NULL); 02596 hold->e1->f2 |= EDGENEW; 02597 hold->e2->f2 |= EDGENEW; 02598 hold->e3->f2 |= EDGENEW; 02599 hold->e4->f2 |= EDGENEW; 02600 hold->e1->f2 |= EDGEINNER; 02601 facecopy(em, efa, hold); 02602 } 02603 else if(v[right]->f1){ 02604 //triangle is composed of cutvert, right and start 02605 hold = addfacelist(em, verts[1],v[right],v[start], NULL, NULL, NULL); 02606 hold->e1->f2 |= EDGENEW; 02607 hold->e2->f2 |= EDGENEW; 02608 hold->e3->f2 |= EDGENEW; 02609 hold->e1->f2 |= EDGEINNER; 02610 facecopy(em, efa, hold); 02611 //quad is composed of cutvert, end, left, right 02612 hold = addfacelist(em, verts[1],v[end], v[left], v[right], NULL, NULL); 02613 hold->e1->f2 |= EDGENEW; 02614 hold->e2->f2 |= EDGENEW; 02615 hold->e3->f2 |= EDGENEW; 02616 hold->e4->f2 |= EDGENEW; 02617 hold->e4->f2 |= EDGEINNER; 02618 facecopy(em, efa, hold); 02619 } 02620 02621 } 02622 02623 // This function takes an example edge, the current point to create and 02624 // the total # of points to create, then creates the point and return the 02625 // editvert pointer to it. 02626 static EditVert *subdivideedgenum(EditMesh *em, EditEdge *edge, int curpoint, int totpoint, float smooth, float fractal, int beauty) 02627 { 02628 EditVert *ev; 02629 float percent; 02630 02631 if (beauty & (B_PERCENTSUBD) && totpoint == 1) 02632 //percent=(float)(edge->tmp.l)/32768.0f; 02633 percent= edge->tmp.fp; 02634 else 02635 percent= (float)curpoint/(float)(totpoint+1); 02636 02637 ev= subdivide_edge_addvert(em, edge, smooth, fractal, beauty, percent); 02638 ev->f = edge->v1->f; 02639 02640 return ev; 02641 } 02642 02643 void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float fractal, int beauty, int numcuts, int corner_pattern, int seltype) 02644 { 02645 EditFace *ef; 02646 EditEdge *eed, *cedge, *sort[4]; 02647 EditVert *eve, **templist; 02648 struct GHash *gh; 02649 float length[4], v1mat[3], v2mat[3], v3mat[3], v4mat[3]; 02650 int i, j, edgecount, touchcount, facetype,hold; 02651 ModifierData *md= obedit->modifiers.first; 02652 int ctrl= 0; // XXX 02653 02654 //Set faces f1 to 0 cause we need it later 02655 for(ef=em->faces.first;ef;ef = ef->next) ef->f1 = 0; 02656 for(eve=em->verts.first; eve; eve=eve->next) { 02657 if(!(beauty & B_KNIFE)) /* knife sets this flag for vertex cuts */ 02658 eve->f1 = 0; 02659 eve->f2 = 0; 02660 } 02661 02662 for (; md; md=md->next) { 02663 if ((md->type==eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) { 02664 MirrorModifierData *mmd = (MirrorModifierData*) md; 02665 02666 if(mmd->flag & MOD_MIR_CLIPPING) { 02667 for (eve= em->verts.first; eve; eve= eve->next) { 02668 eve->f2= 0; 02669 02670 if (mmd->flag & MOD_MIR_AXIS_X && fabsf(eve->co[0]) < mmd->tolerance) eve->f2 |= 1; 02671 if (mmd->flag & MOD_MIR_AXIS_Y && fabsf(eve->co[1]) < mmd->tolerance) eve->f2 |= 2; 02672 if (mmd->flag & MOD_MIR_AXIS_Z && fabsf(eve->co[2]) < mmd->tolerance) eve->f2 |= 4; 02673 02674 } 02675 } 02676 } 02677 } 02678 02679 //Flush vertex flags upward to the edges 02680 for(eed = em->edges.first;eed;eed = eed->next) { 02681 //if(eed->f & flag && eed->v1->f == eed->v2->f) { 02682 // eed->f |= eed->v1->f; 02683 // } 02684 eed->f2 = 0; 02685 if(eed->f & flag) { 02686 eed->f2 |= EDGEOLD; 02687 } 02688 } 02689 02690 // We store an array of verts for each edge that is subdivided, 02691 // we put this array as a value in a ghash which is keyed by the EditEdge* 02692 02693 // Now for beauty subdivide deselect edges based on length 02694 if(beauty & B_BEAUTY) { 02695 for(ef = em->faces.first;ef;ef = ef->next) { 02696 if(!ef->v4) { 02697 continue; 02698 } 02699 if(ef->f & SELECT) { 02700 VECCOPY(v1mat, ef->v1->co); 02701 VECCOPY(v2mat, ef->v2->co); 02702 VECCOPY(v3mat, ef->v3->co); 02703 VECCOPY(v4mat, ef->v4->co); 02704 mul_mat3_m4_v3(obedit->obmat, v1mat); 02705 mul_mat3_m4_v3(obedit->obmat, v2mat); 02706 mul_mat3_m4_v3(obedit->obmat, v3mat); 02707 mul_mat3_m4_v3(obedit->obmat, v4mat); 02708 02709 length[0] = len_v3v3(v1mat, v2mat); 02710 length[1] = len_v3v3(v2mat, v3mat); 02711 length[2] = len_v3v3(v3mat, v4mat); 02712 length[3] = len_v3v3(v4mat, v1mat); 02713 sort[0] = ef->e1; 02714 sort[1] = ef->e2; 02715 sort[2] = ef->e3; 02716 sort[3] = ef->e4; 02717 02718 02719 // Beauty Short Edges 02720 if(beauty & B_BEAUTY_SHORT) { 02721 for(j=0;j<2;j++) { 02722 hold = -1; 02723 for(i=0;i<4;i++) { 02724 if(length[i] < 0) { 02725 continue; 02726 } else if(hold == -1) { 02727 hold = i; 02728 } else { 02729 if(length[hold] < length[i]) { 02730 hold = i; 02731 } 02732 } 02733 } 02734 if (hold > -1) { 02735 sort[hold]->f &= ~SELECT; 02736 sort[hold]->f2 |= EDGENEW; 02737 length[hold] = -1; 02738 } 02739 } 02740 } 02741 02742 // Beauty Long Edges 02743 else { 02744 for(j=0;j<2;j++) { 02745 hold = -1; 02746 for(i=0;i<4;i++) { 02747 if(length[i] < 0) { 02748 continue; 02749 } else if(hold == -1) { 02750 hold = i; 02751 } else { 02752 if(length[hold] > length[i]) { 02753 hold = i; 02754 } 02755 } 02756 } 02757 if (hold > -1) { 02758 sort[hold]->f &= ~SELECT; 02759 sort[hold]->f2 |= EDGENEW; 02760 length[hold] = -1; 02761 } 02762 } 02763 } 02764 } 02765 } 02766 } 02767 02768 gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "subdivideedgenum gh"); 02769 02770 // If we are knifing, We only need the selected edges that were cut, so deselect if it was not cut 02771 if(beauty & B_KNIFE) { 02772 for(eed= em->edges.first;eed;eed=eed->next) { 02773 if( eed->tmp.fp == 0 ) { 02774 EM_select_edge(eed,0); 02775 } 02776 } 02777 } 02778 // So for each edge, if it is selected, we allocate an array of size cuts+2 02779 // so we can have a place for the v1, the new verts and v2 02780 for(eed=em->edges.first;eed;eed = eed->next) { 02781 if(eed->f & flag) { 02782 templist = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"vertlist"); 02783 templist[0] = eed->v1; 02784 for(i=0;i<numcuts;i++) { 02785 // This function creates the new vert and returns it back 02786 // to the array 02787 templist[i+1] = subdivideedgenum(em, eed, i+1, numcuts, smooth, fractal, beauty); 02788 //while we are here, we can copy edge info from the original edge 02789 cedge = addedgelist(em, templist[i],templist[i+1],eed); 02790 // Also set the edge f2 to EDGENEW so that we can use this info later 02791 cedge->f2 = EDGENEW; 02792 } 02793 templist[i+1] = eed->v2; 02794 //Do the last edge too 02795 cedge = addedgelist(em, templist[i],templist[i+1],eed); 02796 cedge->f2 = EDGENEW; 02797 // Now that the edge is subdivided, we can put its verts in the ghash 02798 BLI_ghash_insert(gh, eed, templist); 02799 } 02800 } 02801 02802 // DAG_id_tag_update(obedit->data, 0); 02803 // Now for each face in the mesh we need to figure out How many edges were cut 02804 // and which filling method to use for that face 02805 for(ef = em->faces.first;ef;ef = ef->next) { 02806 edgecount = 0; 02807 facetype = 3; 02808 if(ef->e1->f & flag) {edgecount++;} 02809 if(ef->e2->f & flag) {edgecount++;} 02810 if(ef->e3->f & flag) {edgecount++;} 02811 if(ef->v4) { 02812 facetype = 4; 02813 if(ef->e4->f & flag) {edgecount++;} 02814 } 02815 if(facetype == 4) { 02816 switch(edgecount) { 02817 case 0: 02818 if(beauty & B_KNIFE && numcuts == 1){ 02819 /*Test for when knifing through two opposite verts but no edges*/ 02820 touchcount = 0; 02821 if(ef->v1->f1) touchcount++; 02822 if(ef->v2->f1) touchcount++; 02823 if(ef->v3->f1) touchcount++; 02824 if(ef->v4->f1) touchcount++; 02825 if(touchcount == 2){ 02826 if(ef->v1->f1 && ef->v3->f1){ 02827 ef->f1 = SELECT; 02828 fill_quad_doublevert(em, ef, 1, 3); 02829 } 02830 else if(ef->v2->f1 && ef->v4->f1){ 02831 ef->f1 = SELECT; 02832 fill_quad_doublevert(em, ef, 2, 4); 02833 } 02834 } 02835 } 02836 break; 02837 02838 case 1: 02839 if(beauty & B_KNIFE && numcuts == 1){ 02840 /*Test for when knifing through an edge and one vert*/ 02841 touchcount = 0; 02842 if(ef->v1->f1) touchcount++; 02843 if(ef->v2->f1) touchcount++; 02844 if(ef->v3->f1) touchcount++; 02845 if(ef->v4->f1) touchcount++; 02846 02847 if(touchcount == 1){ 02848 if( (ef->e1->f & flag && ( !ef->e1->v1->f1 && !ef->e1->v2->f1 )) || 02849 (ef->e2->f & flag && ( !ef->e2->v1->f1 && !ef->e2->v2->f1 )) || 02850 (ef->e3->f & flag && ( !ef->e3->v1->f1 && !ef->e3->v2->f1 )) || 02851 (ef->e4->f & flag && ( !ef->e4->v1->f1 && !ef->e4->v2->f1 )) ){ 02852 02853 ef->f1 = SELECT; 02854 fill_quad_singlevert(em, ef, gh); 02855 } 02856 else{ 02857 ef->f1 = SELECT; 02858 fill_quad_single(em, ef, gh, numcuts, seltype); 02859 } 02860 } 02861 else{ 02862 ef->f1 = SELECT; 02863 fill_quad_single(em, ef, gh, numcuts, seltype); 02864 } 02865 } 02866 else{ 02867 ef->f1 = SELECT; 02868 fill_quad_single(em, ef, gh, numcuts, seltype); 02869 } 02870 break; 02871 case 2: ef->f1 = SELECT; 02872 // if there are 2, we check if edge 1 and 3 are either both on or off that way 02873 // we can tell if the selected pair is Adjacent or Opposite of each other 02874 if((ef->e1->f & flag && ef->e3->f & flag) || 02875 (ef->e2->f & flag && ef->e4->f & flag)) { 02876 fill_quad_double_op(em, ef, gh, numcuts); 02877 }else{ 02878 switch(corner_pattern) { 02879 case 0: fill_quad_double_adj_path(em, ef, gh, numcuts); break; 02880 case 1: fill_quad_double_adj_inner(em, ef, gh, numcuts); break; 02881 case 2: fill_quad_double_adj_fan(em, ef, gh, numcuts); break; 02882 } 02883 02884 } 02885 break; 02886 case 3: ef->f1 = SELECT; 02887 fill_quad_triple(em, ef, gh, numcuts); 02888 break; 02889 case 4: ef->f1 = SELECT; 02890 fill_quad_quadruple(em, ef, gh, numcuts, smooth, fractal, beauty); 02891 break; 02892 } 02893 } else { 02894 switch(edgecount) { 02895 case 0: break; 02896 case 1: ef->f1 = SELECT; 02897 fill_tri_single(em, ef, gh, numcuts, seltype); 02898 break; 02899 case 2: ef->f1 = SELECT; 02900 fill_tri_double(em, ef, gh, numcuts); 02901 break; 02902 case 3: ef->f1 = SELECT; 02903 fill_tri_triple(em, ef, gh, numcuts, smooth, fractal, beauty); 02904 break; 02905 } 02906 } 02907 } 02908 02909 // Delete Old Edges and Faces 02910 for(eed = em->edges.first;eed;eed = eed->next) { 02911 if(BLI_ghash_haskey(gh,eed)) { 02912 eed->f1 = SELECT; 02913 } else { 02914 eed->f1 = 0; 02915 } 02916 } 02917 free_tagged_edges_faces(em, em->edges.first, em->faces.first); 02918 02919 if(seltype == SUBDIV_SELECT_ORIG && !ctrl) { 02920 /* bugfix: vertex could get flagged as "not-selected" 02921 // solution: clear flags before, not at the same time as setting SELECT flag -dg 02922 */ 02923 for(eed = em->edges.first;eed;eed = eed->next) { 02924 if(!(eed->f2 & EDGENEW || eed->f2 & EDGEOLD)) { 02925 eed->f &= !flag; 02926 EM_select_edge(eed,0); 02927 } 02928 } 02929 for(eed = em->edges.first;eed;eed = eed->next) { 02930 if(eed->f2 & EDGENEW || eed->f2 & EDGEOLD) { 02931 eed->f |= flag; 02932 EM_select_edge(eed,1); 02933 } 02934 } 02935 } else if ((seltype == SUBDIV_SELECT_INNER || seltype == SUBDIV_SELECT_INNER_SEL)|| ctrl) { 02936 for(eed = em->edges.first;eed;eed = eed->next) { 02937 if(eed->f2 & EDGEINNER) { 02938 eed->f |= flag; 02939 EM_select_edge(eed,1); 02940 if(eed->v1->f & EDGEINNER) eed->v1->f |= SELECT; 02941 if(eed->v2->f & EDGEINNER) eed->v2->f |= SELECT; 02942 }else{ 02943 eed->f &= !flag; 02944 EM_select_edge(eed,0); 02945 } 02946 } 02947 } else if(seltype == SUBDIV_SELECT_LOOPCUT){ 02948 for(eed = em->edges.first;eed;eed = eed->next) { 02949 if(eed->f2 & DOUBLEOPFILL){ 02950 eed->f |= flag; 02951 EM_select_edge(eed,1); 02952 }else{ 02953 eed->f &= !flag; 02954 EM_select_edge(eed,0); 02955 } 02956 } 02957 } 02958 if(em->selectmode & SCE_SELECT_VERTEX) { 02959 for(eed = em->edges.first;eed;eed = eed->next) { 02960 if(eed->f & SELECT) { 02961 eed->v1->f |= SELECT; 02962 eed->v2->f |= SELECT; 02963 } 02964 } 02965 } 02966 02967 //fix hide flags for edges. First pass, hide edges of hidden faces 02968 for(ef=em->faces.first; ef; ef=ef->next){ 02969 if(ef->h){ 02970 ef->e1->h |= 1; 02971 ef->e2->h |= 1; 02972 ef->e3->h |= 1; 02973 if(ef->e4) ef->e4->h |= 1; 02974 } 02975 } 02976 //second pass: unhide edges of visible faces adjacent to hidden faces 02977 for(ef=em->faces.first; ef; ef=ef->next){ 02978 if(ef->h == 0){ 02979 ef->e1->h &= ~1; 02980 ef->e2->h &= ~1; 02981 ef->e3->h &= ~1; 02982 if(ef->e4) ef->e4->h &= ~1; 02983 } 02984 } 02985 02986 //third pass: unhide edges that have both verts visible 02987 //(these were missed if all faces were hidden, bug #21976) 02988 for(eed=em->edges.first; eed; eed=eed->next){ 02989 if(eed->v1->h == 0 && eed->v2->h == 0) 02990 eed->h &= ~1; 02991 } 02992 02993 // Free the ghash and call MEM_freeN on all the value entries to return 02994 // that memory 02995 BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN); 02996 02997 EM_selectmode_flush(em); 02998 for(ef=em->faces.first;ef;ef = ef->next) { 02999 if(ef->e4) { 03000 if( (ef->e1->f & SELECT && ef->e2->f & SELECT) && 03001 (ef->e3->f & SELECT && ef->e4->f & SELECT) ) { 03002 ef->f |= SELECT; 03003 } 03004 } else { 03005 if( (ef->e1->f & SELECT && ef->e2->f & SELECT) && ef->e3->f & SELECT) { 03006 ef->f |= SELECT; 03007 } 03008 } 03009 } 03010 03011 recalc_editnormals(em); 03012 } 03013 03014 static int count_selected_edges(EditEdge *ed) 03015 { 03016 int totedge = 0; 03017 while(ed) { 03018 ed->tmp.p = 0; 03019 if( ed->f & SELECT ) totedge++; 03020 ed= ed->next; 03021 } 03022 return totedge; 03023 } 03024 03025 /* hurms, as if this makes code readable! It's pointerpointer hiding... (ton) */ 03026 typedef EditFace *EVPtr; 03027 typedef EVPtr EVPTuple[2]; 03028 03034 static int collect_quadedges(EVPTuple *efaa, EditEdge *eed, EditFace *efa) 03035 { 03036 EditEdge *e1, *e2, *e3; 03037 EVPtr *evp; 03038 int i = 0; 03039 03040 /* run through edges, if selected, set pointer edge-> facearray */ 03041 while(eed) { 03042 eed->f2= 0; 03043 eed->f1= 0; 03044 if( eed->f & SELECT ) { 03045 eed->tmp.p = (EditVert *) (&efaa[i]); 03046 i++; 03047 } 03048 else eed->tmp.p = NULL; 03049 03050 eed= eed->next; 03051 } 03052 03053 03054 /* find edges pointing to 2 faces by procedure: 03055 03056 - run through faces and their edges, increase 03057 face counter e->f1 for each face 03058 */ 03059 03060 while(efa) { 03061 efa->f1= 0; 03062 if(efa->v4==0 && (efa->f & SELECT)) { /* if selected triangle */ 03063 e1= efa->e1; 03064 e2= efa->e2; 03065 e3= efa->e3; 03066 if(e1->f2<3 && e1->tmp.p) { 03067 if(e1->f2<2) { 03068 evp= (EVPtr *) e1->tmp.p; 03069 evp[(int)e1->f2] = efa; 03070 } 03071 e1->f2+= 1; 03072 } 03073 if(e2->f2<3 && e2->tmp.p) { 03074 if(e2->f2<2) { 03075 evp= (EVPtr *) e2->tmp.p; 03076 evp[(int)e2->f2]= efa; 03077 } 03078 e2->f2+= 1; 03079 } 03080 if(e3->f2<3 && e3->tmp.p) { 03081 if(e3->f2<2) { 03082 evp= (EVPtr *) e3->tmp.p; 03083 evp[(int)e3->f2]= efa; 03084 } 03085 e3->f2+= 1; 03086 } 03087 } 03088 else { 03089 /* set to 3 to make sure these are not flipped or joined */ 03090 efa->e1->f2= 3; 03091 efa->e2->f2= 3; 03092 efa->e3->f2= 3; 03093 if (efa->e4) efa->e4->f2= 3; 03094 } 03095 03096 efa= efa->next; 03097 } 03098 return i; 03099 } 03100 03101 03102 /* returns vertices of two adjacent triangles forming a quad 03103 - can be righthand or lefthand 03104 03105 4-----3 03106 |\ | 03107 | \ 2 | <- efa1 03108 | \ | 03109 efa-> | 1 \ | 03110 | \| 03111 1-----2 03112 03113 */ 03114 #define VTEST(face, num, other) \ 03115 (face->v##num != other->v1 && face->v##num != other->v2 && face->v##num != other->v3) 03116 03117 static void givequadverts(EditFace *efa, EditFace *efa1, EditVert **v1, EditVert **v2, EditVert **v3, EditVert **v4, int *vindex) 03118 { 03119 if VTEST(efa, 1, efa1) { 03120 *v1= efa->v1; 03121 *v2= efa->v2; 03122 vindex[0]= 0; 03123 vindex[1]= 1; 03124 } 03125 else if VTEST(efa, 2, efa1) { 03126 *v1= efa->v2; 03127 *v2= efa->v3; 03128 vindex[0]= 1; 03129 vindex[1]= 2; 03130 } 03131 else if VTEST(efa, 3, efa1) { 03132 *v1= efa->v3; 03133 *v2= efa->v1; 03134 vindex[0]= 2; 03135 vindex[1]= 0; 03136 } 03137 03138 if VTEST(efa1, 1, efa) { 03139 *v3= efa1->v1; 03140 *v4= (efa1->v2 == *v2)? efa1->v3: efa1->v2; 03141 vindex[2]= 0; 03142 vindex[3]= (efa1->v2 == *v2)? 2: 1; 03143 } 03144 else if VTEST(efa1, 2, efa) { 03145 *v3= efa1->v2; 03146 *v4= (efa1->v3 == *v2)? efa1->v1: efa1->v3; 03147 vindex[2]= 1; 03148 vindex[3]= (efa1->v3 == *v2)? 0: 2; 03149 } 03150 else if VTEST(efa1, 3, efa) { 03151 *v3= efa1->v3; 03152 *v4= (efa1->v1 == *v2)? efa1->v2: efa1->v1; 03153 vindex[2]= 2; 03154 vindex[3]= (efa1->v1 == *v2)? 1: 0; 03155 } 03156 else 03157 *v3= *v4= NULL; 03158 } 03159 03160 /* Helper functions for edge/quad edit features*/ 03161 static void untag_edges(EditFace *f) 03162 { 03163 f->e1->f1 = 0; 03164 f->e2->f1 = 0; 03165 f->e3->f1 = 0; 03166 if (f->e4) f->e4->f1 = 0; 03167 } 03168 03170 static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa) 03171 { 03172 EditEdge *nexted; 03173 EditFace *nextvl; 03174 03175 while(efa) { 03176 nextvl= efa->next; 03177 if(efa->f1) { 03178 BLI_remlink(&em->faces, efa); 03179 free_editface(em, efa); 03180 } 03181 else 03182 /* avoid deleting edges that are still in use */ 03183 untag_edges(efa); 03184 efa= nextvl; 03185 } 03186 03187 while(eed) { 03188 nexted= eed->next; 03189 if(eed->f1) { 03190 remedge(em, eed); 03191 free_editedge(em, eed); 03192 } 03193 eed= nexted; 03194 } 03195 } 03196 03197 03198 /* ******************** BEGIN TRIANGLE TO QUAD ************************************* */ 03199 static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, float limit) 03200 { 03201 03202 /*gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make*/ 03203 /*Note: this is more complicated than it needs to be and should be cleaned up...*/ 03204 float measure = 0.0, noA1[3], noA2[3], noB1[3], noB2[3], normalADiff, normalBDiff, 03205 edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3], diff, 03206 minarea, maxarea, areaA, areaB; 03207 03208 /*First Test: Normal difference*/ 03209 normal_tri_v3( noA1,v1->co, v2->co, v3->co); 03210 normal_tri_v3( noA2,v1->co, v3->co, v4->co); 03211 03212 if(noA1[0] == noA2[0] && noA1[1] == noA2[1] && noA1[2] == noA2[2]) normalADiff = 0.0; 03213 else normalADiff = RAD2DEGF(angle_v3v3(noA1, noA2)); 03214 //if(!normalADiff) normalADiff = 179; 03215 normal_tri_v3( noB1,v2->co, v3->co, v4->co); 03216 normal_tri_v3( noB2,v4->co, v1->co, v2->co); 03217 03218 if(noB1[0] == noB2[0] && noB1[1] == noB2[1] && noB1[2] == noB2[2]) normalBDiff = 0.0; 03219 else normalBDiff = RAD2DEGF(angle_v3v3(noB1, noB2)); 03220 //if(!normalBDiff) normalBDiff = 179; 03221 03222 measure += (normalADiff/360) + (normalBDiff/360); 03223 if(measure > limit) return measure; 03224 03225 /*Second test: Colinearity*/ 03226 sub_v3_v3v3(edgeVec1, v1->co, v2->co); 03227 sub_v3_v3v3(edgeVec2, v2->co, v3->co); 03228 sub_v3_v3v3(edgeVec3, v3->co, v4->co); 03229 sub_v3_v3v3(edgeVec4, v4->co, v1->co); 03230 03231 diff = 0.0; 03232 03233 diff = ( 03234 fabsf(RAD2DEGF(angle_v3v3(edgeVec1, edgeVec2)) - 90) + 03235 fabsf(RAD2DEGF(angle_v3v3(edgeVec2, edgeVec3)) - 90) + 03236 fabsf(RAD2DEGF(angle_v3v3(edgeVec3, edgeVec4)) - 90) + 03237 fabsf(RAD2DEGF(angle_v3v3(edgeVec4, edgeVec1)) - 90)) / 360; 03238 if(!diff) return 0.0; 03239 03240 measure += diff; 03241 if(measure > limit) return measure; 03242 03243 /*Third test: Concavity*/ 03244 areaA = area_tri_v3(v1->co, v2->co, v3->co) + area_tri_v3(v1->co, v3->co, v4->co); 03245 areaB = area_tri_v3(v2->co, v3->co, v4->co) + area_tri_v3(v4->co, v1->co, v2->co); 03246 03247 if(areaA <= areaB) minarea = areaA; 03248 else minarea = areaB; 03249 03250 if(areaA >= areaB) maxarea = areaA; 03251 else maxarea = areaB; 03252 03253 if(!maxarea) measure += 1; 03254 else measure += (1 - (minarea / maxarea)); 03255 03256 return measure; 03257 } 03258 03259 #define T2QUV_LIMIT 0.005f 03260 #define T2QCOL_LIMIT 3 03261 static int compareFaceAttribs(EditMesh *em, EditFace *f1, EditFace *f2, EditEdge *eed) 03262 { 03263 /*Test to see if the per-face attributes for the joining edge match within limit*/ 03264 MTFace *tf1, *tf2; 03265 unsigned int *col1, *col2; 03266 short i,attrok=0, flag = 0, /* XXX scene->toolsettings->editbutflag,*/ fe1[2], fe2[2]; 03267 03268 tf1 = CustomData_em_get(&em->fdata, f1->data, CD_MTFACE); 03269 tf2 = CustomData_em_get(&em->fdata, f2->data, CD_MTFACE); 03270 03271 col1 = CustomData_em_get(&em->fdata, f1->data, CD_MCOL); 03272 col2 = CustomData_em_get(&em->fdata, f2->data, CD_MCOL); 03273 03274 /*store indices for faceedges*/ 03275 f1->v1->f1 = 0; 03276 f1->v2->f1 = 1; 03277 f1->v3->f1 = 2; 03278 03279 fe1[0] = eed->v1->f1; 03280 fe1[1] = eed->v2->f1; 03281 03282 f2->v1->f1 = 0; 03283 f2->v2->f1 = 1; 03284 f2->v3->f1 = 2; 03285 03286 fe2[0] = eed->v1->f1; 03287 fe2[1] = eed->v2->f1; 03288 03289 /*compare faceedges for each face attribute. Additional per face attributes can be added later*/ 03290 /*do UVs*/ 03291 if(flag & B_JOINTRIA_UV){ 03292 03293 if(tf1 == NULL || tf2 == NULL) attrok |= B_JOINTRIA_UV; 03294 else if(tf1->tpage != tf2->tpage); /*do nothing*/ 03295 else{ 03296 for(i = 0; i < 2; i++){ 03297 if(tf1->uv[fe1[i]][0] + T2QUV_LIMIT > tf2->uv[fe2[i]][0] && tf1->uv[fe1[i]][0] - T2QUV_LIMIT < tf2->uv[fe2[i]][0] && 03298 tf1->uv[fe1[i]][1] + T2QUV_LIMIT > tf2->uv[fe2[i]][1] && tf1->uv[fe1[i]][1] - T2QUV_LIMIT < tf2->uv[fe2[i]][1]) attrok |= B_JOINTRIA_UV; 03299 } 03300 } 03301 } 03302 03303 /*do VCOLs*/ 03304 if(flag & B_JOINTRIA_VCOL){ 03305 if(!col1 || !col2) attrok |= B_JOINTRIA_VCOL; 03306 else{ 03307 char *f1vcol, *f2vcol; 03308 for(i = 0; i < 2; i++){ 03309 f1vcol = (char *)&(col1[fe1[i]]); 03310 f2vcol = (char *)&(col2[fe2[i]]); 03311 03312 /*compare f1vcol with f2vcol*/ 03313 if( f1vcol[1] + T2QCOL_LIMIT > f2vcol[1] && f1vcol[1] - T2QCOL_LIMIT < f2vcol[1] && 03314 f1vcol[2] + T2QCOL_LIMIT > f2vcol[2] && f1vcol[2] - T2QCOL_LIMIT < f2vcol[2] && 03315 f1vcol[3] + T2QCOL_LIMIT > f2vcol[3] && f1vcol[3] - T2QCOL_LIMIT < f2vcol[3]) attrok |= B_JOINTRIA_VCOL; 03316 } 03317 } 03318 } 03319 03320 if( ((attrok & B_JOINTRIA_UV) == (flag & B_JOINTRIA_UV)) && ((attrok & B_JOINTRIA_VCOL) == (flag & B_JOINTRIA_VCOL)) ) return 1; 03321 return 0; 03322 } 03323 03324 static int fplcmp(const void *v1, const void *v2) 03325 { 03326 const EditEdge *e1= *((EditEdge**)v1), *e2=*((EditEdge**)v2); 03327 03328 if( e1->crease > e2->crease) return 1; 03329 else if( e1->crease < e2->crease) return -1; 03330 03331 return 0; 03332 } 03333 03334 /*Bitflags for edges.*/ 03335 #define T2QDELETE 1 03336 #define T2QCOMPLEX 2 03337 #define T2QJOIN 4 03338 void join_triangles(EditMesh *em) 03339 { 03340 EditVert *v1, *v2, *v3, *v4, *eve; 03341 EditEdge *eed, **edsortblock = NULL, **edb = NULL; 03342 EditFace *efa; 03343 EVPTuple *efaar = NULL; 03344 EVPtr *efaa = NULL; 03345 float *creases = NULL; 03346 float measure; /*Used to set tolerance*/ 03347 float limit = 0.8f; // XXX scene->toolsettings->jointrilimit; 03348 int i, ok, totedge=0, totseledge=0, complexedges, vindex[4]; 03349 03350 /*if we take a long time on very dense meshes we want waitcursor to display*/ 03351 waitcursor(1); 03352 03353 totseledge = count_selected_edges(em->edges.first); 03354 if(totseledge==0) return; 03355 03356 /*abusing crease value to store weights for edge pairs. Nasty*/ 03357 for(eed=em->edges.first; eed; eed=eed->next) totedge++; 03358 if(totedge) creases = MEM_callocN(sizeof(float) * totedge, "Join Triangles Crease Array"); 03359 for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++){ 03360 creases[i] = eed->crease; 03361 eed->crease = 0.0; 03362 } 03363 03364 /*clear temp flags*/ 03365 for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = eve->f2 = 0; 03366 for(eed=em->edges.first; eed; eed=eed->next) eed->f2 = eed->f1 = 0; 03367 for(efa=em->faces.first; efa; efa=efa->next) efa->f1 = efa->tmp.l = 0; 03368 03369 /*For every selected 2 manifold edge, create pointers to its two faces.*/ 03370 efaar= (EVPTuple *) MEM_callocN(totseledge * sizeof(EVPTuple), "Tri2Quad"); 03371 ok = collect_quadedges(efaar, em->edges.first, em->faces.first); 03372 complexedges = 0; 03373 03374 if(ok){ 03375 03376 03377 /*clear tmp.l flag and store number of faces that are selected and coincident to current face here.*/ 03378 for(eed=em->edges.first; eed; eed=eed->next){ 03379 /* eed->f2 is 2 only if this edge is part of exactly two 03380 triangles, and both are selected, and it has EVPTuple assigned */ 03381 if(eed->f2 == 2){ 03382 efaa= (EVPtr *) eed->tmp.p; 03383 efaa[0]->tmp.l++; 03384 efaa[1]->tmp.l++; 03385 } 03386 } 03387 03388 for(eed=em->edges.first; eed; eed=eed->next){ 03389 if(eed->f2 == 2){ 03390 efaa= (EVPtr *) eed->tmp.p; 03391 v1 = v2 = v3 = v4 = NULL; 03392 givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); 03393 if(v1 && v2 && v3 && v4){ 03394 /*test if simple island first. This mimics 2.42 behaviour and the tests are less restrictive.*/ 03395 if(efaa[0]->tmp.l == 1 && efaa[1]->tmp.l == 1){ 03396 eed->f1 |= T2QJOIN; 03397 efaa[0]->f1 = 1; //mark for join 03398 efaa[1]->f1 = 1; //mark for join 03399 } 03400 else{ 03401 03402 /* The face pair is part of a 'complex' island, so the rules for dealing with it are more involved. 03403 Depending on what options the user has chosen, this face pair can be 'thrown out' based upon the following criteria: 03404 03405 1: the two faces do not share the same material 03406 2: the edge joining the two faces is marked as sharp. 03407 3: the two faces UV's do not make a good match 03408 4: the two faces Vertex colors do not make a good match 03409 03410 If the face pair passes all the applicable tests, it is then given a 'weight' with the measure_facepair() function. 03411 This measures things like concavity, colinearity ect. If this weight is below the threshold set by the user 03412 the edge joining them is marked as being 'complex' and will be compared against other possible pairs which contain one of the 03413 same faces in the current pair later. 03414 03415 This technique is based upon an algorithm that Campbell Barton developed for his Tri2Quad script that was previously part of 03416 the python scripts bundled with Blender releases. 03417 */ 03418 03419 // XXX if(scene->toolsettings->editbutflag & B_JOINTRIA_SHARP && eed->sharp); /*do nothing*/ 03420 // else if(scene->toolsettings->editbutflag & B_JOINTRIA_MAT && efaa[0]->mat_nr != efaa[1]->mat_nr); /*do nothing*/ 03421 // else if(((scene->toolsettings->editbutflag & B_JOINTRIA_UV) || (scene->toolsettings->editbutflag & B_JOINTRIA_VCOL)) && 03422 compareFaceAttribs(em, efaa[0], efaa[1], eed); // XXX == 0); /*do nothing*/ 03423 // else{ 03424 measure = measure_facepair(v1, v2, v3, v4, limit); 03425 if(measure < limit){ 03426 complexedges++; 03427 eed->f1 |= T2QCOMPLEX; 03428 eed->crease = measure; /*we dont mark edges for join yet*/ 03429 } 03430 // } 03431 } 03432 } 03433 } 03434 } 03435 03436 /*Quicksort the complex edges according to their weighting*/ 03437 if(complexedges){ 03438 edsortblock = edb = MEM_callocN(sizeof(EditEdge*) * complexedges, "Face Pairs quicksort Array"); 03439 for(eed = em->edges.first; eed; eed=eed->next){ 03440 if(eed->f1 & T2QCOMPLEX){ 03441 *edb = eed; 03442 edb++; 03443 } 03444 } 03445 qsort(edsortblock, complexedges, sizeof(EditEdge*), fplcmp); 03446 /*now go through and mark the edges who get the highest weighting*/ 03447 for(edb=edsortblock, i=0; i < complexedges; edb++, i++){ 03448 efaa = (EVPtr *)((*edb)->tmp.p); /*suspect!*/ 03449 if( !efaa[0]->f1 && !efaa[1]->f1){ 03450 efaa[0]->f1 = 1; //mark for join 03451 efaa[1]->f1 = 1; //mark for join 03452 (*edb)->f1 |= T2QJOIN; 03453 } 03454 } 03455 } 03456 03457 /*finally go through all edges marked for join (simple and complex) and create new faces*/ 03458 for(eed=em->edges.first; eed; eed=eed->next){ 03459 if(eed->f1 & T2QJOIN){ 03460 efaa= (EVPtr *)eed->tmp.p; 03461 v1 = v2 = v3 = v4 = NULL; 03462 givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); 03463 if((v1 && v2 && v3 && v4) && (exist_face(em, v1, v2, v3, v4)==0)){ /*exist_face is very slow! Needs to be addressed.*/ 03464 /*flag for delete*/ 03465 eed->f1 |= T2QDELETE; 03466 /*create new quad and select*/ 03467 efa = EM_face_from_faces(em, efaa[0], efaa[1], vindex[0], vindex[1], 4+vindex[2], 4+vindex[3]); 03468 EM_select_face(efa,1); 03469 } 03470 else{ 03471 efaa[0]->f1 = 0; 03472 efaa[1]->f1 = 0; 03473 } 03474 } 03475 } 03476 } 03477 03478 /*free data and cleanup*/ 03479 if(creases){ 03480 for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++) eed->crease = creases[i]; 03481 MEM_freeN(creases); 03482 } 03483 for(eed=em->edges.first; eed; eed=eed->next){ 03484 if(eed->f1 & T2QDELETE) eed->f1 = 1; 03485 else eed->f1 = 0; 03486 } 03487 free_tagged_edges_faces(em, em->edges.first, em->faces.first); 03488 if(efaar) MEM_freeN(efaar); 03489 if(edsortblock) MEM_freeN(edsortblock); 03490 03491 EM_selectmode_flush(em); 03492 03493 } 03494 /* ******************** END TRIANGLE TO QUAD ************************************* */ 03495 03496 #define FACE_MARKCLEAR(f) (f->f1 = 1) 03497 03498 /* quick hack, basically a copy of beautify_fill */ 03499 static void edge_flip(EditMesh *em) 03500 { 03501 EditVert *v1, *v2, *v3, *v4; 03502 EditEdge *eed, *nexted; 03503 EditFace *efa, *w; 03504 //void **efaar, **efaa; 03505 EVPTuple *efaar; 03506 EVPtr *efaa; 03507 int totedge, ok, vindex[4]; 03508 03509 /* - all selected edges with two faces 03510 * - find the faces: store them in edges (using datablock) 03511 * - per edge: - test convex 03512 * - test edge: flip? 03513 - if true: remedge, addedge, all edges at the edge get new face pointers 03514 */ 03515 03516 EM_selectmode_flush(em); // makes sure in selectmode 'face' the edges of selected faces are selected too 03517 03518 totedge = count_selected_edges(em->edges.first); 03519 if(totedge==0) return; 03520 03521 /* temporary array for : edge -> face[1], face[2] */ 03522 efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "edgeflip"); 03523 03524 ok = collect_quadedges(efaar, em->edges.first, em->faces.first); 03525 03526 eed= em->edges.first; 03527 while(eed) { 03528 nexted= eed->next; 03529 03530 if(eed->f2==2) { /* points to 2 faces */ 03531 03532 efaa= (EVPtr *) eed->tmp.p; 03533 03534 /* don't do it if flagged */ 03535 03536 ok= 1; 03537 efa= efaa[0]; 03538 if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; 03539 efa= efaa[1]; 03540 if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; 03541 03542 if(ok) { 03543 /* test convex */ 03544 givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); 03545 03546 /* 03547 4-----3 4-----3 03548 |\ | | /| 03549 | \ 1 | | 1 / | 03550 | \ | -> | / | 03551 | 0 \ | | / 0 | 03552 | \| |/ | 03553 1-----2 1-----2 03554 */ 03555 /* make new faces */ 03556 if (v1 && v2 && v3) { 03557 if( convex(v1->co, v2->co, v3->co, v4->co) ) { 03558 if(exist_face(em, v1, v2, v3, v4)==0) { 03559 /* outch this may break seams */ 03560 w= EM_face_from_faces(em, efaa[0], efaa[1], vindex[0], 03561 vindex[1], 4+vindex[2], -1); 03562 03563 EM_select_face(w, 1); 03564 03565 /* outch this may break seams */ 03566 w= EM_face_from_faces(em, efaa[0], efaa[1], vindex[0], 03567 4+vindex[2], 4+vindex[3], -1); 03568 03569 EM_select_face(w, 1); 03570 } 03571 /* tag as to-be-removed */ 03572 FACE_MARKCLEAR(efaa[1]); 03573 FACE_MARKCLEAR(efaa[0]); 03574 eed->f1 = 1; 03575 03576 } /* endif test convex */ 03577 } 03578 } 03579 } 03580 eed= nexted; 03581 } 03582 03583 /* clear tagged edges and faces: */ 03584 free_tagged_edges_faces(em, em->edges.first, em->faces.first); 03585 03586 MEM_freeN(efaar); 03587 } 03588 03589 #define DIRECTION_CW 1 03590 #define DIRECTION_CCW 2 03591 03592 static const EnumPropertyItem direction_items[]= { 03593 {DIRECTION_CW, "CW", 0, "Clockwise", ""}, 03594 {DIRECTION_CCW, "CCW", 0, "Counter Clockwise", ""}, 03595 {0, NULL, 0, NULL, NULL}}; 03596 03597 #define AXIS_X 1 03598 #define AXIS_Y 2 03599 03600 static const EnumPropertyItem axis_items_xy[]= { 03601 {AXIS_X, "X", 0, "X", ""}, 03602 {AXIS_Y, "Y", 0, "Y", ""}, 03603 {0, NULL, 0, NULL, NULL}}; 03604 03605 static void edge_rotate(EditMesh *em, wmOperator *op, EditEdge *eed, int dir) 03606 { 03607 EditVert **verts[2]; 03608 EditFace *face[2], *efa /* , *newFace[2] */ /* UNUSED */; 03609 EditEdge **edges[2], **hiddenedges, *srchedge; 03610 int facecount, p1, p2, p3, p4, fac1, fac2, i, j; 03611 int numhidden, numshared, p[2][4]; 03612 03613 /* check to make sure that the edge is only part of 2 faces */ 03614 facecount = 0; 03615 for(efa = em->faces.first;efa;efa = efa->next) { 03616 if((efa->e1 == eed || efa->e2 == eed) || (efa->e3 == eed || efa->e4 == eed)) { 03617 if(facecount >= 2) { 03618 /* more than two faces with this edge */ 03619 return; 03620 } 03621 else { 03622 face[facecount] = efa; 03623 facecount++; 03624 } 03625 } 03626 } 03627 03628 if(facecount < 2) 03629 return; 03630 03631 /* how many edges does each face have */ 03632 if(face[0]->e4) fac1= 4; 03633 else fac1= 3; 03634 03635 if(face[1]->e4) fac2= 4; 03636 else fac2= 3; 03637 03638 /* make a handy array for verts and edges */ 03639 verts[0]= &face[0]->v1; 03640 edges[0]= &face[0]->e1; 03641 verts[1]= &face[1]->v1; 03642 edges[1]= &face[1]->e1; 03643 03644 /* we don't want to rotate edges between faces that share more than one edge */ 03645 numshared= 0; 03646 for(i=0; i<fac1; i++) 03647 for(j=0; j<fac2; j++) 03648 if (edges[0][i] == edges[1][j]) 03649 numshared++; 03650 03651 if(numshared > 1) 03652 return; 03653 03654 /* we want to construct an array of vertex indicis in both faces, starting at 03655 the last vertex of the edge being rotated. 03656 - first we find the two vertices that lie on the rotating edge 03657 - then we make sure they are ordered according to the face vertex order 03658 - and then we construct the array */ 03659 p1= p2= p3= p4= 0; 03660 03661 for(i=0; i<4; i++) { 03662 if(eed->v1 == verts[0][i]) p1 = i; 03663 if(eed->v2 == verts[0][i]) p2 = i; 03664 if(eed->v1 == verts[1][i]) p3 = i; 03665 if(eed->v2 == verts[1][i]) p4 = i; 03666 } 03667 03668 if((p1+1)%fac1 == p2) 03669 SWAP(int, p1, p2); 03670 if((p3+1)%fac2 == p4) 03671 SWAP(int, p3, p4); 03672 03673 for (i = 0; i < 4; i++) { 03674 p[0][i]= (p1 + i)%fac1; 03675 p[1][i]= (p3 + i)%fac2; 03676 } 03677 03678 /* create an Array of the Edges who have h set prior to rotate */ 03679 numhidden = 0; 03680 for(srchedge = em->edges.first;srchedge;srchedge = srchedge->next) 03681 if(srchedge->h && ((srchedge->v1->f & SELECT) || (srchedge->v2->f & SELECT))) 03682 numhidden++; 03683 03684 hiddenedges = MEM_mallocN(sizeof(EditVert*)*numhidden+1, "RotateEdgeHiddenVerts"); 03685 if(!hiddenedges) { 03686 BKE_report(op->reports, RPT_ERROR, "Memory allocation failed"); 03687 return; 03688 } 03689 03690 numhidden = 0; 03691 for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next) 03692 if(srchedge->h && (srchedge->v1->f & SELECT || srchedge->v2->f & SELECT)) 03693 hiddenedges[numhidden++] = srchedge; 03694 03695 /* create the 2 new faces */ 03696 if(fac1 == 3 && fac2 == 3) { 03697 /* no need of reverse setup */ 03698 03699 /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1); 03700 /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1); 03701 } 03702 else if(fac1 == 4 && fac2 == 3) { 03703 if(dir == DIRECTION_CCW) { 03704 /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]); 03705 /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1); 03706 } else if (dir == DIRECTION_CW) { 03707 /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][2], 4+p[1][1], p[0][0], p[0][1]); 03708 /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], 4+p[0][2], p[1][0], p[1][1], -1); 03709 03710 verts[0][p[0][2]]->f |= SELECT; 03711 verts[1][p[1][1]]->f |= SELECT; 03712 } 03713 } 03714 else if(fac1 == 3 && fac2 == 4) { 03715 if(dir == DIRECTION_CCW) { 03716 /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1); 03717 /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]); 03718 } else if (dir == DIRECTION_CW) { 03719 /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][0], p[0][1], 4+p[1][2], -1); 03720 /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], 4+p[0][2]); 03721 03722 verts[0][p[0][1]]->f |= SELECT; 03723 verts[1][p[1][2]]->f |= SELECT; 03724 } 03725 03726 } 03727 else if(fac1 == 4 && fac2 == 4) { 03728 if(dir == DIRECTION_CCW) { 03729 /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]); 03730 /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]); 03731 } else if (dir == DIRECTION_CW) { 03732 /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][2], p[0][3], 4+p[1][1], 4+p[1][2]); 03733 /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][2], p[1][3], 4+p[0][1], 4+p[0][2]); 03734 03735 verts[0][p[0][2]]->f |= SELECT; 03736 verts[1][p[1][2]]->f |= SELECT; 03737 } 03738 } 03739 else 03740 return; /* This should never happen */ 03741 03742 if(dir == DIRECTION_CCW || (fac1 == 3 && fac2 == 3)) { 03743 verts[0][p[0][1]]->f |= SELECT; 03744 verts[1][p[1][1]]->f |= SELECT; 03745 } 03746 03747 /* copy old edge's flags to new center edge*/ 03748 for(srchedge=em->edges.first;srchedge;srchedge=srchedge->next) { 03749 if((srchedge->v1->f & SELECT) && (srchedge->v2->f & SELECT)) { 03750 srchedge->f = eed->f; 03751 srchedge->h = eed->h; 03752 srchedge->dir = eed->dir; 03753 srchedge->seam = eed->seam; 03754 srchedge->crease = eed->crease; 03755 srchedge->bweight = eed->bweight; 03756 } 03757 } 03758 03759 /* resetting hidden flag */ 03760 for(numhidden--; numhidden>=0; numhidden--) 03761 hiddenedges[numhidden]->h= 1; 03762 03763 /* check for orhphan edges */ 03764 for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next) 03765 srchedge->f1= -1; 03766 03767 /* cleanup */ 03768 MEM_freeN(hiddenedges); 03769 03770 /* get rid of the old edge and faces*/ 03771 remedge(em, eed); 03772 free_editedge(em, eed); 03773 BLI_remlink(&em->faces, face[0]); 03774 free_editface(em, face[0]); 03775 BLI_remlink(&em->faces, face[1]); 03776 free_editface(em, face[1]); 03777 } 03778 03779 /* only accepts 1 selected edge, or 2 selected faces */ 03780 static int edge_rotate_selected(bContext *C, wmOperator *op) 03781 { 03782 Object *obedit= CTX_data_edit_object(C); 03783 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 03784 EditEdge *eed; 03785 EditFace *efa; 03786 int dir = RNA_enum_get(op->ptr, "direction"); // dir == 2 when clockwise and ==1 for counter CW. 03787 short edgeCount = 0; 03788 03789 /*clear new flag for new edges, count selected edges */ 03790 for(eed= em->edges.first; eed; eed= eed->next) { 03791 eed->f1= 0; 03792 eed->f2 &= ~2; 03793 if(eed->f & SELECT) edgeCount++; 03794 } 03795 03796 if(edgeCount>1) { 03797 /* more selected edges, check faces */ 03798 for(efa= em->faces.first; efa; efa= efa->next) { 03799 if(efa->f & SELECT) { 03800 efa->e1->f1++; 03801 efa->e2->f1++; 03802 efa->e3->f1++; 03803 if(efa->e4) efa->e4->f1++; 03804 } 03805 } 03806 edgeCount= 0; 03807 for(eed= em->edges.first; eed; eed= eed->next) { 03808 if(eed->f1==2) edgeCount++; 03809 } 03810 if(edgeCount==1) { 03811 for(eed= em->edges.first; eed; eed= eed->next) { 03812 if(eed->f1==2) { 03813 edge_rotate(em, op, eed,dir); 03814 break; 03815 } 03816 } 03817 } 03818 else 03819 { 03820 BKE_report(op->reports, RPT_WARNING, "Select one edge or two adjacent faces"); 03821 BKE_mesh_end_editmesh(obedit->data, em); 03822 return OPERATOR_CANCELLED; 03823 } 03824 } 03825 else if(edgeCount==1) { 03826 for(eed= em->edges.first; eed; eed= eed->next) { 03827 if(eed->f & SELECT) { 03828 EM_select_edge(eed, 0); 03829 edge_rotate(em, op, eed,dir); 03830 break; 03831 } 03832 } 03833 } 03834 else { 03835 BKE_report(op->reports, RPT_WARNING, "Select one edge or two adjacent faces"); 03836 BKE_mesh_end_editmesh(obedit->data, em); 03837 return OPERATOR_CANCELLED; 03838 } 03839 03840 /* flush selected vertices (again) to edges/faces */ 03841 EM_select_flush(em); 03842 03843 BKE_mesh_end_editmesh(obedit->data, em); 03844 03845 DAG_id_tag_update(obedit->data, 0); 03846 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 03847 03848 return OPERATOR_FINISHED; 03849 } 03850 03851 void MESH_OT_edge_rotate(wmOperatorType *ot) 03852 { 03853 /* identifiers */ 03854 ot->name= "Rotate Selected Edge"; 03855 ot->description= "Rotate selected edge or adjoining faces"; 03856 ot->idname= "MESH_OT_edge_rotate"; 03857 03858 /* api callbacks */ 03859 ot->exec= edge_rotate_selected; 03860 ot->poll= ED_operator_editmesh; 03861 03862 /* flags */ 03863 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 03864 03865 /* props */ 03866 RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate the edge around"); 03867 } 03868 03869 03870 /******************* BEVEL CODE STARTS HERE ********************/ 03871 03872 /* XXX old bevel not ported yet */ 03873 03874 static void UNUSED_FUNCTION(bevel_menu)(EditMesh *em) 03875 { 03876 BME_Mesh *bm; 03877 BME_TransData_Head *td; 03878 // TransInfo *t; 03879 int options, res, gbm_free = 0; 03880 03881 // t = BIF_GetTransInfo(); 03882 if (!G.editBMesh) { 03883 G.editBMesh = MEM_callocN(sizeof(*(G.editBMesh)),"bevel_menu() G.editBMesh"); 03884 gbm_free = 1; 03885 } 03886 03887 G.editBMesh->options = BME_BEVEL_RUNNING | BME_BEVEL_SELECT; 03888 G.editBMesh->res = 1; 03889 03890 while(G.editBMesh->options & BME_BEVEL_RUNNING) { 03891 options = G.editBMesh->options; 03892 res = G.editBMesh->res; 03893 bm = BME_editmesh_to_bmesh(em); 03894 // BIF_undo_push("Pre-Bevel"); 03895 free_editMesh(em); 03896 BME_bevel(bm,0.1f,res,options,0,0,&td); 03897 BME_bmesh_to_editmesh(bm, td, em); 03898 EM_selectmode_flush(em); 03899 G.editBMesh->bm = bm; 03900 G.editBMesh->td = td; 03901 // initTransform(TFM_BEVEL,CTX_BMESH); 03902 // Transform(); 03903 BME_free_transdata(td); 03904 BME_free_mesh(bm); 03905 // if (t->state != TRANS_CONFIRM) { 03906 // BIF_undo(); 03907 // } 03908 if (options == G.editBMesh->options) { 03909 G.editBMesh->options &= ~BME_BEVEL_RUNNING; 03910 } 03911 } 03912 03913 if (gbm_free) { 03914 MEM_freeN(G.editBMesh); 03915 G.editBMesh = NULL; 03916 } 03917 } 03918 03919 03920 /* *********** END BEVEL *********/ 03921 03922 /* this utility function checks to see if 2 edit edges share a face, 03923 returns 1 if they do 03924 returns 0 if they do not, or if the function is passed the same edge 2 times 03925 */ 03926 short sharesFace(EditMesh *em, EditEdge* e1, EditEdge* e2) 03927 { 03928 EditFace *search=NULL; 03929 03930 search = em->faces.first; 03931 if (e1 == e2){ 03932 return 0 ; 03933 } 03934 while(search){ 03935 if( 03936 ((search->e1 == e1 || search->e2 == e1) || (search->e3 == e1 || search->e4 == e1)) && 03937 ((search->e1 == e2 || search->e2 == e2) || (search->e3 == e2 || search->e4 == e2)) 03938 ) { 03939 return 1; 03940 } 03941 search = search->next; 03942 } 03943 return 0; 03944 } 03945 03946 int EdgeLoopDelete(EditMesh *UNUSED(em), wmOperator *UNUSED(op)) 03947 { 03948 #if 0 //XXX won't work with new edgeslide 03949 03950 /* temporal flag setting so we keep UVs when deleting edge loops, 03951 * this is a bit of a hack but it works how you would want in almost all cases */ 03952 // short uvcalc_flag_orig = 0; // XXX scene->toolsettings->uvcalc_flag; 03953 // scene->toolsettings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT; 03954 03955 if(!EdgeSlide(em, op, 1, 1)) { 03956 return 0; 03957 } 03958 03959 /* restore uvcalc flag */ 03960 // scene->toolsettings->uvcalc_flag = uvcalc_flag_orig; 03961 03962 EM_select_more(em); 03963 removedoublesflag(em, 1,0, 0.001); 03964 EM_select_flush(em); 03965 // DAG_id_tag_update(obedit->data, 0); 03966 return 1; 03967 #endif 03968 return 0; 03969 } 03970 03971 03972 /* -------------------- More tools ------------------ */ 03973 #if 0 03974 void mesh_set_face_flags(EditMesh *em, short mode) 03975 { 03976 EditFace *efa; 03977 MTFace *tface; 03978 short m_tex=0, m_shared=0, 03979 m_light=0, m_invis=0, m_collision=0, 03980 m_twoside=0, m_obcolor=0, m_halo=0, 03981 m_billboard=0, m_shadow=0, m_text=0, 03982 m_sort=0; 03983 short flag = 0, change = 0; 03984 03985 // XXX if (!EM_texFaceCheck()) { 03986 // error("not a mesh with uv/image layers"); 03987 // return; 03988 // } 03989 03990 add_numbut(0, TOG|SHO, "Texture", 0, 0, &m_tex, NULL); 03991 add_numbut(2, TOG|SHO, "Light", 0, 0, &m_light, NULL); 03992 add_numbut(3, TOG|SHO, "Invisible", 0, 0, &m_invis, NULL); 03993 add_numbut(4, TOG|SHO, "Collision", 0, 0, &m_collision, NULL); 03994 add_numbut(5, TOG|SHO, "Shared", 0, 0, &m_shared, NULL); 03995 add_numbut(6, TOG|SHO, "Twoside", 0, 0, &m_twoside, NULL); 03996 add_numbut(7, TOG|SHO, "ObColor", 0, 0, &m_obcolor, NULL); 03997 add_numbut(8, TOG|SHO, "Halo", 0, 0, &m_halo, NULL); 03998 add_numbut(9, TOG|SHO, "Billboard", 0, 0, &m_billboard, NULL); 03999 add_numbut(10, TOG|SHO, "Shadow", 0, 0, &m_shadow, NULL); 04000 add_numbut(11, TOG|SHO, "Text", 0, 0, &m_text, NULL); 04001 add_numbut(12, TOG|SHO, "Sort", 0, 0, &m_sort, NULL); 04002 04003 if (!do_clever_numbuts((mode ? "Set Flags" : "Clear Flags"), 13, REDRAW)) 04004 return; 04005 04006 /* these 2 cant both be on */ 04007 if (mode) /* are we seeting*/ 04008 if (m_halo) 04009 m_billboard = 0; 04010 04011 if (m_tex) flag |= TF_TEX; 04012 if (m_shared) flag |= TF_SHAREDCOL; 04013 if (m_light) flag |= TF_LIGHT; 04014 if (m_invis) flag |= TF_INVISIBLE; 04015 if (m_collision) flag |= TF_DYNAMIC; 04016 if (m_twoside) flag |= TF_TWOSIDE; 04017 if (m_obcolor) flag |= TF_OBCOL; 04018 if (m_halo) flag |= TF_BILLBOARD; 04019 if (m_billboard) flag |= TF_BILLBOARD2; 04020 if (m_shadow) flag |= TF_SHADOW; 04021 if (m_text) flag |= TF_BMFONT; 04022 if (m_sort) flag |= TF_ALPHASORT; 04023 04024 if (flag==0) 04025 return; 04026 04027 efa= em->faces.first; 04028 while(efa) { 04029 if(efa->f & SELECT) { 04030 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 04031 if (mode) tface->mode |= flag; 04032 else tface->mode &= ~flag; 04033 change = 1; 04034 } 04035 efa= efa->next; 04036 } 04037 04038 } 04039 #endif 04040 04041 /********************** Rip Operator *************************/ 04042 04043 /* helper to find edge for edge_rip */ 04044 static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, const int mval[2]) 04045 { 04046 float vec1[2], vec2[2], mvalf[2]; 04047 04048 ED_view3d_project_float(ar, co1, vec1, mat); 04049 ED_view3d_project_float(ar, co2, vec2, mat); 04050 mvalf[0]= (float)mval[0]; 04051 mvalf[1]= (float)mval[1]; 04052 04053 return dist_to_line_segment_v2(mvalf, vec1, vec2); 04054 } 04055 04056 /* helper for below */ 04057 static void mesh_rip_setface(EditMesh *em, EditFace *sefa) 04058 { 04059 /* put new vertices & edges in best face */ 04060 if(sefa->v1->tmp.v) sefa->v1= sefa->v1->tmp.v; 04061 if(sefa->v2->tmp.v) sefa->v2= sefa->v2->tmp.v; 04062 if(sefa->v3->tmp.v) sefa->v3= sefa->v3->tmp.v; 04063 if(sefa->v4 && sefa->v4->tmp.v) sefa->v4= sefa->v4->tmp.v; 04064 04065 sefa->e1= addedgelist(em, sefa->v1, sefa->v2, sefa->e1); 04066 sefa->e2= addedgelist(em, sefa->v2, sefa->v3, sefa->e2); 04067 if(sefa->v4) { 04068 sefa->e3= addedgelist(em, sefa->v3, sefa->v4, sefa->e3); 04069 sefa->e4= addedgelist(em, sefa->v4, sefa->v1, sefa->e4); 04070 } 04071 else 04072 sefa->e3= addedgelist(em, sefa->v3, sefa->v1, sefa->e3); 04073 04074 } 04075 04076 /* based on mouse cursor position, it defines how is being ripped */ 04077 static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event) 04078 { 04079 ARegion *ar= CTX_wm_region(C); 04080 RegionView3D *rv3d= ar->regiondata; 04081 Object *obedit= CTX_data_edit_object(C); 04082 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 04083 EditVert *eve, *nextve; 04084 EditEdge *eed, *seed= NULL; 04085 EditFace *efa, *sefa= NULL; 04086 float projectMat[4][4], vec[3], dist, mindist; 04087 short doit= 1; 04088 int *mval= event->mval; 04089 04090 /* select flush... vertices are important */ 04091 EM_selectmode_set(em); 04092 04093 ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); 04094 04095 /* find best face, exclude triangles and break on face select or faces with 2 edges select */ 04096 mindist= 1000000.0f; 04097 for(efa= em->faces.first; efa; efa=efa->next) { 04098 if( efa->f & 1) 04099 break; 04100 if(efa->v4 && faceselectedOR(efa, SELECT) ) { 04101 int totsel=0; 04102 04103 if(efa->e1->f & SELECT) totsel++; 04104 if(efa->e2->f & SELECT) totsel++; 04105 if(efa->e3->f & SELECT) totsel++; 04106 if(efa->e4->f & SELECT) totsel++; 04107 04108 if(totsel>1) 04109 break; 04110 ED_view3d_project_float(ar, efa->cent, vec, projectMat); 04111 dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) ); 04112 if(dist<mindist) { 04113 mindist= dist; 04114 sefa= efa; 04115 } 04116 } 04117 } 04118 04119 if(efa) { 04120 BKE_report(op->reports, RPT_WARNING, "Can't perform ripping with faces selected this way"); 04121 BKE_mesh_end_editmesh(obedit->data, em); 04122 return OPERATOR_CANCELLED; 04123 } 04124 if(sefa==NULL) { 04125 BKE_report(op->reports, RPT_WARNING, "No proper selection or faces included"); 04126 BKE_mesh_end_editmesh(obedit->data, em); 04127 return OPERATOR_CANCELLED; 04128 } 04129 04130 04131 /* duplicate vertices, new vertices get selected */ 04132 for(eve = em->verts.last; eve; eve= eve->prev) { 04133 eve->tmp.v = NULL; 04134 if(eve->f & SELECT) { 04135 eve->tmp.v = addvertlist(em, eve->co, eve); 04136 eve->f &= ~SELECT; 04137 eve->tmp.v->f |= SELECT; 04138 } 04139 } 04140 04141 /* find the best candidate edge */ 04142 /* or one of sefa edges is selected... */ 04143 if(sefa->e1->f & SELECT) seed= sefa->e2; 04144 if(sefa->e2->f & SELECT) seed= sefa->e1; 04145 if(sefa->e3->f & SELECT) seed= sefa->e2; 04146 if(sefa->e4 && sefa->e4->f & SELECT) seed= sefa->e3; 04147 04148 /* or we do the distance trick */ 04149 if(seed==NULL) { 04150 mindist= 1000000.0f; 04151 if(sefa->e1->v1->tmp.v || sefa->e1->v2->tmp.v) { 04152 dist = mesh_rip_edgedist(ar, projectMat, 04153 sefa->e1->v1->co, 04154 sefa->e1->v2->co, mval); 04155 if(dist<mindist) { 04156 seed= sefa->e1; 04157 mindist= dist; 04158 } 04159 } 04160 if(sefa->e2->v1->tmp.v || sefa->e2->v2->tmp.v) { 04161 dist = mesh_rip_edgedist(ar, projectMat, 04162 sefa->e2->v1->co, 04163 sefa->e2->v2->co, mval); 04164 if(dist<mindist) { 04165 seed= sefa->e2; 04166 mindist= dist; 04167 } 04168 } 04169 if(sefa->e3->v1->tmp.v || sefa->e3->v2->tmp.v) { 04170 dist= mesh_rip_edgedist(ar, projectMat, 04171 sefa->e3->v1->co, 04172 sefa->e3->v2->co, mval); 04173 if(dist<mindist) { 04174 seed= sefa->e3; 04175 mindist= dist; 04176 } 04177 } 04178 if(sefa->e4 && (sefa->e4->v1->tmp.v || sefa->e4->v2->tmp.v)) { 04179 dist= mesh_rip_edgedist(ar, projectMat, 04180 sefa->e4->v1->co, 04181 sefa->e4->v2->co, mval); 04182 if(dist<mindist) { 04183 seed= sefa->e4; 04184 mindist= dist; 04185 } 04186 } 04187 } 04188 04189 if(seed==NULL) { // never happens? 04190 BKE_report(op->reports, RPT_WARNING, "No proper edge found to start"); 04191 BKE_mesh_end_editmesh(obedit->data, em); 04192 return OPERATOR_CANCELLED; 04193 } 04194 04195 faceloop_select(em, seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1 04196 04197 /* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */ 04198 for(eed = em->edges.last; eed; eed= eed->prev) { 04199 eed->tmp.v = NULL; 04200 if((eed->v1->tmp.v) || (eed->v2->tmp.v)) { 04201 EditEdge *newed; 04202 04203 newed= addedgelist(em, eed->v1->tmp.v?eed->v1->tmp.v:eed->v1, 04204 eed->v2->tmp.v?eed->v2->tmp.v:eed->v2, eed); 04205 if(eed->f & SELECT) { 04206 EM_select_edge(eed, 0); 04207 EM_remove_selection(em, eed, EDITEDGE); 04208 EM_select_edge(newed, 1); 04209 } 04210 eed->tmp.v = (EditVert *)newed; 04211 } 04212 } 04213 04214 /* first clear edges to help finding neighbours */ 04215 for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0; 04216 04217 /* put new vertices & edges && flag in best face */ 04218 mesh_rip_setface(em, sefa); 04219 04220 /* starting with neighbours of best face, we loop over the seam */ 04221 sefa->f1= 2; 04222 doit= 1; 04223 while(doit) { 04224 doit= 0; 04225 04226 for(efa= em->faces.first; efa; efa=efa->next) { 04227 /* new vert in face */ 04228 if (efa->v1->tmp.v || efa->v2->tmp.v || 04229 efa->v3->tmp.v || (efa->v4 && efa->v4->tmp.v)) { 04230 /* face is tagged with loop */ 04231 if(efa->f1==1) { 04232 mesh_rip_setface(em, efa); 04233 efa->f1= 2; 04234 doit= 1; 04235 } 04236 } 04237 } 04238 } 04239 04240 /* remove loose edges, that were part of a ripped face */ 04241 for(eve = em->verts.first; eve; eve= eve->next) eve->f1= 0; 04242 for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0; 04243 for(efa= em->faces.first; efa; efa=efa->next) { 04244 efa->e1->f1= 1; 04245 efa->e2->f1= 1; 04246 efa->e3->f1= 1; 04247 if(efa->e4) efa->e4->f1= 1; 04248 } 04249 04250 for(eed = em->edges.last; eed; eed= seed) { 04251 seed= eed->prev; 04252 if(eed->f1==0) { 04253 if(eed->v1->tmp.v || eed->v2->tmp.v || 04254 (eed->v1->f & SELECT) || (eed->v2->f & SELECT)) { 04255 remedge(em, eed); 04256 free_editedge(em, eed); 04257 eed= NULL; 04258 } 04259 } 04260 if(eed) { 04261 eed->v1->f1= 1; 04262 eed->v2->f1= 1; 04263 } 04264 } 04265 04266 /* and remove loose selected vertices, that got duplicated accidentally */ 04267 for(eve = em->verts.first; eve; eve= nextve) { 04268 nextve= eve->next; 04269 if(eve->f1==0 && (eve->tmp.v || (eve->f & SELECT))) { 04270 BLI_remlink(&em->verts,eve); 04271 free_editvert(em, eve); 04272 } 04273 } 04274 04275 DAG_id_tag_update(obedit->data, 0); 04276 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 04277 04278 BKE_mesh_end_editmesh(obedit->data, em); 04279 04280 // RNA_enum_set(op->ptr, "proportional", 0); 04281 // RNA_boolean_set(op->ptr, "mirror", FALSE); 04282 // WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr); 04283 04284 return OPERATOR_FINISHED; 04285 } 04286 04287 void MESH_OT_rip(wmOperatorType *ot) 04288 { 04289 /* identifiers */ 04290 ot->name= "Rip"; 04291 ot->description= "Rip selection from mesh (quads only)"; 04292 ot->idname= "MESH_OT_rip"; 04293 04294 /* api callbacks */ 04295 ot->invoke= mesh_rip_invoke; 04296 ot->poll= EM_view3d_poll; 04297 04298 /* flags */ 04299 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 04300 04301 /* to give to transform */ 04302 /* XXX Transform this in a macro */ 04303 Transform_Properties(ot, P_CONSTRAINT|P_MIRROR); 04304 } 04305 04306 04307 /************************ Shape Operators *************************/ 04308 04309 static void shape_propagate(Object *obedit, EditMesh *em, wmOperator *op) 04310 { 04311 EditVert *ev = NULL; 04312 Mesh* me = (Mesh*)obedit->data; 04313 Key* ky = NULL; 04314 KeyBlock* kb = NULL; 04315 04316 04317 if(me->key){ 04318 ky = me->key; 04319 } else { 04320 BKE_report(op->reports, RPT_WARNING, "Object Has No Key"); 04321 return; 04322 } 04323 04324 if(ky->block.first){ 04325 for(ev = em->verts.first; ev ; ev = ev->next){ 04326 if(ev->f & SELECT){ 04327 for(kb=ky->block.first;kb;kb = kb->next){ 04328 float *data; 04329 data = kb->data; 04330 VECCOPY(data+(ev->keyindex*3),ev->co); 04331 } 04332 } 04333 } 04334 } else { 04335 BKE_report(op->reports, RPT_WARNING, "Object Has No Blendshapes"); 04336 return; 04337 } 04338 04339 #if 0 04340 //TAG Mesh Objects that share this data 04341 for(base = scene->base.first; base; base = base->next){ 04342 if(base->object && base->object->data == me){ 04343 base->object->recalc = OB_RECALC_DATA; 04344 } 04345 } 04346 #endif 04347 04348 DAG_id_tag_update(obedit->data, 0); 04349 return; 04350 } 04351 04352 04353 static int shape_propagate_to_all_exec(bContext *C, wmOperator *op) 04354 { 04355 Object *obedit= CTX_data_edit_object(C); 04356 Mesh *me= obedit->data; 04357 EditMesh *em= BKE_mesh_get_editmesh(me); 04358 04359 shape_propagate(obedit, em, op); 04360 04361 DAG_id_tag_update(&me->id, 0); 04362 WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); 04363 04364 return OPERATOR_FINISHED; 04365 } 04366 04367 04368 void MESH_OT_shape_propagate_to_all(wmOperatorType *ot) 04369 { 04370 /* identifiers */ 04371 ot->name= "Shape Propagate"; 04372 ot->description= "Apply selected vertex locations to all other shape keys"; 04373 ot->idname= "MESH_OT_shape_propagate_to_all"; 04374 04375 /* api callbacks */ 04376 ot->exec= shape_propagate_to_all_exec; 04377 ot->poll= ED_operator_editmesh; 04378 04379 /* flags */ 04380 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 04381 } 04382 04383 static int blend_from_shape_exec(bContext *C, wmOperator *op) 04384 { 04385 Object *obedit= CTX_data_edit_object(C); 04386 Mesh *me= obedit->data; 04387 Key *key= me->key; 04388 EditMesh *em= BKE_mesh_get_editmesh(me); 04389 EditVert *eve; 04390 KeyBlock *kb, *refkb= NULL; 04391 float *data, *refdata= NULL, co[3]; 04392 float blend= RNA_float_get(op->ptr, "blend"); 04393 int shape= RNA_enum_get(op->ptr, "shape"); 04394 int add= RNA_boolean_get(op->ptr, "add"); 04395 int blended= 0; 04396 04397 if(key && (kb= BLI_findlink(&key->block, shape))) { 04398 data= kb->data; 04399 04400 if(add) { 04401 refkb= BLI_findlink(&key->block, kb->relative); 04402 if(refkb) 04403 refdata = refkb->data; 04404 } 04405 04406 for(eve=em->verts.first; eve; eve=eve->next){ 04407 if(eve->f & SELECT) { 04408 if(eve->keyindex >= 0 && eve->keyindex < kb->totelem) { 04409 copy_v3_v3(co, data + eve->keyindex*3); 04410 04411 if(add) { 04412 /* in add mode, we add relative shape key offset */ 04413 if(refdata && eve->keyindex < refkb->totelem) 04414 sub_v3_v3v3(co, co, refdata + eve->keyindex*3); 04415 04416 madd_v3_v3fl(eve->co, co, blend); 04417 } 04418 else { 04419 /* in blend mode, we interpolate to the shape key */ 04420 interp_v3_v3v3(eve->co, eve->co, co, blend); 04421 } 04422 04423 blended= 1; 04424 } 04425 } 04426 } 04427 } 04428 04429 BKE_mesh_end_editmesh(me, em); 04430 04431 if(!blended) 04432 return OPERATOR_CANCELLED; 04433 04434 DAG_id_tag_update(&me->id, 0); 04435 WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); 04436 04437 return OPERATOR_FINISHED; 04438 } 04439 04440 static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) 04441 { 04442 Object *obedit= CTX_data_edit_object(C); 04443 Mesh *me= (obedit) ? obedit->data : NULL; 04444 Key *key; 04445 KeyBlock *kb, *actkb; 04446 EnumPropertyItem tmp= {0, "", 0, "", ""}, *item= NULL; 04447 int totitem= 0, a; 04448 04449 if(obedit && obedit->type == OB_MESH) { 04450 key= me->key; 04451 actkb= ob_get_keyblock(obedit); 04452 04453 if(key && actkb) { 04454 for(kb=key->block.first, a=0; kb; kb=kb->next, a++) { 04455 if(kb != actkb) { 04456 tmp.value= a; 04457 tmp.identifier= kb->name; 04458 tmp.name= kb->name; 04459 RNA_enum_item_add(&item, &totitem, &tmp); 04460 } 04461 } 04462 } 04463 } 04464 04465 RNA_enum_item_end(&item, &totitem); 04466 *free= 1; 04467 04468 return item; 04469 } 04470 04471 void MESH_OT_blend_from_shape(wmOperatorType *ot) 04472 { 04473 PropertyRNA *prop; 04474 static EnumPropertyItem shape_items[]= {{0, NULL, 0, NULL, NULL}}; 04475 04476 /* identifiers */ 04477 ot->name= "Blend From Shape"; 04478 ot->description= "Blend in shape from a shape key"; 04479 ot->idname= "MESH_OT_blend_from_shape"; 04480 04481 /* api callbacks */ 04482 ot->exec= blend_from_shape_exec; 04483 ot->invoke= WM_operator_props_popup; 04484 ot->poll= ED_operator_editmesh; 04485 04486 /* flags */ 04487 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 04488 04489 /* properties */ 04490 prop= RNA_def_enum(ot->srna, "shape", shape_items, 0, "Shape", "Shape key to use for blending"); 04491 RNA_def_enum_funcs(prop, shape_itemf); 04492 RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor", -2.0f, 2.0f); 04493 RNA_def_boolean(ot->srna, "add", 0, "Add", "Add rather than blend between shapes"); 04494 } 04495 04496 /************************ Merge Operator *************************/ 04497 04498 /* Collection Routines|Currently used by the improved merge code*/ 04499 /* buildEdge_collection() creates a list of lists*/ 04500 /* these lists are filled with edges that are topologically connected.*/ 04501 /* This whole tool needs to be redone, its rather poorly implemented...*/ 04502 04503 typedef struct Collection{ 04504 struct Collection *next, *prev; 04505 int index; 04506 ListBase collectionbase; 04507 } Collection; 04508 04509 typedef struct CollectedEdge{ 04510 struct CollectedEdge *next, *prev; 04511 EditEdge *eed; 04512 } CollectedEdge; 04513 04514 #define MERGELIMIT 0.000001 04515 04516 static void build_edgecollection(EditMesh *em, ListBase *allcollections) 04517 { 04518 EditEdge *eed; 04519 Collection *edgecollection, *newcollection; 04520 CollectedEdge *newedge; 04521 04522 int currtag = 1; 04523 short ebalanced = 0; 04524 short collectionfound = 0; 04525 04526 for (eed=em->edges.first; eed; eed = eed->next){ 04527 eed->tmp.l = 0; 04528 eed->v1->tmp.l = 0; 04529 eed->v2->tmp.l = 0; 04530 } 04531 04532 /*1st pass*/ 04533 for(eed=em->edges.first; eed; eed=eed->next){ 04534 if(eed->f&SELECT){ 04535 eed->v1->tmp.l = currtag; 04536 eed->v2->tmp.l = currtag; 04537 currtag +=1; 04538 } 04539 } 04540 04541 /*2nd pass - Brute force. Loop through selected faces until there are no 'unbalanced' edges left (those with both vertices 'tmp.l' tag matching */ 04542 while(ebalanced == 0){ 04543 ebalanced = 1; 04544 for(eed=em->edges.first; eed; eed = eed->next){ 04545 if(eed->f&SELECT){ 04546 if(eed->v1->tmp.l != eed->v2->tmp.l) /*unbalanced*/{ 04547 if(eed->v1->tmp.l > eed->v2->tmp.l && eed->v2->tmp.l !=0) eed->v1->tmp.l = eed->v2->tmp.l; 04548 else if(eed->v1 != 0) eed->v2->tmp.l = eed->v1->tmp.l; 04549 ebalanced = 0; 04550 } 04551 } 04552 } 04553 } 04554 04555 /*3rd pass, set all the edge flags (unnessecary?)*/ 04556 for(eed=em->edges.first; eed; eed = eed->next){ 04557 if(eed->f&SELECT) eed->tmp.l = eed->v1->tmp.l; 04558 } 04559 04560 for(eed=em->edges.first; eed; eed=eed->next){ 04561 if(eed->f&SELECT){ 04562 if(allcollections->first){ 04563 for(edgecollection = allcollections->first; edgecollection; edgecollection=edgecollection->next){ 04564 if(edgecollection->index == eed->tmp.l){ 04565 newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge"); 04566 newedge->eed = eed; 04567 BLI_addtail(&(edgecollection->collectionbase), newedge); 04568 collectionfound = 1; 04569 break; 04570 } 04571 else collectionfound = 0; 04572 } 04573 } 04574 if(allcollections->first == NULL || collectionfound == 0){ 04575 newcollection = MEM_mallocN(sizeof(Collection), "element collection"); 04576 newcollection->index = eed->tmp.l; 04577 newcollection->collectionbase.first = 0; 04578 newcollection->collectionbase.last = 0; 04579 04580 newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge"); 04581 newedge->eed = eed; 04582 04583 BLI_addtail(&(newcollection->collectionbase), newedge); 04584 BLI_addtail(allcollections, newcollection); 04585 } 04586 } 04587 04588 } 04589 } 04590 04591 static void freecollections(ListBase *allcollections) 04592 { 04593 struct Collection *curcollection; 04594 04595 for(curcollection = allcollections->first; curcollection; curcollection = curcollection->next) 04596 BLI_freelistN(&(curcollection->collectionbase)); 04597 BLI_freelistN(allcollections); 04598 } 04599 04600 /*Begin UV Edge Collapse Code 04601 Like Edge subdivide, Edge Collapse should handle UV's intelligently, but since UV's are a per-face attribute, normal edge collapse will fail 04602 in areas such as the boundaries of 'UV islands'. So for each edge collection we need to build a set of 'welded' UV vertices and edges for it. 04603 The welded UV edges can then be sorted and collapsed. 04604 */ 04605 typedef struct wUV{ 04606 struct wUV *next, *prev; 04607 ListBase nodes; 04608 float u, v; /*cached copy of UV coordinates pointed to by nodes*/ 04609 EditVert *eve; 04610 int f; 04611 } wUV; 04612 04613 typedef struct wUVNode{ 04614 struct wUVNode *next, *prev; 04615 float *u; /*pointer to original tface data*/ 04616 float *v; /*pointer to original tface data*/ 04617 } wUVNode; 04618 04619 typedef struct wUVEdge{ 04620 struct wUVEdge *next, *prev; 04621 float v1uv[2], v2uv[2]; /*nasty.*/ 04622 struct wUV *v1, *v2; /*oriented same as editedge*/ 04623 EditEdge *eed; 04624 int f; 04625 } wUVEdge; 04626 04627 typedef struct wUVEdgeCollect{ /*used for grouping*/ 04628 struct wUVEdgeCollect *next, *prev; 04629 wUVEdge *uved; 04630 int id; 04631 } wUVEdgeCollect; 04632 04633 static void append_weldedUV(EditMesh *em, EditFace *efa, EditVert *eve, int tfindex, ListBase *uvverts) 04634 { 04635 wUV *curwvert, *newwvert; 04636 wUVNode *newnode; 04637 int found; 04638 MTFace *tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 04639 04640 found = 0; 04641 04642 for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){ 04643 if(curwvert->eve == eve && curwvert->u == tf->uv[tfindex][0] && curwvert->v == tf->uv[tfindex][1]){ 04644 newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node"); 04645 newnode->u = &(tf->uv[tfindex][0]); 04646 newnode->v = &(tf->uv[tfindex][1]); 04647 BLI_addtail(&(curwvert->nodes), newnode); 04648 found = 1; 04649 break; 04650 } 04651 } 04652 04653 if(!found){ 04654 newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node"); 04655 newnode->u = &(tf->uv[tfindex][0]); 04656 newnode->v = &(tf->uv[tfindex][1]); 04657 04658 newwvert = MEM_callocN(sizeof(wUV), "Welded UV Vert"); 04659 newwvert->u = *(newnode->u); 04660 newwvert->v = *(newnode->v); 04661 newwvert->eve = eve; 04662 04663 BLI_addtail(&(newwvert->nodes), newnode); 04664 BLI_addtail(uvverts, newwvert); 04665 04666 } 04667 } 04668 04669 static void build_weldedUVs(EditMesh *em, ListBase *uvverts) 04670 { 04671 EditFace *efa; 04672 for(efa=em->faces.first; efa; efa=efa->next){ 04673 if(efa->v1->f1) append_weldedUV(em, efa, efa->v1, 0, uvverts); 04674 if(efa->v2->f1) append_weldedUV(em, efa, efa->v2, 1, uvverts); 04675 if(efa->v3->f1) append_weldedUV(em, efa, efa->v3, 2, uvverts); 04676 if(efa->v4 && efa->v4->f1) append_weldedUV(em, efa, efa->v4, 3, uvverts); 04677 } 04678 } 04679 04680 static void append_weldedUVEdge(EditMesh *em, EditFace *efa, EditEdge *eed, ListBase *uvedges) 04681 { 04682 wUVEdge *curwedge, *newwedge; 04683 int v1tfindex, v2tfindex, found; 04684 MTFace *tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 04685 04686 found = 0; 04687 04688 if(eed->v1 == efa->v1) v1tfindex = 0; 04689 else if(eed->v1 == efa->v2) v1tfindex = 1; 04690 else if(eed->v1 == efa->v3) v1tfindex = 2; 04691 else /* if(eed->v1 == efa->v4) */ v1tfindex = 3; 04692 04693 if(eed->v2 == efa->v1) v2tfindex = 0; 04694 else if(eed->v2 == efa->v2) v2tfindex = 1; 04695 else if(eed->v2 == efa->v3) v2tfindex = 2; 04696 else /* if(eed->v2 == efa->v4) */ v2tfindex = 3; 04697 04698 for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){ 04699 if(curwedge->eed == eed && curwedge->v1uv[0] == tf->uv[v1tfindex][0] && curwedge->v1uv[1] == tf->uv[v1tfindex][1] && curwedge->v2uv[0] == tf->uv[v2tfindex][0] && curwedge->v2uv[1] == tf->uv[v2tfindex][1]){ 04700 found = 1; 04701 break; //do nothing, we don't need another welded uv edge 04702 } 04703 } 04704 04705 if(!found){ 04706 newwedge = MEM_callocN(sizeof(wUVEdge), "Welded UV Edge"); 04707 newwedge->v1uv[0] = tf->uv[v1tfindex][0]; 04708 newwedge->v1uv[1] = tf->uv[v1tfindex][1]; 04709 newwedge->v2uv[0] = tf->uv[v2tfindex][0]; 04710 newwedge->v2uv[1] = tf->uv[v2tfindex][1]; 04711 newwedge->eed = eed; 04712 04713 BLI_addtail(uvedges, newwedge); 04714 } 04715 } 04716 04717 static void build_weldedUVEdges(EditMesh *em, ListBase *uvedges, ListBase *uvverts) 04718 { 04719 wUV *curwvert; 04720 wUVEdge *curwedge; 04721 EditFace *efa; 04722 04723 for(efa=em->faces.first; efa; efa=efa->next){ 04724 if(efa->e1->f1) append_weldedUVEdge(em, efa, efa->e1, uvedges); 04725 if(efa->e2->f1) append_weldedUVEdge(em, efa, efa->e2, uvedges); 04726 if(efa->e3->f1) append_weldedUVEdge(em, efa, efa->e3, uvedges); 04727 if(efa->e4 && efa->e4->f1) append_weldedUVEdge(em, efa, efa->e4, uvedges); 04728 } 04729 04730 04731 //link vertices: for each uvedge, search uvverts to populate v1 and v2 pointers 04732 for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){ 04733 for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){ 04734 if(curwedge->eed->v1 == curwvert->eve && curwedge->v1uv[0] == curwvert->u && curwedge->v1uv[1] == curwvert->v){ 04735 curwedge->v1 = curwvert; 04736 break; 04737 } 04738 } 04739 for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){ 04740 if(curwedge->eed->v2 == curwvert->eve && curwedge->v2uv[0] == curwvert->u && curwedge->v2uv[1] == curwvert->v){ 04741 curwedge->v2 = curwvert; 04742 break; 04743 } 04744 } 04745 } 04746 } 04747 04748 static void free_weldedUVs(ListBase *uvverts) 04749 { 04750 wUV *curwvert; 04751 for(curwvert = uvverts->first; curwvert; curwvert=curwvert->next) BLI_freelistN(&(curwvert->nodes)); 04752 BLI_freelistN(uvverts); 04753 } 04754 04755 static void collapse_edgeuvs(EditMesh *em) 04756 { 04757 ListBase uvedges, uvverts, allcollections; 04758 wUVEdge *curwedge; 04759 wUVNode *curwnode; 04760 wUVEdgeCollect *collectedwuve, *newcollectedwuve; 04761 Collection *wuvecollection, *newcollection; 04762 int curtag, balanced, collectionfound= 0, vcount; 04763 float avg[2]; 04764 04765 if (!EM_texFaceCheck(em)) 04766 return; 04767 04768 uvverts.first = uvverts.last = uvedges.first = uvedges.last = allcollections.first = allcollections.last = NULL; 04769 04770 build_weldedUVs(em, &uvverts); 04771 build_weldedUVEdges(em, &uvedges, &uvverts); 04772 04773 curtag = 0; 04774 04775 for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){ 04776 curwedge->v1->f = curtag; 04777 curwedge->v2->f = curtag; 04778 curtag +=1; 04779 } 04780 04781 balanced = 0; 04782 while(!balanced){ 04783 balanced = 1; 04784 for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){ 04785 if(curwedge->v1->f != curwedge->v2->f){ 04786 if(curwedge->v1->f > curwedge->v2->f) curwedge->v1->f = curwedge->v2->f; 04787 else curwedge->v2->f = curwedge->v1->f; 04788 balanced = 0; 04789 } 04790 } 04791 } 04792 04793 for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next) curwedge->f = curwedge->v1->f; 04794 04795 04796 for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){ 04797 if(allcollections.first){ 04798 for(wuvecollection = allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){ 04799 if(wuvecollection->index == curwedge->f){ 04800 newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge"); 04801 newcollectedwuve->uved = curwedge; 04802 BLI_addtail(&(wuvecollection->collectionbase), newcollectedwuve); 04803 collectionfound = 1; 04804 break; 04805 } 04806 04807 else collectionfound = 0; 04808 } 04809 } 04810 if(allcollections.first == NULL || collectionfound == 0){ 04811 newcollection = MEM_callocN(sizeof(Collection), "element collection"); 04812 newcollection->index = curwedge->f; 04813 newcollection->collectionbase.first = 0; 04814 newcollection->collectionbase.last = 0; 04815 04816 newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge"); 04817 newcollectedwuve->uved = curwedge; 04818 04819 BLI_addtail(&(newcollection->collectionbase), newcollectedwuve); 04820 BLI_addtail(&allcollections, newcollection); 04821 } 04822 } 04823 04824 for(wuvecollection=allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){ 04825 04826 vcount = avg[0] = avg[1] = 0; 04827 04828 for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){ 04829 avg[0] += collectedwuve->uved->v1uv[0]; 04830 avg[1] += collectedwuve->uved->v1uv[1]; 04831 04832 avg[0] += collectedwuve->uved->v2uv[0]; 04833 avg[1] += collectedwuve->uved->v2uv[1]; 04834 04835 vcount +=2; 04836 04837 } 04838 04839 avg[0] /= vcount; avg[1] /= vcount; 04840 04841 for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){ 04842 for(curwnode=collectedwuve->uved->v1->nodes.first; curwnode; curwnode=curwnode->next){ 04843 *(curwnode->u) = avg[0]; 04844 *(curwnode->v) = avg[1]; 04845 } 04846 for(curwnode=collectedwuve->uved->v2->nodes.first; curwnode; curwnode=curwnode->next){ 04847 *(curwnode->u) = avg[0]; 04848 *(curwnode->v) = avg[1]; 04849 } 04850 } 04851 } 04852 04853 free_weldedUVs(&uvverts); 04854 BLI_freelistN(&uvedges); 04855 freecollections(&allcollections); 04856 } 04857 04858 /*End UV Edge collapse code*/ 04859 04860 static void collapseuvs(EditMesh *em, EditVert *mergevert) 04861 { 04862 EditFace *efa; 04863 MTFace *tf; 04864 int uvcount; 04865 float uvav[2]; 04866 04867 if (!EM_texFaceCheck(em)) 04868 return; 04869 04870 uvcount = 0; 04871 uvav[0] = 0; 04872 uvav[1] = 0; 04873 04874 for(efa = em->faces.first; efa; efa=efa->next){ 04875 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 04876 04877 if(efa->v1->f1 && ELEM(mergevert, NULL, efa->v1)) { 04878 uvav[0] += tf->uv[0][0]; 04879 uvav[1] += tf->uv[0][1]; 04880 uvcount += 1; 04881 } 04882 if(efa->v2->f1 && ELEM(mergevert, NULL, efa->v2)){ 04883 uvav[0] += tf->uv[1][0]; 04884 uvav[1] += tf->uv[1][1]; 04885 uvcount += 1; 04886 } 04887 if(efa->v3->f1 && ELEM(mergevert, NULL, efa->v3)){ 04888 uvav[0] += tf->uv[2][0]; 04889 uvav[1] += tf->uv[2][1]; 04890 uvcount += 1; 04891 } 04892 if(efa->v4 && efa->v4->f1 && ELEM(mergevert, NULL, efa->v4)){ 04893 uvav[0] += tf->uv[3][0]; 04894 uvav[1] += tf->uv[3][1]; 04895 uvcount += 1; 04896 } 04897 } 04898 04899 if(uvcount > 0) { 04900 uvav[0] /= uvcount; 04901 uvav[1] /= uvcount; 04902 04903 for(efa = em->faces.first; efa; efa=efa->next){ 04904 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 04905 04906 if(efa->v1->f1){ 04907 tf->uv[0][0] = uvav[0]; 04908 tf->uv[0][1] = uvav[1]; 04909 } 04910 if(efa->v2->f1){ 04911 tf->uv[1][0] = uvav[0]; 04912 tf->uv[1][1] = uvav[1]; 04913 } 04914 if(efa->v3->f1){ 04915 tf->uv[2][0] = uvav[0]; 04916 tf->uv[2][1] = uvav[1]; 04917 } 04918 if(efa->v4 && efa->v4->f1){ 04919 tf->uv[3][0] = uvav[0]; 04920 tf->uv[3][1] = uvav[1]; 04921 } 04922 } 04923 } 04924 } 04925 04926 static int collapseEdges(EditMesh *em) 04927 { 04928 EditVert *eve; 04929 EditEdge *eed; 04930 04931 ListBase allcollections; 04932 CollectedEdge *curredge; 04933 Collection *edgecollection; 04934 04935 int totedges, mergecount,vcount /*, groupcount*/; 04936 float avgcount[3]; 04937 04938 allcollections.first = 0; 04939 allcollections.last = 0; 04940 04941 mergecount = 0; 04942 04943 build_edgecollection(em, &allcollections); 04944 /*groupcount = BLI_countlist(&allcollections);*/ /*UNUSED*/ 04945 04946 04947 for(edgecollection = allcollections.first; edgecollection; edgecollection = edgecollection->next){ 04948 totedges = BLI_countlist(&(edgecollection->collectionbase)); 04949 mergecount += totedges; 04950 avgcount[0] = 0; avgcount[1] = 0; avgcount[2] = 0; 04951 04952 vcount = 0; 04953 04954 for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){ 04955 avgcount[0] += ((EditEdge*)curredge->eed)->v1->co[0]; 04956 avgcount[1] += ((EditEdge*)curredge->eed)->v1->co[1]; 04957 avgcount[2] += ((EditEdge*)curredge->eed)->v1->co[2]; 04958 04959 avgcount[0] += ((EditEdge*)curredge->eed)->v2->co[0]; 04960 avgcount[1] += ((EditEdge*)curredge->eed)->v2->co[1]; 04961 avgcount[2] += ((EditEdge*)curredge->eed)->v2->co[2]; 04962 04963 vcount +=2; 04964 } 04965 04966 avgcount[0] /= vcount; avgcount[1] /=vcount; avgcount[2] /= vcount; 04967 04968 for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){ 04969 VECCOPY(((EditEdge*)curredge->eed)->v1->co,avgcount); 04970 VECCOPY(((EditEdge*)curredge->eed)->v2->co,avgcount); 04971 } 04972 04973 if (EM_texFaceCheck(em)) { 04974 /*uv collapse*/ 04975 for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = 0; 04976 for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = 0; 04977 for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){ 04978 curredge->eed->v1->f1 = 1; 04979 curredge->eed->v2->f1 = 1; 04980 curredge->eed->f1 = 1; 04981 } 04982 collapse_edgeuvs(em); 04983 } 04984 04985 } 04986 freecollections(&allcollections); 04987 removedoublesflag(em, 1, 0, MERGELIMIT); 04988 04989 return mergecount; 04990 } 04991 04992 static int merge_firstlast(EditMesh *em, int first, int uvmerge) 04993 { 04994 EditVert *eve,*mergevert; 04995 EditSelection *ese; 04996 04997 /* do sanity check in mergemenu in edit.c ?*/ 04998 if(first == 0){ 04999 ese = em->selected.last; 05000 mergevert= (EditVert*)ese->data; 05001 } 05002 else{ 05003 ese = em->selected.first; 05004 mergevert = (EditVert*)ese->data; 05005 } 05006 05007 if(mergevert->f&SELECT){ 05008 for (eve=em->verts.first; eve; eve=eve->next){ 05009 if (eve->f&SELECT) 05010 VECCOPY(eve->co,mergevert->co); 05011 } 05012 } 05013 05014 if(uvmerge && CustomData_has_layer(&em->fdata, CD_MTFACE)){ 05015 05016 for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = 0; 05017 for(eve=em->verts.first; eve; eve=eve->next){ 05018 if(eve->f&SELECT) eve->f1 = 1; 05019 } 05020 collapseuvs(em, mergevert); 05021 } 05022 05023 return removedoublesflag(em, 1, 0, MERGELIMIT); 05024 } 05025 05026 static void em_snap_to_center(EditMesh *em) 05027 { 05028 EditVert *eve; 05029 float cent[3] = {0.0f, 0.0f, 0.0f}; 05030 int i=0; 05031 05032 for (eve=em->verts.first; eve; eve=eve->next) { 05033 if (eve->f & SELECT) { 05034 add_v3_v3(cent, eve->co); 05035 i++; 05036 } 05037 } 05038 05039 if (!i) 05040 return; 05041 05042 mul_v3_fl(cent, 1.0f / (float)i); 05043 05044 for (eve=em->verts.first; eve; eve=eve->next) { 05045 if (eve->f & SELECT) { 05046 VECCOPY(eve->co, cent); 05047 } 05048 } 05049 } 05050 05051 static void em_snap_to_cursor(EditMesh *em, bContext *C) 05052 { 05053 Scene *scene = CTX_data_scene(C); 05054 Object *ob= CTX_data_edit_object(C); 05055 View3D *v3d = CTX_wm_view3d(C); 05056 EditVert *eve; 05057 float co[3], *vco, invmat[4][4]; 05058 05059 invert_m4_m4(invmat, ob->obmat); 05060 05061 vco = give_cursor(scene, v3d); 05062 VECCOPY(co, vco); 05063 mul_m4_v3(invmat, co); 05064 05065 for (eve=em->verts.first; eve; eve=eve->next) { 05066 if (eve->f & SELECT) { 05067 VECCOPY(eve->co, co); 05068 } 05069 } 05070 } 05071 05072 static int merge_target(bContext *C, EditMesh *em, int target, int uvmerge) 05073 { 05074 EditVert *eve; 05075 05076 // XXX not working 05077 if(target) em_snap_to_cursor(em, C); 05078 else em_snap_to_center(em); 05079 05080 if(uvmerge && CustomData_has_layer(&em->fdata, CD_MTFACE)){ 05081 for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = 0; 05082 for(eve=em->verts.first; eve; eve=eve->next){ 05083 if(eve->f&SELECT) eve->f1 = 1; 05084 } 05085 collapseuvs(em, NULL); 05086 } 05087 05088 return removedoublesflag(em, 1, 0, MERGELIMIT); 05089 } 05090 #undef MERGELIMIT 05091 05092 static int merge_exec(bContext *C, wmOperator *op) 05093 { 05094 Object *obedit= CTX_data_edit_object(C); 05095 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 05096 int count= 0, uvs= RNA_boolean_get(op->ptr, "uvs"); 05097 EditSelection *ese; 05098 int totvert= em->totvert, totedge= em->totedge, totface= em->totface; 05099 05100 switch(RNA_enum_get(op->ptr, "type")) { 05101 case 3: 05102 count = merge_target(C, em, 0, uvs); 05103 break; 05104 case 4: 05105 count = merge_target(C, em, 1, uvs); 05106 break; 05107 case 1: 05108 ese= (EditSelection *)em->selected.last; 05109 if(ese && ese->type == EDITVERT) { 05110 count = merge_firstlast(em, 0, uvs); 05111 } else { 05112 BKE_report(op->reports, RPT_WARNING, "no last selected vertex set"); 05113 } 05114 break; 05115 case 6: 05116 ese= (EditSelection *)em->selected.first; 05117 if(ese && ese->type == EDITVERT) { 05118 count = merge_firstlast(em, 1, uvs); 05119 } 05120 else { 05121 BKE_report(op->reports, RPT_WARNING, "no last selected vertex set"); 05122 } 05123 break; 05124 case 5: 05125 count = collapseEdges(em); 05126 break; 05127 } 05128 05129 if (!(totvert != em->totvert || totedge != em->totedge || totface != em->totface)) 05130 return OPERATOR_CANCELLED; 05131 05132 recalc_editnormals(em); 05133 05134 BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s", count, (count==1)?"ex":"ices"); 05135 05136 BKE_mesh_end_editmesh(obedit->data, em); 05137 05138 DAG_id_tag_update(obedit->data, 0); 05139 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 05140 05141 return OPERATOR_FINISHED; 05142 } 05143 05144 static EnumPropertyItem merge_type_items[]= { 05145 {6, "FIRST", 0, "At First", ""}, 05146 {1, "LAST", 0, "At Last", ""}, 05147 {3, "CENTER", 0, "At Center", ""}, 05148 {4, "CURSOR", 0, "At Cursor", ""}, 05149 {5, "COLLAPSE", 0, "Collapse", ""}, 05150 {0, NULL, 0, NULL, NULL}}; 05151 05152 static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) 05153 { 05154 Object *obedit= CTX_data_edit_object(C); 05155 EnumPropertyItem *item= NULL; 05156 int totitem= 0; 05157 05158 if (C==NULL) { 05159 return merge_type_items; 05160 } 05161 05162 if(obedit && obedit->type == OB_MESH) { 05163 EditMesh *em= BKE_mesh_get_editmesh(obedit->data); 05164 05165 if(em->selectmode & SCE_SELECT_VERTEX) { 05166 if(em->selected.first && em->selected.last && 05167 ((EditSelection*)em->selected.first)->type == EDITVERT && ((EditSelection*)em->selected.last)->type == EDITVERT) { 05168 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6); 05169 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1); 05170 } 05171 else if(em->selected.first && ((EditSelection*)em->selected.first)->type == EDITVERT) 05172 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1); 05173 else if(em->selected.last && ((EditSelection*)em->selected.last)->type == EDITVERT) 05174 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6); 05175 } 05176 05177 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3); 05178 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4); 05179 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5); 05180 } 05181 05182 RNA_enum_item_end(&item, &totitem); 05183 *free= 1; 05184 05185 return item; 05186 } 05187 05188 void MESH_OT_merge(wmOperatorType *ot) 05189 { 05190 PropertyRNA *prop; 05191 05192 /* identifiers */ 05193 ot->name= "Merge"; 05194 ot->description= "Merge selected vertices"; 05195 ot->idname= "MESH_OT_merge"; 05196 05197 /* api callbacks */ 05198 ot->exec= merge_exec; 05199 ot->invoke= WM_menu_invoke; 05200 ot->poll= ED_operator_editmesh; 05201 05202 /* flags */ 05203 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 05204 05205 /* properties */ 05206 prop= RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use"); 05207 RNA_def_enum_funcs(prop, merge_type_itemf); 05208 ot->prop= prop; 05209 RNA_def_boolean(ot->srna, "uvs", 0, "UVs", "Move UVs according to merge"); 05210 } 05211 05212 /************************ Vertex Path Operator *************************/ 05213 05214 typedef struct PathNode { 05215 int u; 05216 int visited; 05217 ListBase edges; 05218 } PathNode; 05219 05220 typedef struct PathEdge { 05221 struct PathEdge *next, *prev; 05222 int v; 05223 float w; 05224 } PathEdge; 05225 05226 #define PATH_SELECT_EDGE_LENGTH 0 05227 #define PATH_SELECT_TOPOLOGICAL 1 05228 05229 static int select_vertex_path_exec(bContext *C, wmOperator *op) 05230 { 05231 Object *obedit= CTX_data_edit_object(C); 05232 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 05233 EditVert *eve, *s, *t; 05234 EditEdge *eed; 05235 PathEdge *newpe, *currpe; 05236 PathNode *currpn; 05237 PathNode *Q; 05238 int v, *previous, pathvert, pnindex; /*pnindex redundant?*/ 05239 int unbalanced, totnodes; 05240 float *cost; 05241 int type= RNA_enum_get(op->ptr, "type"); 05242 Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/ 05243 05244 s = t = NULL; 05245 for(eve=em->verts.first; eve; eve=eve->next) { 05246 if(eve->f&SELECT) { 05247 if(s == NULL) s= eve; 05248 else if(t == NULL) t= eve; 05249 else { 05250 /* more than two vertices are selected, 05251 show warning message and cancel operator */ 05252 s = t = NULL; 05253 break; 05254 } 05255 05256 } 05257 05258 /*need to find out if t is actually reachable by s....*/ 05259 eve->f1 = 0; 05260 } 05261 05262 if(s != NULL && t != NULL) { 05263 s->f1 = 1; 05264 05265 unbalanced = 1; 05266 totnodes = 1; 05267 while(unbalanced){ 05268 unbalanced = 0; 05269 for(eed=em->edges.first; eed; eed=eed->next){ 05270 if(!eed->h){ 05271 if(eed->v1->f1 && !eed->v2->f1){ 05272 eed->v2->f1 = 1; 05273 totnodes++; 05274 unbalanced = 1; 05275 } 05276 else if(eed->v2->f1 && !eed->v1->f1){ 05277 eed->v1->f1 = 1; 05278 totnodes++; 05279 unbalanced = 1; 05280 } 05281 } 05282 } 05283 } 05284 05285 if(s->f1 && t->f1){ /* t can be reached by s */ 05286 Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes"); 05287 totnodes = 0; 05288 for(eve=em->verts.first; eve; eve=eve->next){ 05289 if(eve->f1){ 05290 Q[totnodes].u = totnodes; 05291 Q[totnodes].edges.first = 0; 05292 Q[totnodes].edges.last = 0; 05293 Q[totnodes].visited = 0; 05294 eve->tmp.p = &(Q[totnodes]); 05295 totnodes++; 05296 } 05297 else eve->tmp.p = NULL; 05298 } 05299 05300 for(eed=em->edges.first; eed; eed=eed->next){ 05301 if(!eed->h){ 05302 if(eed->v1->f1){ 05303 currpn = ((PathNode*)eed->v1->tmp.p); 05304 05305 newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge"); 05306 newpe->v = ((PathNode*)eed->v2->tmp.p)->u; 05307 if (type == PATH_SELECT_EDGE_LENGTH) { 05308 newpe->w = len_v3v3(eed->v1->co, eed->v2->co); 05309 } 05310 else newpe->w = 1; 05311 newpe->next = 0; 05312 newpe->prev = 0; 05313 BLI_addtail(&(currpn->edges), newpe); 05314 } 05315 if(eed->v2->f1){ 05316 currpn = ((PathNode*)eed->v2->tmp.p); 05317 newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge"); 05318 newpe->v = ((PathNode*)eed->v1->tmp.p)->u; 05319 if (type == PATH_SELECT_EDGE_LENGTH) { 05320 newpe->w = len_v3v3(eed->v1->co, eed->v2->co); 05321 } 05322 else newpe->w = 1; 05323 newpe->next = 0; 05324 newpe->prev = 0; 05325 BLI_addtail(&(currpn->edges), newpe); 05326 } 05327 } 05328 } 05329 05330 heap = BLI_heap_new(); 05331 cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs"); 05332 previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices"); 05333 05334 for(v=0; v < totnodes; v++){ 05335 cost[v] = 1000000; 05336 previous[v] = -1; /*array of indices*/ 05337 } 05338 05339 pnindex = ((PathNode*)s->tmp.p)->u; 05340 cost[pnindex] = 0; 05341 BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(pnindex)); 05342 05343 while( !BLI_heap_empty(heap) ){ 05344 05345 pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap)); 05346 currpn = &(Q[pnindex]); 05347 05348 if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/ 05349 break; 05350 05351 for(currpe=currpn->edges.first; currpe; currpe=currpe->next){ 05352 if(!Q[currpe->v].visited){ 05353 if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){ 05354 cost[currpe->v] = cost[currpn->u] + currpe->w; 05355 previous[currpe->v] = currpn->u; 05356 Q[currpe->v].visited = 1; 05357 BLI_heap_insert(heap, cost[currpe->v], SET_INT_IN_POINTER(currpe->v)); 05358 } 05359 } 05360 } 05361 } 05362 05363 pathvert = ((PathNode*)t->tmp.p)->u; 05364 while(pathvert != -1){ 05365 for(eve=em->verts.first; eve; eve=eve->next){ 05366 if(eve->f1){ 05367 if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT; 05368 } 05369 } 05370 pathvert = previous[pathvert]; 05371 } 05372 05373 for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges)); 05374 MEM_freeN(Q); 05375 MEM_freeN(cost); 05376 MEM_freeN(previous); 05377 BLI_heap_free(heap, NULL); 05378 EM_select_flush(em); 05379 } 05380 } 05381 else { 05382 BKE_mesh_end_editmesh(obedit->data, em); 05383 BKE_report(op->reports, RPT_WARNING, "Path Selection requires that exactly two vertices be selected"); 05384 return OPERATOR_CANCELLED; 05385 } 05386 05387 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); 05388 BKE_mesh_end_editmesh(obedit->data, em); 05389 05390 return OPERATOR_FINISHED; 05391 } 05392 05393 void MESH_OT_select_vertex_path(wmOperatorType *ot) 05394 { 05395 static const EnumPropertyItem type_items[] = { 05396 {PATH_SELECT_EDGE_LENGTH, "EDGE_LENGTH", 0, "Edge Length", NULL}, 05397 {PATH_SELECT_TOPOLOGICAL, "TOPOLOGICAL", 0, "Topological", NULL}, 05398 {0, NULL, 0, NULL, NULL}}; 05399 05400 /* identifiers */ 05401 ot->name= "Select Vertex Path"; 05402 ot->description= "Select shortest path between two vertices by distance type"; 05403 ot->idname= "MESH_OT_select_vertex_path"; 05404 05405 /* api callbacks */ 05406 ot->exec= select_vertex_path_exec; 05407 ot->poll= ED_operator_editmesh; 05408 05409 /* flags */ 05410 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 05411 05412 /* properties */ 05413 ot->prop= RNA_def_enum(ot->srna, "type", type_items, PATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance"); 05414 } 05415 05416 /********************** Region/Loop Operators *************************/ 05417 05418 static int region_to_loop(bContext *C, wmOperator *UNUSED(op)) 05419 { 05420 Object *obedit= CTX_data_edit_object(C); 05421 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 05422 EditEdge *eed; 05423 EditFace *efa; 05424 int selected= 0; 05425 05426 for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = 0; 05427 05428 for(efa=em->faces.first; efa; efa=efa->next){ 05429 if(efa->f&SELECT){ 05430 efa->e1->f1++; 05431 efa->e2->f1++; 05432 efa->e3->f1++; 05433 if(efa->e4) 05434 efa->e4->f1++; 05435 05436 selected= 1; 05437 } 05438 } 05439 05440 if(!selected) 05441 return OPERATOR_CANCELLED; 05442 05443 EM_clear_flag_all(em, SELECT); 05444 05445 for(eed=em->edges.first; eed; eed=eed->next){ 05446 if(eed->f1 == 1) EM_select_edge(eed, 1); 05447 } 05448 05449 em->selectmode = SCE_SELECT_EDGE; 05450 CTX_data_tool_settings(C)->selectmode= em->selectmode; 05451 EM_selectmode_set(em); 05452 05453 BKE_mesh_end_editmesh(obedit->data, em); 05454 05455 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); 05456 05457 return OPERATOR_FINISHED; 05458 } 05459 05460 void MESH_OT_region_to_loop(wmOperatorType *ot) 05461 { 05462 /* identifiers */ 05463 ot->name= "Region to Loop"; 05464 ot->description= "Select a region as a loop of connected edges"; 05465 ot->idname= "MESH_OT_region_to_loop"; 05466 05467 /* api callbacks */ 05468 ot->exec= region_to_loop; 05469 ot->poll= ED_operator_editmesh; 05470 05471 /* flags */ 05472 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 05473 } 05474 05475 static int validate_loop(EditMesh *em, Collection *edgecollection) 05476 { 05477 EditEdge *eed; 05478 EditFace *efa; 05479 CollectedEdge *curredge; 05480 05481 /*1st test*/ 05482 for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ 05483 curredge->eed->v1->f1 = 0; 05484 curredge->eed->v2->f1 = 0; 05485 } 05486 for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ 05487 curredge->eed->v1->f1++; 05488 curredge->eed->v2->f1++; 05489 } 05490 for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ 05491 if(curredge->eed->v1->f1 > 2) return(0); else 05492 if(curredge->eed->v2->f1 > 2) return(0); 05493 } 05494 05495 /*2nd test*/ 05496 for(eed = em->edges.first; eed; eed=eed->next) eed->f1 = 0; 05497 for(efa=em->faces.first; efa; efa=efa->next){ 05498 efa->e1->f1++; 05499 efa->e2->f1++; 05500 efa->e3->f1++; 05501 if(efa->e4) efa->e4->f1++; 05502 } 05503 for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ 05504 if(curredge->eed->f1 > 2) return(0); 05505 } 05506 return(1); 05507 } 05508 05509 static int loop_bisect(EditMesh *em, Collection *edgecollection) 05510 { 05511 EditFace *efa, *sf1, *sf2; 05512 EditEdge *eed, *sed; 05513 CollectedEdge *curredge; 05514 int totsf1, totsf2, unbalanced,balancededges; 05515 05516 for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = eed->f2 = 0; 05517 for(efa=em->faces.first; efa; efa=efa->next) efa->f1 = 0; 05518 05519 for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next) curredge->eed->f1 = 1; 05520 05521 sf1 = sf2 = NULL; 05522 sed = ((CollectedEdge*)edgecollection->collectionbase.first)->eed; 05523 05524 for(efa=em->faces.first; efa; efa=efa->next){ 05525 if(sf2) break; 05526 else if(sf1){ 05527 if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf2 = efa; 05528 } 05529 else{ 05530 if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf1 = efa; 05531 } 05532 } 05533 05534 if(sf1==NULL || sf2==NULL) 05535 return(-1); 05536 05537 if(!(sf1->e1->f1)) sf1->e1->f2 = 1; 05538 if(!(sf1->e2->f1)) sf1->e2->f2 = 1; 05539 if(!(sf1->e3->f1)) sf1->e3->f2 = 1; 05540 if(sf1->e4 && !(sf1->e4->f1)) sf1->e4->f2 = 1; 05541 sf1->f1 = 1; 05542 totsf1 = 1; 05543 05544 if(!(sf2->e1->f1)) sf2->e1->f2 = 2; 05545 if(!(sf2->e2->f1)) sf2->e2->f2 = 2; 05546 if(!(sf2->e3->f1)) sf2->e3->f2 = 2; 05547 if(sf2->e4 && !(sf2->e4->f1)) sf2->e4->f2 = 2; 05548 sf2->f1 = 2; 05549 totsf2 = 1; 05550 05551 /*do sf1*/ 05552 unbalanced = 1; 05553 while(unbalanced){ 05554 unbalanced = 0; 05555 for(efa=em->faces.first; efa; efa=efa->next){ 05556 balancededges = 0; 05557 if(efa->f1 == 0){ 05558 if(efa->e1->f2 == 1 || efa->e2->f2 == 1 || efa->e3->f2 == 1 || ( (efa->e4) ? efa->e4->f2 == 1 : 0) ){ 05559 balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 1; 05560 balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 1; 05561 balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 1; 05562 if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 1; 05563 if(balancededges){ 05564 unbalanced = 1; 05565 efa->f1 = 1; 05566 totsf1++; 05567 } 05568 } 05569 } 05570 } 05571 } 05572 05573 /*do sf2*/ 05574 unbalanced = 1; 05575 while(unbalanced){ 05576 unbalanced = 0; 05577 for(efa=em->faces.first; efa; efa=efa->next){ 05578 balancededges = 0; 05579 if(efa->f1 == 0){ 05580 if(efa->e1->f2 == 2 || efa->e2->f2 == 2 || efa->e3->f2 == 2 || ( (efa->e4) ? efa->e4->f2 == 2 : 0) ){ 05581 balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 2; 05582 balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 2; 05583 balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 2; 05584 if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 2; 05585 if(balancededges){ 05586 unbalanced = 1; 05587 efa->f1 = 2; 05588 totsf2++; 05589 } 05590 } 05591 } 05592 } 05593 } 05594 05595 if(totsf1 < totsf2) return(1); 05596 else return(2); 05597 } 05598 05599 static int loop_to_region(bContext *C, wmOperator *UNUSED(op)) 05600 { 05601 Object *obedit= CTX_data_edit_object(C); 05602 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 05603 05604 05605 EditFace *efa; 05606 ListBase allcollections={NULL,NULL}; 05607 Collection *edgecollection; 05608 int testflag; 05609 05610 build_edgecollection(em, &allcollections); 05611 05612 for(edgecollection = (Collection *)allcollections.first; edgecollection; edgecollection=edgecollection->next){ 05613 if(validate_loop(em, edgecollection)){ 05614 testflag = loop_bisect(em, edgecollection); 05615 for(efa=em->faces.first; efa; efa=efa->next){ 05616 if(efa->f1 == testflag){ 05617 if(efa->f&SELECT) EM_select_face(efa, 0); 05618 else EM_select_face(efa,1); 05619 } 05620 } 05621 } 05622 } 05623 05624 for(efa=em->faces.first; efa; efa=efa->next){ /*fix this*/ 05625 if(efa->f&SELECT) EM_select_face(efa,1); 05626 } 05627 05628 freecollections(&allcollections); 05629 BKE_mesh_end_editmesh(obedit->data, em); 05630 05631 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); 05632 05633 return OPERATOR_FINISHED; 05634 } 05635 05636 void MESH_OT_loop_to_region(wmOperatorType *ot) 05637 { 05638 /* identifiers */ 05639 ot->name= "Loop to Region"; 05640 ot->description= "Select a loop of connected edges as a region"; 05641 ot->idname= "MESH_OT_loop_to_region"; 05642 05643 /* api callbacks */ 05644 ot->exec= loop_to_region; 05645 ot->poll= ED_operator_editmesh; 05646 05647 /* flags */ 05648 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 05649 } 05650 05651 /********************** UV/Color Operators *************************/ 05652 05653 // XXX please check if these functions do what you want them to 05654 /* texface and vertex color editmode tools for the face menu */ 05655 05656 static int mesh_rotate_uvs(bContext *C, wmOperator *op) 05657 { 05658 Object *obedit= CTX_data_edit_object(C); 05659 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 05660 05661 EditFace *efa; 05662 short change = 0; 05663 MTFace *tf; 05664 float u1, v1; 05665 int dir= RNA_enum_get(op->ptr, "direction"); 05666 05667 if (!EM_texFaceCheck(em)) { 05668 BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers"); 05669 BKE_mesh_end_editmesh(obedit->data, em); 05670 return OPERATOR_CANCELLED; 05671 } 05672 05673 for(efa=em->faces.first; efa; efa=efa->next) { 05674 if (efa->f & SELECT) { 05675 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 05676 u1= tf->uv[0][0]; 05677 v1= tf->uv[0][1]; 05678 05679 if (dir == DIRECTION_CCW) { 05680 if(efa->v4) { 05681 tf->uv[0][0]= tf->uv[3][0]; 05682 tf->uv[0][1]= tf->uv[3][1]; 05683 05684 tf->uv[3][0]= tf->uv[2][0]; 05685 tf->uv[3][1]= tf->uv[2][1]; 05686 } else { 05687 tf->uv[0][0]= tf->uv[2][0]; 05688 tf->uv[0][1]= tf->uv[2][1]; 05689 } 05690 05691 tf->uv[2][0]= tf->uv[1][0]; 05692 tf->uv[2][1]= tf->uv[1][1]; 05693 05694 tf->uv[1][0]= u1; 05695 tf->uv[1][1]= v1; 05696 } else { 05697 tf->uv[0][0]= tf->uv[1][0]; 05698 tf->uv[0][1]= tf->uv[1][1]; 05699 05700 tf->uv[1][0]= tf->uv[2][0]; 05701 tf->uv[1][1]= tf->uv[2][1]; 05702 05703 if(efa->v4) { 05704 tf->uv[2][0]= tf->uv[3][0]; 05705 tf->uv[2][1]= tf->uv[3][1]; 05706 05707 tf->uv[3][0]= u1; 05708 tf->uv[3][1]= v1; 05709 } 05710 else { 05711 tf->uv[2][0]= u1; 05712 tf->uv[2][1]= v1; 05713 } 05714 } 05715 change = 1; 05716 } 05717 } 05718 05719 BKE_mesh_end_editmesh(obedit->data, em); 05720 05721 if(!change) 05722 return OPERATOR_CANCELLED; 05723 05724 DAG_id_tag_update(obedit->data, 0); 05725 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 05726 05727 return OPERATOR_FINISHED; 05728 } 05729 05730 static int mesh_mirror_uvs(bContext *C, wmOperator *op) 05731 { 05732 Object *obedit= CTX_data_edit_object(C); 05733 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 05734 05735 EditFace *efa; 05736 short change = 0; 05737 MTFace *tf; 05738 float u1, v1; 05739 int axis= RNA_enum_get(op->ptr, "axis"); 05740 05741 if (!EM_texFaceCheck(em)) { 05742 BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers"); 05743 BKE_mesh_end_editmesh(obedit->data, em); 05744 return OPERATOR_CANCELLED; 05745 } 05746 05747 for(efa=em->faces.first; efa; efa=efa->next) { 05748 if (efa->f & SELECT) { 05749 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 05750 if (axis == AXIS_Y) { 05751 u1= tf->uv[1][0]; 05752 v1= tf->uv[1][1]; 05753 if(efa->v4) { 05754 05755 tf->uv[1][0]= tf->uv[2][0]; 05756 tf->uv[1][1]= tf->uv[2][1]; 05757 05758 tf->uv[2][0]= u1; 05759 tf->uv[2][1]= v1; 05760 05761 u1= tf->uv[3][0]; 05762 v1= tf->uv[3][1]; 05763 05764 tf->uv[3][0]= tf->uv[0][0]; 05765 tf->uv[3][1]= tf->uv[0][1]; 05766 05767 tf->uv[0][0]= u1; 05768 tf->uv[0][1]= v1; 05769 } 05770 else { 05771 tf->uv[1][0]= tf->uv[2][0]; 05772 tf->uv[1][1]= tf->uv[2][1]; 05773 tf->uv[2][0]= u1; 05774 tf->uv[2][1]= v1; 05775 } 05776 05777 } else { 05778 u1= tf->uv[0][0]; 05779 v1= tf->uv[0][1]; 05780 if(efa->v4) { 05781 05782 tf->uv[0][0]= tf->uv[1][0]; 05783 tf->uv[0][1]= tf->uv[1][1]; 05784 05785 tf->uv[1][0]= u1; 05786 tf->uv[1][1]= v1; 05787 05788 u1= tf->uv[3][0]; 05789 v1= tf->uv[3][1]; 05790 05791 tf->uv[3][0]= tf->uv[2][0]; 05792 tf->uv[3][1]= tf->uv[2][1]; 05793 05794 tf->uv[2][0]= u1; 05795 tf->uv[2][1]= v1; 05796 } 05797 else { 05798 tf->uv[0][0]= tf->uv[1][0]; 05799 tf->uv[0][1]= tf->uv[1][1]; 05800 tf->uv[1][0]= u1; 05801 tf->uv[1][1]= v1; 05802 } 05803 } 05804 change = 1; 05805 } 05806 } 05807 05808 BKE_mesh_end_editmesh(obedit->data, em); 05809 05810 if(!change) 05811 return OPERATOR_CANCELLED; 05812 05813 DAG_id_tag_update(obedit->data, 0); 05814 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 05815 05816 return OPERATOR_FINISHED; 05817 } 05818 05819 static int mesh_rotate_colors(bContext *C, wmOperator *op) 05820 { 05821 Object *obedit= CTX_data_edit_object(C); 05822 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 05823 05824 EditFace *efa; 05825 short change = 0; 05826 MCol tmpcol, *mcol; 05827 int dir= RNA_enum_get(op->ptr, "direction"); 05828 05829 if (!EM_vertColorCheck(em)) { 05830 BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers"); 05831 BKE_mesh_end_editmesh(obedit->data, em); 05832 return OPERATOR_CANCELLED; 05833 } 05834 05835 for(efa=em->faces.first; efa; efa=efa->next) { 05836 if (efa->f & SELECT) { 05837 mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); 05838 tmpcol= mcol[0]; 05839 05840 if (dir == DIRECTION_CCW) { 05841 if(efa->v4) { 05842 mcol[0]= mcol[3]; 05843 mcol[3]= mcol[2]; 05844 } else { 05845 mcol[0]= mcol[2]; 05846 } 05847 mcol[2]= mcol[1]; 05848 mcol[1]= tmpcol; 05849 } else { 05850 mcol[0]= mcol[1]; 05851 mcol[1]= mcol[2]; 05852 05853 if(efa->v4) { 05854 mcol[2]= mcol[3]; 05855 mcol[3]= tmpcol; 05856 } 05857 else 05858 mcol[2]= tmpcol; 05859 } 05860 change = 1; 05861 } 05862 } 05863 05864 BKE_mesh_end_editmesh(obedit->data, em); 05865 05866 if(!change) 05867 return OPERATOR_CANCELLED; 05868 05869 DAG_id_tag_update(obedit->data, 0); 05870 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 05871 05872 return OPERATOR_FINISHED; 05873 } 05874 05875 05876 static int mesh_mirror_colors(bContext *C, wmOperator *op) 05877 { 05878 Object *obedit= CTX_data_edit_object(C); 05879 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 05880 05881 EditFace *efa; 05882 short change = 0; 05883 MCol tmpcol, *mcol; 05884 int axis= RNA_enum_get(op->ptr, "axis"); 05885 05886 if (!EM_vertColorCheck(em)) { 05887 BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers"); 05888 BKE_mesh_end_editmesh(obedit->data, em); 05889 return OPERATOR_CANCELLED; 05890 } 05891 05892 for(efa=em->faces.first; efa; efa=efa->next) { 05893 if (efa->f & SELECT) { 05894 mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); 05895 if (axis == AXIS_Y) { 05896 tmpcol= mcol[1]; 05897 mcol[1]= mcol[2]; 05898 mcol[2]= tmpcol; 05899 05900 if(efa->v4) { 05901 tmpcol= mcol[0]; 05902 mcol[0]= mcol[3]; 05903 mcol[3]= tmpcol; 05904 } 05905 } else { 05906 tmpcol= mcol[0]; 05907 mcol[0]= mcol[1]; 05908 mcol[1]= tmpcol; 05909 05910 if(efa->v4) { 05911 tmpcol= mcol[2]; 05912 mcol[2]= mcol[3]; 05913 mcol[3]= tmpcol; 05914 } 05915 } 05916 change = 1; 05917 } 05918 } 05919 05920 BKE_mesh_end_editmesh(obedit->data, em); 05921 05922 if(!change) 05923 return OPERATOR_CANCELLED; 05924 05925 DAG_id_tag_update(obedit->data, 0); 05926 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 05927 05928 return OPERATOR_FINISHED; 05929 } 05930 05931 void MESH_OT_uvs_rotate(wmOperatorType *ot) 05932 { 05933 /* identifiers */ 05934 ot->name= "Rotate UVs"; 05935 ot->description= "Rotate selected UVs"; 05936 ot->idname= "MESH_OT_uvs_rotate"; 05937 05938 /* api callbacks */ 05939 ot->exec= mesh_rotate_uvs; 05940 ot->poll= ED_operator_editmesh; 05941 05942 /* flags */ 05943 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 05944 05945 /* props */ 05946 RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around"); 05947 } 05948 05949 void MESH_OT_uvs_mirror(wmOperatorType *ot) 05950 { 05951 /* identifiers */ 05952 ot->name= "Mirror UVs"; 05953 ot->description= "Mirror selected UVs"; 05954 ot->idname= "MESH_OT_uvs_mirror"; 05955 05956 /* api callbacks */ 05957 ot->exec= mesh_mirror_uvs; 05958 ot->poll= ED_operator_editmesh; 05959 05960 /* flags */ 05961 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 05962 05963 /* props */ 05964 RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror UVs around"); 05965 } 05966 05967 void MESH_OT_colors_rotate(wmOperatorType *ot) 05968 { 05969 /* identifiers */ 05970 ot->name= "Rotate Colors"; 05971 ot->description= "Rotate UV/image color layer"; 05972 ot->idname= "MESH_OT_colors_rotate"; 05973 05974 /* api callbacks */ 05975 ot->exec= mesh_rotate_colors; 05976 ot->poll= ED_operator_editmesh; 05977 05978 /* flags */ 05979 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 05980 05981 /* props */ 05982 RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around"); 05983 } 05984 05985 void MESH_OT_colors_mirror(wmOperatorType *ot) 05986 { 05987 /* identifiers */ 05988 ot->name= "Mirror Colors"; 05989 ot->description= "Mirror UV/image color layer"; 05990 ot->idname= "MESH_OT_colors_mirror"; 05991 05992 /* api callbacks */ 05993 ot->exec= mesh_mirror_colors; 05994 ot->poll= ED_operator_editmesh; 05995 05996 /* flags */ 05997 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 05998 05999 /* props */ 06000 RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror colors around"); 06001 } 06002 06003 /********************** Subdivide Operator *************************/ 06004 06005 static int subdivide_exec(bContext *C, wmOperator *op) 06006 { 06007 ToolSettings *ts= CTX_data_tool_settings(C); 06008 Object *obedit= CTX_data_edit_object(C); 06009 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 06010 int cuts= RNA_int_get(op->ptr,"number_cuts"); 06011 float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness"); 06012 float fractal= RNA_float_get(op->ptr, "fractal")/100; 06013 int corner_cut_pattern= RNA_enum_get(op->ptr,"corner_cut_pattern"); 06014 int flag= 0; 06015 06016 if(smooth != 0.0f) 06017 flag |= B_SMOOTH; 06018 if(fractal != 0.0f) 06019 flag |= B_FRACTAL; 06020 06021 esubdivideflag(obedit, em, 1, smooth, fractal, ts->editbutflag|flag, cuts, corner_cut_pattern, 0); 06022 06023 DAG_id_tag_update(obedit->data, 0); 06024 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 06025 06026 return OPERATOR_FINISHED; 06027 } 06028 06029 void MESH_OT_subdivide(wmOperatorType *ot) 06030 { 06031 /* identifiers */ 06032 ot->name= "Subdivide"; 06033 ot->description= "Subdivide selected edges"; 06034 ot->idname= "MESH_OT_subdivide"; 06035 06036 /* api callbacks */ 06037 ot->exec= subdivide_exec; 06038 ot->poll= ED_operator_editmesh; 06039 06040 /* flags */ 06041 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 06042 06043 /* properties */ 06044 RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10); 06045 RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor", 0.0f, 1.0f); 06046 RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f); 06047 RNA_def_enum(ot->srna, "corner_cut_pattern", corner_type_items, SUBDIV_CORNER_INNERVERT, "Corner Cut Pattern", "Topology pattern to use to fill a face after cutting across its corner"); 06048 } 06049 06050 /********************** Fill Operators *************************/ 06051 06052 /* note; the EM_selectmode_set() calls here illustrate how badly constructed it all is... from before the 06053 edge/face flags, with very mixed results.... */ 06054 static void beautify_fill(EditMesh *em) 06055 { 06056 EditVert *v1, *v2, *v3, *v4; 06057 EditEdge *eed, *nexted; 06058 EditEdge dia1, dia2; 06059 EditFace *efa, *w; 06060 // void **efaar, **efaa; 06061 EVPTuple *efaar; 06062 EVPtr *efaa; 06063 float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2; 06064 int totedge, ok, notbeauty=8, onedone, vindex[4]; 06065 06066 /* - all selected edges with two faces 06067 * - find the faces: store them in edges (using datablock) 06068 * - per edge: - test convex 06069 * - test edge: flip? 06070 * - if true: remedge, addedge, all edges at the edge get new face pointers 06071 */ 06072 06073 EM_selectmode_set(em); // makes sure in selectmode 'face' the edges of selected faces are selected too 06074 06075 totedge = count_selected_edges(em->edges.first); 06076 if(totedge==0) return; 06077 06078 /* temp block with face pointers */ 06079 efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "beautyfill"); 06080 06081 while (notbeauty) { 06082 notbeauty--; 06083 06084 ok = collect_quadedges(efaar, em->edges.first, em->faces.first); 06085 06086 /* there we go */ 06087 onedone= 0; 06088 06089 eed= em->edges.first; 06090 while(eed) { 06091 nexted= eed->next; 06092 06093 /* f2 is set in collect_quadedges() */ 06094 if(eed->f2==2 && eed->h==0) { 06095 06096 efaa = (EVPtr *) eed->tmp.p; 06097 06098 /* none of the faces should be treated before, nor be part of fgon */ 06099 ok= 1; 06100 efa= efaa[0]; 06101 if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; 06102 if(efa->fgonf) ok= 0; 06103 efa= efaa[1]; 06104 if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; 06105 if(efa->fgonf) ok= 0; 06106 06107 if(ok) { 06108 /* test convex */ 06109 givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); 06110 if(v1 && v2 && v3 && v4) { 06111 if( convex(v1->co, v2->co, v3->co, v4->co) ) { 06112 06113 /* test edges */ 06114 if( (v1) > (v3) ) { 06115 dia1.v1= v3; 06116 dia1.v2= v1; 06117 } 06118 else { 06119 dia1.v1= v1; 06120 dia1.v2= v3; 06121 } 06122 06123 if( (v2) > (v4) ) { 06124 dia2.v1= v4; 06125 dia2.v2= v2; 06126 } 06127 else { 06128 dia2.v1= v2; 06129 dia2.v2= v4; 06130 } 06131 06132 /* testing rule: 06133 * the area divided by the total edge lengths 06134 */ 06135 06136 len1= len_v3v3(v1->co, v2->co); 06137 len2= len_v3v3(v2->co, v3->co); 06138 len3= len_v3v3(v3->co, v4->co); 06139 len4= len_v3v3(v4->co, v1->co); 06140 len5= len_v3v3(v1->co, v3->co); 06141 len6= len_v3v3(v2->co, v4->co); 06142 06143 opp1= area_tri_v3(v1->co, v2->co, v3->co); 06144 opp2= area_tri_v3(v1->co, v3->co, v4->co); 06145 06146 fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5); 06147 06148 opp1= area_tri_v3(v2->co, v3->co, v4->co); 06149 opp2= area_tri_v3(v2->co, v4->co, v1->co); 06150 06151 fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6); 06152 06153 ok= 0; 06154 if(fac1 > fac2) { 06155 if(dia2.v1==eed->v1 && dia2.v2==eed->v2) { 06156 eed->f1= 1; 06157 efa= efaa[0]; 06158 efa->f1= 1; 06159 efa= efaa[1]; 06160 efa->f1= 1; 06161 06162 w= EM_face_from_faces(em, efaa[0], efaa[1], 06163 vindex[0], vindex[1], 4+vindex[2], -1); 06164 EM_select_face(w, 1); 06165 06166 06167 w= EM_face_from_faces(em, efaa[0], efaa[1], 06168 vindex[0], 4+vindex[2], 4+vindex[3], -1); 06169 EM_select_face(w, 1); 06170 06171 onedone= 1; 06172 } 06173 } 06174 else if(fac1 < fac2) { 06175 if(dia1.v1==eed->v1 && dia1.v2==eed->v2) { 06176 eed->f1= 1; 06177 efa= efaa[0]; 06178 efa->f1= 1; 06179 efa= efaa[1]; 06180 efa->f1= 1; 06181 06182 06183 w= EM_face_from_faces(em, efaa[0], efaa[1], 06184 vindex[1], 4+vindex[2], 4+vindex[3], -1); 06185 EM_select_face(w, 1); 06186 06187 w= EM_face_from_faces(em, efaa[0], efaa[1], 06188 vindex[0], 4+vindex[1], 4+vindex[3], -1); 06189 EM_select_face(w, 1); 06190 06191 onedone= 1; 06192 } 06193 } 06194 } 06195 } 06196 } 06197 06198 } 06199 eed= nexted; 06200 } 06201 06202 free_tagged_edges_faces(em, em->edges.first, em->faces.first); 06203 06204 if(onedone==0) break; 06205 06206 EM_selectmode_set(em); // new edges/faces were added 06207 } 06208 06209 MEM_freeN(efaar); 06210 06211 EM_select_flush(em); 06212 06213 } 06214 06215 /* Got this from scanfill.c. You will need to juggle around the 06216 * callbacks for the scanfill.c code a bit for this to work. */ 06217 static void fill_mesh(EditMesh *em) 06218 { 06219 EditVert *eve,*v1; 06220 EditEdge *eed,*e1,*nexted; 06221 EditFace *efa,*nextvl, *efan; 06222 short ok; 06223 06224 if(em==NULL) return; 06225 waitcursor(1); 06226 06227 /* copy all selected vertices */ 06228 eve= em->verts.first; 06229 while(eve) { 06230 if(eve->f & SELECT) { 06231 v1= BLI_addfillvert(eve->co); 06232 eve->tmp.v= v1; 06233 v1->tmp.v= eve; 06234 v1->xs= 0; // used for counting edges 06235 } 06236 eve= eve->next; 06237 } 06238 /* copy all selected edges */ 06239 eed= em->edges.first; 06240 while(eed) { 06241 if( (eed->v1->f & SELECT) && (eed->v2->f & SELECT) ) { 06242 e1= BLI_addfilledge(eed->v1->tmp.v, eed->v2->tmp.v); 06243 e1->v1->xs++; 06244 e1->v2->xs++; 06245 } 06246 eed= eed->next; 06247 } 06248 /* from all selected faces: remove vertices and edges to prevent doubles */ 06249 /* all edges add values, faces subtract, 06250 then remove edges with vertices ->xs<2 */ 06251 efa= em->faces.first; 06252 ok= 0; 06253 while(efa) { 06254 nextvl= efa->next; 06255 if( faceselectedAND(efa, 1) ) { 06256 efa->v1->tmp.v->xs--; 06257 efa->v2->tmp.v->xs--; 06258 efa->v3->tmp.v->xs--; 06259 if(efa->v4) efa->v4->tmp.v->xs--; 06260 ok= 1; 06261 06262 } 06263 efa= nextvl; 06264 } 06265 if(ok) { /* there are faces selected */ 06266 eed= filledgebase.first; 06267 while(eed) { 06268 nexted= eed->next; 06269 if(eed->v1->xs<2 || eed->v2->xs<2) { 06270 BLI_remlink(&filledgebase,eed); 06271 } 06272 eed= nexted; 06273 } 06274 } 06275 06276 if(BLI_edgefill(em->mat_nr)) { 06277 efa= fillfacebase.first; 06278 while(efa) { 06279 /* normals default pointing up */ 06280 efan= addfacelist(em, efa->v3->tmp.v, efa->v2->tmp.v, 06281 efa->v1->tmp.v, 0, NULL, NULL); 06282 if(efan) EM_select_face(efan, 1); 06283 efa= efa->next; 06284 } 06285 } 06286 06287 BLI_end_edgefill(); 06288 beautify_fill(em); 06289 06290 WM_cursor_wait(0); 06291 EM_select_flush(em); 06292 06293 } 06294 06295 static int fill_mesh_exec(bContext *C, wmOperator *UNUSED(op)) 06296 { 06297 Object *obedit= CTX_data_edit_object(C); 06298 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 06299 06300 fill_mesh(em); 06301 06302 BKE_mesh_end_editmesh(obedit->data, em); 06303 06304 DAG_id_tag_update(obedit->data, 0); 06305 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 06306 06307 return OPERATOR_FINISHED; 06308 06309 } 06310 06311 void MESH_OT_fill(wmOperatorType *ot) 06312 { 06313 /* identifiers */ 06314 ot->name= "Fill"; 06315 ot->description= "Create a segment, edge or face"; 06316 ot->idname= "MESH_OT_fill"; 06317 06318 /* api callbacks */ 06319 ot->exec= fill_mesh_exec; 06320 ot->poll= ED_operator_editmesh; 06321 06322 /* flags */ 06323 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 06324 } 06325 06326 static int beautify_fill_exec(bContext *C, wmOperator *UNUSED(op)) 06327 { 06328 Object *obedit= CTX_data_edit_object(C); 06329 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 06330 06331 beautify_fill(em); 06332 06333 BKE_mesh_end_editmesh(obedit->data, em); 06334 06335 DAG_id_tag_update(obedit->data, 0); 06336 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 06337 06338 return OPERATOR_FINISHED; 06339 } 06340 06341 void MESH_OT_beautify_fill(wmOperatorType *ot) 06342 { 06343 /* identifiers */ 06344 ot->name= "Beautify Fill"; 06345 ot->description= "Rearrange geometry on a selected surface to avoid skinny faces"; 06346 ot->idname= "MESH_OT_beautify_fill"; 06347 06348 /* api callbacks */ 06349 ot->exec= beautify_fill_exec; 06350 ot->poll= ED_operator_editmesh; 06351 06352 /* flags */ 06353 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 06354 } 06355 06356 /* ********************** SORT FACES ******************* */ 06357 06358 static void permutate(void *list, int num, int size, int *index) 06359 { 06360 void *buf; 06361 int len; 06362 int i; 06363 06364 len = num * size; 06365 06366 buf = MEM_mallocN(len, "permutate"); 06367 memcpy(buf, list, len); 06368 06369 for (i = 0; i < num; i++) { 06370 memcpy((char *)list + (i * size), (char *)buf + (index[i] * size), size); 06371 } 06372 MEM_freeN(buf); 06373 } 06374 06375 /* sort faces on view axis */ 06376 static float *face_sort_floats; 06377 static int float_sort(const void *v1, const void *v2) 06378 { 06379 float x1, x2; 06380 06381 x1 = face_sort_floats[((int *) v1)[0]]; 06382 x2 = face_sort_floats[((int *) v2)[0]]; 06383 06384 if( x1 > x2 ) return 1; 06385 else if( x1 < x2 ) return -1; 06386 return 0; 06387 } 06388 06389 06390 static int sort_faces_exec(bContext *C, wmOperator *op) 06391 { 06392 RegionView3D *rv3d= ED_view3d_context_rv3d(C); 06393 View3D *v3d= CTX_wm_view3d(C); 06394 Object *ob= CTX_data_edit_object(C); 06395 Scene *scene= CTX_data_scene(C); 06396 Mesh *me; 06397 CustomDataLayer *layer; 06398 int i, *index; 06399 int event; 06400 float reverse = 1; 06401 // XXX int ctrl= 0; 06402 06403 if (!v3d) return OPERATOR_CANCELLED; 06404 06405 /* This operator work in Object Mode, not in edit mode. 06406 * After talk with Campbell we agree that there is no point to port this to EditMesh right now. 06407 * so for now, we just exit_editmode and enter_editmode at the end of this function. 06408 */ 06409 ED_object_exit_editmode(C, EM_FREEDATA); 06410 06411 me= ob->data; 06412 if(me->totface==0) { 06413 ED_object_enter_editmode(C, 0); 06414 return OPERATOR_FINISHED; 06415 } 06416 06417 event= RNA_enum_get(op->ptr, "type"); 06418 06419 // XXX 06420 //if(ctrl) 06421 // reverse = -1; 06422 06423 /* create index list */ 06424 index= (int *)MEM_mallocN(sizeof(int) * me->totface, "sort faces"); 06425 for (i = 0; i < me->totface; i++) { 06426 index[i] = i; 06427 } 06428 06429 face_sort_floats = (float *) MEM_mallocN(sizeof(float) * me->totface, "sort faces float"); 06430 06431 /* sort index list instead of faces itself 06432 * and apply this permutation to all face layers 06433 */ 06434 if (event == 5) { 06435 /* Random */ 06436 for(i=0; i<me->totface; i++) { 06437 face_sort_floats[i] = BLI_frand(); 06438 } 06439 qsort(index, me->totface, sizeof(int), float_sort); 06440 } else { 06441 MFace *mf; 06442 float vec[3]; 06443 float mat[4][4]; 06444 float cur[3]; 06445 06446 if (event == 1) 06447 mult_m4_m4m4(mat, rv3d->viewmat, OBACT->obmat); /* apply the view matrix to the object matrix */ 06448 else if (event == 2) { /* sort from cursor */ 06449 if( v3d && v3d->localvd ) { 06450 VECCOPY(cur, v3d->cursor); 06451 } else { 06452 VECCOPY(cur, scene->cursor); 06453 } 06454 invert_m4_m4(mat, OBACT->obmat); 06455 mul_m4_v3(mat, cur); 06456 } 06457 06458 mf= me->mface; 06459 06460 for(i=0; i<me->totface; i++, mf++) { 06461 if (event==3) { 06462 face_sort_floats[i] = ((float)mf->mat_nr)*reverse; 06463 } else if (event==4) { 06464 /*selected first*/ 06465 if (mf->flag & ME_FACE_SEL) 06466 face_sort_floats[i] = 0.0; 06467 else 06468 face_sort_floats[i] = reverse; 06469 } else { 06470 /* find the faces center */ 06471 add_v3_v3v3(vec, (me->mvert+mf->v1)->co, (me->mvert+mf->v2)->co); 06472 if (mf->v4) { 06473 add_v3_v3(vec, (me->mvert+mf->v3)->co); 06474 add_v3_v3(vec, (me->mvert+mf->v4)->co); 06475 mul_v3_fl(vec, 0.25f); 06476 } else { 06477 add_v3_v3(vec, (me->mvert+mf->v3)->co); 06478 mul_v3_fl(vec, 1.0f/3.0f); 06479 } /* done */ 06480 06481 if (event == 1) { /* sort on view axis */ 06482 mul_m4_v3(mat, vec); 06483 face_sort_floats[i] = vec[2] * reverse; 06484 } else if(event == 2) { /* distance from cursor*/ 06485 face_sort_floats[i] = len_v3v3(cur, vec) * reverse; /* back to front */ 06486 } 06487 } 06488 } 06489 qsort(index, me->totface, sizeof(int), float_sort); 06490 } 06491 06492 MEM_freeN(face_sort_floats); 06493 for(i = 0; i < me->fdata.totlayer; i++) { 06494 layer = &me->fdata.layers[i]; 06495 permutate(layer->data, me->totface, CustomData_sizeof(layer->type), index); 06496 } 06497 06498 MEM_freeN(index); 06499 DAG_id_tag_update(ob->data, 0); 06500 06501 /* Return to editmode. */ 06502 ED_object_enter_editmode(C, 0); 06503 06504 return OPERATOR_FINISHED; 06505 } 06506 06507 void MESH_OT_sort_faces(wmOperatorType *ot) 06508 { 06509 static EnumPropertyItem type_items[]= { 06510 { 1, "VIEW_AXIS", 0, "View Axis", "" }, 06511 { 2, "CURSOR_DISTANCE", 0, "Cursor Distance", "" }, 06512 { 3, "MATERIAL", 0, "Material", "" }, 06513 { 4, "SELECTED", 0, "Selected", "" }, 06514 { 5, "RANDOMIZE", 0, "Randomize", "" }, 06515 { 0, NULL, 0, NULL, NULL }}; 06516 06517 /* identifiers */ 06518 ot->name= "Sort Faces"; // XXX (Ctrl to reverse)%t| 06519 ot->description= "The faces of the active Mesh Object are sorted, based on the current view"; 06520 ot->idname= "MESH_OT_sort_faces"; 06521 06522 /* api callbacks */ 06523 ot->invoke= WM_menu_invoke; 06524 ot->exec= sort_faces_exec; 06525 ot->poll= ED_operator_editmesh; 06526 06527 /* flags */ 06528 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 06529 06530 /* properties */ 06531 ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", ""); 06532 } 06533 06534 /********************** Quad/Tri Operators *************************/ 06535 06536 static int quads_convert_to_tris_exec(bContext *C, wmOperator *UNUSED(op)) 06537 { 06538 Object *obedit= CTX_data_edit_object(C); 06539 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 06540 06541 convert_to_triface(em,0); 06542 06543 DAG_id_tag_update(obedit->data, 0); 06544 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 06545 06546 BKE_mesh_end_editmesh(obedit->data, em); 06547 return OPERATOR_FINISHED; 06548 } 06549 06550 void MESH_OT_quads_convert_to_tris(wmOperatorType *ot) 06551 { 06552 /* identifiers */ 06553 ot->name= "Quads to Tris"; 06554 ot->description= "Convert selected quads to triangles"; 06555 ot->idname= "MESH_OT_quads_convert_to_tris"; 06556 06557 /* api callbacks */ 06558 ot->exec= quads_convert_to_tris_exec; 06559 ot->poll= ED_operator_editmesh; 06560 06561 /* flags */ 06562 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 06563 } 06564 06565 static int tris_convert_to_quads_exec(bContext *C, wmOperator *UNUSED(op)) 06566 { 06567 Object *obedit= CTX_data_edit_object(C); 06568 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 06569 06570 join_triangles(em); 06571 06572 DAG_id_tag_update(obedit->data, 0); 06573 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 06574 06575 BKE_mesh_end_editmesh(obedit->data, em); 06576 return OPERATOR_FINISHED; 06577 } 06578 06579 void MESH_OT_tris_convert_to_quads(wmOperatorType *ot) 06580 { 06581 /* identifiers */ 06582 ot->name= "Tris to Quads"; 06583 ot->description= "Convert selected triangles to quads"; 06584 ot->idname= "MESH_OT_tris_convert_to_quads"; 06585 06586 /* api callbacks */ 06587 ot->exec= tris_convert_to_quads_exec; 06588 ot->poll= ED_operator_editmesh; 06589 06590 /* flags */ 06591 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 06592 } 06593 06594 static int edge_flip_exec(bContext *C, wmOperator *UNUSED(op)) 06595 { 06596 Object *obedit= CTX_data_edit_object(C); 06597 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 06598 06599 edge_flip(em); 06600 06601 DAG_id_tag_update(obedit->data, 0); 06602 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 06603 06604 BKE_mesh_end_editmesh(obedit->data, em); 06605 return OPERATOR_FINISHED; 06606 } 06607 06608 void MESH_OT_edge_flip(wmOperatorType *ot) 06609 { 06610 /* identifiers */ 06611 ot->name= "Edge Flip"; 06612 ot->description= "Flip selected edge or adjoining faces"; 06613 ot->idname= "MESH_OT_edge_flip"; 06614 06615 /* api callbacks */ 06616 ot->exec= edge_flip_exec; 06617 ot->poll= ED_operator_editmesh; 06618 06619 /* flags */ 06620 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 06621 } 06622 06623 /********************** Smooth/Solid Operators *************************/ 06624 06625 static void mesh_set_smooth_faces(EditMesh *em, short smooth) 06626 { 06627 EditFace *efa; 06628 06629 if(em==NULL) return; 06630 06631 for(efa= em->faces.first; efa; efa=efa->next) { 06632 if(efa->f & SELECT) { 06633 if(smooth) efa->flag |= ME_SMOOTH; 06634 else efa->flag &= ~ME_SMOOTH; 06635 } 06636 } 06637 06638 recalc_editnormals(em); 06639 } 06640 06641 static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op)) 06642 { 06643 Object *obedit= CTX_data_edit_object(C); 06644 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 06645 06646 mesh_set_smooth_faces(em, 1); 06647 06648 BKE_mesh_end_editmesh(obedit->data, em); 06649 06650 DAG_id_tag_update(obedit->data, 0); 06651 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 06652 06653 return OPERATOR_FINISHED; 06654 } 06655 06656 void MESH_OT_faces_shade_smooth(wmOperatorType *ot) 06657 { 06658 /* identifiers */ 06659 ot->name= "Shade Smooth"; 06660 ot->description= "Display faces 'smooth' (using vertex normals)"; 06661 ot->idname= "MESH_OT_faces_shade_smooth"; 06662 06663 /* api callbacks */ 06664 ot->exec= mesh_faces_shade_smooth_exec; 06665 ot->poll= ED_operator_editmesh; 06666 06667 /* flags */ 06668 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 06669 } 06670 06671 static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op)) 06672 { 06673 Object *obedit= CTX_data_edit_object(C); 06674 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 06675 06676 mesh_set_smooth_faces(em, 0); 06677 06678 DAG_id_tag_update(obedit->data, 0); 06679 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 06680 06681 return OPERATOR_FINISHED; 06682 } 06683 06684 void MESH_OT_faces_shade_flat(wmOperatorType *ot) 06685 { 06686 /* identifiers */ 06687 ot->name= "Shade Flat"; 06688 ot->description= "Display faces 'flat'"; 06689 ot->idname= "MESH_OT_faces_shade_flat"; 06690 06691 /* api callbacks */ 06692 ot->exec= mesh_faces_shade_flat_exec; 06693 ot->poll= ED_operator_editmesh; 06694 06695 /* flags */ 06696 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 06697 } 06698 06699 /* TODO - some way to select on an arbitrary axis */ 06700 static int select_axis_exec(bContext *C, wmOperator *op) 06701 { 06702 Object *obedit= CTX_data_edit_object(C); 06703 EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); 06704 06705 int axis= RNA_enum_get(op->ptr, "axis"); 06706 int mode= RNA_enum_get(op->ptr, "mode"); /* -1==aligned, 0==neg, 1==pos*/ 06707 06708 EditSelection *ese = em->selected.last; 06709 06710 06711 if (ese==NULL || ese->type != EDITVERT) { 06712 BKE_report(op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)"); 06713 return OPERATOR_CANCELLED; 06714 } 06715 else { 06716 EditVert *ev; 06717 EditVert *act_vert= (EditVert*)ese->data; 06718 float value= act_vert->co[axis]; 06719 float limit= CTX_data_tool_settings(C)->doublimit; // XXX 06720 06721 if(mode==0) value -= limit; 06722 else if (mode==1) value += limit; 06723 06724 for(ev=em->verts.first;ev;ev=ev->next) { 06725 if(!ev->h) { 06726 switch(mode) { 06727 case -1: /* aligned */ 06728 if(fabs(ev->co[axis] - value) < limit) 06729 ev->f |= SELECT; 06730 break; 06731 case 0: /* neg */ 06732 if(ev->co[axis] > value) 06733 ev->f |= SELECT; 06734 break; 06735 case 1: /* pos */ 06736 if(ev->co[axis] < value) 06737 ev->f |= SELECT; 06738 break; 06739 } 06740 } 06741 } 06742 } 06743 06744 EM_select_flush(em); 06745 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); 06746 06747 return OPERATOR_FINISHED; 06748 } 06749 06750 void MESH_OT_select_axis(wmOperatorType *ot) 06751 { 06752 static EnumPropertyItem axis_mode_items[] = { 06753 {0, "POSITIVE", 0, "Positive Axis", ""}, 06754 {1, "NEGATIVE", 0, "Negative Axis", ""}, 06755 {-1, "ALIGNED", 0, "Aligned Axis", ""}, 06756 {0, NULL, 0, NULL, NULL}}; 06757 06758 static EnumPropertyItem axis_items_xyz[] = { 06759 {0, "X_AXIS", 0, "X Axis", ""}, 06760 {1, "Y_AXIS", 0, "Y Axis", ""}, 06761 {2, "Z_AXIS", 0, "Z Axis", ""}, 06762 {0, NULL, 0, NULL, NULL}}; 06763 06764 /* identifiers */ 06765 ot->name= "Select Axis"; 06766 ot->description= "Select all data in the mesh on a single axis"; 06767 ot->idname= "MESH_OT_select_axis"; 06768 06769 /* api callbacks */ 06770 ot->exec= select_axis_exec; 06771 ot->poll= ED_operator_editmesh; 06772 06773 /* flags */ 06774 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 06775 06776 /* properties */ 06777 RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting"); 06778 RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on"); 06779 } 06780