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