remove mesh and object arguments from bmesh operators, these are stored within the...
[blender-staging.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
49 #include "RNA_types.h"
50 #include "RNA_define.h"
51 #include "RNA_access.h"
52
53 #include "BLI_utildefines.h"
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 #include "BLI_smallhash.h"
63
64 #include "BKE_material.h"
65 #include "BKE_context.h"
66 #include "BKE_customdata.h"
67 #include "BKE_DerivedMesh.h"
68 #include "BKE_cdderivedmesh.h"
69 #include "BKE_depsgraph.h"
70 #include "BKE_global.h"
71 #include "BKE_library.h"
72 #include "BKE_mesh.h"
73 #include "BKE_object.h"
74 #include "BKE_bmesh.h"
75 #include "BKE_report.h"
76 #include "BKE_tessmesh.h"
77 #include "BKE_texture.h"
78 #include "BKE_main.h"
79
80 #include "BIF_gl.h"
81 #include "BIF_glutil.h"
82
83 #include "WM_api.h"
84 #include "WM_types.h"
85
86 #include "ED_mesh.h"
87 #include "ED_view3d.h"
88 #include "ED_util.h"
89 #include "ED_screen.h"
90 #include "ED_transform.h"
91 #include "ED_object.h"
92
93 #include "UI_interface.h"
94
95 #include "RE_render_ext.h"
96
97 #include "mesh_intern.h"
98 #include "bmesh.h"
99
100 #include "editbmesh_bvh.h"
101
102 static void add_normal_aligned(float *nor, float *add)
103 {
104         if( INPR(nor, add) < -0.9999f)
105                 sub_v3_v3v3(nor, nor, add);
106         else
107                 add_v3_v3v3(nor, nor, add);
108 }
109
110
111 static int subdivide_exec(bContext *C, wmOperator *op)
112 {
113         ToolSettings *ts = CTX_data_tool_settings(C);
114         Object *obedit= CTX_data_edit_object(C);
115         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
116         int cuts= RNA_int_get(op->ptr,"number_cuts");
117         float fractal= RNA_float_get(op->ptr, "fractal")/2.5;
118         int flag= 0;
119
120         if(fractal != 0.0f)
121                 flag |= B_FRACTAL;
122         
123         if (RNA_boolean_get(op->ptr, "quadtri") && 
124             RNA_enum_get(op->ptr, "quadcorner") == SUBD_STRAIGHT_CUT)
125         {
126                 RNA_enum_set(op->ptr, "quadcorner", SUBD_INNERVERT);    
127         }
128         
129         BM_esubdivideflag(obedit, em->bm, BM_SELECT, 
130                           0.0f, fractal, 
131                           ts->editbutflag|flag, 
132                           cuts, 0, RNA_enum_get(op->ptr, "quadcorner"), 
133                           RNA_boolean_get(op->ptr, "quadtri"),
134                           1, RNA_int_get(op->ptr, "seed"));
135
136         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
137         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
138
139         return OPERATOR_FINISHED;
140 }
141
142 /* Note, these values must match delete_mesh() event values */
143 static EnumPropertyItem prop_mesh_cornervert_types[] = {
144         {SUBD_INNERVERT,     "INNERVERT", 0,      "Inner Vert", ""},
145         {SUBD_PATH,          "PATH", 0,           "Path", ""},
146         {SUBD_STRAIGHT_CUT,  "STRAIGHT_CUT", 0,   "Straight Cut", ""},
147         {SUBD_FAN,           "FAN", 0,            "Fan", ""},
148         {0, NULL, 0, NULL, NULL}
149 };
150
151 void MESH_OT_subdivide(wmOperatorType *ot)
152 {
153         /* identifiers */
154         ot->name= "Subdivide";
155         ot->description= "Subdivide selected edges.";
156         ot->idname= "MESH_OT_subdivide";
157
158         /* api callbacks */
159         ot->exec= subdivide_exec;
160         ot->poll= ED_operator_editmesh;
161
162         /* flags */
163         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
164
165         /* properties */
166         RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
167
168         RNA_def_boolean(ot->srna, "quadtri", 0, "Quad/Tri Mode", "Tries to prevent ngons");
169         RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_STRAIGHT_CUT, "Quad Corner Type", "How to subdivide quad corners (anything other then Straight Cut will prevent ngons)");
170
171         RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
172         RNA_def_int(ot->srna, "seed", 0, 0, 10000, "Random Seed", "Seed for the random number generator", 0, 50);
173 }
174
175
176 void EMBM_project_snap_verts(bContext *C, ARegion *ar, Object *obedit, BMEditMesh *em)
177 {
178         BMIter iter;
179         BMVert *eve;
180
181         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
182                 if (BM_TestHFlag(eve, BM_SELECT)) {
183                         float mval[2], vec[3], no_dummy[3];
184                         int dist_dummy;
185                         mul_v3_m4v3(vec, obedit->obmat, eve->co);
186                         project_float_noclip(ar, vec, mval);
187                         if(snapObjectsContext(C, mval, &dist_dummy, vec, no_dummy, SNAP_NOT_OBEDIT)) {
188                                 mul_v3_m4v3(eve->co, obedit->imat, vec);
189                         }
190                 }
191         }
192 }
193
194
195 /* individual face extrude */
196 /* will use vertex normals for extrusion directions, so *nor is unaffected */
197 static short EDBM_Extrude_face_indiv(BMEditMesh *em, wmOperator *op, short flag, float *UNUSED(nor)) 
198 {
199         BMOIter siter;
200         BMIter liter;
201         BMFace *f;
202         BMLoop *l;
203         BMOperator bmop;
204
205         EDBM_InitOpf(em, &bmop, op, "extrude_face_indiv faces=%hf", flag);
206
207         /*deselect original verts*/
208         EDBM_clear_flag_all(em, BM_SELECT);
209
210         BMO_Exec_Op(em->bm, &bmop);
211         
212         BMO_ITER(f, &siter, em->bm, &bmop, "faceout", BM_FACE) {
213                 BM_Select(em->bm, f, 1);
214
215                 /*set face vertex normals to face normal*/
216                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
217                         VECCOPY(l->v->no, f->no);
218                 }
219         }
220
221         if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
222
223         return 's'; // s is shrink/fatten
224 }
225
226 #if 0
227 short EDBM_Extrude_face_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) 
228         EditVert *eve, *v1, *v2, *v3, *v4;
229         EditEdge *eed;
230         EditFace *efa, *nextfa;
231         
232         if(em==NULL) return 0;
233         
234         /* selected edges with 1 or more selected face become faces */
235         /* selected faces each makes new faces */
236         /* always remove old faces, keeps volumes manifold */
237         /* select the new extrusion, deselect old */
238         
239         /* step 1; init, count faces in edges */
240         recalc_editnormals(em);
241         
242         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;      // new select flag
243
244         for(eed= em->edges.first; eed; eed= eed->next) {
245                 eed->f2= 0; // amount of unselected faces
246         }
247         for(efa= em->faces.first; efa; efa= efa->next) {
248                 if(efa->f & SELECT);
249                 else {
250                         efa->e1->f2++;
251                         efa->e2->f2++;
252                         efa->e3->f2++;
253                         if(efa->e4) efa->e4->f2++;
254                 }
255         }
256
257         /* step 2: make new faces from faces */
258         for(efa= em->faces.last; efa; efa= efa->prev) {
259                 if(efa->f & SELECT) {
260                         v1= addvertlist(em, efa->v1->co, efa->v1);
261                         v2= addvertlist(em, efa->v2->co, efa->v2);
262                         v3= addvertlist(em, efa->v3->co, efa->v3);
263                         
264                         v1->f1= v2->f1= v3->f1= 1;
265                         VECCOPY(v1->no, efa->n);
266                         VECCOPY(v2->no, efa->n);
267                         VECCOPY(v3->no, efa->n);
268                         if(efa->v4) {
269                                 v4= addvertlist(em, efa->v4->co, efa->v4); 
270                                 v4->f1= 1;
271                                 VECCOPY(v4->no, efa->n);
272                         }
273                         else v4= NULL;
274                         
275                         /* side faces, clockwise */
276                         addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL);
277                         addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL);
278                         if(efa->v4) {
279                                 addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL);
280                                 addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL);
281                         }
282                         else {
283                                 addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL);
284                         }
285                         /* top face */
286                         addfacelist(em, v1, v2, v3, v4, efa, NULL);
287                 }
288         }
289         
290         /* step 3: remove old faces */
291         efa= em->faces.first;
292         while(efa) {
293                 nextfa= efa->next;
294                 if(efa->f & SELECT) {
295                         BLI_remlink(&em->faces, efa);
296                         free_editface(em, efa);
297                 }
298                 efa= nextfa;
299         }
300
301         /* step 4: redo selection */
302         EM_clear_flag_all(em, SELECT);
303         
304         for(eve= em->verts.first; eve; eve= eve->next) {
305                 if(eve->f1)  eve->f |= SELECT;
306         }
307         
308         EM_select_flush(em);
309         
310         return 'n';
311 }
312 #endif
313
314 /* extrudes individual edges */
315 static short EDBM_Extrude_edges_indiv(BMEditMesh *em, wmOperator *op, short flag, float *UNUSED(nor)) 
316 {
317         BMOperator bmop;
318
319         EDBM_InitOpf(em, &bmop, op, "extrude_edge_only edges=%he", flag);
320
321         /*deselect original verts*/
322         EDBM_clear_flag_all(em, BM_SELECT);
323
324         BMO_Exec_Op(em->bm, &bmop);
325         BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_VERT|BM_EDGE);
326
327         if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
328
329         return 'n'; // n is normal grab
330 }
331
332 #if 0
333 /* nor is filled with constraint vector */
334 short EDBM_Extrude_edges_indiv(BMEditMesh *em, short flag, float *nor) 
335 {
336         EditVert *eve;
337         EditEdge *eed;
338         EditFace *efa;
339         
340         for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL;
341         for(eed= em->edges.first; eed; eed= eed->next) {
342                 eed->tmp.f = NULL;
343                 eed->f2= ((eed->f & flag)!=0);
344         }
345         
346         set_edge_directions_f2(em, 2);
347
348         /* sample for next loop */
349         for(efa= em->faces.first; efa; efa= efa->next) {
350                 efa->e1->tmp.f = efa;
351                 efa->e2->tmp.f = efa;
352                 efa->e3->tmp.f = efa;
353                 if(efa->e4) efa->e4->tmp.f = efa;
354         }
355         /* make the faces */
356         for(eed= em->edges.first; eed; eed= eed->next) {
357                 if(eed->f & flag) {
358                         if(eed->v1->tmp.v == NULL)
359                                 eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
360                         if(eed->v2->tmp.v == NULL)
361                                 eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
362
363                         if(eed->dir==1) 
364                                 addfacelist(em, eed->v1, eed->v2, 
365                                                         eed->v2->tmp.v, eed->v1->tmp.v, 
366                                                         eed->tmp.f, NULL);
367                         else 
368                                 addfacelist(em, eed->v2, eed->v1, 
369                                                         eed->v1->tmp.v, eed->v2->tmp.v, 
370                                                         eed->tmp.f, NULL);
371
372                         /* for transform */
373                         if(eed->tmp.f) {
374                                 efa = eed->tmp.f;
375                                 if (efa->f & SELECT) add_normal_aligned(nor, efa->n);
376                         }
377                 }
378         }
379         normalize_v3(nor);
380         
381         /* set correct selection */
382         EM_clear_flag_all(em, SELECT);
383         for(eve= em->verts.last; eve; eve= eve->prev) {
384                 if(eve->tmp.v) {
385                         eve->tmp.v->f |= flag;
386                 }
387         }
388
389         for(eed= em->edges.first; eed; eed= eed->next) {
390                 if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
391         }
392         
393         if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab
394         return 'n';  // n is for normal constraint
395 }
396 #endif
397
398 /* extrudes individual vertices */
399 static short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float *UNUSED(nor)) 
400 {
401         BMOperator bmop;
402
403         EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", flag);
404
405         /*deselect original verts*/
406         BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "verts", BM_SELECT, BM_VERT);
407
408         BMO_Exec_Op(em->bm, &bmop);
409         BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_VERT);
410
411         if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
412
413         return 'g'; // g is grab
414 }
415
416 static short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int flag, float *nor)
417 {
418         BMesh *bm = em->bm;
419         BMIter iter;
420         BMOIter siter;
421         BMOperator extop;
422         BMVert *vert;
423         BMEdge *edge;
424         BMFace *f;
425         ModifierData *md;
426         BMHeader *el;
427         
428         BMO_Init_Op(&extop, "extrudefaceregion");
429         BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein",
430                                flag, BM_VERT|BM_EDGE|BM_FACE);
431
432         /* If a mirror modifier with clipping is on, we need to adjust some 
433          * of the cases above to handle edges on the line of symmetry.
434          */
435         md = obedit->modifiers.first;
436         for (; md; md=md->next) {
437                 if (md->type==eModifierType_Mirror) {
438                         MirrorModifierData *mmd = (MirrorModifierData*) md;     
439                 
440                         if(mmd->flag & MOD_MIR_CLIPPING) {
441                                 float mtx[4][4];
442                                 if (mmd->mirror_ob) {
443                                         float imtx[4][4];
444                                         invert_m4_m4(imtx, mmd->mirror_ob->obmat);
445                                         mul_m4_m4m4(mtx, obedit->obmat, imtx);
446                                 }
447
448                                 for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL);
449                                      edge; edge=BMIter_Step(&iter))
450                                 {
451                                         if(edge->head.flag & flag) {
452                                                 float co1[3], co2[3];
453
454                                                 copy_v3_v3(co1, edge->v1->co);
455                                                 copy_v3_v3(co2, edge->v2->co);
456
457                                                 if (mmd->mirror_ob) {
458                                                         mul_v3_m4v3(co1, mtx, co1);
459                                                         mul_v3_m4v3(co2, mtx, co2);
460                                                 }
461
462                                                 if (mmd->flag & MOD_MIR_AXIS_X)
463                                                         if ( (fabs(co1[0]) < mmd->tolerance) &&
464                                                                  (fabs(co2[0]) < mmd->tolerance) )
465                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
466
467                                                 if (mmd->flag & MOD_MIR_AXIS_Y)
468                                                         if ( (fabs(co1[1]) < mmd->tolerance) &&
469                                                                  (fabs(co2[1]) < mmd->tolerance) )
470                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
471
472                                                 if (mmd->flag & MOD_MIR_AXIS_Z)
473                                                         if ( (fabs(co1[2]) < mmd->tolerance) &&
474                                                                  (fabs(co2[2]) < mmd->tolerance) )
475                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
476                                         }
477                                 }
478                         }
479                 }
480         }
481
482         BM_ITER(vert, &iter, bm, BM_VERTS_OF_MESH, NULL) {
483                 BM_Select(bm, vert, 0);
484         }
485
486         BM_ITER(edge, &iter, bm, BM_EDGES_OF_MESH, NULL) {
487                 BM_Select(bm, edge, 0);
488         }
489
490         BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
491                 BM_Select(bm, f, 0);
492         }
493
494         BMO_Exec_Op(bm, &extop);
495
496         nor[0] = nor[1] = nor[2] = 0.0f;
497         
498         BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) {
499                 BM_Select(bm, el, 1);
500
501                 if (el->type == BM_FACE) {
502                         f = (BMFace*)el;
503                         add_normal_aligned(nor, f->no);
504                 };
505         }
506
507         normalize_v3(nor);
508
509         BMO_Finish_Op(bm, &extop);
510
511         if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
512         return 'n'; // normal constraint 
513
514 }
515 static short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, short flag, float *nor)
516 {
517                 BMIter iter;
518                 BMEdge *eed;
519                 
520                 /*ensure vert flags are consistent for edge selections*/
521                 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
522                 for ( ; eed; eed=BMIter_Step(&iter)) {
523                         if (BM_TestHFlag(eed, flag)) {
524                                 if (flag != BM_SELECT) {
525                                         BM_SetHFlag(eed->v1, flag);
526                                         BM_SetHFlag(eed->v2, flag);
527                                 } else {
528                                         BM_Select(em->bm, eed->v1, 1);
529                                         BM_Select(em->bm, eed->v2, 1);
530                                 }
531                         } else {
532                                 if (BM_TestHFlag(eed->v1, flag) && BM_TestHFlag(eed->v2, flag)) {
533                                         if (flag != BM_SELECT)
534                                                 BM_SetHFlag(eed, flag);
535                                         else BM_Select(em->bm, eed, 1);
536                                 }
537                         }
538                 }
539
540                 return EDBM_Extrude_edge(obedit, em, flag, nor);
541
542 }
543
544 static int extrude_repeat_mesh(bContext *C, wmOperator *op)
545 {
546         Object *obedit= CTX_data_edit_object(C);
547         BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
548         RegionView3D *rv3d = CTX_wm_region_view3d(C);           
549                 
550         int steps = RNA_int_get(op->ptr,"steps");
551         
552         float offs = RNA_float_get(op->ptr,"offset");
553         float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
554         short a;
555
556         /* dvec */
557         dvec[0]= rv3d->persinv[2][0];
558         dvec[1]= rv3d->persinv[2][1];
559         dvec[2]= rv3d->persinv[2][2];
560         normalize_v3(dvec);
561         dvec[0]*= offs;
562         dvec[1]*= offs;
563         dvec[2]*= offs;
564
565         /* base correction */
566         copy_m3_m4(bmat, obedit->obmat);
567         invert_m3_m3(tmat, bmat);
568         mul_m3_v3(tmat, dvec);
569
570         for(a=0; a<steps; a++) {
571                 EDBM_Extrude_edge(obedit, em, BM_SELECT, nor);
572                 //BMO_CallOpf(em->bm, "extrudefaceregion edgefacein=%hef", BM_SELECT);
573                 BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT);
574                 //extrudeflag(obedit, em, SELECT, nor);
575                 //translateflag(em, SELECT, dvec);
576         }
577         
578         EDBM_RecalcNormals(em);
579
580         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
581         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
582
583         return OPERATOR_FINISHED;
584 }
585
586 void MESH_OT_extrude_repeat(wmOperatorType *ot)
587 {
588         /* identifiers */
589         ot->name= "Extrude Repeat Mesh";
590         ot->description= "Extrude selected vertices, edges or faces repeatedly.";
591         ot->idname= "MESH_OT_extrude_repeat";
592         
593         /* api callbacks */
594         ot->exec= extrude_repeat_mesh;
595         ot->poll= ED_operator_editmesh;
596         
597         /* flags */
598         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
599         
600         /* props */
601         RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX);
602         RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX);
603 }
604
605 /* generic extern called extruder */
606 static int EDBM_Extrude_Mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOperator *op, float *norin)
607 {
608         short nr, transmode= 0;
609         float stacknor[3] = {0.0f, 0.0f, 0.0f};
610         float *nor = norin ? norin : stacknor;
611
612         nor[0] = nor[1] = nor[2] = 0.0f;
613
614         if(em->selectmode & SCE_SELECT_VERTEX) {
615                 if(em->bm->totvertsel==0) nr= 0;
616                 else if(em->bm->totvertsel==1) nr= 4;
617                 else if(em->bm->totedgesel==0) nr= 4;
618                 else if(em->bm->totfacesel==0) 
619                         nr= 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
620                 else if(em->bm->totfacesel==1)
621                         nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
622                 else 
623                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
624         }
625         else if(em->selectmode & SCE_SELECT_EDGE) {
626                 if (em->bm->totedgesel==0) nr = 0;
627                 
628                 nr = 1;
629                 /*else if (em->totedgesel==1) nr = 3;
630                 else if(em->totfacesel==0) nr = 3;
631                 else if(em->totfacesel==1)
632                         nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3");
633                 else
634                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
635                 */
636         }
637         else {
638                 if (em->bm->totfacesel == 0) nr = 0;
639                 else if (em->bm->totfacesel == 1) nr = 1;
640                 else
641                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
642         }
643
644         if(nr<1) return 'g';
645
646         if(nr==1 && em->selectmode & SCE_SELECT_VERTEX) 
647                 transmode= EDBM_Extrude_vert(obedit, em, SELECT, nor);
648         else if (nr == 1) transmode= EDBM_Extrude_edge(obedit, em, SELECT, nor);
649         else if(nr==4) transmode= EDBM_Extrude_verts_indiv(em, op, SELECT, nor);
650         else if(nr==3) transmode= EDBM_Extrude_edges_indiv(em, op, SELECT, nor);
651         else transmode= EDBM_Extrude_face_indiv(em, op, SELECT, nor);
652         
653         if(transmode==0) {
654                 BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
655         }
656         else {
657                 
658                         /* We need to force immediate calculation here because 
659                         * transform may use derived objects (which are now stale).
660                         *
661                         * This shouldn't be necessary, derived queries should be
662                         * automatically building this data if invalid. Or something.
663                         */
664 //              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
665                 object_handle_update(scene, obedit);
666
667                 /* individual faces? */
668 //              BIF_TransformSetUndo("Extrude");
669                 if(nr==2) {
670 //                      initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
671 //                      Transform();
672                 }
673                 else {
674 //                      initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
675                         if(transmode=='n') {
676                                 mul_m4_v3(obedit->obmat, nor);
677                                 sub_v3_v3v3(nor, nor, obedit->obmat[3]);
678 //                              BIF_setSingleAxisConstraint(nor, "along normal");
679                         }
680 //                      Transform();
681                 }
682         }
683         
684         return transmode;
685 }
686
687 /* extrude without transform */
688 static int mesh_extrude_region_exec(bContext *C, wmOperator *op)
689 {
690         Scene *scene = CTX_data_scene(C);
691         Object *obedit= CTX_data_edit_object(C);
692         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
693         
694         EDBM_Extrude_Mesh(scene, obedit, em, op, NULL);
695
696         /*This normally happens when pushing undo but modal operators
697           like this one don't push undo data until after modal mode is
698           done.*/
699         EDBM_RecalcNormals(em);
700         BMEdit_RecalcTesselation(em);
701
702         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
703         
704         return OPERATOR_FINISHED;       
705 }
706
707 void MESH_OT_extrude_region(wmOperatorType *ot)
708 {
709         /* identifiers */
710         ot->name= "Extrude Region";
711         ot->idname= "MESH_OT_extrude_region";
712         
713         /* api callbacks */
714         //ot->invoke= mesh_extrude_region_invoke;
715         ot->exec= mesh_extrude_region_exec;
716         ot->poll= ED_operator_editmesh;
717         
718         /* flags */
719         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
720
721         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
722 }
723
724 static int mesh_extrude_verts_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_verts_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_verts_indiv(wmOperatorType *ot)
738 {
739         /* identifiers */
740         ot->name= "Extrude Only Vertices";
741         ot->idname= "MESH_OT_extrude_verts_indiv";
742         
743         /* api callbacks */
744         ot->exec= mesh_extrude_verts_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_edges_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_edges_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_edges_indiv(wmOperatorType *ot)
768 {
769         /* identifiers */
770         ot->name= "Extrude Only Edges";
771         ot->idname= "MESH_OT_extrude_edges_indiv";
772         
773         /* api callbacks */
774         ot->exec= mesh_extrude_edges_exec;
775         ot->poll= ED_operator_editmesh;
776         
777         /* flags */
778         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
779
780         /* to give to transform */
781         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
782 }
783
784 static int mesh_extrude_faces_exec(bContext *C, wmOperator *op)
785 {
786         Object *obedit= CTX_data_edit_object(C);
787         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
788         float nor[3];
789
790         EDBM_Extrude_face_indiv(em, op, BM_SELECT, nor);
791         
792         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
793         
794         return OPERATOR_FINISHED;       
795 }
796
797 void MESH_OT_extrude_faces_indiv(wmOperatorType *ot)
798 {
799         /* identifiers */
800         ot->name= "Extrude Individual Faces";
801         ot->idname= "MESH_OT_extrude_faces_indiv";
802         
803         /* api callbacks */
804         ot->exec= mesh_extrude_faces_exec;
805         ot->poll= ED_operator_editmesh;
806         
807         /* flags */
808         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
809
810         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
811 }
812
813 /* ******************** (de)select all operator **************** */
814
815 void EDBM_toggle_select_all(BMEditMesh *em) /* exported for UV */
816 {
817         if(em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
818                 EDBM_clear_flag_all(em, SELECT);
819         else 
820                 EDBM_set_flag_all(em, SELECT);
821 }
822
823 static int toggle_select_all_exec(bContext *C, wmOperator *UNUSED(op))
824 {
825         Object *obedit= CTX_data_edit_object(C);
826         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
827         
828         EDBM_toggle_select_all(em);
829         
830         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
831
832         return OPERATOR_FINISHED;
833 }
834
835 void MESH_OT_select_all(wmOperatorType *ot)
836 {
837         /* identifiers */
838         ot->name= "Select/Deselect All";
839         ot->idname= "MESH_OT_select_all";
840         ot->description= "(de)select all vertices, edges or faces.";
841         
842         /* api callbacks */
843         ot->exec= toggle_select_all_exec;
844         ot->poll= ED_operator_editmesh;
845         
846         /* flags */
847         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
848 }
849
850 /* *************** add-click-mesh (extrude) operator ************** */
851 /* in trunk see: 'editmesh_add.c' */
852 static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
853 {
854         ViewContext vc;
855         BMVert *v1;
856         BMIter iter;
857         float min[3], max[3];
858         int done= 0;
859         short use_proj;
860         
861         em_setup_viewcontext(C, &vc);
862         
863         use_proj= (vc.scene->toolsettings->snap_flag & SCE_SNAP) &&     (vc.scene->toolsettings->snap_mode==SCE_SNAP_MODE_FACE);
864
865         INIT_MINMAX(min, max);
866         
867         BM_ITER(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH, NULL) {
868                 if (BM_TestHFlag(v1, BM_SELECT)) {
869                         DO_MINMAX(v1->co, min, max);
870                         done= 1;
871                 }
872         }
873
874         /* call extrude? */
875         if(done) {
876                 const short rot_src= RNA_boolean_get(op->ptr, "rotate_source");
877                 BMEdge *eed;
878                 float vec[3], cent[3], mat[3][3];
879                 float nor[3]= {0.0, 0.0, 0.0};
880
881                 /* 2D normal calc */
882                 float mval_f[2];
883
884                 mval_f[0]= (float)event->mval[0];
885                 mval_f[1]= (float)event->mval[1];
886
887                 /* check for edges that are half selected, use for rotation */
888                 done= 0;
889                 BM_ITER(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH, NULL) {
890                         if (BM_TestHFlag(eed, BM_SELECT)) {
891                                 float co1[3], co2[3];
892                                 mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co);
893                                 mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co);
894                                 project_float_noclip(vc.ar, co1, co1);
895                                 project_float_noclip(vc.ar, co2, co2);
896
897                                 /* 2D rotate by 90d while adding.
898                                  *  (x, y) = (y, -x)
899                                  *
900                                  * accumulate the screenspace normal in 2D,
901                                  * with screenspace edge length weighting the result. */
902                                 if(line_point_side_v2(co1, co2, mval_f) >= 0.0f) {
903                                         nor[0] +=  (co1[1] - co2[1]);
904                                         nor[1] += -(co1[0] - co2[0]);
905                                 }
906                                 else {
907                                         nor[0] +=  (co2[1] - co1[1]);
908                                         nor[1] += -(co2[0] - co1[0]);
909                                 }
910                         }
911                         done= 1;
912                 }
913
914                 if(done) {
915                         float view_vec[3], cross[3];
916
917                         /* convert the 2D nomal into 3D */
918                         mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */
919                         mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */
920
921                         /* correct the normal to be aligned on the view plane */
922                         copy_v3_v3(view_vec, vc.rv3d->viewinv[2]);
923                         mul_mat3_m4_v3(vc.obedit->imat, view_vec);
924                         cross_v3_v3v3(cross, nor, view_vec);
925                         cross_v3_v3v3(nor, view_vec, cross);
926                         normalize_v3(nor);
927                 }
928                 
929                 /* center */
930                 mid_v3_v3v3(cent, min, max);
931                 copy_v3_v3(min, cent);
932
933                 mul_m4_v3(vc.obedit->obmat, min);       // view space
934                 view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE);
935                 mul_m4_v3(vc.obedit->imat, min); // back in object space
936
937                 sub_v3_v3(min, cent);
938                 
939                 /* calculate rotation */
940                 unit_m3(mat);
941                 if(done) {
942                         float dot;
943
944                         copy_v3_v3(vec, min);
945                         normalize_v3(vec);
946                         dot= INPR(vec, nor);
947
948                         if( fabs(dot)<0.999) {
949                                 float cross[3], si, q1[4];
950
951                                 cross_v3_v3v3(cross, nor, vec);
952                                 normalize_v3(cross);
953                                 dot= 0.5f*saacos(dot);
954
955                                 /* halve the rotation if its applied twice */
956                                 if(rot_src) dot *= 0.5f;
957
958                                 si= (float)sin(dot);
959                                 q1[0]= (float)cos(dot);
960                                 q1[1]= cross[0]*si;
961                                 q1[2]= cross[1]*si;
962                                 q1[3]= cross[2]*si;
963                                 quat_to_mat3( mat,q1);
964                         }
965                 }
966                 
967                 if(rot_src) {
968                         EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
969                                 BM_SELECT, cent, mat);
970
971                         /* also project the source, for retopo workflow */
972                         if(use_proj)
973                                 EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
974                 }
975
976                 EDBM_Extrude_edge(vc.obedit, vc.em, SELECT, nor);
977                 EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
978                         BM_SELECT, cent, mat);
979                 EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v",
980                         BM_SELECT, min);
981         }
982         else {
983                 float *curs= give_cursor(vc.scene, vc.v3d);
984                 BMOperator bmop;
985                 BMOIter oiter;
986                 
987                 copy_v3_v3(min, curs);
988                 view3d_get_view_aligned_coordinate(&vc, min, event->mval, 0);
989
990                 invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); 
991                 mul_m4_v3(vc.obedit->imat, min); // back in object space
992                 
993                 EDBM_InitOpf(vc.em, &bmop, op, "makevert co=%v", min);
994                 BMO_Exec_Op(vc.em->bm, &bmop);
995
996                 BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) {
997                         BM_Select(vc.em->bm, v1, 1);
998                 }
999
1000                 if (!EDBM_FinishOp(vc.em, &bmop, op, 1))
1001                         return OPERATOR_CANCELLED;
1002         }
1003
1004         if(use_proj)
1005                 EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
1006
1007         WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data); 
1008         DAG_id_tag_update(vc.obedit->data, OB_RECALC_DATA);
1009         
1010         return OPERATOR_FINISHED;
1011 }
1012
1013 void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
1014 {
1015         /* identifiers */
1016         ot->name= "Duplicate or Extrude at 3D Cursor";
1017         ot->idname= "MESH_OT_dupli_extrude_cursor";
1018         
1019         /* api callbacks */
1020         ot->invoke= dupli_extrude_cursor;
1021         ot->description= "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor.";
1022         ot->poll= ED_operator_editmesh;
1023         
1024         /* flags */
1025         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1026
1027         RNA_def_boolean(ot->srna, "rotate_source", 1, "Rotate Source", "Rotate initial selection giving better shape");
1028 }
1029
1030 static int delete_mesh(bContext *C, Object *obedit, wmOperator *op, int event, Scene *UNUSED(scene))
1031 {
1032         BMEditMesh *bem = ((Mesh*)obedit->data)->edit_btmesh;
1033         
1034         if(event<1) return OPERATOR_CANCELLED;
1035
1036         if(event==10 ) {
1037                 //"Erase Vertices";
1038
1039                 if (!EDBM_CallOpf(bem, op, "del geom=%hv context=%i", BM_SELECT, DEL_VERTS))
1040                         return OPERATOR_CANCELLED;
1041         } 
1042         else if(event==11) {
1043                 //"Edge Loop"
1044                 if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_SELECT))
1045                         return OPERATOR_CANCELLED;
1046         }
1047         else if(event==7) {
1048                 //"Dissolve"
1049                 if (bem->selectmode & SCE_SELECT_FACE) {
1050                         if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf",BM_SELECT))
1051                                 return OPERATOR_CANCELLED;
1052                 } else if (bem->selectmode & SCE_SELECT_EDGE) {
1053                         if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he",BM_SELECT))
1054                                 return OPERATOR_CANCELLED;
1055                 } else if (bem->selectmode & SCE_SELECT_VERTEX) {
1056                         if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv",BM_SELECT))
1057                                 return OPERATOR_CANCELLED;
1058                 }
1059         }
1060         else if(event==4) {
1061                 //Edges and Faces
1062                 if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_SELECT, DEL_EDGESFACES))
1063                         return OPERATOR_CANCELLED;
1064         } 
1065         else if(event==1) {
1066                 //"Erase Edges"
1067                 if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_SELECT, DEL_EDGES))
1068                         return OPERATOR_CANCELLED;
1069         }
1070         else if(event==2) {
1071                 //"Erase Faces";
1072                 if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_SELECT, DEL_FACES))
1073                         return OPERATOR_CANCELLED;
1074         }
1075         else if(event==5) {
1076                 //"Erase Only Faces";
1077                 if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d",
1078                                   BM_SELECT, DEL_ONLYFACES))
1079                         return OPERATOR_CANCELLED;
1080         }
1081         
1082         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1083         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1084
1085         return OPERATOR_FINISHED;
1086 }
1087
1088 /* Note, these values must match delete_mesh() event values */
1089 static EnumPropertyItem prop_mesh_delete_types[] = {
1090         {7, "DISSOLVE",         0, "Dissolve", ""},
1091         {12, "COLLAPSE", 0, "Collapse", ""},
1092         {10,"VERT",             0, "Vertices", ""},
1093         {1, "EDGE",             0, "Edges", ""},
1094         {2, "FACE",             0, "Faces", ""},
1095         {11, "EDGE_LOOP", 0, "Edge Loop", ""},
1096         {4, "EDGE_FACE", 0, "Edges & Faces", ""},
1097         {5, "ONLY_FACE", 0, "Only Faces", ""},
1098         {0, NULL, 0, NULL, NULL}
1099 };
1100
1101 static int delete_mesh_exec(bContext *C, wmOperator *op)
1102 {
1103         Object *obedit= CTX_data_edit_object(C);
1104         BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
1105         Scene *scene = CTX_data_scene(C);
1106         int type = RNA_enum_get(op->ptr, "type");
1107         
1108         if (type != 12) {
1109                 if (delete_mesh(C, obedit, op, type, scene) == OPERATOR_CANCELLED)
1110                         return OPERATOR_CANCELLED;
1111                 EDBM_clear_flag_all(em, BM_SELECT);
1112         } else {
1113                 if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_SELECT))
1114                         return OPERATOR_CANCELLED;
1115                 DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1116         }
1117
1118         WM_event_add_notifier(C, NC_GEOM|ND_DATA|ND_SELECT, obedit);
1119         
1120         return OPERATOR_FINISHED;
1121 }
1122
1123 void MESH_OT_delete(wmOperatorType *ot)
1124 {
1125         /* identifiers */
1126         ot->name= "Delete";
1127         ot->description= "Delete selected vertices, edges or faces.";
1128         ot->idname= "MESH_OT_delete";
1129         
1130         /* api callbacks */
1131         ot->invoke= WM_menu_invoke;
1132         ot->exec= delete_mesh_exec;
1133         
1134         ot->poll= ED_operator_editmesh;
1135         
1136         /* flags */
1137         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1138         
1139         /*props */
1140         ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
1141 }
1142
1143
1144 static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
1145 {
1146         BMOperator bmop;
1147         Object *obedit= CTX_data_edit_object(C);
1148         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1149         
1150         if (!EDBM_InitOpf(em, &bmop, op, "contextual_create geom=%hfev", BM_SELECT))
1151                 return OPERATOR_CANCELLED;
1152         
1153         BMO_Exec_Op(em->bm, &bmop);
1154         BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT, BM_FACE);
1155
1156         if (!EDBM_FinishOp(em, &bmop, op, 1))
1157                 return OPERATOR_CANCELLED;
1158
1159         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1160         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1161         
1162         return OPERATOR_FINISHED;
1163 }
1164
1165 void MESH_OT_edge_face_add(wmOperatorType *ot)
1166 {
1167         /* identifiers */
1168         ot->name= "Make Edge/Face";
1169         ot->description= "Add an edge or face to selected.";
1170         ot->idname= "MESH_OT_edge_face_add";
1171         
1172         /* api callbacks */
1173         ot->exec= addedgeface_mesh_exec;
1174         ot->poll= ED_operator_editmesh;
1175         
1176         /* flags */
1177         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1178         
1179 }
1180
1181 static EnumPropertyItem prop_mesh_edit_types[] = {
1182         {1, "VERT", 0, "Vertices", ""},
1183         {2, "EDGE", 0, "Edges", ""},
1184         {3, "FACE", 0, "Faces", ""},
1185         {0, NULL, 0, NULL, NULL}
1186 };
1187
1188 static int mesh_selection_type_exec(bContext *C, wmOperator *op)
1189 {               
1190         
1191         Object *obedit= CTX_data_edit_object(C);
1192         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1193         int type = RNA_enum_get(op->ptr,"type");
1194
1195         switch (type) {
1196                 case 1:
1197                         em->selectmode = SCE_SELECT_VERTEX;
1198                         break;
1199                 case 2:
1200                         em->selectmode = SCE_SELECT_EDGE;
1201                         break;
1202                 case 3:
1203                         em->selectmode = SCE_SELECT_FACE;
1204                         break;
1205         }
1206
1207         EDBM_selectmode_set(em);
1208         CTX_data_tool_settings(C)->selectmode = em->selectmode;
1209
1210         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1211         
1212         return OPERATOR_FINISHED;
1213 }
1214
1215 static void MESH_OT_selection_type(wmOperatorType *ot)
1216 {
1217         /* identifiers */
1218         ot->name= "Selection Mode";
1219         ot->description= "Set the selection mode type.";
1220         ot->idname= "MESH_OT_selection_type";
1221         
1222         /* api callbacks */
1223         ot->invoke= WM_menu_invoke;
1224         ot->exec= mesh_selection_type_exec;
1225         
1226         ot->poll= ED_operator_editmesh;
1227         
1228         /* flags */
1229         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1230         
1231         /* props */
1232         RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type");
1233         RNA_def_boolean(ot->srna, "inclusive", 0, "Inclusive", "Selects geometry around selected geometry, occording to selection mode");       
1234 }
1235
1236 /* ************************* SEAMS AND EDGES **************** */
1237
1238 static int editbmesh_mark_seam(bContext *C, wmOperator *op)
1239 {
1240         Object *obedit= CTX_data_edit_object(C);
1241         Mesh *me= ((Mesh *)obedit->data);
1242         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1243         BMesh *bm = em->bm;
1244         BMEdge *eed;
1245         BMIter iter;
1246         int clear = RNA_boolean_get(op->ptr, "clear");
1247         
1248         /* auto-enable seams drawing */
1249         if(clear==0) {
1250                 me->drawflag |= ME_DRAWSEAMS;
1251         }
1252
1253         if(clear) {
1254                 BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
1255                         if (!BM_TestHFlag(eed, BM_SELECT) || BM_TestHFlag(eed, BM_HIDDEN))
1256                                 continue;
1257                         
1258                         BM_ClearHFlag(eed, BM_SEAM);
1259                 }
1260         }
1261         else {
1262                 BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
1263                         if (!BM_TestHFlag(eed, BM_SELECT) || BM_TestHFlag(eed, BM_HIDDEN))
1264                                 continue;
1265                         BM_SetHFlag(eed, BM_SEAM);
1266                 }
1267         }
1268
1269         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1270         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1271
1272         return OPERATOR_FINISHED;
1273 }
1274
1275 void MESH_OT_mark_seam(wmOperatorType *ot)
1276 {
1277         /* identifiers */
1278         ot->name= "Mark Seam";
1279         ot->idname= "MESH_OT_mark_seam";
1280         ot->description= "(un)mark selected edges as a seam.";
1281         
1282         /* api callbacks */
1283         ot->exec= editbmesh_mark_seam;
1284         ot->poll= ED_operator_editmesh;
1285         
1286         /* flags */
1287         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1288         
1289         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1290 }
1291
1292 static int editbmesh_mark_sharp(bContext *C, wmOperator *op)
1293 {
1294         Object *obedit= CTX_data_edit_object(C);
1295         Mesh *me= ((Mesh *)obedit->data);
1296         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1297         BMesh *bm = em->bm;
1298         BMEdge *eed;
1299         BMIter iter;
1300         int clear = RNA_boolean_get(op->ptr, "clear");
1301
1302         /* auto-enable sharp edge drawing */
1303         if(clear == 0) {
1304                 me->drawflag |= ME_DRAWSHARP;
1305         }
1306
1307         if(!clear) {
1308                 BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
1309                         if (!BM_TestHFlag(eed, BM_SELECT) || BM_TestHFlag(eed, BM_HIDDEN))
1310                                 continue;
1311                         
1312                         BM_SetHFlag(eed, BM_SHARP);
1313                 }
1314         } else {
1315                 BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
1316                         if (!BM_TestHFlag(eed, BM_SELECT) || BM_TestHFlag(eed, BM_HIDDEN))
1317                                 continue;
1318                         
1319                         BM_ClearHFlag(eed, BM_SHARP);
1320                 }
1321         }
1322
1323
1324         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1325         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1326
1327         return OPERATOR_FINISHED;
1328 }
1329
1330 void MESH_OT_mark_sharp(wmOperatorType *ot)
1331 {
1332         /* identifiers */
1333         ot->name= "Mark Sharp";
1334         ot->idname= "MESH_OT_mark_sharp";
1335         ot->description= "(un)mark selected edges as sharp.";
1336         
1337         /* api callbacks */
1338         ot->exec= editbmesh_mark_sharp;
1339         ot->poll= ED_operator_editmesh;
1340         
1341         /* flags */
1342         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1343         
1344         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1345 }
1346
1347
1348 static int editbmesh_vert_connect(bContext *C, wmOperator *UNUSED(op))
1349 {
1350         Object *obedit= CTX_data_edit_object(C);
1351         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1352         BMesh *bm = em->bm;
1353         BMOperator bmop;
1354         int len = 0;
1355         
1356         BMO_InitOpf(bm, &bmop, "connectverts verts=%hv", BM_SELECT);
1357         BMO_Exec_Op(bm, &bmop);
1358         len = BMO_GetSlot(&bmop, "edgeout")->len;
1359         BMO_Finish_Op(bm, &bmop);
1360         
1361         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1362         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1363
1364         return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1365 }
1366
1367 void MESH_OT_vert_connect(wmOperatorType *ot)
1368 {
1369         /* identifiers */
1370         ot->name= "Vertex Connect";
1371         ot->idname= "MESH_OT_vert_connect";
1372         
1373         /* api callbacks */
1374         ot->exec= editbmesh_vert_connect;
1375         ot->poll= ED_operator_editmesh;
1376         
1377         /* flags */
1378         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1379 }
1380
1381 static int editbmesh_edge_split(bContext *C, wmOperator *op)
1382 {
1383         Object *obedit= CTX_data_edit_object(C);
1384         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1385         BMesh *bm = em->bm;
1386         BMOperator bmop;
1387         int len = 0;
1388         
1389         BMO_InitOpf(bm, &bmop, "edgesplit edges=%he numcuts=%d", BM_SELECT, RNA_int_get(op->ptr,"number_cuts"));
1390         BMO_Exec_Op(bm, &bmop);
1391         len = BMO_GetSlot(&bmop, "outsplit")->len;
1392         BMO_Finish_Op(bm, &bmop);
1393         
1394         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1395         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1396
1397         return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1398 }
1399
1400 void MESH_OT_edge_split(wmOperatorType *ot)
1401 {
1402         /* identifiers */
1403         ot->name= "Edge Split";
1404         ot->idname= "MESH_OT_edge_split";
1405         
1406         /* api callbacks */
1407         ot->exec= editbmesh_edge_split;
1408         ot->poll= ED_operator_editmesh;
1409         
1410         /* flags */
1411         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1412
1413         RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX);
1414 }
1415
1416 /****************** add duplicate operator ***************/
1417
1418 static int mesh_duplicate_exec(bContext *C, wmOperator *op)
1419 {
1420         Object *ob= CTX_data_edit_object(C);
1421         BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh;
1422         BMOperator bmop;
1423
1424         EDBM_InitOpf(em, &bmop, op, "dupe geom=%hvef", BM_SELECT);
1425         
1426         BMO_Exec_Op(em->bm, &bmop);
1427         EDBM_clear_flag_all(em, BM_SELECT);
1428
1429         BMO_HeaderFlag_Buffer(em->bm, &bmop, "newout", BM_SELECT, BM_ALL);
1430
1431         if (!EDBM_FinishOp(em, &bmop, op, 1))
1432                 return OPERATOR_CANCELLED;
1433
1434         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
1435         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
1436         
1437         return OPERATOR_FINISHED;
1438 }
1439
1440 static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1441 {
1442         WM_cursor_wait(1);
1443         mesh_duplicate_exec(C, op);
1444         WM_cursor_wait(0);
1445         
1446         return OPERATOR_FINISHED;
1447 }
1448
1449 void MESH_OT_duplicate(wmOperatorType *ot)
1450 {
1451         /* identifiers */
1452         ot->name= "Duplicate";
1453         ot->description= "Duplicate selected vertices, edges or faces.";
1454         ot->idname= "MESH_OT_duplicate";
1455         
1456         /* api callbacks */
1457         ot->invoke= mesh_duplicate_invoke;
1458         ot->exec= mesh_duplicate_exec;
1459         
1460         ot->poll= ED_operator_editmesh;
1461         
1462         /* to give to transform */
1463         RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
1464 }
1465
1466 static int flip_normals(bContext *C, wmOperator *op)
1467 {
1468         Object *obedit= CTX_data_edit_object(C);
1469         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1470         
1471         if (!EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT))
1472                 return OPERATOR_CANCELLED;
1473         
1474         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1475         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1476
1477         return OPERATOR_FINISHED;
1478 }
1479
1480 void MESH_OT_flip_normals(wmOperatorType *ot)
1481 {
1482         /* identifiers */
1483         ot->name= "Flip Normals";
1484         ot->description= "Flip the direction of selected face's vertex and face normals";
1485         ot->idname= "MESH_OT_flip_normals";
1486         
1487         /* api callbacks */
1488         ot->exec= flip_normals;
1489         ot->poll= ED_operator_editmesh;
1490         
1491         /* flags */
1492         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1493 }
1494
1495 float *bm_get_cd_float(CustomData *cdata, void *data, int type)
1496 {
1497         float *f = CustomData_bmesh_get(cdata, data, type);
1498
1499         return f;
1500 }
1501
1502 static const EnumPropertyItem direction_items[]= {
1503         {DIRECTION_CW, "CW", 0, "Clockwise", ""},
1504         {DIRECTION_CCW, "CCW", 0, "Counter Clockwise", ""},
1505         {0, NULL, 0, NULL, NULL}};
1506
1507 /* only accepts 1 selected edge, or 2 selected faces */
1508 static int edge_rotate_selected(bContext *C, wmOperator *op)
1509 {
1510         Object *obedit= CTX_data_edit_object(C);
1511         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1512         BMOperator bmop;
1513         BMEdge *eed;
1514         BMIter iter;
1515         int ccw = RNA_int_get(op->ptr, "direction") == 1; // direction == 2 when clockwise and ==1 for counter CW.
1516         
1517         if (!(em->bm->totfacesel == 2 || em->bm->totedgesel == 1)) {
1518                 BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
1519                 return OPERATOR_CANCELLED;
1520         }
1521
1522         /*first see if we have two adjacent faces*/
1523         BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1524                 if (BM_Edge_FaceCount(eed) == 2) {
1525                         if ((BM_TestHFlag(eed->l->f, BM_SELECT) && BM_TestHFlag(((BMLoop*)eed->l->radial_next)->f, BM_SELECT))
1526                                  && !(BM_TestHFlag(eed->l->f, BM_HIDDEN) || BM_TestHFlag(((BMLoop*)eed->l->radial_next)->f, BM_HIDDEN)))
1527                         {
1528                                 break;
1529                         }
1530                 }
1531         }
1532         
1533         /*ok, we don't have two adjacent faces, but we do have two selected ones.
1534           that's an error condition.*/
1535         if (!eed && em->bm->totfacesel == 2) {
1536                 BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
1537                 return OPERATOR_CANCELLED;
1538         }
1539
1540         if (!eed) {
1541                 BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1542                         if (BM_TestHFlag(eed, BM_SELECT) && !BM_TestHFlag(eed, BM_HIDDEN))
1543                                 break;
1544                 }
1545         }
1546
1547         /*this should never happen*/
1548         if (!eed)
1549                 return OPERATOR_CANCELLED;
1550         
1551         EDBM_InitOpf(em, &bmop, op, "edgerotate edges=%e ccw=%d", eed, ccw);
1552         BMO_Exec_Op(em->bm, &bmop);
1553
1554         BMO_HeaderFlag_Buffer(em->bm, &bmop, "edgeout", BM_SELECT, BM_EDGE);
1555
1556         if (!EDBM_FinishOp(em, &bmop, op, 1))
1557                 return OPERATOR_CANCELLED;
1558
1559         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1560         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1561
1562         return OPERATOR_FINISHED;
1563 }
1564
1565 void MESH_OT_edge_rotate(wmOperatorType *ot)
1566 {
1567         /* identifiers */
1568         ot->name= "Rotate Selected Edge";
1569         ot->description= "Rotate selected edge or adjoining faces.";
1570         ot->idname= "MESH_OT_edge_rotate";
1571
1572         /* api callbacks */
1573         ot->exec= edge_rotate_selected;
1574         ot->poll= ED_operator_editmesh;
1575
1576         /* flags */
1577         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1578
1579         /* props */
1580         RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "direction", "direction to rotate edge around.");
1581 }
1582
1583 /* swap is 0 or 1, if 1 it hides not selected */
1584 void EDBM_hide_mesh(BMEditMesh *em, int swap)
1585 {
1586         BMIter iter;
1587         BMHeader *h;
1588         int itermode;
1589
1590         if(em==NULL) return;
1591         
1592         if (em->selectmode & SCE_SELECT_VERTEX)
1593                 itermode = BM_VERTS_OF_MESH;
1594         else if (em->selectmode & SCE_SELECT_EDGE)
1595                 itermode = BM_EDGES_OF_MESH;
1596         else
1597                 itermode = BM_FACES_OF_MESH;
1598
1599         BM_ITER(h, &iter, em->bm, itermode, NULL) {
1600                 if (BM_TestHFlag(h, BM_SELECT) ^ swap)
1601                         BM_Hide(em->bm, h, 1);
1602         }
1603
1604         EDBM_selectmode_flush(em);
1605
1606         /*original hide flushing comment (OUTDATED): 
1607           hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
1608         /*  - vertex hidden, always means edge is hidden too
1609                 - edge hidden, always means face is hidden too
1610                 - face hidden, only set face hide
1611                 - then only flush back down what's absolute hidden
1612         */
1613
1614 }
1615
1616 static int hide_mesh_exec(bContext *C, wmOperator *op)
1617 {
1618         Object *obedit= CTX_data_edit_object(C);
1619         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1620         
1621         EDBM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
1622                 
1623         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1624         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1625
1626         return OPERATOR_FINISHED;       
1627 }
1628
1629 void MESH_OT_hide(wmOperatorType *ot)
1630 {
1631         /* identifiers */
1632         ot->name= "Hide Selection";
1633         ot->idname= "MESH_OT_hide";
1634         
1635         /* api callbacks */
1636         ot->exec= hide_mesh_exec;
1637         ot->poll= ED_operator_editmesh;
1638          ot->description= "Hide (un)selected vertices, edges or faces.";
1639
1640         /* flags */
1641         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1642         
1643         /* props */
1644         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
1645 }
1646
1647
1648 void EDBM_reveal_mesh(BMEditMesh *em)
1649 {
1650         BMIter iter;
1651         BMHeader *ele;
1652         int i, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1653         int sels[3] = {1, !(em->selectmode & SCE_SELECT_VERTEX), !(em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE))};
1654
1655         /*Reveal all hidden elements. Handle the reveal in order of faces,
1656           edges, and finally vertices. This is important because revealing
1657           edges may reveal faces, and revealing verts may reveal edges and
1658           faces. Revealing edges or faces in an earlier pass would keep them
1659           from getting selected in the later passes.*/
1660         for (i=2; i>=0; i--) {
1661                 BM_ITER(ele, &iter, em->bm, types[i], NULL) {
1662                         if (BM_TestHFlag(ele, BM_HIDDEN)) {
1663                                 BM_Hide(em->bm, ele, 0);
1664
1665                                 if (sels[i])
1666                                         BM_Select(em->bm, ele, 1);
1667                         }
1668                 }
1669         }
1670
1671         EDBM_selectmode_flush(em);
1672 }
1673
1674 static int reveal_mesh_exec(bContext *C, wmOperator *UNUSED(op))
1675 {
1676         Object *obedit= CTX_data_edit_object(C);
1677         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1678         
1679         EDBM_reveal_mesh(em);
1680
1681         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1682         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1683
1684         return OPERATOR_FINISHED;       
1685 }
1686
1687 void MESH_OT_reveal(wmOperatorType *ot)
1688 {
1689         /* identifiers */
1690         ot->name= "Reveal Hidden";
1691         ot->idname= "MESH_OT_reveal";
1692         ot->description= "Reveal all hidden vertices, edges and faces.";
1693         
1694         /* api callbacks */
1695         ot->exec= reveal_mesh_exec;
1696         ot->poll= ED_operator_editmesh;
1697         
1698         /* flags */
1699         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1700 }
1701
1702 static int normals_make_consistent_exec(bContext *C, wmOperator *op)
1703 {
1704         Object *obedit= CTX_data_edit_object(C);
1705         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1706         
1707         /* doflip has to do with bmesh_rationalize_normals, it's an internal
1708          * thing*/
1709         if (!EDBM_CallOpf(em, op, "righthandfaces faces=%hf doflip=%d", BM_SELECT, 1))
1710                 return OPERATOR_CANCELLED;
1711
1712         if (RNA_boolean_get(op->ptr, "inside"))
1713                 EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT);
1714
1715         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1716         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1717
1718         return OPERATOR_FINISHED;       
1719 }
1720
1721 void MESH_OT_normals_make_consistent(wmOperatorType *ot)
1722 {
1723         /* identifiers */
1724         ot->name= "Make Normals Consistent";
1725         ot->description= "Make face and vertex normals point either outside or inside the mesh";
1726         ot->idname= "MESH_OT_normals_make_consistent";
1727         
1728         /* api callbacks */
1729         ot->exec= normals_make_consistent_exec;
1730         ot->poll= ED_operator_editmesh;
1731         
1732         /* flags */
1733         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1734         
1735         RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
1736 }
1737
1738
1739
1740 static int do_smooth_vertex(bContext *C, wmOperator *op)
1741 {
1742         Object *obedit= CTX_data_edit_object(C);
1743         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1744         ModifierData *md;
1745         int mirrx=0, mirry=0, mirrz=0;
1746         int i, repeat;
1747
1748         /* if there is a mirror modifier with clipping, flag the verts that
1749          * are within tolerance of the plane(s) of reflection 
1750          */
1751         for(md=obedit->modifiers.first; md; md=md->next) {
1752                 if(md->type==eModifierType_Mirror) {
1753                         MirrorModifierData *mmd = (MirrorModifierData*) md;     
1754                 
1755                         if(mmd->flag & MOD_MIR_CLIPPING) {
1756                                 if (mmd->flag & MOD_MIR_AXIS_X)
1757                                         mirrx = 1;
1758                                 if (mmd->flag & MOD_MIR_AXIS_Y)
1759                                         mirry = 1;
1760                                 if (mmd->flag & MOD_MIR_AXIS_Z)
1761                                         mirrz = 1;
1762                         }
1763                 }
1764         }
1765
1766         repeat = RNA_int_get(op->ptr,"repeat");
1767         if (!repeat)
1768                 repeat = 1;
1769         
1770         for (i=0; i<repeat; i++) {
1771                 if (!EDBM_CallOpf(em, op, "vertexsmooth verts=%hv mirror_clip_x=%d mirror_clip_y=%d mirror_clip_z=%d",
1772                                   BM_SELECT, mirrx, mirry, mirrz))
1773                 {
1774                         return OPERATOR_CANCELLED;
1775                 }
1776         }
1777
1778         //BMESH_TODO: need to handle the x-axis editing option here properly.
1779         //should probably make a helper function for that? I dunno.
1780
1781         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1782         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1783
1784         return OPERATOR_FINISHED;
1785 }       
1786         
1787 void MESH_OT_vertices_smooth(wmOperatorType *ot)
1788 {
1789         /* identifiers */
1790         ot->name= "Smooth Vertex";
1791         ot->description= "Flatten angles of selected vertices.";
1792         ot->idname= "MESH_OT_vertices_smooth";
1793         
1794         /* api callbacks */
1795         ot->exec= do_smooth_vertex;
1796         ot->poll= ED_operator_editmesh;
1797         
1798         /* flags */
1799         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1800
1801         RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
1802 }
1803
1804
1805 static int bm_test_exec(bContext *C, wmOperator *UNUSED(op))
1806 {
1807         Object *obedit= CTX_data_edit_object(C);
1808         ARegion *ar = CTX_wm_region(C);
1809         View3D *v3d = CTX_wm_view3d(C);
1810         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1811         BMBVHTree *tree = BMBVH_NewBVH(em, 0, NULL, NULL);
1812         BMIter iter;
1813         BMEdge *e;
1814
1815         /*hide all back edges*/
1816         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1817                 if (!BM_TestHFlag(e, BM_SELECT))
1818                         continue;
1819
1820                 if (!BMBVH_EdgeVisible(tree, e, ar, v3d, obedit))
1821                         BM_Select(em->bm, e, 0);
1822         }
1823
1824         BMBVH_FreeBVH(tree);
1825         
1826 #if 0 //uv island walker test
1827         BMIter iter, liter;
1828         BMFace *f;
1829         BMLoop *l, *l2;
1830         MLoopUV *luv;
1831         BMWalker walker;
1832         int i=0;
1833
1834         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1835                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
1836                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1837                 }
1838         }
1839
1840         BMW_Init(&walker, em->bm, BMW_UVISLAND, 0);
1841
1842         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1843                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
1844                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1845                         if (luv->flag & MLOOPUV_VERTSEL) {
1846                                 l2 = BMW_Begin(&walker, l);
1847                                 for (; l2; l2=BMW_Step(&walker)) {
1848                                         luv = CustomData_bmesh_get(&em->bm->ldata, l2->head.data, CD_MLOOPUV);
1849                                         luv->flag |= MLOOPUV_VERTSEL;
1850                                 }                               
1851                         }
1852                 }
1853         }
1854
1855         BMW_End(&walker);
1856 #endif
1857         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1858         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1859
1860         return OPERATOR_FINISHED;
1861 }       
1862         
1863 void MESH_OT_bm_test(wmOperatorType *ot)
1864 {
1865         /* identifiers */
1866         ot->name= "BMesh Test Operator";
1867         ot->idname= "MESH_OT_bm_test";
1868         
1869         /* api callbacks */
1870         ot->exec= bm_test_exec;
1871         ot->poll= ED_operator_editmesh;
1872         
1873         /* flags */
1874         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1875
1876         //RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
1877 }
1878
1879 /********************** Smooth/Solid Operators *************************/
1880
1881 static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
1882 {
1883         BMIter iter;
1884         BMFace *efa;
1885
1886         if(em==NULL) return;
1887         
1888         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1889                 if (BM_TestHFlag(efa, BM_SELECT)) {
1890                         if (smooth)
1891                                 BM_SetHFlag(efa, BM_SMOOTH);
1892                         else
1893                                 BM_ClearHFlag(efa, BM_SMOOTH);
1894                 }
1895         }
1896 }
1897
1898 static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
1899 {
1900         Object *obedit= CTX_data_edit_object(C);
1901         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1902
1903         mesh_set_smooth_faces(em, 1);
1904
1905         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1906         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1907
1908         return OPERATOR_FINISHED;
1909 }
1910
1911 void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
1912 {
1913         /* identifiers */
1914         ot->name= "Shade Smooth";
1915          ot->description= "Display faces smooth (using vertex normals).";
1916         ot->idname= "MESH_OT_faces_shade_smooth";
1917
1918         /* api callbacks */
1919         ot->exec= mesh_faces_shade_smooth_exec;
1920         ot->poll= ED_operator_editmesh;
1921
1922         /* flags */
1923         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1924 }
1925
1926 static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
1927 {
1928         Object *obedit= CTX_data_edit_object(C);
1929         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1930
1931         mesh_set_smooth_faces(em, 0);
1932
1933         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1934         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1935
1936         return OPERATOR_FINISHED;
1937 }
1938
1939 void MESH_OT_faces_shade_flat(wmOperatorType *ot)
1940 {
1941         /* identifiers */
1942         ot->name= "Shade Flat";
1943         ot->description= "Display faces flat.";
1944         ot->idname= "MESH_OT_faces_shade_flat";
1945
1946         /* api callbacks */
1947         ot->exec= mesh_faces_shade_flat_exec;
1948         ot->poll= ED_operator_editmesh;
1949
1950         /* flags */
1951         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1952 }
1953
1954
1955 /********************** UV/Color Operators *************************/
1956
1957
1958 static const EnumPropertyItem axis_items[]= {
1959         {OPUVC_AXIS_X, "X", 0, "X", ""},
1960         {OPUVC_AXIS_Y, "Y", 0, "Y", ""},
1961         {0, NULL, 0, NULL, NULL}};
1962
1963 static int mesh_rotate_uvs(bContext *C, wmOperator *op)
1964 {
1965         Object *ob = CTX_data_edit_object(C);
1966         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
1967         BMOperator bmop;
1968
1969         /* get the direction from RNA */
1970         int dir = RNA_enum_get(op->ptr, "direction");
1971
1972         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
1973         EDBM_InitOpf(em, &bmop, op, "meshrotateuvs faces=%hf dir=%d", BM_SELECT, dir);
1974
1975         /* execute the operator */
1976         BMO_Exec_Op(em->bm, &bmop);
1977
1978         /* finish the operator */
1979         if( !EDBM_FinishOp(em, &bmop, op, 1) )
1980                 return OPERATOR_CANCELLED;
1981
1982
1983         /* dependencies graph and notification stuff */
1984         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
1985         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
1986 /*      DAG_id_tag_update(ob->data, OB_RECALC_DATA);
1987         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
1988 */
1989         /* we succeeded */
1990         return OPERATOR_FINISHED;
1991 }
1992
1993 static int mesh_reverse_uvs(bContext *C, wmOperator *op)
1994 {
1995         Object *ob = CTX_data_edit_object(C);
1996         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
1997         BMOperator bmop;
1998
1999         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2000         EDBM_InitOpf(em, &bmop, op, "meshreverseuvs faces=%hf", BM_SELECT);
2001
2002         /* execute the operator */
2003         BMO_Exec_Op(em->bm, &bmop);
2004
2005         /* finish the operator */
2006         if( !EDBM_FinishOp(em, &bmop, op, 1) )
2007                 return OPERATOR_CANCELLED;
2008
2009         /* dependencies graph and notification stuff */
2010         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2011         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2012 /*      DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2013         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2014 */
2015         /* we succeeded */
2016         return OPERATOR_FINISHED;
2017 }
2018
2019 static int mesh_rotate_colors(bContext *C, wmOperator *op)
2020 {
2021         Object *ob = CTX_data_edit_object(C);
2022         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
2023         BMOperator bmop;
2024
2025         /* get the direction from RNA */
2026         int dir = RNA_enum_get(op->ptr, "direction");
2027
2028         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2029         EDBM_InitOpf(em, &bmop, op, "meshrotatecolors faces=%hf dir=%d", BM_SELECT, dir);
2030
2031         /* execute the operator */
2032         BMO_Exec_Op(em->bm, &bmop);
2033
2034         /* finish the operator */
2035         if( !EDBM_FinishOp(em, &bmop, op, 1) )
2036                 return OPERATOR_CANCELLED;
2037
2038
2039         /* dependencies graph and notification stuff */
2040         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2041         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2042 /*      DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
2043         WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob);
2044 */
2045         /* we succeeded */
2046         return OPERATOR_FINISHED;
2047 }
2048
2049
2050 static int mesh_reverse_colors(bContext *C, wmOperator *op)
2051 {
2052         Object *ob = CTX_data_edit_object(C);
2053         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
2054         BMOperator bmop;
2055
2056         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2057         EDBM_InitOpf(em, &bmop, op, "meshreversecolors faces=%hf", BM_SELECT);
2058
2059         /* execute the operator */
2060         BMO_Exec_Op(em->bm, &bmop);
2061
2062         /* finish the operator */
2063         if( !EDBM_FinishOp(em, &bmop, op, 1) )
2064                 return OPERATOR_CANCELLED;
2065
2066         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2067         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2068
2069         /* we succeeded */
2070         return OPERATOR_FINISHED;
2071 #if 0
2072         Scene *scene= CTX_data_scene(C);
2073         Object *obedit= CTX_data_edit_object(C);
2074         EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
2075
2076         EditFace *efa;
2077         short change = 0;
2078         MCol tmpcol, *mcol;
2079         int axis= RNA_enum_get(op->ptr, "axis");
2080
2081         if (!EM_vertColorCheck(em)) {
2082                 BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers");
2083                 BKE_mesh_end_editmesh(obedit->data, em);
2084                 return OPERATOR_CANCELLED;
2085         }
2086
2087         for(efa=em->faces.first; efa; efa=efa->next) {
2088                 if (efa->f & SELECT) {
2089                         mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
2090                         if (axis == AXIS_Y) {
2091                                 tmpcol= mcol[1];
2092                                 mcol[1]= mcol[2];
2093                                 mcol[2]= tmpcol;
2094
2095                                 if(efa->v4) {
2096                                         tmpcol= mcol[0];
2097                                         mcol[0]= mcol[3];
2098                                         mcol[3]= tmpcol;
2099                                 }
2100                         } else {
2101                                 tmpcol= mcol[0];
2102                                 mcol[0]= mcol[1];
2103                                 mcol[1]= tmpcol;
2104
2105                                 if(efa->v4) {
2106                                         tmpcol= mcol[2];
2107                                         mcol[2]= mcol[3];
2108                                         mcol[3]= tmpcol;
2109                                 }
2110                         }
2111                         change = 1;
2112                 }
2113         }
2114
2115         BKE_mesh_end_editmesh(obedit->data, em);
2116
2117         if(!change)
2118                 return OPERATOR_CANCELLED;
2119
2120         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2121         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2122
2123 #endif
2124         return OPERATOR_FINISHED;
2125 }
2126
2127 void MESH_OT_uvs_rotate(wmOperatorType *ot)
2128 {
2129         /* identifiers */
2130         ot->name= "Rotate UVs";
2131         ot->idname= "MESH_OT_uvs_rotate";
2132
2133         /* api callbacks */
2134         ot->exec= mesh_rotate_uvs;
2135         ot->poll= ED_operator_editmesh;
2136
2137         /* flags */
2138         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2139
2140         /* props */
2141         RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around.");
2142 }
2143
2144 //void MESH_OT_uvs_mirror(wmOperatorType *ot)
2145 void MESH_OT_uvs_reverse(wmOperatorType *ot)
2146 {
2147         /* identifiers */
2148         ot->name= "Reverse UVs";
2149         ot->idname= "MESH_OT_uvs_reverse";
2150
2151         /* api callbacks */
2152         ot->exec= mesh_reverse_uvs;
2153         ot->poll= ED_operator_editmesh;
2154
2155         /* flags */
2156         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2157
2158         /* props */
2159         //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around.");
2160 }
2161
2162 void MESH_OT_colors_rotate(wmOperatorType *ot)
2163 {
2164         /* identifiers */
2165         ot->name= "Rotate Colors";
2166         ot->idname= "MESH_OT_colors_rotate";
2167
2168         /* api callbacks */
2169         ot->exec= mesh_rotate_colors;
2170         ot->poll= ED_operator_editmesh;
2171
2172         /* flags */
2173         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2174
2175         /* props */
2176         RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around.");
2177 }
2178
2179 void MESH_OT_colors_reverse(wmOperatorType *ot)
2180 {
2181         /* identifiers */
2182         ot->name= "Reverse Colors";
2183         ot->idname= "MESH_OT_colors_reverse";
2184
2185         /* api callbacks */
2186         ot->exec= mesh_reverse_colors;
2187         ot->poll= ED_operator_editmesh;
2188
2189         /* flags */
2190         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2191
2192         /* props */
2193         //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around.");
2194 }
2195
2196
2197 static int merge_firstlast(BMEditMesh *em, int first, int uvmerge, wmOperator *wmop)
2198 {
2199         BMVert *mergevert;
2200         BMEditSelection *ese;
2201
2202         /* do sanity check in mergemenu in edit.c ?*/
2203         if(first == 0){
2204                 ese = em->bm->selected.last;
2205                 mergevert= (BMVert*)ese->data;
2206         }
2207         else{
2208                 ese = em->bm->selected.first;
2209                 mergevert = (BMVert*)ese->data;
2210         }
2211
2212         if (!BM_TestHFlag(mergevert, BM_SELECT))
2213                 return OPERATOR_CANCELLED;
2214         
2215         if (uvmerge) {
2216                 if (!EDBM_CallOpf(em, wmop, "pointmerge_facedata verts=%hv snapv=%e", BM_SELECT, mergevert))
2217                         return OPERATOR_CANCELLED;
2218         }
2219
2220         if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_SELECT, mergevert->co))
2221                 return OPERATOR_CANCELLED;
2222
2223         return OPERATOR_FINISHED;
2224 }
2225
2226 static int merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob, 
2227                         int target, int uvmerge, wmOperator *wmop)
2228 {
2229         BMIter iter;
2230         BMVert *v;
2231         float *vco=NULL, co[3], cent[3] = {0.0f, 0.0f, 0.0f};
2232
2233         if (target) {
2234                 vco = give_cursor(scene, v3d);
2235                 VECCOPY(co, vco);
2236                 mul_m4_v3(ob->imat, co);
2237         }
2238         else {
2239                 float fac;
2240                 int 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 *UNUSED(ptr),  PropertyRNA *UNUSED(prop), 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; */ /* UNUSED */
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"); */ /* UNUSED */
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 static 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->poll= ED_operator_editmesh;
2665
2666         /* flags */
2667         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2668
2669         /* properties */
2670         RNA_def_enum(ot->srna, "type", type_items, VPATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance.");
2671 }
2672 /********************** Rip Operator *************************/
2673
2674 /* helper to find edge for edge_rip */
2675 static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, const int mval[2])
2676 {
2677         float vec1[3], vec2[3], mvalf[2];
2678
2679         ED_view3d_project_float(ar, co1, vec1, mat);
2680         ED_view3d_project_float(ar, co2, vec2, mat);
2681         mvalf[0]= (float)mval[0];
2682         mvalf[1]= (float)mval[1];
2683
2684         return dist_to_line_segment_v2(mvalf, vec1, vec2);
2685 }
2686
2687 /* based on mouse cursor position, it defines how is being ripped */
2688 static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
2689 {
2690         Object *obedit= CTX_data_edit_object(C);
2691         ARegion *ar= CTX_wm_region(C);
2692         View3D *v3d = CTX_wm_view3d(C);
2693         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2694         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2695         BMOperator bmop;
2696         BMBVHTree *bvhtree;
2697         BMOIter siter;
2698         BMIter iter, eiter, liter;
2699         BMLoop *l;
2700         BMEdge *e, *e2, *closest = NULL;
2701         BMVert *v;
2702         int side = 0, i, singlesel = 0;
2703         float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1], 0.0f};
2704         float dist = FLT_MAX, d;
2705
2706         ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
2707
2708         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2709                 if (BM_TestHFlag(e, BM_SELECT))
2710                         BM_SetIndex(e, 1);
2711                 else BM_SetIndex(e, 0);
2712         }
2713
2714         /*handle case of one vert selected.  identify
2715           closest edge around that vert to mouse cursor,
2716           then rip two adjacent edges in the vert fan.*/
2717         if (em->bm->totvertsel == 1 && em->bm->totedgesel == 0 && em->bm->totfacesel == 0) {
2718                 singlesel = 1;
2719
2720                 /*find selected vert*/
2721                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2722                         if (BM_TestHFlag(v, BM_SELECT))
2723                                 break;
2724                 }
2725
2726                 /*this should be impossible, but sanity checks are a good thing*/
2727                 if (!v)
2728                         return OPERATOR_CANCELLED;
2729
2730                 /*find closest edge to mouse cursor*/
2731                 e2 = NULL;
2732                 BM_ITER(e, &iter, em->bm, BM_EDGES_OF_VERT, v) {
2733                         d = mesh_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, event->mval);
2734                         if (d < dist) {
2735                                 dist = d;
2736                                 e2 = e;
2737                         }
2738                 }
2739
2740                 if (!e2)
2741                         return OPERATOR_CANCELLED;
2742
2743                 /*rip two adjacent edges*/
2744                 if (BM_Edge_FaceCount(e2) == 1) {
2745                         l = e2->l;
2746                         e = BM_OtherFaceLoop(e2, l->f, v)->e;
2747
2748                         BM_SetIndex(e, 1);
2749                         BM_SetHFlag(e, BM_SELECT);
2750                 } else if (BM_Edge_FaceCount(e2) == 2) {
2751                         l = e2->l;
2752                         e = BM_OtherFaceLoop(e2, l->f, v)->e;
2753                         BM_SetIndex(e, 1);
2754                         BM_SetHFlag(e, BM_SELECT);
2755                         
2756                         l = e2->l->radial_next;
2757                         e = BM_OtherFaceLoop(e2, l->f, v)->e;
2758                         BM_SetIndex(e, 1);
2759                         BM_SetHFlag(e, BM_SELECT);
2760                 }
2761
2762                 dist = FLT_MAX;
2763         } else {
2764                 /*expand edge selection*/
2765                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2766                         e2 = NULL;
2767                         i = 0;
2768                         BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
2769                                 if (BM_GetIndex(e)) {
2770                                         e2 = e;
2771                                         i++;
2772                                 }
2773                         }
2774                         
2775                         if (i == 1 && e2->l) {
2776                                 l = BM_OtherFaceLoop(e2, e2->l->f, v);
2777                                 l = (BMLoop*)l->radial_next;
2778                                 l = BM_OtherFaceLoop(l->e, l->f, v);
2779
2780                                 if (l)
2781                                         BM_Select(em->bm, l->e, 1);
2782                         }
2783                 }
2784         }
2785
2786         if (!EDBM_InitOpf(em, &bmop, op, "edgesplit edges=%he", BM_SELECT)) {
2787                 return OPERATOR_CANCELLED;
2788         }
2789         
2790         BMO_Exec_Op(em->bm, &bmop);
2791
2792         /*build bvh tree for edge visibility tests*/
2793         bvhtree = BMBVH_NewBVH(em, 0, NULL, NULL);
2794
2795         for (i=0; i<2; i++) {
2796                 BMO_ITER(e, &siter, em->bm, &bmop, i ? "edgeout2":"edgeout1", BM_EDGE) {
2797                         float cent[3] = {0, 0, 0}, mid[4], vec[3];
2798
2799                         if (!BMBVH_EdgeVisible(bvhtree, e, ar, v3d, obedit) || !e->l)
2800                                 continue;
2801
2802                         /*method for calculating distance:
2803                         
2804                           for each edge: calculate face center, then made a vector
2805                           from edge midpoint to face center.  offset edge midpoint
2806                           by a small amount along this vector.*/
2807                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, e->l->f) {
2808                                 add_v3_v3v3(cent, cent, l->v->co);
2809                         }
2810                         mul_v3_fl(cent, 1.0f/(float)e->l->f->len);
2811
2812                         add_v3_v3v3(mid, e->v1->co, e->v2->co);
2813                         mul_v3_fl(mid, 0.5f);
2814                         sub_v3_v3v3(vec, cent, mid);
2815                         normalize_v3(vec);
2816                         mul_v3_fl(vec, 0.01f);
2817                         add_v3_v3v3(mid, mid, vec);
2818
2819                         /*yay we have our comparison point, now project it*/
2820                         ED_view3d_project_float(ar, mid, mid, projectMat);
2821
2822                         vec[0] = fmval[0] - mid[0];
2823                         vec[1] = fmval[1] - mid[1];
2824                         d = vec[0]*vec[0] + vec[1]*vec[1];
2825
2826                         if (d < dist) {
2827                                 side = i;
2828                                 closest = e;
2829                                 dist = d;
2830                         }
2831                 }
2832         }
2833         
2834         EDBM_clear_flag_all(em, BM_SELECT);
2835         BMO_HeaderFlag_Buffer(em->bm, &bmop, side?"edgeout2":"edgeout1", BM_SELECT, BM_EDGE);
2836
2837         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2838                 if (BM_TestHFlag(e, BM_SELECT))
2839                         BM_SetIndex(e, 1);
2840                 else BM_SetIndex(e, 0);
2841         }
2842
2843         /*constrict edge selection again*/
2844         BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2845                 e2 = NULL;
2846                 i = 0;
2847                 BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
2848                         if (BM_GetIndex(e)) {
2849                                 e2 = e;
2850                                 i++;
2851                         }
2852                 }
2853                 
2854                 if (i == 1)  {
2855                         if (singlesel)
2856                                 BM_Select(em->bm, v, 0);
2857                         else
2858                                 BM_Select(em->bm, e2, 0);
2859                 }
2860         }
2861
2862         EDBM_selectmode_flush(em);
2863         
2864         if (!EDBM_FinishOp(em, &bmop, op, 1)) {
2865                 BMBVH_FreeBVH(bvhtree);
2866                 return OPERATOR_CANCELLED;
2867         }
2868         
2869         BMBVH_FreeBVH(bvhtree);
2870
2871         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2872         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2873
2874         return OPERATOR_FINISHED;
2875 }
2876
2877 void MESH_OT_rip(wmOperatorType *ot)
2878 {
2879         /* identifiers */
2880         ot->name= "Rip";
2881         ot->idname= "MESH_OT_rip";
2882
2883         /* api callbacks */
2884         ot->invoke= mesh_rip_invoke;
2885         ot->poll= EM_view3d_poll;
2886
2887         /* flags */
2888         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2889
2890         /* to give to transform */
2891         Transform_Properties(ot, P_PROPORTIONAL);
2892         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
2893 }
2894
2895 /************************ Shape Operators *************************/
2896
2897 /*BMESH_TODO this should be properly encapsulated in a bmop.  but later.*/
2898 static void shape_propagate(Object *obedit, BMEditMesh *em, wmOperator *op)
2899 {
2900         BMIter iter;
2901         BMVert *eve = NULL;
2902         float *co;
2903         int i, totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
2904
2905         if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
2906                 BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys");
2907                 return;
2908         }
2909         
2910         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2911                 if (!BM_TestHFlag(eve, BM_SELECT) || BM_TestHFlag(eve, BM_HIDDEN))
2912                         continue;
2913
2914                 for (i=0; i<totshape; i++) {
2915                         co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i);
2916                         VECCOPY(co, eve->co);
2917                 }
2918         }
2919
2920 #if 0
2921         //TAG Mesh Objects that share this data
2922         for(base = scene->base.first; base; base = base->next){
2923                 if(base->object && base->object->data == me){
2924                         base->object->recalc = OB_RECALC_DATA;
2925                 }
2926         }
2927 #endif
2928
2929         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2930 }
2931
2932
2933 static int shape_propagate_to_all_exec(bContext *C, wmOperator *op)
2934 {
2935         Object *obedit= CTX_data_edit_object(C);
2936         Mesh *me= obedit->data;
2937         BMEditMesh *em= me->edit_btmesh;
2938
2939         shape_propagate(obedit, em, op);
2940
2941         DAG_id_tag_update(&me->id, OB_RECALC_DATA);
2942         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
2943
2944         return OPERATOR_FINISHED;
2945 }
2946
2947
2948 void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
2949 {
2950         /* identifiers */
2951         ot->name= "Shape Propagate";
2952         ot->description= "Apply selected vertex locations to all other shape keys.";
2953         ot->idname= "MESH_OT_shape_propagate_to_all";
2954
2955         /* api callbacks */
2956         ot->exec= shape_propagate_to_all_exec;
2957         ot->poll= ED_operator_editmesh;
2958
2959         /* flags */
2960         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2961 }
2962
2963 /*BMESH_TODO this should be properly encapsulated in a bmop.  but later.*/
2964 static int blend_from_shape_exec(bContext *C, wmOperator *op)
2965 {
2966         Object *obedit= CTX_data_edit_object(C);
2967         Mesh *me= obedit->data;
2968         BMEditMesh *em= me->edit_btmesh;
2969         BMVert *eve;
2970         BMIter iter;
2971         float co[3], *sco;
2972         float blend= RNA_float_get(op->ptr, "blend");
2973         int shape= RNA_enum_get(op->ptr, "shape");
2974         int add= RNA_boolean_get(op->ptr, "add");
2975         int totshape;
2976
2977         /*sanity check*/
2978         totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
2979         if (totshape == 0 || shape < 0 || shape >= totshape)
2980                 return OPERATOR_CANCELLED;
2981
2982         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2983                 if (!BM_TestHFlag(eve, BM_SELECT) || BM_TestHFlag(eve, BM_HIDDEN))
2984                         continue;
2985
2986                 sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
2987                 VECCOPY(co, sco);
2988
2989
2990                 if(add) {
2991                         mul_v3_fl(co, blend);
2992                         add_v3_v3v3(eve->co, eve->co, co);
2993                 }
2994                 else
2995                         interp_v3_v3v3(eve->co, eve->co, co, blend);
2996                 
2997                 VECCOPY(sco, co);
2998         }
2999
3000         DAG_id_tag_update(&me->id, OB_RECALC_DATA);
3001         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
3002
3003         return OPERATOR_FINISHED;
3004 }
3005
3006 static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr),  PropertyRNA *UNUSED(prop), int *free)
3007 {       
3008         Object *obedit= CTX_data_edit_object(C);
3009         Mesh *me= (obedit) ? obedit->data : NULL;
3010         BMEditMesh *em = me->edit_btmesh;
3011         EnumPropertyItem *item= NULL;
3012         int totitem= 0;
3013
3014         if(obedit && obedit->type == OB_MESH && CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
3015                 EnumPropertyItem tmp= {0, "", 0, "", ""};
3016                 int a;
3017
3018                 for (a=0; a<em->bm->vdata.totlayer; a++) {
3019                         if (em->bm->vdata.layers[a].type != CD_SHAPEKEY)
3020                                 continue;
3021
3022                         tmp.value= totitem;
3023                         tmp.identifier= em->bm->vdata.layers[a].name;
3024                         tmp.name= em->bm->vdata.layers[a].name;
3025                         RNA_enum_item_add(&item, &totitem, &tmp);
3026
3027                         totitem++;
3028                 }
3029         }
3030
3031         RNA_enum_item_end(&item, &totitem);
3032         *free= 1;
3033
3034         return item;
3035 }
3036
3037 void MESH_OT_blend_from_shape(wmOperatorType *ot)
3038 {
3039         PropertyRNA *prop;
3040         static EnumPropertyItem shape_items[]= {{0, NULL, 0, NULL, NULL}};
3041
3042         /* identifiers */
3043         ot->name= "Blend From Shape";
3044         ot->description= "Blend in shape from a shape key.";
3045         ot->idname= "MESH_OT_blend_from_shape";
3046
3047         /* api callbacks */
3048         ot->exec= blend_from_shape_exec;
3049         ot->invoke= WM_operator_props_popup;
3050         ot->poll= ED_operator_editmesh;
3051
3052         /* flags */
3053         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3054
3055         /* properties */
3056         prop= RNA_def_enum(ot->srna, "shape", shape_items, 0, "Shape", "Shape key to use for blending.");
3057         RNA_def_enum_funcs(prop, shape_itemf);
3058         RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor.", -2.0f, 2.0f);
3059         RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather then blend between shapes.");
3060 }
3061
3062 /* BMESH_TODO - some way to select on an arbitrary axis */
3063 static int select_axis_exec(bContext *C, wmOperator *op)
3064 {
3065         Object *obedit= CTX_data_edit_object(C);
3066         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
3067         BMEditSelection *ese = em->bm->selected.last;
3068         int axis= RNA_enum_get(op->ptr, "axis");
3069         int mode= RNA_enum_get(op->ptr, "mode"); /* -1==aligned, 0==neg, 1==pos*/
3070
3071         if(ese==NULL)
3072                 return OPERATOR_CANCELLED;
3073
3074         if(ese->type==BM_VERT) {
3075                 BMVert *ev, *act_vert= (BMVert*)ese->data;
3076                 BMIter iter;
3077                 float value= act_vert->co[axis];
3078                 float limit=  CTX_data_tool_settings(C)->doublimit; // XXX
3079
3080                 if(mode==0)
3081                         value -= limit;
3082                 else if (mode==1) 
3083                         value += limit;
3084
3085                 BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
3086                         if(!BM_TestHFlag(ev, BM_HIDDEN)) {
3087                                 switch(mode) {
3088                                 case -1: /* aligned */
3089                                         if(fabs(ev->co[axis] - value) < limit)
3090                                                 BM_Select(em->bm, ev, 1);
3091                                         break;
3092                                 case 0: /* neg */
3093                                         if(ev->co[axis] > value)
3094                                                 BM_Select(em->bm, ev, 1);
3095                                         break;
3096                                 case 1: /* pos */
3097                                         if(ev->co[axis] < value)
3098                                                 BM_Select(em->bm, ev, 1);
3099                                         break;
3100                                 }
3101                         }
3102                 }
3103         }
3104
3105         EDBM_selectmode_flush(em);
3106         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
3107
3108         return OPERATOR_FINISHED;
3109 }
3110
3111 void MESH_OT_select_axis(wmOperatorType *ot)
3112 {
3113         static EnumPropertyItem axis_mode_items[] = {
3114                 {0,  "POSITIVE", 0, "Positive Axis", ""},
3115                 {1,  "NEGATIVE", 0, "Negative Axis", ""},
3116                 {-1, "ALIGNED",  0, "Aligned Axis", ""},
3117                 {0, NULL, 0, NULL, NULL}};
3118
3119         static EnumPropertyItem axis_items_xyz[] = {
3120                 {0, "X_AXIS", 0, "X Axis", ""},
3121                 {1, "Y_AXIS", 0, "Y Axis", ""},
3122                 {2, "Z_AXIS", 0, "Z Axis", ""},
3123                 {0, NULL, 0, NULL, NULL}};
3124
3125         /* identifiers */
3126         ot->name= "Select Axis";
3127         ot->description= "Select all data in the mesh on a single axis.";
3128         ot->idname= "MESH_OT_select_axis";
3129
3130         /* api callbacks */
3131         ot->exec= select_axis_exec;
3132         ot->poll= ED_operator_editmesh;
3133
3134         /* flags */
3135         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3136
3137         /* properties */
3138         RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting");
3139         RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on");
3140 }
3141
3142 static int solidify_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
3143 {
3144 #if 0
3145         Object *obedit= CTX_data_edit_object(C);
3146         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
3147         float nor[3] = {0,0,1};
3148
3149         float thickness= RNA_float_get(op->ptr, "thickness");
3150
3151         extrudeflag(obedit, em, SELECT, nor, 1);
3152         EM_make_hq_normals(em);
3153         EM_solidify(em, thickness);
3154
3155
3156         /* update vertex normals too */
3157         recalc_editnormals(em);
3158
3159         BKE_mesh_end_editmesh(obedit->data, em);
3160
3161         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
3162         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
3163
3164         return OPERATOR_FINISHED;
3165 #endif
3166         return OPERATOR_CANCELLED;
3167 }
3168
3169
3170 void MESH_OT_solidify(wmOperatorType *ot)
3171 {
3172         PropertyRNA *prop;
3173         /* identifiers */
3174         ot->name= "Solidify";
3175         ot->description= "Create a solid skin by extruding, compensating for sharp angles.";
3176         ot->idname= "MESH_OT_solidify";
3177
3178         /* api callbacks */
3179         ot->exec= solidify_exec;
3180         ot->poll= ED_operator_editmesh;
3181
3182         /* flags */
3183         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3184
3185         prop= RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "thickness", "", -10.0f, 10.0f);
3186         RNA_def_property_ui_range(prop, -10, 10, 0.1, 4);
3187 }
3188
3189 #define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */
3190 #define TRAIL_FREEHAND 2
3191 #define TRAIL_MIXED    3 /* (1|2) */
3192 #define TRAIL_AUTO     4 
3193 #define TRAIL_MIDPOINTS 8
3194
3195 typedef struct CutCurve {
3196         float  x; 
3197         float  y;
3198 } CutCurve;
3199
3200 /* ******************************************************************** */
3201 /* Knife Subdivide Tool.  Subdivides edges intersected by a mouse trail
3202         drawn by user.
3203         
3204         Currently mapped to KKey when in MeshEdit mode.
3205         Usage:
3206                 Hit Shift K, Select Centers or Exact
3207                 Hold LMB down to draw path, hit RETKEY.
3208                 ESC cancels as expected.
3209    
3210         Contributed by Robert Wenzlaff (Det. Thorn).
3211
3212     2.5 revamp:
3213     - non modal (no menu before cutting)
3214     - exit on mouse release
3215     - polygon/segment drawing can become handled by WM cb later