merge with/from trunk at r35190
[blender.git] / source / blender / editors / mesh / bmesh_tools.c
1  /* $Id: bmesh_tools.c
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2004 by Blender Foundation.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): Joseph Eagar
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "MEM_guardedalloc.h"
35 #include "PIL_time.h"
36
37 #include "BLO_sys_types.h" // for intptr_t support
38
39 #include "DNA_mesh_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_modifier_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_view3d_types.h"
47 #include "DNA_key_types.h"
48 #include "DNA_windowmanager_types.h"
49
50 #include "RNA_types.h"
51 #include "RNA_define.h"
52 #include "RNA_access.h"
53
54 #include "BLI_blenlib.h"
55 #include "BLI_math.h"
56 #include "BLI_editVert.h"
57 #include "BLI_rand.h"
58 #include "BLI_ghash.h"
59 #include "BLI_linklist.h"
60 #include "BLI_heap.h"
61 #include "BLI_array.h"
62
63 #include "BKE_material.h"
64 #include "BKE_context.h"
65 #include "BKE_customdata.h"
66 #include "BKE_depsgraph.h"
67 #include "BKE_global.h"
68 #include "BKE_library.h"
69 #include "BKE_mesh.h"
70 #include "BKE_object.h"
71 #include "BKE_utildefines.h"
72 #include "BKE_bmesh.h"
73 #include "BKE_report.h"
74 #include "BKE_tessmesh.h"
75 #include "BKE_texture.h"
76 #include "BKE_main.h"
77
78 #include "BIF_gl.h"
79 #include "BIF_glutil.h"
80
81 #include "WM_api.h"
82 #include "WM_types.h"
83
84 #include "ED_mesh.h"
85 #include "ED_view3d.h"
86 #include "ED_util.h"
87 #include "ED_screen.h"
88 #include "ED_transform.h"
89 #include "ED_object.h"
90
91 #include "UI_interface.h"
92
93 #include "RE_render_ext.h"
94
95 #include "mesh_intern.h"
96 #include "bmesh.h"
97
98 #include "editbmesh_bvh.h"
99
100 static void add_normal_aligned(float *nor, float *add)
101 {
102         if( INPR(nor, add) < -0.9999f)
103                 sub_v3_v3v3(nor, nor, add);
104         else
105                 add_v3_v3v3(nor, nor, add);
106 }
107
108
109 static int subdivide_exec(bContext *C, wmOperator *op)
110 {
111         ToolSettings *ts = CTX_data_tool_settings(C);
112         Object *obedit= CTX_data_edit_object(C);
113         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
114         int cuts= RNA_int_get(op->ptr,"number_cuts");
115         float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness");
116         float fractal= RNA_float_get(op->ptr, "fractal")/100;
117         int flag= 0;
118
119         if(smooth != 0.0f)
120                 flag |= B_SMOOTH;
121         if(fractal != 0.0f)
122                 flag |= B_FRACTAL;
123
124         BM_esubdivideflag(obedit, em->bm, BM_SELECT, 
125                           smooth, fractal, 
126                           ts->editbutflag|flag, 
127                           cuts, 0, RNA_enum_get(op->ptr, "quadcorner"), 
128                           RNA_boolean_get(op->ptr, "tess_single_edge"),
129                           RNA_boolean_get(op->ptr, "gridfill"));
130
131         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
132         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
133
134         return OPERATOR_FINISHED;
135 }
136
137 /* Note, these values must match delete_mesh() event values */
138 static EnumPropertyItem prop_mesh_cornervert_types[] = {
139         {SUBD_INNERVERT,     "INNERVERT", 0,      "Inner Vert", ""},
140         {SUBD_PATH,          "PATH", 0,           "Path", ""},
141         {SUBD_STRAIGHT_CUT,  "STRAIGHT_CUT", 0,   "Straight Cut", ""},
142         {SUBD_FAN,           "FAN", 0,            "Fan", ""},
143         {0, NULL, 0, NULL, NULL}
144 };
145
146 void MESH_OT_subdivide(wmOperatorType *ot)
147 {
148         /* identifiers */
149         ot->name= "Subdivide";
150         ot->description= "Subdivide selected edges.";
151         ot->idname= "MESH_OT_subdivide";
152
153         /* api callbacks */
154         ot->exec= subdivide_exec;
155         ot->poll= ED_operator_editmesh;
156
157         /* flags */
158         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
159
160         /* properties */
161         RNA_def_int(ot->srna, "number_cuts", 1, 1, 20, "Number of Cuts", "", 1, INT_MAX);
162         RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
163         RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1000.0f, "Smoothness", "Smoothness factor.", 0.0f, FLT_MAX);
164
165         /*props */
166         RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_STRAIGHT_CUT, "Quad Corner Type", "Method used for subdividing two adjacent edges in a quad");
167         RNA_def_boolean(ot->srna, "tess_single_edge", 0, "Tesselate Single Edge", "Adds triangles to single edges belonging to triangles or quads");
168         RNA_def_boolean(ot->srna, "gridfill", 1, "Grid Fill", "Fill Fully Selected Triangles and Quads With A Grid");
169 }
170
171 /* individual face extrude */
172 /* will use vertex normals for extrusion directions, so *nor is unaffected */
173 short EDBM_Extrude_face_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) 
174 {
175         BMOIter siter;
176         BMIter liter;
177         BMFace *f;
178         BMLoop *l;
179         BMOperator bmop;
180
181         EDBM_InitOpf(em, &bmop, op, "extrude_face_indiv faces=%hf", flag);
182
183         /*deselect original verts*/
184         EDBM_clear_flag_all(em, BM_SELECT);
185
186         BMO_Exec_Op(em->bm, &bmop);
187         
188         BMO_ITER(f, &siter, em->bm, &bmop, "faceout", BM_FACE) {
189                 BM_Select(em->bm, f, 1);
190
191                 /*set face vertex normals to face normal*/
192                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
193                         VECCOPY(l->v->no, f->no);
194                 }
195         }
196
197         if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
198
199         return 's'; // s is shrink/fatten
200 }
201
202 #if 0
203 short EDBM_Extrude_face_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) 
204         EditVert *eve, *v1, *v2, *v3, *v4;
205         EditEdge *eed;
206         EditFace *efa, *nextfa;
207         
208         if(em==NULL) return 0;
209         
210         /* selected edges with 1 or more selected face become faces */
211         /* selected faces each makes new faces */
212         /* always remove old faces, keeps volumes manifold */
213         /* select the new extrusion, deselect old */
214         
215         /* step 1; init, count faces in edges */
216         recalc_editnormals(em);
217         
218         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;      // new select flag
219
220         for(eed= em->edges.first; eed; eed= eed->next) {
221                 eed->f2= 0; // amount of unselected faces
222         }
223         for(efa= em->faces.first; efa; efa= efa->next) {
224                 if(efa->f & SELECT);
225                 else {
226                         efa->e1->f2++;
227                         efa->e2->f2++;
228                         efa->e3->f2++;
229                         if(efa->e4) efa->e4->f2++;
230                 }
231         }
232
233         /* step 2: make new faces from faces */
234         for(efa= em->faces.last; efa; efa= efa->prev) {
235                 if(efa->f & SELECT) {
236                         v1= addvertlist(em, efa->v1->co, efa->v1);
237                         v2= addvertlist(em, efa->v2->co, efa->v2);
238                         v3= addvertlist(em, efa->v3->co, efa->v3);
239                         
240                         v1->f1= v2->f1= v3->f1= 1;
241                         VECCOPY(v1->no, efa->n);
242                         VECCOPY(v2->no, efa->n);
243                         VECCOPY(v3->no, efa->n);
244                         if(efa->v4) {
245                                 v4= addvertlist(em, efa->v4->co, efa->v4); 
246                                 v4->f1= 1;
247                                 VECCOPY(v4->no, efa->n);
248                         }
249                         else v4= NULL;
250                         
251                         /* side faces, clockwise */
252                         addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL);
253                         addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL);
254                         if(efa->v4) {
255                                 addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL);
256                                 addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL);
257                         }
258                         else {
259                                 addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL);
260                         }
261                         /* top face */
262                         addfacelist(em, v1, v2, v3, v4, efa, NULL);
263                 }
264         }
265         
266         /* step 3: remove old faces */
267         efa= em->faces.first;
268         while(efa) {
269                 nextfa= efa->next;
270                 if(efa->f & SELECT) {
271                         BLI_remlink(&em->faces, efa);
272                         free_editface(em, efa);
273                 }
274                 efa= nextfa;
275         }
276
277         /* step 4: redo selection */
278         EM_clear_flag_all(em, SELECT);
279         
280         for(eve= em->verts.first; eve; eve= eve->next) {
281                 if(eve->f1)  eve->f |= SELECT;
282         }
283         
284         EM_select_flush(em);
285         
286         return 'n';
287 }
288 #endif
289
290 /* extrudes individual edges */
291 short EDBM_Extrude_edges_indiv(BMEditMesh *em, wmOperator *op, short flag, float *UNUSED(nor)) 
292 {
293         BMOperator bmop;
294
295         EDBM_InitOpf(em, &bmop, op, "extrude_edge_only edges=%he", flag);
296
297         /*deselect original verts*/
298         EDBM_clear_flag_all(em, BM_SELECT);
299
300         BMO_Exec_Op(em->bm, &bmop);
301         BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_VERT|BM_EDGE);
302
303         if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
304
305         return 'n'; // n is normal grab
306 }
307
308 #if 0
309 /* nor is filled with constraint vector */
310 short EDBM_Extrude_edges_indiv(BMEditMesh *em, short flag, float *nor) 
311 {
312         EditVert *eve;
313         EditEdge *eed;
314         EditFace *efa;
315         
316         for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL;
317         for(eed= em->edges.first; eed; eed= eed->next) {
318                 eed->tmp.f = NULL;
319                 eed->f2= ((eed->f & flag)!=0);
320         }
321         
322         set_edge_directions_f2(em, 2);
323
324         /* sample for next loop */
325         for(efa= em->faces.first; efa; efa= efa->next) {
326                 efa->e1->tmp.f = efa;
327                 efa->e2->tmp.f = efa;
328                 efa->e3->tmp.f = efa;
329                 if(efa->e4) efa->e4->tmp.f = efa;
330         }
331         /* make the faces */
332         for(eed= em->edges.first; eed; eed= eed->next) {
333                 if(eed->f & flag) {
334                         if(eed->v1->tmp.v == NULL)
335                                 eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
336                         if(eed->v2->tmp.v == NULL)
337                                 eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
338
339                         if(eed->dir==1) 
340                                 addfacelist(em, eed->v1, eed->v2, 
341                                                         eed->v2->tmp.v, eed->v1->tmp.v, 
342                                                         eed->tmp.f, NULL);
343                         else 
344                                 addfacelist(em, eed->v2, eed->v1, 
345                                                         eed->v1->tmp.v, eed->v2->tmp.v, 
346                                                         eed->tmp.f, NULL);
347
348                         /* for transform */
349                         if(eed->tmp.f) {
350                                 efa = eed->tmp.f;
351                                 if (efa->f & SELECT) add_normal_aligned(nor, efa->n);
352                         }
353                 }
354         }
355         normalize_v3(nor);
356         
357         /* set correct selection */
358         EM_clear_flag_all(em, SELECT);
359         for(eve= em->verts.last; eve; eve= eve->prev) {
360                 if(eve->tmp.v) {
361                         eve->tmp.v->f |= flag;
362                 }
363         }
364
365         for(eed= em->edges.first; eed; eed= eed->next) {
366                 if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
367         }
368         
369         if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab
370         return 'n';  // n is for normal constraint
371 }
372 #endif
373
374 /* extrudes individual vertices */
375 short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) 
376 {
377         BMOperator bmop;
378
379         EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", flag);
380
381         /*deselect original verts*/
382         BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "verts", BM_SELECT, BM_VERT);
383
384         BMO_Exec_Op(em->bm, &bmop);
385         BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_VERT);
386
387         if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
388
389         return 'g'; // g is grab
390 }
391
392 short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int flag, float *nor)
393 {
394         BMesh *bm = em->bm;
395         BMIter iter;
396         BMOIter siter;
397         BMOperator extop;
398         BMVert *vert;
399         BMEdge *edge;
400         BMFace *f;
401         ModifierData *md;
402         BMHeader *el;
403         
404         BMO_Init_Op(&extop, "extrudefaceregion");
405         BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein",
406                                flag, BM_VERT|BM_EDGE|BM_FACE);
407
408         /* If a mirror modifier with clipping is on, we need to adjust some 
409          * of the cases above to handle edges on the line of symmetry.
410          */
411         md = obedit->modifiers.first;
412         for (; md; md=md->next) {
413                 if (md->type==eModifierType_Mirror) {
414                         MirrorModifierData *mmd = (MirrorModifierData*) md;     
415                 
416                         if(mmd->flag & MOD_MIR_CLIPPING) {
417                                 float mtx[4][4];
418                                 if (mmd->mirror_ob) {
419                                         float imtx[4][4];
420                                         invert_m4_m4(imtx, mmd->mirror_ob->obmat);
421                                         mul_m4_m4m4(mtx, obedit->obmat, imtx);
422                                 }
423
424                                 for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL);
425                                      edge; edge=BMIter_Step(&iter))
426                                 {
427                                         if(edge->head.flag & flag) {
428                                                 float co1[3], co2[3];
429
430                                                 copy_v3_v3(co1, edge->v1->co);
431                                                 copy_v3_v3(co2, edge->v2->co);
432
433                                                 if (mmd->mirror_ob) {
434                                                         mul_v3_m4v3(co1, mtx, co1);
435                                                         mul_v3_m4v3(co2, mtx, co2);
436                                                 }
437
438                                                 if (mmd->flag & MOD_MIR_AXIS_X)
439                                                         if ( (fabs(co1[0]) < mmd->tolerance) &&
440                                                                  (fabs(co2[0]) < mmd->tolerance) )
441                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
442
443                                                 if (mmd->flag & MOD_MIR_AXIS_Y)
444                                                         if ( (fabs(co1[1]) < mmd->tolerance) &&
445                                                                  (fabs(co2[1]) < mmd->tolerance) )
446                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
447
448                                                 if (mmd->flag & MOD_MIR_AXIS_Z)
449                                                         if ( (fabs(co1[2]) < mmd->tolerance) &&
450                                                                  (fabs(co2[2]) < mmd->tolerance) )
451                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
452                                         }
453                                 }
454                         }
455                 }
456         }
457
458         BM_ITER(vert, &iter, bm, BM_VERTS_OF_MESH, NULL) {
459                 BM_Select(bm, vert, 0);
460         }
461
462         BM_ITER(edge, &iter, bm, BM_EDGES_OF_MESH, NULL) {
463                 BM_Select(bm, edge, 0);
464         }
465
466         BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
467                 BM_Select(bm, f, 0);
468         }
469
470         BMO_Exec_Op(bm, &extop);
471
472         nor[0] = nor[1] = nor[2] = 0.0f;
473         
474         BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) {
475                 BM_Select(bm, el, 1);
476
477                 if (el->type == BM_FACE) {
478                         f = (BMFace*)el;
479                         add_normal_aligned(nor, f->no);
480                 };
481         }
482
483         normalize_v3(nor);
484
485         BMO_Finish_Op(bm, &extop);
486
487         if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
488         return 'n'; // normal constraint 
489
490 }
491 short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, short flag, float *nor)
492 {
493                 BMIter iter;
494                 BMEdge *eed;
495                 
496                 /*ensure vert flags are consistent for edge selections*/
497                 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
498                 for ( ; eed; eed=BMIter_Step(&iter)) {
499                         if (BM_TestHFlag(eed, flag)) {
500                                 if (flag != BM_SELECT) {
501                                         BM_SetHFlag(eed->v1, flag);
502                                         BM_SetHFlag(eed->v2, flag);
503                                 } else {
504                                         BM_Select(em->bm, eed->v1, 1);
505                                         BM_Select(em->bm, eed->v2, 1);
506                                 }
507                         } else {
508                                 if (BM_TestHFlag(eed->v1, flag) && BM_TestHFlag(eed->v2, flag)) {
509                                         if (flag != BM_SELECT)
510                                                 BM_SetHFlag(eed, flag);
511                                         else BM_Select(em->bm, eed, 1);
512                                 }
513                         }
514                 }
515
516                 return EDBM_Extrude_edge(obedit, em, flag, nor);
517
518 }
519
520 static int extrude_repeat_mesh(bContext *C, wmOperator *op)
521 {
522         Object *obedit= CTX_data_edit_object(C);
523         BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
524         RegionView3D *rv3d = CTX_wm_region_view3d(C);           
525                 
526         int steps = RNA_int_get(op->ptr,"steps");
527         
528         float offs = RNA_float_get(op->ptr,"offset");
529         float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
530         short a;
531
532         /* dvec */
533         dvec[0]= rv3d->persinv[2][0];
534         dvec[1]= rv3d->persinv[2][1];
535         dvec[2]= rv3d->persinv[2][2];
536         normalize_v3(dvec);
537         dvec[0]*= offs;
538         dvec[1]*= offs;
539         dvec[2]*= offs;
540
541         /* base correction */
542         copy_m3_m4(bmat, obedit->obmat);
543         invert_m3_m3(tmat, bmat);
544         mul_m3_v3(tmat, dvec);
545
546         for(a=0; a<steps; a++) {
547                 EDBM_Extrude_edge(obedit, em, BM_SELECT, nor);
548                 //BMO_CallOpf(em->bm, "extrudefaceregion edgefacein=%hef", BM_SELECT);
549                 BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT);
550                 //extrudeflag(obedit, em, SELECT, nor);
551                 //translateflag(em, SELECT, dvec);
552         }
553         
554         EDBM_RecalcNormals(em);
555
556         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
557         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
558
559         return OPERATOR_FINISHED;
560 }
561
562 void MESH_OT_extrude_repeat(wmOperatorType *ot)
563 {
564         /* identifiers */
565         ot->name= "Extrude Repeat Mesh";
566         ot->description= "Extrude selected vertices, edges or faces repeatedly.";
567         ot->idname= "MESH_OT_extrude_repeat";
568         
569         /* api callbacks */
570         ot->exec= extrude_repeat_mesh;
571         ot->poll= ED_operator_editmesh;
572         
573         /* flags */
574         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
575         
576         /* props */
577         RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX);
578         RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX);
579 }
580
581 /* generic extern called extruder */
582 int EDBM_Extrude_Mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOperator *op, float *norin)
583 {
584         short nr, transmode= 0;
585         float stacknor[3] = {0.0f, 0.0f, 0.0f};
586         float *nor = norin ? norin : stacknor;
587
588         nor[0] = nor[1] = nor[2] = 0.0f;
589
590         if(em->selectmode & SCE_SELECT_VERTEX) {
591                 if(em->bm->totvertsel==0) nr= 0;
592                 else if(em->bm->totvertsel==1) nr= 4;
593                 else if(em->bm->totedgesel==0) nr= 4;
594                 else if(em->bm->totfacesel==0) 
595                         nr= 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
596                 else if(em->bm->totfacesel==1)
597                         nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
598                 else 
599                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
600         }
601         else if(em->selectmode & SCE_SELECT_EDGE) {
602                 if (em->bm->totedgesel==0) nr = 0;
603                 
604                 nr = 1;
605                 /*else if (em->totedgesel==1) nr = 3;
606                 else if(em->totfacesel==0) nr = 3;
607                 else if(em->totfacesel==1)
608                         nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3");
609                 else
610                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
611                 */
612         }
613         else {
614                 if (em->bm->totfacesel == 0) nr = 0;
615                 else if (em->bm->totfacesel == 1) nr = 1;
616                 else
617                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
618         }
619
620         if(nr<1) return 'g';
621
622         if(nr==1 && em->selectmode & SCE_SELECT_VERTEX) 
623                 transmode= EDBM_Extrude_vert(obedit, em, SELECT, nor);
624         else if (nr == 1) transmode= EDBM_Extrude_edge(obedit, em, SELECT, nor);
625         else if(nr==4) transmode= EDBM_Extrude_verts_indiv(em, op, SELECT, nor);
626         else if(nr==3) transmode= EDBM_Extrude_edges_indiv(em, op, SELECT, nor);
627         else transmode= EDBM_Extrude_face_indiv(em, op, SELECT, nor);
628         
629         if(transmode==0) {
630                 BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
631         }
632         else {
633                 
634                         /* We need to force immediate calculation here because 
635                         * transform may use derived objects (which are now stale).
636                         *
637                         * This shouldn't be necessary, derived queries should be
638                         * automatically building this data if invalid. Or something.
639                         */
640 //              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
641                 object_handle_update(scene, obedit);
642
643                 /* individual faces? */
644 //              BIF_TransformSetUndo("Extrude");
645                 if(nr==2) {
646 //                      initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
647 //                      Transform();
648                 }
649                 else {
650 //                      initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
651                         if(transmode=='n') {
652                                 mul_m4_v3(obedit->obmat, nor);
653                                 sub_v3_v3v3(nor, nor, obedit->obmat[3]);
654 //                              BIF_setSingleAxisConstraint(nor, "along normal");
655                         }
656 //                      Transform();
657                 }
658         }
659         
660         return transmode;
661 }
662
663 /* extrude without transform */
664 static int mesh_extrude_region_exec(bContext *C, wmOperator *op)
665 {
666         Scene *scene = CTX_data_scene(C);
667         Object *obedit= CTX_data_edit_object(C);
668         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
669         
670         EDBM_Extrude_Mesh(scene, obedit, em, op, NULL);
671         
672         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
673         
674         return OPERATOR_FINISHED;       
675 }
676
677 void MESH_OT_extrude_region(wmOperatorType *ot)
678 {
679         /* identifiers */
680         ot->name= "Extrude Region";
681         ot->idname= "MESH_OT_extrude_region";
682         
683         /* api callbacks */
684         //ot->invoke= mesh_extrude_region_invoke;
685         ot->exec= mesh_extrude_region_exec;
686         ot->poll= ED_operator_editmesh;
687         
688         /* flags */
689         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
690
691         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
692 }
693
694 static int mesh_extrude_verts_exec(bContext *C, wmOperator *op)
695 {
696         Object *obedit= CTX_data_edit_object(C);
697         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
698         float nor[3];
699
700         EDBM_Extrude_verts_indiv(em, op, BM_SELECT, nor);
701         
702         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
703         
704         return OPERATOR_FINISHED;       
705 }
706
707 void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
708 {
709         /* identifiers */
710         ot->name= "Extrude Only Vertices";
711         ot->idname= "MESH_OT_extrude_verts_indiv";
712         
713         /* api callbacks */
714         ot->exec= mesh_extrude_verts_exec;
715         ot->poll= ED_operator_editmesh;
716         
717         /* flags */
718         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
719
720         /* to give to transform */
721         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
722 }
723
724 static int mesh_extrude_edges_exec(bContext *C, wmOperator *op)
725 {
726         Object *obedit= CTX_data_edit_object(C);
727         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
728         float nor[3];
729
730         EDBM_Extrude_edges_indiv(em, op, BM_SELECT, nor);
731         
732         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
733         
734         return OPERATOR_FINISHED;       
735 }
736
737 void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
738 {
739         /* identifiers */
740         ot->name= "Extrude Only Edges";
741         ot->idname= "MESH_OT_extrude_edges_indiv";
742         
743         /* api callbacks */
744         ot->exec= mesh_extrude_edges_exec;
745         ot->poll= ED_operator_editmesh;
746         
747         /* flags */
748         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
749
750         /* to give to transform */
751         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
752 }
753
754 static int mesh_extrude_faces_exec(bContext *C, wmOperator *op)
755 {
756         Object *obedit= CTX_data_edit_object(C);
757         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
758         float nor[3];
759
760         EDBM_Extrude_face_indiv(em, op, BM_SELECT, nor);
761         
762         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
763         
764         return OPERATOR_FINISHED;       
765 }
766
767 void MESH_OT_extrude_faces_indiv(wmOperatorType *ot)
768 {
769         /* identifiers */
770         ot->name= "Extrude Individual Faces";
771         ot->idname= "MESH_OT_extrude_faces_indiv";
772         
773         /* api callbacks */
774         ot->exec= mesh_extrude_faces_exec;
775         ot->poll= ED_operator_editmesh;
776         
777         /* flags */
778         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
779
780         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
781 }
782
783 /* ******************** (de)select all operator **************** */
784
785 void EDBM_toggle_select_all(BMEditMesh *em) /* exported for UV */
786 {
787         if(em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
788                 EDBM_clear_flag_all(em, SELECT);
789         else 
790                 EDBM_set_flag_all(em, SELECT);
791 }
792
793 static int toggle_select_all_exec(bContext *C, wmOperator *op)
794 {
795         Object *obedit= CTX_data_edit_object(C);
796         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
797         
798         EDBM_toggle_select_all(em);
799         
800         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
801
802         return OPERATOR_FINISHED;
803 }
804
805 void MESH_OT_select_all(wmOperatorType *ot)
806 {
807         /* identifiers */
808         ot->name= "Select/Deselect All";
809         ot->idname= "MESH_OT_select_all";
810         ot->description= "(de)select all vertices, edges or faces.";
811         
812         /* api callbacks */
813         ot->exec= toggle_select_all_exec;
814         ot->poll= ED_operator_editmesh;
815         
816         /* flags */
817         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
818 }
819
820 /* *************** add-click-mesh (extrude) operator ************** */
821
822 static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
823 {
824         ViewContext vc;
825         BMVert *v1;
826         BMIter iter;
827         float min[3], max[3];
828         int done= 0;
829         
830         em_setup_viewcontext(C, &vc);
831         
832         INIT_MINMAX(min, max);
833         
834         BM_ITER_SELECT(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH, NULL)
835                 DO_MINMAX(v1->co, min, max);
836                 done= 1;
837         }
838
839         /* call extrude? */
840         if(done) {
841                 BMEdge *eed;
842                 float vec[3], cent[3], mat[3][3];
843                 float nor[3]= {0.0, 0.0, 0.0};
844                 
845                 /* check for edges that are half selected, use for rotation */
846                 done= 0;
847                 BM_ITER(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH, NULL) {
848                         if (BM_TestHFlag(eed->v1, BM_SELECT) ^ BM_TestHFlag(eed->v2, BM_SELECT)) {
849                                 if(BM_TestHFlag(eed->v1, BM_SELECT)) 
850                                         sub_v3_v3v3(vec, eed->v1->co, eed->v2->co);
851                                 else 
852                                         sub_v3_v3v3(vec, eed->v2->co, eed->v1->co);
853                                 add_v3_v3v3(nor, nor, vec);
854                                 done= 1;
855                         }
856                 }
857                 if(done) normalize_v3(nor);
858                 
859                 /* center */
860                 add_v3_v3v3(cent, min, max);
861                 mul_v3_fl(cent, 0.5f);
862                 VECCOPY(min, cent);
863                 
864                 mul_m4_v3(vc.obedit->obmat, min);       // view space
865                 view3d_get_view_aligned_coordinate(&vc, min, event->mval);
866                 invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); 
867                 mul_m4_v3(vc.obedit->imat, min); // back in object space
868                 
869                 sub_v3_v3v3(min, min, cent);
870                 
871                 /* calculate rotation */
872                 unit_m3(mat);
873                 if(done) {
874                         float dot;
875                         
876                         VECCOPY(vec, min);
877                         normalize_v3(vec);
878                         dot= INPR(vec, nor);
879
880                         if( fabs(dot)<0.999) {
881                                 float cross[3], si, q1[4];
882                                 
883                                 cross_v3_v3v3(cross, nor, vec);
884                                 normalize_v3(cross);
885                                 dot= 0.5f*saacos(dot);
886                                 si= (float)sin(dot);
887                                 q1[0]= (float)cos(dot);
888                                 q1[1]= cross[0]*si;
889                                 q1[2]= cross[1]*si;
890                                 q1[3]= cross[2]*si;
891                                 
892                                 quat_to_mat3( mat,q1);
893                         }
894                 }
895                 
896
897                 EDBM_Extrude_edge(vc.obedit, vc.em, SELECT, nor);
898                 EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
899                         BM_SELECT, cent, mat);
900                 EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v",
901                         BM_SELECT, min);
902         }
903         else {
904                 float *curs= give_cursor(vc.scene, vc.v3d);
905                 BMOperator bmop;
906                 BMOIter oiter;
907                 
908                 VECCOPY(min, curs);
909
910                 view3d_get_view_aligned_coordinate(&vc, min, event->mval);
911                 invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); 
912                 mul_m4_v3(vc.obedit->imat, min); // back in object space
913                 
914                 EDBM_InitOpf(vc.em, &bmop, op, "makevert co=%v", min);
915                 BMO_Exec_Op(vc.em->bm, &bmop);
916
917                 BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) {
918                         BM_Select(vc.em->bm, v1, 1);
919                 }
920
921                 if (!EDBM_FinishOp(vc.em, &bmop, op, 1))
922                         return OPERATOR_CANCELLED;
923         }
924
925         //retopo_do_all();
926         WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data); 
927         DAG_id_tag_update(vc.obedit->data, OB_RECALC_DATA);
928         
929         return OPERATOR_FINISHED;
930 }
931
932 void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
933 {
934         /* identifiers */
935         ot->name= "Duplicate or Extrude at 3D Cursor";
936         ot->idname= "MESH_OT_dupli_extrude_cursor";
937         
938         /* api callbacks */
939         ot->invoke= dupli_extrude_cursor;
940         ot->description= "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor.";
941         ot->poll= ED_operator_editmesh;
942         
943         /* flags */
944         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
945 }
946
947 static int delete_mesh(bContext *C, Object *obedit, wmOperator *op, int event, Scene *UNUSED(scene))
948 {
949         BMEditMesh *bem = ((Mesh*)obedit->data)->edit_btmesh;
950         
951         if(event<1) return OPERATOR_CANCELLED;
952
953         if(event==10 ) {
954                 //"Erase Vertices";
955
956                 if (!EDBM_CallOpf(bem, op, "del geom=%hv context=%i", BM_SELECT, DEL_VERTS))
957                         return OPERATOR_CANCELLED;
958         } 
959         else if(event==11) {
960                 //"Edge Loop"
961                 if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_SELECT))
962                         return OPERATOR_CANCELLED;
963         }
964         else if(event==7) {
965                 //"Dissolve"
966                 if (bem->selectmode & SCE_SELECT_FACE) {
967                         if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf",BM_SELECT))
968                                 return OPERATOR_CANCELLED;
969                 } else if (bem->selectmode & SCE_SELECT_EDGE) {
970                         if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he",BM_SELECT))
971                                 return OPERATOR_CANCELLED;
972                 } else if (bem->selectmode & SCE_SELECT_VERTEX) {
973                         if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv",BM_SELECT))
974                                 return OPERATOR_CANCELLED;
975                 }
976         }
977         else if(event==4) {
978                 //Edges and Faces
979                 if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_SELECT, DEL_EDGESFACES))
980                         return OPERATOR_CANCELLED;
981         } 
982         else if(event==1) {
983                 //"Erase Edges"
984                 if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_SELECT, DEL_EDGES))
985                         return OPERATOR_CANCELLED;
986         }
987         else if(event==2) {
988                 //"Erase Faces";
989                 if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_SELECT, DEL_FACES))
990                         return OPERATOR_CANCELLED;
991         }
992         else if(event==5) {
993                 //"Erase Only Faces";
994                 if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d",
995                                   BM_SELECT, DEL_ONLYFACES))
996                         return OPERATOR_CANCELLED;
997         }
998         
999         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1000         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1001
1002         return OPERATOR_FINISHED;
1003 }
1004
1005 /* Note, these values must match delete_mesh() event values */
1006 static EnumPropertyItem prop_mesh_delete_types[] = {
1007         {7, "DISSOLVE",         0, "Dissolve", ""},
1008         {10,"VERT",             0, "Vertices", ""},
1009         {1, "EDGE",             0, "Edges", ""},
1010         {2, "FACE",             0, "Faces", ""},
1011         {11, "EDGE_LOOP", 0, "Edge Loop", ""},
1012         {4, "EDGE_FACE", 0, "Edges & Faces", ""},
1013         {5, "ONLY_FACE", 0, "Only Faces", ""},
1014         {0, NULL, 0, NULL, NULL}
1015 };
1016
1017 static int delete_mesh_exec(bContext *C, wmOperator *op)
1018 {
1019         Object *obedit= CTX_data_edit_object(C);
1020         Scene *scene = CTX_data_scene(C);
1021
1022         delete_mesh(C, obedit, op, RNA_enum_get(op->ptr, "type"), scene);
1023         
1024         WM_event_add_notifier(C, NC_GEOM|ND_DATA|ND_SELECT, obedit);
1025         
1026         return OPERATOR_FINISHED;
1027 }
1028
1029 void MESH_OT_delete(wmOperatorType *ot)
1030 {
1031         /* identifiers */
1032         ot->name= "Delete";
1033         ot->description= "Delete selected vertices, edges or faces.";
1034         ot->idname= "MESH_OT_delete";
1035         
1036         /* api callbacks */
1037         ot->invoke= WM_menu_invoke;
1038         ot->exec= delete_mesh_exec;
1039         
1040         ot->poll= ED_operator_editmesh;
1041         
1042         /* flags */
1043         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1044         
1045         /*props */
1046         ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
1047 }
1048
1049
1050 static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
1051 {
1052         BMOperator bmop;
1053         Object *obedit= CTX_data_edit_object(C);
1054         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1055         
1056         if (!EDBM_InitOpf(em, &bmop, op, "contextual_create geom=%hfev", BM_SELECT))
1057                 return OPERATOR_CANCELLED;
1058         
1059         BMO_Exec_Op(em->bm, &bmop);
1060         BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT, BM_FACE);
1061
1062         if (!EDBM_FinishOp(em, &bmop, op, 1))
1063                 return OPERATOR_CANCELLED;
1064
1065         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1066         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1067         
1068         return OPERATOR_FINISHED;
1069 }
1070
1071 void MESH_OT_edge_face_add(wmOperatorType *ot)
1072 {
1073         /* identifiers */
1074         ot->name= "Make Edge/Face";
1075         ot->description= "Add an edge or face to selected.";
1076         ot->idname= "MESH_OT_edge_face_add";
1077         
1078         /* api callbacks */
1079         ot->exec= addedgeface_mesh_exec;
1080         ot->poll= ED_operator_editmesh;
1081         
1082         /* flags */
1083         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1084         
1085 }
1086
1087 static EnumPropertyItem prop_mesh_edit_types[] = {
1088         {1, "VERT", 0, "Vertices", ""},
1089         {2, "EDGE", 0, "Edges", ""},
1090         {3, "FACE", 0, "Faces", ""},
1091         {0, NULL, 0, NULL, NULL}
1092 };
1093
1094 static int mesh_selection_type_exec(bContext *C, wmOperator *op)
1095 {               
1096         
1097         Object *obedit= CTX_data_edit_object(C);
1098         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1099         int type = RNA_enum_get(op->ptr,"type");
1100
1101         switch (type) {
1102                 case 1:
1103                         em->selectmode = SCE_SELECT_VERTEX;
1104                         break;
1105                 case 2:
1106                         em->selectmode = SCE_SELECT_EDGE;
1107                         break;
1108                 case 3:
1109                         em->selectmode = SCE_SELECT_FACE;
1110                         break;
1111         }
1112
1113         EDBM_selectmode_set(em);
1114         CTX_data_tool_settings(C)->selectmode = em->selectmode;
1115
1116         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1117         
1118         return OPERATOR_FINISHED;
1119 }
1120
1121 void MESH_OT_selection_type(wmOperatorType *ot)
1122 {
1123         /* identifiers */
1124         ot->name= "Selection Mode";
1125         ot->description= "Set the selection mode type.";
1126         ot->idname= "MESH_OT_selection_type";
1127         
1128         /* api callbacks */
1129         ot->invoke= WM_menu_invoke;
1130         ot->exec= mesh_selection_type_exec;
1131         
1132         ot->poll= ED_operator_editmesh;
1133         
1134         /* flags */
1135         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1136         
1137         /* props */
1138         RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type");
1139         RNA_def_boolean(ot->srna, "inclusive", 0, "Inclusive", "Selects geometry around selected geometry, occording to selection mode");       
1140 }
1141
1142 /* ************************* SEAMS AND EDGES **************** */
1143
1144 static int editbmesh_mark_seam(bContext *C, wmOperator *op)
1145 {
1146         Object *obedit= CTX_data_edit_object(C);
1147         Mesh *me= ((Mesh *)obedit->data);
1148         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1149         BMesh *bm = em->bm;
1150         BMEdge *eed;
1151         BMIter iter;
1152         int clear = RNA_boolean_get(op->ptr, "clear");
1153         
1154         /* auto-enable seams drawing */
1155         if(clear==0) {
1156                 me->drawflag |= ME_DRAWSEAMS;
1157         }
1158
1159         if(clear) {
1160                 BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
1161                         BM_ClearHFlag(eed, BM_SEAM);
1162                 }
1163         }
1164         else {
1165                 BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
1166                         BM_SetHFlag(eed, BM_SEAM);
1167                 }
1168         }
1169
1170         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1171         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1172
1173         return OPERATOR_FINISHED;
1174 }
1175
1176 void MESH_OT_mark_seam(wmOperatorType *ot)
1177 {
1178         /* identifiers */
1179         ot->name= "Mark Seam";
1180         ot->idname= "MESH_OT_mark_seam";
1181         ot->description= "(un)mark selected edges as a seam.";
1182         
1183         /* api callbacks */
1184         ot->exec= editbmesh_mark_seam;
1185         ot->poll= ED_operator_editmesh;
1186         
1187         /* flags */
1188         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1189         
1190         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1191 }
1192
1193 static int editbmesh_mark_sharp(bContext *C, wmOperator *op)
1194 {
1195         Object *obedit= CTX_data_edit_object(C);
1196         Mesh *me= ((Mesh *)obedit->data);
1197         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1198         BMesh *bm = em->bm;
1199         BMEdge *eed;
1200         BMIter iter;
1201         int clear = RNA_boolean_get(op->ptr, "clear");
1202
1203         /* auto-enable sharp edge drawing */
1204         if(clear == 0) {
1205                 me->drawflag |= ME_DRAWSHARP;
1206         }
1207
1208         if(!clear) {
1209                 BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
1210                         BM_SetHFlag(eed, BM_SHARP);
1211                 }
1212         } else {
1213                 BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
1214                         BM_ClearHFlag(eed, BM_SHARP);
1215                 }
1216         }
1217
1218
1219         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1220         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1221
1222         return OPERATOR_FINISHED;
1223 }
1224
1225 void MESH_OT_mark_sharp(wmOperatorType *ot)
1226 {
1227         /* identifiers */
1228         ot->name= "Mark Sharp";
1229         ot->idname= "MESH_OT_mark_sharp";
1230         ot->description= "(un)mark selected edges as sharp.";
1231         
1232         /* api callbacks */
1233         ot->exec= editbmesh_mark_sharp;
1234         ot->poll= ED_operator_editmesh;
1235         
1236         /* flags */
1237         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1238         
1239         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1240 }
1241
1242
1243 static int editbmesh_vert_connect(bContext *C, wmOperator *op)
1244 {
1245         Object *obedit= CTX_data_edit_object(C);
1246         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1247         BMesh *bm = em->bm;
1248         BMOperator bmop;
1249         int len = 0;
1250         
1251         BMO_InitOpf(bm, &bmop, "connectverts verts=%hv", BM_SELECT);
1252         BMO_Exec_Op(bm, &bmop);
1253         len = BMO_GetSlot(&bmop, "edgeout")->len;
1254         BMO_Finish_Op(bm, &bmop);
1255         
1256         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1257         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1258
1259         return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1260 }
1261
1262 void MESH_OT_vert_connect(wmOperatorType *ot)
1263 {
1264         /* identifiers */
1265         ot->name= "Vertex Connect";
1266         ot->idname= "MESH_OT_vert_connect";
1267         
1268         /* api callbacks */
1269         ot->exec= editbmesh_vert_connect;
1270         ot->poll= ED_operator_editmesh;
1271         
1272         /* flags */
1273         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1274 }
1275
1276 static int editbmesh_edge_split(bContext *C, wmOperator *op)
1277 {
1278         Object *obedit= CTX_data_edit_object(C);
1279         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1280         BMesh *bm = em->bm;
1281         BMOperator bmop;
1282         int len = 0;
1283         
1284         BMO_InitOpf(bm, &bmop, "edgesplit edges=%he numcuts=%d", BM_SELECT, RNA_int_get(op->ptr,"number_cuts"));
1285         BMO_Exec_Op(bm, &bmop);
1286         len = BMO_GetSlot(&bmop, "outsplit")->len;
1287         BMO_Finish_Op(bm, &bmop);
1288         
1289         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1290         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1291
1292         return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1293 }
1294
1295 void MESH_OT_edge_split(wmOperatorType *ot)
1296 {
1297         /* identifiers */
1298         ot->name= "Edge Split";
1299         ot->idname= "MESH_OT_edge_split";
1300         
1301         /* api callbacks */
1302         ot->exec= editbmesh_edge_split;
1303         ot->poll= ED_operator_editmesh;
1304         
1305         /* flags */
1306         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1307
1308         RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX);
1309 }
1310
1311 /****************** add duplicate operator ***************/
1312
1313 static int mesh_duplicate_exec(bContext *C, wmOperator *op)
1314 {
1315         Object *ob= CTX_data_edit_object(C);
1316         BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh;
1317         BMOperator bmop;
1318
1319         EDBM_InitOpf(em, &bmop, op, "dupe geom=%hvef", BM_SELECT);
1320         
1321         BMO_Exec_Op(em->bm, &bmop);
1322         EDBM_clear_flag_all(em, BM_SELECT);
1323
1324         BMO_HeaderFlag_Buffer(em->bm, &bmop, "newout", BM_SELECT, BM_ALL);
1325
1326         if (!EDBM_FinishOp(em, &bmop, op, 1))
1327                 return OPERATOR_CANCELLED;
1328
1329         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
1330         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
1331         
1332         return OPERATOR_FINISHED;
1333 }
1334
1335 static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
1336 {
1337         WM_cursor_wait(1);
1338         mesh_duplicate_exec(C, op);
1339         WM_cursor_wait(0);
1340         
1341         return OPERATOR_FINISHED;
1342 }
1343
1344 void MESH_OT_duplicate(wmOperatorType *ot)
1345 {
1346         /* identifiers */
1347         ot->name= "Duplicate";
1348         ot->description= "Duplicate selected vertices, edges or faces.";
1349         ot->idname= "MESH_OT_duplicate";
1350         
1351         /* api callbacks */
1352         ot->invoke= mesh_duplicate_invoke;
1353         ot->exec= mesh_duplicate_exec;
1354         
1355         ot->poll= ED_operator_editmesh;
1356         
1357         /* to give to transform */
1358         RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
1359 }
1360
1361 static int flip_normals(bContext *C, wmOperator *op)
1362 {
1363         Object *obedit= CTX_data_edit_object(C);
1364         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1365         
1366         if (!EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT))
1367                 return OPERATOR_CANCELLED;
1368         
1369         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1370         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1371
1372         return OPERATOR_FINISHED;
1373 }
1374
1375 void MESH_OT_flip_normals(wmOperatorType *ot)
1376 {
1377         /* identifiers */
1378         ot->name= "Flip Normals";
1379         ot->description= "Flip the direction of selected face's vertex and face normals";
1380         ot->idname= "MESH_OT_flip_normals";
1381         
1382         /* api callbacks */
1383         ot->exec= flip_normals;
1384         ot->poll= ED_operator_editmesh;
1385         
1386         /* flags */
1387         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1388 }
1389
1390 float *bm_get_cd_float(CustomData *cdata, void *data, int type)
1391 {
1392         float *f = CustomData_bmesh_get(cdata, data, type);
1393
1394         return f;
1395 }
1396
1397 static const EnumPropertyItem direction_items[]= {
1398         {DIRECTION_CW, "CW", 0, "Clockwise", ""},
1399         {DIRECTION_CCW, "CCW", 0, "Counter Clockwise", ""},
1400         {0, NULL, 0, NULL, NULL}};
1401
1402 /* only accepts 1 selected edge, or 2 selected faces */
1403 static int edge_rotate_selected(bContext *C, wmOperator *op)
1404 {
1405         Object *obedit= CTX_data_edit_object(C);
1406         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1407         BMOperator bmop;
1408         BMEdge *eed;
1409         BMIter iter;
1410         int ccw = RNA_int_get(op->ptr, "direction") == 1; // direction == 2 when clockwise and ==1 for counter CW.
1411         
1412         if (!(em->bm->totfacesel == 2 || em->bm->totedgesel == 1)) {
1413                 BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
1414                 return OPERATOR_CANCELLED;
1415         }
1416
1417         /*first see if we have two adjacent faces*/
1418         BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1419                 if (BM_Edge_FaceCount(eed) == 2) {
1420                         if ((BM_TestHFlag(eed->l->f, BM_SELECT) && BM_TestHFlag(((BMLoop*)eed->l->radial_next)->f, BM_SELECT))
1421                                  && !(BM_TestHFlag(eed->l->f, BM_HIDDEN) || BM_TestHFlag(((BMLoop*)eed->l->radial_next)->f, BM_HIDDEN)))
1422                         {
1423                                 break;
1424                         }
1425                 }
1426         }
1427         
1428         /*ok, we don't have two adjacent faces, but we do have two selected ones.
1429           that's an error condition.*/
1430         if (!eed && em->bm->totfacesel == 2) {
1431                 BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
1432                 return OPERATOR_CANCELLED;
1433         }
1434
1435         if (!eed) {
1436                 BM_ITER_SELECT(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL)
1437                         if (BM_TestHFlag(eed, BM_SELECT))
1438                                 break;
1439                 }
1440         }
1441
1442         /*this should never happen*/
1443         if (!eed)
1444                 return OPERATOR_CANCELLED;
1445         
1446         EDBM_InitOpf(em, &bmop, op, "edgerotate edges=%e ccw=%d", eed, ccw);
1447         BMO_Exec_Op(em->bm, &bmop);
1448
1449         BMO_HeaderFlag_Buffer(em->bm, &bmop, "edgeout", BM_SELECT, BM_EDGE);
1450
1451         if (!EDBM_FinishOp(em, &bmop, op, 1))
1452                 return OPERATOR_CANCELLED;
1453
1454         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1455         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1456
1457         return OPERATOR_FINISHED;
1458 }
1459
1460 void MESH_OT_edge_rotate(wmOperatorType *ot)
1461 {
1462         /* identifiers */
1463         ot->name= "Rotate Selected Edge";
1464         ot->description= "Rotate selected edge or adjoining faces.";
1465         ot->idname= "MESH_OT_edge_rotate";
1466
1467         /* api callbacks */
1468         ot->exec= edge_rotate_selected;
1469         ot->poll= ED_operator_editmesh;
1470
1471         /* flags */
1472         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1473
1474         /* props */
1475         RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "direction", "direction to rotate edge around.");
1476 }
1477
1478 /* pinning code */
1479
1480 /* swap is 0 or 1, if 1 it pins not selected */
1481 void EDBM_pin_mesh(BMEditMesh *em, int swap)
1482 {
1483         BMIter iter;
1484         BMHeader *h;
1485         int itermode;
1486
1487         if(em==NULL) return;
1488         
1489         if (em->selectmode & SCE_SELECT_VERTEX)
1490                 itermode = BM_VERTS_OF_MESH;
1491         else if (em->selectmode & SCE_SELECT_EDGE)
1492                 itermode = BM_EDGES_OF_MESH;
1493         else
1494                 itermode = BM_FACES_OF_MESH;
1495
1496         BM_ITER(h, &iter, em->bm, itermode, NULL) {
1497                 if (BM_TestHFlag(h, BM_SELECT) ^ swap)
1498                         BM_Pin(em->bm, h, 1);
1499         }
1500
1501         EDBM_selectmode_flush(em);
1502 }
1503
1504 static int pin_mesh_exec(bContext *C, wmOperator *op)
1505 {
1506         Object *obedit= CTX_data_edit_object(C);
1507         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1508         Mesh *me= ((Mesh *)obedit->data);
1509
1510         me->drawflag |= ME_DRAW_PINS;
1511         
1512         EDBM_pin_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
1513                 
1514         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1515         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1516
1517         return OPERATOR_FINISHED;       
1518 }
1519
1520 void MESH_OT_pin(wmOperatorType *ot)
1521 {
1522         /* identifiers */
1523         ot->name= "Pin Selection";
1524         ot->idname= "MESH_OT_pin";
1525         
1526         /* api callbacks */
1527         ot->exec= pin_mesh_exec;
1528         ot->poll= ED_operator_editmesh;
1529         ot->description= "Pin (un)selected vertices, edges or faces.";
1530
1531         /* flags */
1532         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1533         
1534         /* props */
1535         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Pin unselected rather than selected.");
1536 }
1537
1538 /* swap is 0 or 1, if 1 it unhides not selected */
1539 void EDBM_unpin_mesh(BMEditMesh *em, int swap)
1540 {
1541         BMIter iter;
1542         BMHeader *ele;
1543         int itermode;
1544         
1545         if(em==NULL) return;
1546         
1547         if (em->selectmode & SCE_SELECT_VERTEX)
1548                 itermode = BM_VERTS_OF_MESH;
1549         else if (em->selectmode & SCE_SELECT_EDGE)
1550                 itermode = BM_EDGES_OF_MESH;
1551         else
1552                 itermode = BM_FACES_OF_MESH;
1553
1554         BM_ITER(ele, &iter, em->bm, itermode, NULL) {
1555                 if (BM_TestHFlag(ele, BM_SELECT) ^ swap)
1556                         BM_Pin(em->bm, ele, 0);
1557         }
1558
1559         EDBM_selectmode_flush(em);
1560 }
1561
1562 static int unpin_mesh_exec(bContext *C, wmOperator *op)
1563 {
1564         Object *obedit= CTX_data_edit_object(C);
1565         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1566         
1567         EDBM_unpin_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
1568
1569         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1570         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1571
1572         return OPERATOR_FINISHED;       
1573 }
1574
1575 void MESH_OT_unpin(wmOperatorType *ot)
1576 {
1577         /* identifiers */
1578         ot->name= "Unpin Selection";
1579         ot->idname= "MESH_OT_unpin";
1580         ot->description= "Unpin (un)selected vertices, edges or faces.";
1581         
1582         /* api callbacks */
1583         ot->exec= unpin_mesh_exec;
1584         ot->poll= ED_operator_editmesh;
1585         
1586         /* flags */
1587         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1588
1589         /* props */
1590         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Unpin unselected rather than selected.");
1591 }
1592
1593
1594 /* swap is 0 or 1, if 1 it hides not selected */
1595 void EDBM_hide_mesh(BMEditMesh *em, int swap)
1596 {
1597         BMIter iter;
1598         BMHeader *h;
1599         int itermode;
1600
1601         if(em==NULL) return;
1602         
1603         if (em->selectmode & SCE_SELECT_VERTEX)
1604                 itermode = BM_VERTS_OF_MESH;
1605         else if (em->selectmode & SCE_SELECT_EDGE)
1606                 itermode = BM_EDGES_OF_MESH;
1607         else
1608                 itermode = BM_FACES_OF_MESH;
1609
1610         BM_ITER(h, &iter, em->bm, itermode, NULL) {
1611                 if (BM_TestHFlag(h, BM_SELECT) ^ swap)
1612                         BM_Hide(em->bm, h, 1);
1613         }
1614
1615         /*original hide flushing comment (OUTDATED): 
1616           hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
1617         /*  - vertex hidden, always means edge is hidden too
1618                 - edge hidden, always means face is hidden too
1619                 - face hidden, only set face hide
1620                 - then only flush back down what's absolute hidden
1621         */
1622
1623 }
1624
1625 static int hide_mesh_exec(bContext *C, wmOperator *op)
1626 {
1627         Object *obedit= CTX_data_edit_object(C);
1628         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1629         
1630         EDBM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
1631                 
1632         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1633         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1634
1635         return OPERATOR_FINISHED;       
1636 }
1637
1638 void MESH_OT_hide(wmOperatorType *ot)
1639 {
1640         /* identifiers */
1641         ot->name= "Hide Selection";
1642         ot->idname= "MESH_OT_hide";
1643         
1644         /* api callbacks */
1645         ot->exec= hide_mesh_exec;
1646         ot->poll= ED_operator_editmesh;
1647          ot->description= "Hide (un)selected vertices, edges or faces.";
1648
1649         /* flags */
1650         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1651         
1652         /* props */
1653         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
1654 }
1655
1656
1657 void EDBM_reveal_mesh(BMEditMesh *em)
1658 {
1659         BMIter iter;
1660         BMHeader *ele;
1661         int i, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1662         int sels[3] = {1, !(em->selectmode & SCE_SELECT_VERTEX), !(em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE))};
1663
1664         for (i=0; i<3; i++) {
1665                 BM_ITER(ele, &iter, em->bm, types[i], NULL) {
1666                         if (BM_TestHFlag(ele, BM_HIDDEN)) {
1667                                 BM_Hide(em->bm, ele, 0);
1668
1669                                 if (sels[i])
1670                                         BM_Select(em->bm, ele, 1);
1671                         }
1672                 }
1673         }
1674
1675         EDBM_selectmode_flush(em);
1676 }
1677
1678 static int reveal_mesh_exec(bContext *C, wmOperator *op)
1679 {
1680         Object *obedit= CTX_data_edit_object(C);
1681         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1682         
1683         EDBM_reveal_mesh(em);
1684
1685         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1686         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1687
1688         return OPERATOR_FINISHED;       
1689 }
1690
1691 void MESH_OT_reveal(wmOperatorType *ot)
1692 {
1693         /* identifiers */
1694         ot->name= "Reveal Hidden";
1695         ot->idname= "MESH_OT_reveal";
1696         ot->description= "Reveal all hidden vertices, edges and faces.";
1697         
1698         /* api callbacks */
1699         ot->exec= reveal_mesh_exec;
1700         ot->poll= ED_operator_editmesh;
1701         
1702         /* flags */
1703         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1704 }
1705
1706 static int normals_make_consistent_exec(bContext *C, wmOperator *op)
1707 {
1708         Object *obedit= CTX_data_edit_object(C);
1709         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1710         
1711         if (!EDBM_CallOpf(em, op, "righthandfaces faces=%hf", BM_SELECT))
1712                 return OPERATOR_CANCELLED;
1713         
1714         if (RNA_boolean_get(op->ptr, "inside"))
1715                 EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT);
1716
1717         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1718         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1719
1720         return OPERATOR_FINISHED;       
1721 }
1722
1723 void MESH_OT_normals_make_consistent(wmOperatorType *ot)
1724 {
1725         /* identifiers */
1726         ot->name= "Make Normals Consistent";
1727         ot->description= "Make face and vertex normals point either outside or inside the mesh";
1728         ot->idname= "MESH_OT_normals_make_consistent";
1729         
1730         /* api callbacks */
1731         ot->exec= normals_make_consistent_exec;
1732         ot->poll= ED_operator_editmesh;
1733         
1734         /* flags */
1735         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1736         
1737         RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
1738 }
1739
1740
1741
1742 static int do_smooth_vertex(bContext *C, wmOperator *op)
1743 {
1744         Object *obedit= CTX_data_edit_object(C);
1745         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1746         ModifierData *md;
1747         int mirrx=0, mirry=0, mirrz=0;
1748         int i, repeat;
1749
1750         /* if there is a mirror modifier with clipping, flag the verts that
1751          * are within tolerance of the plane(s) of reflection 
1752          */
1753         for(md=obedit->modifiers.first; md; md=md->next) {
1754                 if(md->type==eModifierType_Mirror) {
1755                         MirrorModifierData *mmd = (MirrorModifierData*) md;     
1756                 
1757                         if(mmd->flag & MOD_MIR_CLIPPING) {
1758                                 if (mmd->flag & MOD_MIR_AXIS_X)
1759                                         mirrx = 1;
1760                                 if (mmd->flag & MOD_MIR_AXIS_Y)
1761                                         mirry = 1;
1762                                 if (mmd->flag & MOD_MIR_AXIS_Z)
1763                                         mirrz = 1;
1764                         }
1765                 }
1766         }
1767
1768         repeat = RNA_int_get(op->ptr,"repeat");
1769         if (!repeat)
1770                 repeat = 1;
1771         
1772         for (i=0; i<repeat; i++) {
1773                 if (!EDBM_CallOpf(em, op, "vertexsmooth verts=%hv mirror_clip_x=%d mirror_clip_y=%d mirror_clip_z=%d",
1774                                   BM_SELECT, mirrx, mirry, mirrz))
1775                 {
1776                         return OPERATOR_CANCELLED;
1777                 }
1778         }
1779
1780         //BMESH_TODO: need to handle the x-axis editing option here properly.
1781         //should probably make a helper function for that? I dunno.
1782
1783         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1784         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1785
1786         return OPERATOR_FINISHED;
1787 }       
1788         
1789 void MESH_OT_vertices_smooth(wmOperatorType *ot)
1790 {
1791         /* identifiers */
1792         ot->name= "Smooth Vertex";
1793         ot->description= "Flatten angles of selected vertices.";
1794         ot->idname= "MESH_OT_vertices_smooth";
1795         
1796         /* api callbacks */
1797         ot->exec= do_smooth_vertex;
1798         ot->poll= ED_operator_editmesh;
1799         
1800         /* flags */
1801         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1802
1803         RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
1804 }
1805
1806
1807 static int bm_test_exec(bContext *C, wmOperator *op)
1808 {
1809         Object *obedit= CTX_data_edit_object(C);
1810         RegionView3D *r3d = CTX_wm_region_view3d(C);            
1811         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1812         BMBVHTree *tree = BMBVH_NewBVH(em);
1813         BMIter iter;
1814         BMEdge *e;
1815
1816         /*hide all back edges*/
1817         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1818                 if (!BM_TestHFlag(e, BM_SELECT))
1819                         continue;
1820
1821                 if (!BMBVH_EdgeVisible(tree, e, r3d, obedit))
1822                         BM_Select(em->bm, e, 0);
1823         }
1824
1825         BMBVH_FreeBVH(tree);
1826         
1827 #if 0 //uv island walker test
1828         BMIter iter, liter;
1829         BMFace *f;
1830         BMLoop *l, *l2;
1831         MLoopUV *luv;
1832         BMWalker walker;
1833         int i=0;
1834
1835         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1836                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
1837                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1838                 }
1839         }
1840
1841         BMW_Init(&walker, em->bm, BMW_UVISLAND, 0);
1842
1843         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1844                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
1845                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1846                         if (luv->flag & MLOOPUV_VERTSEL) {
1847                                 l2 = BMW_Begin(&walker, l);
1848                                 for (; l2; l2=BMW_Step(&walker)) {
1849                                         luv = CustomData_bmesh_get(&em->bm->ldata, l2->head.data, CD_MLOOPUV);
1850                                         luv->flag |= MLOOPUV_VERTSEL;
1851                                 }                               
1852                         }
1853                 }
1854         }
1855
1856         BMW_End(&walker);
1857 #endif
1858         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1859         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1860
1861         return OPERATOR_FINISHED;
1862 }       
1863         
1864 void MESH_OT_bm_test(wmOperatorType *ot)
1865 {
1866         /* identifiers */
1867         ot->name= "BMesh Test Operator";
1868         ot->idname= "MESH_OT_bm_test";
1869         
1870         /* api callbacks */
1871         ot->exec= bm_test_exec;
1872         ot->poll= ED_operator_editmesh;
1873         
1874         /* flags */
1875         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1876
1877         //RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
1878 }
1879
1880 /********************** Smooth/Solid Operators *************************/
1881
1882 void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
1883 {
1884         BMIter iter;
1885         BMFace *efa;
1886
1887         if(em==NULL) return;
1888         
1889         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1890                 if (BM_TestHFlag(efa, BM_SELECT)) {
1891                         if (smooth)
1892                                 BM_SetHFlag(efa, BM_SMOOTH);
1893                         else
1894                                 BM_ClearHFlag(efa, BM_SMOOTH);
1895                 }
1896         }
1897 }
1898
1899 static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *op)
1900 {
1901         Object *obedit= CTX_data_edit_object(C);
1902         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1903
1904         mesh_set_smooth_faces(em, 1);
1905
1906         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1907         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1908
1909         return OPERATOR_FINISHED;
1910 }
1911
1912 void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
1913 {
1914         /* identifiers */
1915         ot->name= "Shade Smooth";
1916          ot->description= "Display faces smooth (using vertex normals).";
1917         ot->idname= "MESH_OT_faces_shade_smooth";
1918
1919         /* api callbacks */
1920         ot->exec= mesh_faces_shade_smooth_exec;
1921         ot->poll= ED_operator_editmesh;
1922
1923         /* flags */
1924         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1925 }
1926
1927 static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *op)
1928 {
1929         Object *obedit= CTX_data_edit_object(C);
1930         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1931
1932         mesh_set_smooth_faces(em, 0);
1933
1934         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1935         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1936
1937         return OPERATOR_FINISHED;
1938 }
1939
1940 void MESH_OT_faces_shade_flat(wmOperatorType *ot)
1941 {
1942         /* identifiers */
1943         ot->name= "Shade Flat";
1944         ot->description= "Display faces flat.";
1945         ot->idname= "MESH_OT_faces_shade_flat";
1946
1947         /* api callbacks */
1948         ot->exec= mesh_faces_shade_flat_exec;
1949         ot->poll= ED_operator_editmesh;
1950
1951         /* flags */
1952         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1953 }
1954
1955
1956 /********************** UV/Color Operators *************************/
1957
1958
1959 static const EnumPropertyItem axis_items[]= {
1960         {OPUVC_AXIS_X, "X", 0, "X", ""},
1961         {OPUVC_AXIS_Y, "Y", 0, "Y", ""},
1962         {0, NULL, 0, NULL, NULL}};
1963
1964 static int mesh_rotate_uvs(bContext *C, wmOperator *op)
1965 {
1966         Object *ob = CTX_data_edit_object(C);
1967         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
1968         BMOperator bmop;
1969
1970         /* get the direction from RNA */
1971         int dir = RNA_enum_get(op->ptr, "direction");
1972
1973         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
1974         EDBM_InitOpf(em, &bmop, op, "meshrotateuvs faces=%hf dir=%d", BM_SELECT, dir);
1975
1976         /* execute the operator */
1977         BMO_Exec_Op(em->bm, &bmop);
1978
1979         /* finish the operator */
1980         if( !EDBM_FinishOp(em, &bmop, op, 1) )
1981                 return OPERATOR_CANCELLED;
1982
1983
1984         /* dependencies graph and notification stuff */
1985         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
1986         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
1987 /*      DAG_id_tag_update(ob->data, OB_RECALC_DATA);
1988         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
1989 */
1990         /* we succeeded */
1991         return OPERATOR_FINISHED;
1992 }
1993
1994 static int mesh_reverse_uvs(bContext *C, wmOperator *op)
1995 {
1996         Object *ob = CTX_data_edit_object(C);
1997         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
1998         BMOperator bmop;
1999
2000         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2001         EDBM_InitOpf(em, &bmop, op, "meshreverseuvs faces=%hf", BM_SELECT);
2002
2003         /* execute the operator */
2004         BMO_Exec_Op(em->bm, &bmop);
2005
2006         /* finish the operator */
2007         if( !EDBM_FinishOp(em, &bmop, op, 1) )
2008                 return OPERATOR_CANCELLED;
2009
2010         /* dependencies graph and notification stuff */
2011         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2012         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2013 /*      DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2014         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2015 */
2016         /* we succeeded */
2017         return OPERATOR_FINISHED;
2018 }
2019
2020 static int mesh_rotate_colors(bContext *C, wmOperator *op)
2021 {
2022         Object *ob = CTX_data_edit_object(C);
2023         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
2024         BMOperator bmop;
2025
2026         /* get the direction from RNA */
2027         int dir = RNA_enum_get(op->ptr, "direction");
2028
2029         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2030         EDBM_InitOpf(em, &bmop, op, "meshrotatecolors faces=%hf dir=%d", BM_SELECT, dir);
2031
2032         /* execute the operator */
2033         BMO_Exec_Op(em->bm, &bmop);
2034
2035         /* finish the operator */
2036         if( !EDBM_FinishOp(em, &bmop, op, 1) )
2037                 return OPERATOR_CANCELLED;
2038
2039
2040         /* dependencies graph and notification stuff */
2041         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2042         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2043 /*      DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
2044         WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob);
2045 */
2046         /* we succeeded */
2047         return OPERATOR_FINISHED;
2048 }
2049
2050
2051 static int mesh_reverse_colors(bContext *C, wmOperator *op)
2052 {
2053         Object *ob = CTX_data_edit_object(C);
2054         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
2055         BMOperator bmop;
2056
2057         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2058         EDBM_InitOpf(em, &bmop, op, "meshreversecolors faces=%hf", BM_SELECT);
2059
2060         /* execute the operator */
2061         BMO_Exec_Op(em->bm, &bmop);
2062
2063         /* finish the operator */
2064         if( !EDBM_FinishOp(em, &bmop, op, 1) )
2065                 return OPERATOR_CANCELLED;
2066
2067         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2068         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2069
2070         /* we succeeded */
2071         return OPERATOR_FINISHED;
2072 #if 0
2073         Scene *scene= CTX_data_scene(C);
2074         Object *obedit= CTX_data_edit_object(C);
2075         EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
2076
2077         EditFace *efa;
2078         short change = 0;
2079         MCol tmpcol, *mcol;
2080         int axis= RNA_enum_get(op->ptr, "axis");
2081
2082         if (!EM_vertColorCheck(em)) {
2083                 BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers");
2084                 BKE_mesh_end_editmesh(obedit->data, em);
2085                 return OPERATOR_CANCELLED;
2086         }
2087
2088         for(efa=em->faces.first; efa; efa=efa->next) {
2089                 if (efa->f & SELECT) {
2090                         mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
2091                         if (axis == AXIS_Y) {
2092                                 tmpcol= mcol[1];
2093                                 mcol[1]= mcol[2];
2094                                 mcol[2]= tmpcol;
2095
2096                                 if(efa->v4) {
2097                                         tmpcol= mcol[0];
2098                                         mcol[0]= mcol[3];
2099                                         mcol[3]= tmpcol;
2100                                 }
2101                         } else {
2102                                 tmpcol= mcol[0];
2103                                 mcol[0]= mcol[1];
2104                                 mcol[1]= tmpcol;
2105
2106                                 if(efa->v4) {
2107                                         tmpcol= mcol[2];
2108                                         mcol[2]= mcol[3];
2109                                         mcol[3]= tmpcol;
2110                                 }
2111                         }
2112                         change = 1;
2113                 }
2114         }
2115
2116         BKE_mesh_end_editmesh(obedit->data, em);
2117
2118         if(!change)
2119                 return OPERATOR_CANCELLED;
2120
2121         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2122         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2123
2124 #endif
2125         return OPERATOR_FINISHED;
2126 }
2127
2128 void MESH_OT_uvs_rotate(wmOperatorType *ot)
2129 {
2130         /* identifiers */
2131         ot->name= "Rotate UVs";
2132         ot->idname= "MESH_OT_uvs_rotate";
2133
2134         /* api callbacks */
2135         ot->exec= mesh_rotate_uvs;
2136         ot->poll= ED_operator_editmesh;
2137
2138         /* flags */
2139         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2140
2141         /* props */
2142         RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around.");
2143 }
2144
2145 //void MESH_OT_uvs_mirror(wmOperatorType *ot)
2146 void MESH_OT_uvs_reverse(wmOperatorType *ot)
2147 {
2148         /* identifiers */
2149         ot->name= "Reverse UVs";
2150         ot->idname= "MESH_OT_uvs_reverse";
2151
2152         /* api callbacks */
2153         ot->exec= mesh_reverse_uvs;
2154         ot->poll= ED_operator_editmesh;
2155
2156         /* flags */
2157         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2158
2159         /* props */
2160         //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around.");
2161 }
2162
2163 void MESH_OT_colors_rotate(wmOperatorType *ot)
2164 {
2165         /* identifiers */
2166         ot->name= "Rotate Colors";
2167         ot->idname= "MESH_OT_colors_rotate";
2168
2169         /* api callbacks */
2170         ot->exec= mesh_rotate_colors;
2171         ot->poll= ED_operator_editmesh;
2172
2173         /* flags */
2174         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2175
2176         /* props */
2177         RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around.");
2178 }
2179
2180 void MESH_OT_colors_reverse(wmOperatorType *ot)
2181 {
2182         /* identifiers */
2183         ot->name= "Reverse Colors";
2184         ot->idname= "MESH_OT_colors_reverse";
2185
2186         /* api callbacks */
2187         ot->exec= mesh_reverse_colors;
2188         ot->poll= ED_operator_editmesh;
2189
2190         /* flags */
2191         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2192
2193         /* props */
2194         //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around.");
2195 }
2196
2197
2198 static int merge_firstlast(BMEditMesh *em, int first, int uvmerge, wmOperator *wmop)
2199 {
2200         BMVert *mergevert;
2201         BMEditSelection *ese;
2202
2203         /* do sanity check in mergemenu in edit.c ?*/
2204         if(first == 0){
2205                 ese = em->bm->selected.last;
2206                 mergevert= (BMVert*)ese->data;
2207         }
2208         else{
2209                 ese = em->bm->selected.first;
2210                 mergevert = (BMVert*)ese->data;
2211         }
2212
2213         if (!BM_TestHFlag(mergevert, BM_SELECT))
2214                 return OPERATOR_CANCELLED;
2215         
2216         if (uvmerge) {
2217                 if (!EDBM_CallOpf(em, wmop, "pointmerge_facedata verts=%hv snapv=%e", BM_SELECT, mergevert))
2218                         return OPERATOR_CANCELLED;
2219         }
2220
2221         if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_SELECT, mergevert->co))
2222                 return OPERATOR_CANCELLED;
2223
2224         return OPERATOR_FINISHED;
2225 }
2226
2227 static int merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob, 
2228                         int target, int uvmerge, wmOperator *wmop)
2229 {
2230         BMIter iter;
2231         BMVert *v;
2232         float *vco=NULL, co[3], cent[3] = {0.0f, 0.0f, 0.0f}, fac;
2233         int i;
2234
2235         if (target) {
2236                 vco = give_cursor(scene, v3d);
2237                 VECCOPY(co, vco);
2238                 mul_m4_v3(ob->imat, co);
2239         } else {
2240                 i = 0;
2241                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2242                         if (!BM_TestHFlag(v, BM_SELECT))
2243                                 continue;
2244                         VECADD(cent, cent, v->co);
2245                         i++;
2246                 }
2247                 
2248                 if (!i)
2249                         return OPERATOR_CANCELLED;
2250
2251                 fac = 1.0f / (float)i;
2252                 mul_v3_fl(cent, fac);
2253                 copy_v3_v3(co, cent);
2254                 vco = co;
2255         }
2256
2257         if (!vco)
2258                 return OPERATOR_CANCELLED;
2259         
2260         if (uvmerge) {
2261                 if (!EDBM_CallOpf(em, wmop, "vert_average_facedata verts=%hv", BM_SELECT))
2262                         return OPERATOR_CANCELLED;
2263         }
2264
2265         if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_SELECT, co))
2266                 return OPERATOR_CANCELLED;
2267
2268         return OPERATOR_FINISHED;
2269 }
2270
2271 static int merge_exec(bContext *C, wmOperator *op)
2272 {
2273         Scene *scene= CTX_data_scene(C);
2274         View3D *v3d = CTX_wm_view3d(C);
2275         Object *obedit= CTX_data_edit_object(C);
2276         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2277         int status= 0, uvs= RNA_boolean_get(op->ptr, "uvs");
2278
2279         switch(RNA_enum_get(op->ptr, "type")) {
2280                 case 3:
2281                         status = merge_target(em, scene, v3d, obedit, 0, uvs, op);
2282                         break;
2283                 case 4:
2284                         status = merge_target(em, scene, v3d, obedit, 1, uvs, op);
2285                         break;
2286                 case 1:
2287                         status = merge_firstlast(em, 0, uvs, op);
2288                         break;
2289                 case 6:
2290                         status = merge_firstlast(em, 1, uvs, op);
2291                         break;
2292                 case 5:
2293                         status = 1;
2294                         if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_SELECT))
2295                                 status = 0;
2296                         break;
2297         }
2298
2299         if(!status)
2300                 return OPERATOR_CANCELLED;
2301
2302         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2303         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2304
2305         return OPERATOR_FINISHED;
2306 }
2307
2308 static EnumPropertyItem merge_type_items[]= {
2309         {6, "FIRST", 0, "At First", ""},
2310         {1, "LAST", 0, "At Last", ""},
2311         {3, "CENTER", 0, "At Center", ""},
2312         {4, "CURSOR", 0, "At Cursor", ""},
2313         {5, "COLLAPSE", 0, "Collapse", ""},
2314         {0, NULL, 0, NULL, NULL}};
2315
2316 static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *ptr, int *free)
2317 {       
2318         Object *obedit;
2319         EnumPropertyItem *item= NULL;
2320         int totitem= 0;
2321         
2322         if(!C) /* needed for docs */
2323                 return merge_type_items;
2324         
2325         obedit= CTX_data_edit_object(C);
2326         if(obedit && obedit->type == OB_MESH) {
2327                 BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2328
2329                 if(em->selectmode & SCE_SELECT_VERTEX) {
2330                         if(em->bm->selected.first && em->bm->selected.last &&
2331                                 ((BMEditSelection*)em->bm->selected.first)->type == BM_VERT && ((BMEditSelection*)em->bm->selected.last)->type == BM_VERT) {
2332                                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
2333                                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
2334                         }
2335                         else if(em->bm->selected.first && ((BMEditSelection*)em->bm->selected.first)->type == BM_VERT)
2336                                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
2337                         else if(em->bm->selected.last && ((BMEditSelection*)em->bm->selected.last)->type == BM_VERT)
2338                                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
2339                 }
2340
2341                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3);
2342                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4);
2343                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5);
2344                 RNA_enum_item_end(&item, &totitem);
2345
2346                 *free= 1;
2347
2348                 return item;
2349         }
2350         
2351         return NULL;
2352 }
2353
2354 void MESH_OT_merge(wmOperatorType *ot)
2355 {
2356         /* identifiers */
2357         ot->name= "Merge";
2358         ot->idname= "MESH_OT_merge";
2359
2360         /* api callbacks */
2361         ot->exec= merge_exec;
2362         ot->invoke= WM_menu_invoke;
2363         ot->poll= ED_operator_editmesh;
2364
2365         /* flags */
2366         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2367
2368         /* properties */
2369         ot->prop= RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use.");
2370         RNA_def_enum_funcs(ot->prop, merge_type_itemf);
2371         RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Move UVs according to merge.");
2372 }
2373
2374
2375 static int removedoublesflag_exec(bContext *C, wmOperator *op)
2376 {
2377         Object *obedit= CTX_data_edit_object(C);
2378         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2379         BMOperator bmop;
2380         int count;
2381
2382         EDBM_InitOpf(em, &bmop, op, "finddoubles verts=%hv dist=%f", 
2383                 BM_SELECT, RNA_float_get(op->ptr, "mergedist"));
2384         BMO_Exec_Op(em->bm, &bmop);
2385
2386         count = BMO_CountSlotMap(em->bm, &bmop, "targetmapout");
2387
2388         if (!EDBM_CallOpf(em, op, "weldverts targetmap=%s", &bmop, "targetmapout")) {
2389                 BMO_Finish_Op(em->bm, &bmop);
2390                 return OPERATOR_CANCELLED;
2391         }
2392
2393         if (!EDBM_FinishOp(em, &bmop, op, 1))
2394                 return OPERATOR_CANCELLED;
2395
2396         /*we need a better way of reporting this, since this doesn't work
2397           with the last operator panel correctly.
2398         if(count)
2399         {
2400                 sprintf(msg, "Removed %d vertices", count);
2401                 BKE_report(op->reports, RPT_INFO, msg);
2402         }
2403         */
2404
2405         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2406         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2407
2408         return OPERATOR_FINISHED;
2409 }
2410
2411 void MESH_OT_remove_doubles(wmOperatorType *ot)
2412 {
2413         /* identifiers */
2414         ot->name= "Remove Doubles";
2415         ot->idname= "MESH_OT_remove_doubles";
2416
2417         /* api callbacks */
2418         ot->exec= removedoublesflag_exec;
2419         ot->poll= ED_operator_editmesh;
2420
2421         /* flags */
2422         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2423
2424         RNA_def_float(ot->srna, "mergedist", 0.0001f, 0.000001f, 50.0f, 
2425                 "Merge Distance", 
2426                 "Minimum distance between elements to merge.", 0.00001, 10.0);
2427 }
2428
2429 /************************ Vertex Path Operator *************************/
2430
2431 typedef struct PathNode {
2432         int u;
2433         int visited;
2434         ListBase edges;
2435 } PathNode;
2436
2437 typedef struct PathEdge {
2438         struct PathEdge *next, *prev;
2439         int v;
2440         float w;
2441 } PathEdge;
2442
2443
2444
2445 int select_vertex_path_exec(bContext *C, wmOperator *op)
2446 {
2447         Object *ob = CTX_data_edit_object(C);
2448         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
2449         BMOperator bmop;
2450         BMEditSelection *sv, *ev;
2451
2452         /* get the type from RNA */
2453         int type = RNA_enum_get(op->ptr, "type");
2454
2455         sv = em->bm->selected.last;
2456         if( sv != NULL )
2457                 ev = sv->prev;
2458         else return OPERATOR_CANCELLED;
2459         if( ev == NULL )
2460                 return OPERATOR_CANCELLED;
2461
2462         if( sv->type != BM_VERT || ev->type != BM_VERT )
2463                 return OPERATOR_CANCELLED;
2464
2465         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2466         EDBM_InitOpf(em, &bmop, op, "vertexshortestpath startv=%e endv=%e type=%d", sv->data, ev->data, type);
2467
2468         /* execute the operator */
2469         BMO_Exec_Op(em->bm, &bmop);
2470
2471         /* DO NOT clear the existing selection */
2472         /* EDBM_clear_flag_all(em, BM_SELECT); */
2473
2474         /* select the output */
2475         BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_ALL);
2476
2477         /* finish the operator */
2478         if( !EDBM_FinishOp(em, &bmop, op, 1) )
2479                 return OPERATOR_CANCELLED;
2480
2481         EDBM_selectmode_flush(em);
2482
2483         /* dependencies graph and notification stuff */
2484 /*      DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
2485         WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob);
2486 */
2487         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2488         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2489
2490
2491         /* we succeeded */
2492         return OPERATOR_FINISHED;
2493 #if 0
2494         Object *obedit= CTX_data_edit_object(C);
2495         EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
2496         EditVert *eve, *s, *t;
2497         EditEdge *eed;
2498         EditSelection *ese;
2499         PathEdge *newpe, *currpe;
2500         PathNode *currpn;
2501         PathNode *Q;
2502         int v, *previous, pathvert, pnindex; /*pnindex redundant?*/
2503         int unbalanced, totnodes;
2504         short physical;
2505         float *cost;
2506         Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/
2507
2508         s = t = NULL;
2509
2510         ese = ((EditSelection*)em->selected.last);
2511         if(ese && ese->type == EDITVERT && ese->prev && ese->prev->type == EDITVERT){
2512                 physical= pupmenu("Distance Method? %t|Edge Length%x1|Topological%x0");
2513
2514                 t = (EditVert*)ese->data;
2515                 s = (EditVert*)ese->prev->data;
2516
2517                 /*need to find out if t is actually reachable by s....*/
2518                 for(eve=em->verts.first; eve; eve=eve->next){
2519                         eve->f1 = 0;
2520                 }
2521
2522                 s->f1 = 1;
2523
2524                 unbalanced = 1;
2525                 totnodes = 1;
2526                 while(unbalanced){
2527                         unbalanced = 0;
2528                         for(eed=em->edges.first; eed; eed=eed->next){
2529                                 if(!eed->h){
2530                                         if(eed->v1->f1 && !eed->v2->f1){
2531                                                         eed->v2->f1 = 1;
2532                                                         totnodes++;
2533                                                         unbalanced = 1;
2534                                         }
2535                                         else if(eed->v2->f1 && !eed->v1->f1){
2536                                                         eed->v1->f1 = 1;
2537                                                         totnodes++;
2538                                                         unbalanced = 1;
2539                                         }
2540                                 }
2541                         }
2542                 }
2543
2544                 if(s->f1 && t->f1){ /* t can be reached by s */
2545                         Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes");
2546                         totnodes = 0;
2547                         for(eve=em->verts.first; eve; eve=eve->next){
2548                                 if(eve->f1){
2549                                         Q[totnodes].u = totnodes;
2550                                         Q[totnodes].edges.first = 0;
2551                                         Q[totnodes].edges.last = 0;
2552                                         Q[totnodes].visited = 0;
2553                                         eve->tmp.p = &(Q[totnodes]);
2554                                         totnodes++;
2555                                 }
2556                                 else eve->tmp.p = NULL;
2557                         }
2558
2559                         for(eed=em->edges.first; eed; eed=eed->next){
2560                                 if(!eed->h){
2561                                         if(eed->v1->f1){
2562                                                 currpn = ((PathNode*)eed->v1->tmp.p);
2563
2564                                                 newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
2565                                                 newpe->v = ((PathNode*)eed->v2->tmp.p)->u;
2566                                                 if(physical){
2567                                                                 newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
2568                                                 }
2569                                                 else newpe->w = 1;
2570                                                 newpe->next = 0;
2571                                                 newpe->prev = 0;
2572                                                 BLI_addtail(&(currpn->edges), newpe);
2573                                         }
2574                                         if(eed->v2->f1){
2575                                                 currpn = ((PathNode*)eed->v2->tmp.p);
2576                                                 newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
2577                                                 newpe->v = ((PathNode*)eed->v1->tmp.p)->u;
2578                                                 if(physical){
2579                                                                 newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
2580                                                 }
2581                                                 else newpe->w = 1;
2582                                                 newpe->next = 0;
2583                                                 newpe->prev = 0;
2584                                                 BLI_addtail(&(currpn->edges), newpe);
2585                                         }
2586                                 }
2587                         }
2588
2589                         heap = BLI_heap_new();
2590                         cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs");
2591                         previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices");
2592
2593                         for(v=0; v < totnodes; v++){
2594                                 cost[v] = 1000000;
2595                                 previous[v] = -1; /*array of indices*/
2596                         }
2597
2598                         pnindex = ((PathNode*)s->tmp.p)->u;
2599                         cost[pnindex] = 0;
2600                         BLI_heap_insert(heap,  0.0f, SET_INT_IN_POINTER(pnindex));
2601
2602                         while( !BLI_heap_empty(heap) ){
2603
2604                                 pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
2605                                 currpn = &(Q[pnindex]);
2606
2607                                 if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/
2608                                         break;
2609
2610                                 for(currpe=currpn->edges.first; currpe; currpe=currpe->next){
2611                                         if(!Q[currpe->v].visited){
2612                                                 if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){
2613                                                         cost[currpe->v] = cost[currpn->u] + currpe->w;
2614                                                         previous[currpe->v] = currpn->u;
2615                                                         Q[currpe->v].visited = 1;
2616                                                         BLI_heap_insert(heap, cost[currpe->v], SET_INT_IN_POINTER(currpe->v));
2617                                                 }
2618                                         }
2619                                 }
2620                         }
2621
2622                         pathvert = ((PathNode*)t->tmp.p)->u;
2623                         while(pathvert != -1){
2624                                 for(eve=em->verts.first; eve; eve=eve->next){
2625                                         if(eve->f1){
2626                                                 if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT;
2627                                         }
2628                                 }
2629                                 pathvert = previous[pathvert];
2630                         }
2631
2632                         for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges));
2633                         MEM_freeN(Q);
2634                         MEM_freeN(cost);
2635                         MEM_freeN(previous);
2636                         BLI_heap_free(heap, NULL);
2637                         EM_select_flush(em);
2638                 }
2639         }
2640         else {
2641                 BKE_mesh_end_editmesh(obedit->data, em);
2642                 BKE_report(op->reports, RPT_ERROR, "Path Selection requires that exactly two vertices be selected");
2643                 return OPERATOR_CANCELLED;
2644         }
2645
2646         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2647         BKE_mesh_end_editmesh(obedit->data, em);
2648 #endif
2649 }
2650
2651 void MESH_OT_select_vertex_path(wmOperatorType *ot)
2652 {
2653         static const EnumPropertyItem type_items[] = {
2654                 {VPATH_SELECT_EDGE_LENGTH, "EDGE_LENGTH", 0, "Edge Length", NULL},
2655                 {VPATH_SELECT_TOPOLOGICAL, "TOPOLOGICAL", 0, "Topological", NULL},
2656                 {0, NULL, 0, NULL, NULL}};
2657
2658         /* identifiers */
2659         ot->name= "Select Vertex Path";
2660         ot->idname= "MESH_OT_select_vertex_path";
2661
2662         /* api callbacks */
2663         ot->exec= select_vertex_path_exec;
2664         ot->invoke= WM_menu_invoke;
2665         ot->poll= ED_operator_editmesh;
2666
2667         /* flags */
2668         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2669
2670         /* properties */
2671         RNA_def_enum(ot->srna, "type", type_items, VPATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance.");
2672 }
2673 /********************** Rip Operator *************************/
2674
2675 #if 0
2676 /* helper for below */
2677 static void mesh_rip_setface(EditMesh *em, EditFace *sefa)
2678 {
2679         /* put new vertices & edges in best face */
2680         if(sefa->v1->tmp.v) sefa->v1= sefa->v1->tmp.v;
2681         if(sefa->v2->tmp.v) sefa->v2= sefa->v2->tmp.v;
2682         if(sefa->v3->tmp.v) sefa->v3= sefa->v3->tmp.v;
2683         if(sefa->v4 && sefa->v4->tmp.v) sefa->v4= sefa->v4->tmp.v;
2684
2685         sefa->e1= addedgelist(em, sefa->v1, sefa->v2, sefa->e1);
2686         sefa->e2= addedgelist(em, sefa->v2, sefa->v3, sefa->e2);
2687         if(sefa->v4) {
2688                 sefa->e3= addedgelist(em, sefa->v3, sefa->v4, sefa->e3);
2689                 sefa->e4= addedgelist(em, sefa->v4, sefa->v1, sefa->e4);
2690         }
2691         else
2692                 sefa->e3= addedgelist(em, sefa->v3, sefa->v1, sefa->e3);
2693
2694 }
2695 #endif
2696
2697 /* helper to find edge for edge_rip */
2698 static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, short *mval)
2699 {
2700         float vec1[3], vec2[3], mvalf[2];
2701
2702         view3d_project_float(ar, co1, vec1, mat);
2703         view3d_project_float(ar, co2, vec2, mat);
2704         mvalf[0]= (float)mval[0];
2705         mvalf[1]= (float)mval[1];
2706
2707         return dist_to_line_segment_v2(mvalf, vec1, vec2);
2708 }
2709
2710 /* based on mouse cursor position, it defines how is being ripped */
2711 static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
2712 {
2713         Object *obedit= CTX_data_edit_object(C);
2714         ARegion *ar= CTX_wm_region(C);
2715         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2716         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2717         BMOperator bmop;
2718         BMBVHTree *bvhtree;
2719         BMOIter siter;
2720         BMIter iter, eiter, liter;
2721         BMLoop *l;
2722         BMEdge *e, *e2, *closest = NULL;
2723         BMVert *v;
2724         int side = 0, i, singlesel = 0;
2725         float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1], 0.0f};
2726         float dist = FLT_MAX, d;
2727
2728         view3d_get_object_project_mat(rv3d, obedit, projectMat);
2729
2730         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2731                 if (BM_TestHFlag(e, BM_SELECT))
2732                         BMINDEX_SET(e, 1);
2733                 else BMINDEX_SET(e, 0);
2734         }
2735
2736         /*handle case of one vert selected.  we identify
2737           the closest edge around that vert to the mouse cursor,
2738           then rip the two adjacent edges in the vert fan.*/
2739         if (em->bm->totvertsel == 1 && em->bm->totedgesel == 0 && em->bm->totfacesel == 0) {
2740                 singlesel = 1;
2741
2742                 /*find selected vert*/
2743                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2744                         if (BM_TestHFlag(v, BM_SELECT))
2745                                 break;
2746                 }
2747
2748                 /*this should be impossible, but sanity checks are a good thing*/
2749                 if (!v)
2750                         return OPERATOR_CANCELLED;
2751
2752                 /*find closest edge to mouse cursor*/
2753                 e2 = NULL;
2754                 BM_ITER(e, &iter, em->bm, BM_EDGES_OF_VERT, v) {
2755                         d = mesh_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, event->mval);
2756                         if (d < dist) {
2757                                 dist = d;
2758                                 e2 = e;
2759                         }
2760                 }
2761
2762                 if (!e2)
2763                         return OPERATOR_CANCELLED;
2764
2765                 /*rip two adjacent edges*/
2766                 if (BM_Edge_FaceCount(e2) == 1) {
2767                         l = e2->l;
2768                         e = BM_OtherFaceLoop(e2, l->f, v)->e;
2769
2770                         BMINDEX_SET(e, 1);
2771                         BM_SetHFlag(e, BM_SELECT);
2772                 } else if (BM_Edge_FaceCount(e2) == 2) {
2773                         l = e2->l;
2774                         e = BM_OtherFaceLoop(e2, l->f, v)->e;
2775                         BMINDEX_SET(e, 1);
2776                         BM_SetHFlag(e, BM_SELECT);
2777                         
2778                         l = e2->l->radial_next;
2779                         e = BM_OtherFaceLoop(e2, l->f, v)->e;
2780                         BMINDEX_SET(e, 1);
2781                         BM_SetHFlag(e, BM_SELECT);
2782                 }
2783
2784                 dist = FLT_MAX;
2785         } else {
2786                 /*expand edge selection*/
2787                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2788                         e2 = NULL;
2789                         i = 0;
2790                         BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
2791                                 if (BMINDEX_GET(e)) {
2792                                         e2 = e;
2793                                         i++;
2794                                 }
2795                         }
2796                         
2797                         if (i == 1 && e2->l) {
2798                                 l = BM_OtherFaceLoop(e2, e2->l->f, v);
2799                                 l = (BMLoop*)l->radial_next;
2800                                 l = BM_OtherFaceLoop(l->e, l->f, v);
2801
2802                                 if (l)
2803                                         BM_Select(em->bm, l->e, 1);
2804                         }
2805                 }
2806         }
2807
2808         if (!EDBM_InitOpf(em, &bmop, op, "edgesplit edges=%he", BM_SELECT)) {
2809                 return OPERATOR_CANCELLED;
2810         }
2811         
2812         BMO_Exec_Op(em->bm, &bmop);
2813
2814         /*build bvh tree for edge visibility tests*/
2815         bvhtree = BMBVH_NewBVH(em);
2816
2817         for (i=0; i<2; i++) {
2818                 BMO_ITER(e, &siter, em->bm, &bmop, i ? "edgeout2":"edgeout1", BM_EDGE) {
2819                         float cent[3] = {0, 0, 0}, mid[4], vec[3];
2820
2821                         if (!BMBVH_EdgeVisible(bvhtree, e, rv3d, obedit) || !e->l)
2822                                 continue;
2823
2824                         /*method for calculating distance:
2825                         
2826                           for each edge: calculate face center, then made a vector
2827                           from edge midpoint to face center.  offset edge midpoint
2828                           by a small amount along this vector.*/
2829                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, e->l->f) {
2830                                 add_v3_v3v3(cent, cent, l->v->co);
2831                         }
2832                         mul_v3_fl(cent, 1.0f/(float)e->l->f->len);
2833
2834                         add_v3_v3v3(mid, e->v1->co, e->v2->co);
2835                         mul_v3_fl(mid, 0.5f);
2836                         sub_v3_v3v3(vec, cent, mid);
2837                         normalize_v3(vec);
2838                         mul_v3_fl(vec, 0.01f);
2839                         add_v3_v3v3(mid, mid, vec);
2840
2841                         /*yay we have our comparison point, now project it*/
2842                         view3d_project_float(ar, mid, mid, projectMat);
2843
2844                         vec[0] = fmval[0] - mid[0];
2845                         vec[1] = fmval[1] - mid[1];
2846                         d = vec[0]*vec[0] + vec[1]*vec[1];
2847
2848                         if (d < dist) {
2849                                 side = i;
2850                                 closest = e;
2851                                 dist = d;
2852                         }
2853                 }
2854         }
2855
2856         EDBM_clear_flag_all(em, BM_SELECT);
2857         BMO_HeaderFlag_Buffer(em->bm, &bmop, side?"edgeout2":"edgeout1", BM_SELECT, BM_EDGE);
2858
2859         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2860                 if (BM_TestHFlag(e, BM_SELECT))
2861                         BMINDEX_SET(e, 1);
2862                 else BMINDEX_SET(e, 0);
2863         }
2864
2865         /*constrict edge selection again*/
2866         BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2867                 e2 = NULL;
2868                 i = 0;
2869                 BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
2870                         if (BMINDEX_GET(e)) {
2871                                 e2 = e;
2872                                 i++;
2873                         }
2874                 }
2875                 
2876                 if (i == 1)  {
2877                         if (singlesel)
2878                                 BM_Select(em->bm, v, 0);
2879                         else
2880                                 BM_Select(em->bm, e2, 0);
2881                 }
2882         }
2883
2884         EDBM_selectmode_flush(em);
2885         
2886         if (!EDBM_FinishOp(em, &bmop, op, 1)) {
2887                 BMBVH_FreeBVH(bvhtree);
2888                 return OPERATOR_CANCELLED;
2889         }
2890         
2891         BMBVH_FreeBVH(bvhtree);
2892
2893         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2894         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2895
2896         return OPERATOR_FINISHED;
2897 #if 0 //BMESH_TODO
2898         ARegion *ar= CTX_wm_region(C);
2899         RegionView3D *rv3d= ar->regiondata;
2900         Object *obedit= CTX_data_edit_object(C);
2901         EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
2902         EditVert *eve, *nextve;
2903         EditEdge *eed, *seed= NULL;
2904         EditFace *efa, *sefa= NULL;
2905         float projectMat[4][4], vec[3], dist, mindist;
2906         short doit= 1, *mval= event->mval;
2907
2908         /* select flush... vertices are important */
2909         EM_selectmode_set(em);
2910
2911         view3d_get_object_project_mat(rv3d, obedit, projectMat);
2912
2913         /* find best face, exclude triangles and break on face select or faces with 2 edges select */
2914         mindist= 1000000.0f;
2915         for(efa= em->faces.first; efa; efa=efa->next) {
2916                 if( efa->f & 1)
2917                         break;
2918                 if(efa->v4 && faceselectedOR(efa, SELECT) ) {
2919                         int totsel=0;
2920
2921                         if(efa->e1->f & SELECT) totsel++;
2922                         if(efa->e2->f & SELECT) totsel++;
2923                         if(efa->e3->f & SELECT) totsel++;
2924                         if(efa->e4->f & SELECT) totsel++;
2925
2926                         if(totsel>1)
2927                                 break;
2928                         view3d_project_float(ar, efa->cent, vec, projectMat);
2929                         dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) );
2930                         if(dist<mindist) {
2931                                 mindist= dist;
2932                                 sefa= efa;
2933                         }
2934                 }
2935         }
2936
2937         if(efa) {
2938                 BKE_report(op->reports, RPT_ERROR, "Can't perform ripping with faces selected this way");
2939                 BKE_mesh_end_editmesh(obedit->data, em);
2940                 return OPERATOR_CANCELLED;
2941         }
2942         if(sefa==NULL) {
2943                 BKE_report(op->reports, RPT_ERROR, "No proper selection or faces included");
2944                 BKE_mesh_end_editmesh(obedit->data, em);
2945                 return OPERATOR_CANCELLED;
2946         }
2947
2948
2949         /* duplicate vertices, new vertices get selected */
2950         for(eve = em->verts.last; eve; eve= eve->prev) {
2951                 eve->tmp.v = NULL;
2952                 if(eve->f & SELECT) {
2953                         eve->tmp.v = addvertlist(em, eve->co, eve);
2954                         eve->f &= ~SELECT;
2955                         eve->tmp.v->f |= SELECT;
2956                 }
2957         }
2958
2959         /* find the best candidate edge */
2960         /* or one of sefa edges is selected... */
2961         if(sefa->e1->f & SELECT) seed= sefa->e2;
2962         if(sefa->e2->f & SELECT) seed= sefa->e1;
2963         if(sefa->e3->f & SELECT) seed= sefa->e2;
2964         if(sefa->e4 && sefa->e4->f & SELECT) seed= sefa->e3;
2965
2966         /* or we do the distance trick */
2967         if(seed==NULL) {
2968                 mindist= 1000000.0f;
2969                 if(sefa->e1->v1->tmp.v || sefa->e1->v2->tmp.v) {
2970                         dist = mesh_rip_edgedist(ar, projectMat,
2971                                                                          sefa->e1->v1->co,
2972                                                                          sefa->e1->v2->co, mval);
2973                         if(dist<mindist) {
2974                                 seed= sefa->e1;
2975                                 mindist= dist;
2976                         }
2977                 }
2978                 if(sefa->e2->v1->tmp.v || sefa->e2->v2->tmp.v) {
2979                         dist = mesh_rip_edgedist(ar, projectMat,
2980                                                                          sefa->e2->v1->co,
2981                                                                          sefa->e2->v2->co, mval);
2982                         if(dist<mindist) {
2983                                 seed= sefa->e2;
2984                                 mindist= dist;
2985                         }
2986                 }
2987                 if(sefa->e3->v1->tmp.v || sefa->e3->v2->tmp.v) {
2988                         dist= mesh_rip_edgedist(ar, projectMat,
2989                                                                         sefa->e3->v1->co,
2990                                                                         sefa->e3->v2->co, mval);
2991                         if(dist<mindist) {
2992                                 seed= sefa->e3;
2993                                 mindist= dist;
2994                         }
2995                 }
2996                 if(sefa->e4 && (sefa->e4->v1->tmp.v || sefa->e4->v2->tmp.v)) {
2997                         dist= mesh_rip_edgedist(ar, projectMat,
2998                                                                         sefa->e4->v1->co,
2999                                                                         sefa->e4->v2->co, mval);
3000                         if(dist<mindist) {
3001                                 seed= sefa->e4;
3002                                 mindist= dist;
3003                         }
3004                 }
3005         }
3006
3007         if(seed==NULL) {        // never happens?
3008                 BKE_report(op->reports, RPT_ERROR, "No proper edge found to start");
3009                 BKE_mesh_end_editmesh(obedit->data, em);
3010                 return OPERATOR_CANCELLED;
3011         }
3012
3013         faceloop_select(em, seed, 2);   // tmp abuse for finding all edges that need duplicated, returns OK faces with f1
3014
3015         /* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */
3016         for(eed = em->edges.last; eed; eed= eed->prev) {
3017                 eed->tmp.v = NULL;
3018                 if((eed->v1->tmp.v) || (eed->v2->tmp.v)) {
3019                         EditEdge *newed;
3020
3021                         newed= addedgelist(em, eed->v1->tmp.v?eed->v1->tmp.v:eed->v1,
3022                                                            eed->v2->tmp.v?eed->v2->tmp.v:eed->v2, eed);
3023                         if(eed->f & SELECT) {
3024                                 EM_select_edge(eed, 0);
3025                                 EM_remove_selection(em, eed, EDITEDGE);
3026                                 EM_select_edge(newed, 1);
3027                         }
3028                         eed->tmp.v = (EditVert *)newed;
3029                 }
3030         }
3031
3032         /* first clear edges to help finding neighbours */
3033         for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
3034
3035         /* put new vertices & edges && flag in best face */
3036         mesh_rip_setface(em, sefa);
3037
3038         /* starting with neighbours of best face, we loop over the seam */
3039         sefa->f1= 2;
3040         doit= 1;
3041         while(doit) {
3042                 doit= 0;
3043
3044                 for(efa= em->faces.first; efa; efa=efa->next) {
3045                         /* new vert in face */
3046                         if (efa->v1->tmp.v || efa->v2->tmp.v ||
3047                                 efa->v3->tmp.v || (efa->v4 && efa->v4->tmp.v)) {
3048                                 /* face is tagged with loop */
3049                                 if(efa->f1==1) {
3050                                         mesh_rip_setface(em, efa);
3051                                         efa->f1= 2;
3052                                         doit= 1;
3053                                 }
3054                         }
3055                 }
3056         }
3057
3058         /* remove loose edges, that were part of a ripped face */
3059         for(eve = em->verts.first; eve; eve= eve->next) eve->f1= 0;
3060         for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
3061         for(efa= em->faces.first; efa; efa=efa->next) {
3062                 efa->e1->f1= 1;
3063                 efa->e2->f1= 1;
3064                 efa->e3->f1= 1;
3065                 if(efa->e4) efa->e4->f1= 1;
3066         }
3067
3068         for(eed = em->edges.last; eed; eed= seed) {
3069                 seed= eed->prev;
3070                 if(eed->f1==0) {
3071                         if(eed->v1->tmp.v || eed->v2->tmp.v ||
3072                            (eed->v1->f & SELECT) || (eed->v2->f & SELECT)) {
3073                                 remedge(em, eed);
3074                                 free_editedge(em, eed);
3075                                 eed= NULL;
3076                         }
3077                 }
3078                 if(eed) {
3079                         eed->v1->f1= 1;
3080                         eed->v2->f1= 1;
3081                 }
3082         }
3083
3084         /* and remove loose selected vertices, that got duplicated accidentally */
3085         for(eve = em->verts.first; eve; eve= nextve) {
3086                 nextve= eve->next;
3087                 if(eve->f1==0 && (eve->tmp.v || (eve->f & SELECT))) {
3088                         BLI_remlink(&em->verts,eve);
3089                         free_editvert(em, eve);
3090                 }
3091         }
3092
3093         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
3094         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
3095
3096         BKE_mesh_end_editmesh(obedit->data, em);
3097
3098 //      RNA_enum_set(op->ptr, "proportional", 0);
3099 //      RNA_boolean_set(op->ptr, "mirror", 0);
3100 //      WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
3101 #endif
3102 }
3103
3104 void MESH_OT_rip(wmOperatorType *ot)
3105 {
3106         /* identifiers */
3107         ot->name= "Rip";
3108         ot->idname= "MESH_OT_rip";
3109
3110         /* api callbacks */
3111         ot->invoke= mesh_rip_invoke;
3112         ot->poll= EM_view3d_poll;
3113
3114         /* flags */
3115         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3116
3117         /* to give to transform */
3118         Transform_Properties(ot, P_PROPORTIONAL);
3119         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
3120 }
3121
3122 /************************ Shape Operators *************************/
3123
3124 /*BMESH_TODO this should be properly encapsulated in a bmop.  but later.*/
3125 static void shape_propagate(Object *obedit, BMEditMesh *em, wmOperator *op)
3126 {
3127         BMIter iter;
3128         BMVert *eve = NULL;
3129         float *co;
3130         int i, totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
3131
3132         if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
3133                 BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys");
3134                 return;
3135         }
3136         
3137         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
3138                 if (!BM_TestHFlag(eve, BM_SELECT) || BM_TestHFlag(eve, BM_HIDDEN))
3139                         continue;
3140
3141                 for (i=0; i<totshape; i++) {
3142                         co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i);
3143                         VECCOPY(co, eve->co);
3144                 }
3145         }
3146
3147 #if 0
3148         //TAG Mesh Objects that share this data
3149         for(base = scene->base.first; base; base = base->next){
3150                 if(base->object && base->object->data == me){
3151                         base->object->recalc = OB_RECALC_DATA;
3152                 }
3153         }
3154 #endif
3155
3156         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
3157 }
3158
3159
3160 static int shape_propagate_to_all_exec(bContext *C, wmOperator *op)
3161 {
3162         Object *obedit= CTX_data_edit_object(C);
3163         Mesh *me= obedit->data;
3164         BMEditMesh *em= me->edit_btmesh;
3165
3166         shape_propagate(obedit, em, op);
3167
3168         DAG_id_tag_update(&me->id, OB_RECALC_DATA);
3169         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
3170
3171         return OPERATOR_FINISHED;
3172 }
3173
3174
3175 void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
3176 {
3177         /* identifiers */
3178         ot->name= "Shape Propagate";
3179         ot->description= "Apply selected vertex locations to all other shape keys.";
3180         ot->idname= "MESH_OT_shape_propagate_to_all";
3181
3182         /* api callbacks */
3183         ot->exec= shape_propagate_to_all_exec;
3184         ot->poll= ED_operator_editmesh;
3185
3186         /* flags */
3187         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3188 }
3189
3190 /*BMESH_TODO this should be properly encapsulated in a bmop.  but later.*/
3191 static int blend_from_shape_exec(bContext *C, wmOperator *op)
3192 {
3193         Object *obedit= CTX_data_edit_object(C);
3194         Mesh *me= obedit->data;
3195         BMEditMesh *em= me->edit_btmesh;
3196         BMVert *eve;
3197         BMIter iter;
3198         float co[3], *sco;
3199         float blend= RNA_float_get(op->ptr, "blend");
3200         int shape= RNA_enum_get(op->ptr, "shape");
3201         int add= RNA_int_get(op->ptr, "add");
3202         int totshape;
3203
3204         /*sanity check*/
3205         totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
3206         if (totshape == 0 || shape < 0 || shape >= totshape)
3207                 return OPERATOR_CANCELLED;
3208
3209         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
3210                 if (!BM_TestHFlag(eve, BM_SELECT) || BM_TestHFlag(eve, BM_HIDDEN))
3211                         continue;
3212
3213                 sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
3214                 VECCOPY(co, sco);
3215
3216
3217                 if(add) {
3218                         mul_v3_fl(co, blend);
3219                         add_v3_v3v3(eve->co, eve->co, co);
3220                 }
3221                 else
3222                         interp_v3_v3v3(eve->co, eve->co, co, blend);
3223                 
3224                 VECCOPY(sco, co);
3225         }
3226
3227         DAG_id_tag_update(&me->id, OB_RECALC_DATA);
3228         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
3229
3230         return OPERATOR_FINISHED;
3231 }
3232
3233 static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *ptr, int *free)
3234 {       
3235         Object *obedit= CTX_data_edit_object(C);
3236         Mesh *me= (obedit) ? obedit->data : NULL;
3237         BMEditMesh *em = me->edit_btmesh;
3238         EnumPropertyItem tmp= {0, "", 0, "", ""}, *item= NULL;
3239         int totitem= 0, a;
3240
3241         if(obedit && obedit->type == OB_MESH && CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
3242                 for (a=0; a<em->bm->vdata.totlayer; a++) {
3243                         if (em->bm->vdata.layers[a].type != CD_SHAPEKEY)
3244                                 continue;
3245
3246                         tmp.value= totitem;
3247                         tmp.identifier= em->bm->vdata.layers[a].name;
3248                         tmp.name= em->bm->vdata.layers[a].name;
3249                         RNA_enum_item_add(&item, &totitem, &tmp);
3250
3251                         totitem++;
3252                 }
3253         }
3254
3255         RNA_enum_item_end(&item, &totitem);
3256         *free= 1;
3257
3258         return item;
3259 }
3260
3261 void MESH_OT_blend_from_shape(wmOperatorType *ot)
3262 {
3263         PropertyRNA *prop;
3264         static EnumPropertyItem shape_items[]= {{0, NULL, 0, NULL, NULL}};
3265
3266         /* identifiers */
3267         ot->name= "Blend From Shape";
3268         ot->description= "Blend in shape from a shape key.";
3269         ot->idname= "MESH_OT_blend_from_shape";
3270
3271         /* api callbacks */
3272         ot->exec= blend_from_shape_exec;
3273         ot->invoke= WM_operator_props_popup;
3274         ot->poll= ED_operator_editmesh;
3275
3276         /* flags */
3277         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3278
3279         /* properties */
3280         prop= RNA_def_enum(ot->srna, "shape", shape_items, 0, "Shape", "Shape key to use for blending.");
3281         RNA_def_enum_funcs(prop, shape_itemf);
3282         RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor.", -2.0f, 2.0f);
3283         RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather then blend between shapes.");
3284 }
3285
3286 /* TODO - some way to select on an arbitrary axis */
3287 static int select_axis_exec(bContext *C, wmOperator *op)
3288 {
3289         Object *obedit= CTX_data_edit_object(C);
3290         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
3291         BMEditSelection *ese = em->bm->selected.last;
3292         int axis= RNA_int_get(op->ptr, "axis");