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