Blender V2.61 - r43446

editmesh_tools.c

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