svn merge -r40166:40279 ^/trunk/blender
[blender.git] / source / blender / editors / mesh / bmesh_tools.c
1  /* $Id: bmesh_tools.c
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2004 by Blender Foundation.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): Joseph Eagar
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "MEM_guardedalloc.h"
35 #include "PIL_time.h"
36
37 #include "BLO_sys_types.h" // for intptr_t support
38
39 #include "DNA_mesh_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_modifier_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_view3d_types.h"
47 #include "DNA_key_types.h"
48
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                         copy_v3_v3(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                         copy_v3_v3(v1->no, efa->n);
266                         copy_v3_v3(v2->no, efa->n);
267                         copy_v3_v3(v3->no, efa->n);
268                         if(efa->v4) {
269                                 v4= addvertlist(em, efa->v4->co, efa->v4); 
270                                 v4->f1= 1;
271                                 copy_v3_v3(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) && (md->mode & eModifierMode_Realtime)) {
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         const int do_ccw = RNA_enum_get(op->ptr, "direction") == 1;
1516         int do_deselect= FALSE; /* do we deselect */
1517         
1518         if (!(em->bm->totfacesel == 2 || em->bm->totedgesel == 1)) {
1519                 BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
1520                 return OPERATOR_CANCELLED;
1521         }
1522
1523         /*first see if we have two adjacent faces*/
1524         BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1525                 if (BM_Edge_FaceCount(eed) == 2) {
1526                         if ((BM_TestHFlag(eed->l->f, BM_SELECT) && BM_TestHFlag(eed->l->radial_next->f, BM_SELECT))
1527                                  && !(BM_TestHFlag(eed->l->f, BM_HIDDEN) || BM_TestHFlag(eed->l->radial_next->f, BM_HIDDEN)))
1528                         {
1529                                 break;
1530                         }
1531                 }
1532         }
1533         
1534         /*ok, we don't have two adjacent faces, but we do have two selected ones.
1535           that's an error condition.*/
1536         if (!eed && em->bm->totfacesel == 2) {
1537                 BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
1538                 return OPERATOR_CANCELLED;
1539         }
1540
1541         if (!eed) {
1542                 BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1543                         if (BM_TestHFlag(eed, BM_SELECT) && !BM_TestHFlag(eed, BM_HIDDEN)) {
1544                                 /* de-select the edge before */
1545                                 do_deselect = TRUE;
1546                                 break;
1547                         }
1548                 }
1549         }
1550
1551         /*this should never happen*/
1552         if (!eed)
1553                 return OPERATOR_CANCELLED;
1554         
1555         EDBM_InitOpf(em, &bmop, op, "edgerotate edges=%e ccw=%d", eed, do_ccw);
1556
1557         /* avoid adding to the selection if we start off with only a selected edge,
1558          * we could also just deselect the single edge easily but use the BMO api
1559          * since it seems this is more 'correct' */
1560         if(do_deselect) BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "edges", BM_SELECT, BM_EDGE);
1561
1562         BMO_Exec_Op(em->bm, &bmop);
1563         BMO_HeaderFlag_Buffer(em->bm, &bmop, "edgeout", BM_SELECT, BM_EDGE);
1564
1565         if (!EDBM_FinishOp(em, &bmop, op, 1))
1566                 return OPERATOR_CANCELLED;
1567
1568         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1569         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1570
1571         return OPERATOR_FINISHED;
1572 }
1573
1574 void MESH_OT_edge_rotate(wmOperatorType *ot)
1575 {
1576         /* identifiers */
1577         ot->name= "Rotate Selected Edge";
1578         ot->description= "Rotate selected edge or adjoining faces.";
1579         ot->idname= "MESH_OT_edge_rotate";
1580
1581         /* api callbacks */
1582         ot->exec= edge_rotate_selected;
1583         ot->poll= ED_operator_editmesh;
1584
1585         /* flags */
1586         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1587
1588         /* props */
1589         RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "direction", "direction to rotate edge around.");
1590 }
1591
1592 /* swap is 0 or 1, if 1 it hides not selected */
1593 void EDBM_hide_mesh(BMEditMesh *em, int swap)
1594 {
1595         BMIter iter;
1596         BMHeader *h;
1597         int itermode;
1598
1599         if(em==NULL) return;
1600         
1601         if (em->selectmode & SCE_SELECT_VERTEX)
1602                 itermode = BM_VERTS_OF_MESH;
1603         else if (em->selectmode & SCE_SELECT_EDGE)
1604                 itermode = BM_EDGES_OF_MESH;
1605         else
1606                 itermode = BM_FACES_OF_MESH;
1607
1608         BM_ITER(h, &iter, em->bm, itermode, NULL) {
1609                 if (BM_TestHFlag(h, BM_SELECT) ^ swap)
1610                         BM_Hide(em->bm, h, 1);
1611         }
1612
1613         EDBM_selectmode_flush(em);
1614
1615         /*original hide flushing comment (OUTDATED): 
1616           hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
1617         /*  - vertex hidden, always means edge is hidden too
1618                 - edge hidden, always means face is hidden too
1619                 - face hidden, only set face hide
1620                 - then only flush back down what's absolute hidden
1621         */
1622
1623 }
1624
1625 static int hide_mesh_exec(bContext *C, wmOperator *op)
1626 {
1627         Object *obedit= CTX_data_edit_object(C);
1628         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1629         
1630         EDBM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
1631                 
1632         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1633         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1634
1635         return OPERATOR_FINISHED;       
1636 }
1637
1638 void MESH_OT_hide(wmOperatorType *ot)
1639 {
1640         /* identifiers */
1641         ot->name= "Hide Selection";
1642         ot->idname= "MESH_OT_hide";
1643         
1644         /* api callbacks */
1645         ot->exec= hide_mesh_exec;
1646         ot->poll= ED_operator_editmesh;
1647          ot->description= "Hide (un)selected vertices, edges or faces.";
1648
1649         /* flags */
1650         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1651         
1652         /* props */
1653         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
1654 }
1655
1656
1657 void EDBM_reveal_mesh(BMEditMesh *em)
1658 {
1659         BMIter iter;
1660         BMHeader *ele;
1661         int i, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1662         int sels[3] = {1, !(em->selectmode & SCE_SELECT_VERTEX), !(em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE))};
1663
1664         /*Reveal all hidden elements. Handle the reveal in order of faces,
1665           edges, and finally vertices. This is important because revealing
1666           edges may reveal faces, and revealing verts may reveal edges and
1667           faces. Revealing edges or faces in an earlier pass would keep them
1668           from getting selected in the later passes.*/
1669         for (i=2; i>=0; i--) {
1670                 BM_ITER(ele, &iter, em->bm, types[i], NULL) {
1671                         if (BM_TestHFlag(ele, BM_HIDDEN)) {
1672                                 BM_Hide(em->bm, ele, 0);
1673
1674                                 if (sels[i])
1675                                         BM_Select(em->bm, ele, 1);
1676                         }
1677                 }
1678         }
1679
1680         EDBM_selectmode_flush(em);
1681 }
1682
1683 static int reveal_mesh_exec(bContext *C, wmOperator *UNUSED(op))
1684 {
1685         Object *obedit= CTX_data_edit_object(C);
1686         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1687         
1688         EDBM_reveal_mesh(em);
1689
1690         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1691         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1692
1693         return OPERATOR_FINISHED;       
1694 }
1695
1696 void MESH_OT_reveal(wmOperatorType *ot)
1697 {
1698         /* identifiers */
1699         ot->name= "Reveal Hidden";
1700         ot->idname= "MESH_OT_reveal";
1701         ot->description= "Reveal all hidden vertices, edges and faces.";
1702         
1703         /* api callbacks */
1704         ot->exec= reveal_mesh_exec;
1705         ot->poll= ED_operator_editmesh;
1706         
1707         /* flags */
1708         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1709 }
1710
1711 static int normals_make_consistent_exec(bContext *C, wmOperator *op)
1712 {
1713         Object *obedit= CTX_data_edit_object(C);
1714         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1715         
1716         /* doflip has to do with bmesh_rationalize_normals, it's an internal
1717          * thing*/
1718         if (!EDBM_CallOpf(em, op, "righthandfaces faces=%hf doflip=%d", BM_SELECT, 1))
1719                 return OPERATOR_CANCELLED;
1720
1721         if (RNA_boolean_get(op->ptr, "inside"))
1722                 EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT);
1723
1724         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1725         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1726
1727         return OPERATOR_FINISHED;       
1728 }
1729
1730 void MESH_OT_normals_make_consistent(wmOperatorType *ot)
1731 {
1732         /* identifiers */
1733         ot->name= "Make Normals Consistent";
1734         ot->description= "Make face and vertex normals point either outside or inside the mesh";
1735         ot->idname= "MESH_OT_normals_make_consistent";
1736         
1737         /* api callbacks */
1738         ot->exec= normals_make_consistent_exec;
1739         ot->poll= ED_operator_editmesh;
1740         
1741         /* flags */
1742         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1743         
1744         RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
1745 }
1746
1747
1748
1749 static int do_smooth_vertex(bContext *C, wmOperator *op)
1750 {
1751         Object *obedit= CTX_data_edit_object(C);
1752         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1753         ModifierData *md;
1754         int mirrx=0, mirry=0, mirrz=0;
1755         int i, repeat;
1756
1757         /* if there is a mirror modifier with clipping, flag the verts that
1758          * are within tolerance of the plane(s) of reflection 
1759          */
1760         for(md=obedit->modifiers.first; md; md=md->next) {
1761                 if(md->type==eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
1762                         MirrorModifierData *mmd = (MirrorModifierData*) md;     
1763                 
1764                         if(mmd->flag & MOD_MIR_CLIPPING) {
1765                                 if (mmd->flag & MOD_MIR_AXIS_X)
1766                                         mirrx = 1;
1767                                 if (mmd->flag & MOD_MIR_AXIS_Y)
1768                                         mirry = 1;
1769                                 if (mmd->flag & MOD_MIR_AXIS_Z)
1770                                         mirrz = 1;
1771                         }
1772                 }
1773         }
1774
1775         repeat = RNA_int_get(op->ptr,"repeat");
1776         if (!repeat)
1777                 repeat = 1;
1778         
1779         for (i=0; i<repeat; i++) {
1780                 if (!EDBM_CallOpf(em, op, "vertexsmooth verts=%hv mirror_clip_x=%d mirror_clip_y=%d mirror_clip_z=%d",
1781                                   BM_SELECT, mirrx, mirry, mirrz))
1782                 {
1783                         return OPERATOR_CANCELLED;
1784                 }
1785         }
1786
1787         //BMESH_TODO: need to handle the x-axis editing option here properly.
1788         //should probably make a helper function for that? I dunno.
1789
1790         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1791         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1792
1793         return OPERATOR_FINISHED;
1794 }       
1795         
1796 void MESH_OT_vertices_smooth(wmOperatorType *ot)
1797 {
1798         /* identifiers */
1799         ot->name= "Smooth Vertex";
1800         ot->description= "Flatten angles of selected vertices.";
1801         ot->idname= "MESH_OT_vertices_smooth";
1802         
1803         /* api callbacks */
1804         ot->exec= do_smooth_vertex;
1805         ot->poll= ED_operator_editmesh;
1806         
1807         /* flags */
1808         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1809
1810         RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
1811 }
1812
1813
1814 static int bm_test_exec(bContext *C, wmOperator *UNUSED(op))
1815 {
1816         Object *obedit= CTX_data_edit_object(C);
1817         ARegion *ar = CTX_wm_region(C);
1818         View3D *v3d = CTX_wm_view3d(C);
1819         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1820         BMBVHTree *tree = BMBVH_NewBVH(em, 0, NULL, NULL);
1821         BMIter iter;
1822         BMEdge *e;
1823
1824         /*hide all back edges*/
1825         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1826                 if (!BM_TestHFlag(e, BM_SELECT))
1827                         continue;
1828
1829                 if (!BMBVH_EdgeVisible(tree, e, ar, v3d, obedit))
1830                         BM_Select(em->bm, e, 0);
1831         }
1832
1833         BMBVH_FreeBVH(tree);
1834         
1835 #if 0 //uv island walker test
1836         BMIter iter, liter;
1837         BMFace *f;
1838         BMLoop *l, *l2;
1839         MLoopUV *luv;
1840         BMWalker walker;
1841         int i=0;
1842
1843         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1844                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
1845                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1846                 }
1847         }
1848
1849         BMW_Init(&walker, em->bm, BMW_UVISLAND, 0);
1850
1851         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1852                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
1853                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1854                         if (luv->flag & MLOOPUV_VERTSEL) {
1855                                 l2 = BMW_Begin(&walker, l);
1856                                 for (; l2; l2=BMW_Step(&walker)) {
1857                                         luv = CustomData_bmesh_get(&em->bm->ldata, l2->head.data, CD_MLOOPUV);
1858                                         luv->flag |= MLOOPUV_VERTSEL;
1859                                 }                               
1860                         }
1861                 }
1862         }
1863
1864         BMW_End(&walker);
1865 #endif
1866         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1867         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1868
1869         return OPERATOR_FINISHED;
1870 }       
1871         
1872 void MESH_OT_bm_test(wmOperatorType *ot)
1873 {
1874         /* identifiers */
1875         ot->name= "BMesh Test Operator";
1876         ot->idname= "MESH_OT_bm_test";
1877         
1878         /* api callbacks */
1879         ot->exec= bm_test_exec;
1880         ot->poll= ED_operator_editmesh;
1881         
1882         /* flags */
1883         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1884
1885         //RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
1886 }
1887
1888 /********************** Smooth/Solid Operators *************************/
1889
1890 static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
1891 {
1892         BMIter iter;
1893         BMFace *efa;
1894
1895         if(em==NULL) return;
1896         
1897         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1898                 if (BM_TestHFlag(efa, BM_SELECT)) {
1899                         if (smooth)
1900                                 BM_SetHFlag(efa, BM_SMOOTH);
1901                         else
1902                                 BM_ClearHFlag(efa, BM_SMOOTH);
1903                 }
1904         }
1905 }
1906
1907 static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
1908 {
1909         Object *obedit= CTX_data_edit_object(C);
1910         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1911
1912         mesh_set_smooth_faces(em, 1);
1913
1914         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1915         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1916
1917         return OPERATOR_FINISHED;
1918 }
1919
1920 void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
1921 {
1922         /* identifiers */
1923         ot->name= "Shade Smooth";
1924          ot->description= "Display faces smooth (using vertex normals).";
1925         ot->idname= "MESH_OT_faces_shade_smooth";
1926
1927         /* api callbacks */
1928         ot->exec= mesh_faces_shade_smooth_exec;
1929         ot->poll= ED_operator_editmesh;
1930
1931         /* flags */
1932         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1933 }
1934
1935 static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
1936 {
1937         Object *obedit= CTX_data_edit_object(C);
1938         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1939
1940         mesh_set_smooth_faces(em, 0);
1941
1942         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
1943         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1944
1945         return OPERATOR_FINISHED;
1946 }
1947
1948 void MESH_OT_faces_shade_flat(wmOperatorType *ot)
1949 {
1950         /* identifiers */
1951         ot->name= "Shade Flat";
1952         ot->description= "Display faces flat.";
1953         ot->idname= "MESH_OT_faces_shade_flat";
1954
1955         /* api callbacks */
1956         ot->exec= mesh_faces_shade_flat_exec;
1957         ot->poll= ED_operator_editmesh;
1958
1959         /* flags */
1960         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1961 }
1962
1963
1964 /********************** UV/Color Operators *************************/
1965
1966
1967 static const EnumPropertyItem axis_items[]= {
1968         {OPUVC_AXIS_X, "X", 0, "X", ""},
1969         {OPUVC_AXIS_Y, "Y", 0, "Y", ""},
1970         {0, NULL, 0, NULL, NULL}};
1971
1972 static int mesh_rotate_uvs(bContext *C, wmOperator *op)
1973 {
1974         Object *ob = CTX_data_edit_object(C);
1975         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
1976         BMOperator bmop;
1977
1978         /* get the direction from RNA */
1979         int dir = RNA_enum_get(op->ptr, "direction");
1980
1981         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
1982         EDBM_InitOpf(em, &bmop, op, "meshrotateuvs faces=%hf dir=%d", BM_SELECT, dir);
1983
1984         /* execute the operator */
1985         BMO_Exec_Op(em->bm, &bmop);
1986
1987         /* finish the operator */
1988         if( !EDBM_FinishOp(em, &bmop, op, 1) )
1989                 return OPERATOR_CANCELLED;
1990
1991
1992         /* dependencies graph and notification stuff */
1993         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
1994         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
1995 /*      DAG_id_tag_update(ob->data, OB_RECALC_DATA);
1996         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
1997 */
1998         /* we succeeded */
1999         return OPERATOR_FINISHED;
2000 }
2001
2002 static int mesh_reverse_uvs(bContext *C, wmOperator *op)
2003 {
2004         Object *ob = CTX_data_edit_object(C);
2005         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
2006         BMOperator bmop;
2007
2008         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2009         EDBM_InitOpf(em, &bmop, op, "meshreverseuvs faces=%hf", BM_SELECT);
2010
2011         /* execute the operator */
2012         BMO_Exec_Op(em->bm, &bmop);
2013
2014         /* finish the operator */
2015         if( !EDBM_FinishOp(em, &bmop, op, 1) )
2016                 return OPERATOR_CANCELLED;
2017
2018         /* dependencies graph and notification stuff */
2019         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2020         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2021 /*      DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2022         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2023 */
2024         /* we succeeded */
2025         return OPERATOR_FINISHED;
2026 }
2027
2028 static int mesh_rotate_colors(bContext *C, wmOperator *op)
2029 {
2030         Object *ob = CTX_data_edit_object(C);
2031         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
2032         BMOperator bmop;
2033
2034         /* get the direction from RNA */
2035         int dir = RNA_enum_get(op->ptr, "direction");
2036
2037         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2038         EDBM_InitOpf(em, &bmop, op, "meshrotatecolors faces=%hf dir=%d", BM_SELECT, dir);
2039
2040         /* execute the operator */
2041         BMO_Exec_Op(em->bm, &bmop);
2042
2043         /* finish the operator */
2044         if( !EDBM_FinishOp(em, &bmop, op, 1) )
2045                 return OPERATOR_CANCELLED;
2046
2047
2048         /* dependencies graph and notification stuff */
2049         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2050         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2051 /*      DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
2052         WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob);
2053 */
2054         /* we succeeded */
2055         return OPERATOR_FINISHED;
2056 }
2057
2058
2059 static int mesh_reverse_colors(bContext *C, wmOperator *op)
2060 {
2061         Object *ob = CTX_data_edit_object(C);
2062         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
2063         BMOperator bmop;
2064
2065         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2066         EDBM_InitOpf(em, &bmop, op, "meshreversecolors faces=%hf", BM_SELECT);
2067
2068         /* execute the operator */
2069         BMO_Exec_Op(em->bm, &bmop);
2070
2071         /* finish the operator */
2072         if( !EDBM_FinishOp(em, &bmop, op, 1) )
2073                 return OPERATOR_CANCELLED;
2074
2075         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2076         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2077
2078         /* we succeeded */
2079         return OPERATOR_FINISHED;
2080 #if 0
2081         Scene *scene= CTX_data_scene(C);
2082         Object *obedit= CTX_data_edit_object(C);
2083         EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
2084
2085         EditFace *efa;
2086         short change = 0;
2087         MCol tmpcol, *mcol;
2088         int axis= RNA_enum_get(op->ptr, "axis");
2089
2090         if (!EM_vertColorCheck(em)) {
2091                 BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers");
2092                 BKE_mesh_end_editmesh(obedit->data, em);
2093                 return OPERATOR_CANCELLED;
2094         }
2095
2096         for(efa=em->faces.first; efa; efa=efa->next) {
2097                 if (efa->f & SELECT) {
2098                         mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
2099                         if (axis == AXIS_Y) {
2100                                 tmpcol= mcol[1];
2101                                 mcol[1]= mcol[2];
2102                                 mcol[2]= tmpcol;
2103
2104                                 if(efa->v4) {
2105                                         tmpcol= mcol[0];
2106                                         mcol[0]= mcol[3];
2107                                         mcol[3]= tmpcol;
2108                                 }
2109                         } else {
2110                                 tmpcol= mcol[0];
2111                                 mcol[0]= mcol[1];
2112                                 mcol[1]= tmpcol;
2113
2114                                 if(efa->v4) {
2115                                         tmpcol= mcol[2];
2116                                         mcol[2]= mcol[3];
2117                                         mcol[3]= tmpcol;
2118                                 }
2119                         }
2120                         change = 1;
2121                 }
2122         }
2123
2124         BKE_mesh_end_editmesh(obedit->data, em);
2125
2126         if(!change)
2127                 return OPERATOR_CANCELLED;
2128
2129         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2130         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2131
2132 #endif
2133         return OPERATOR_FINISHED;
2134 }
2135
2136 void MESH_OT_uvs_rotate(wmOperatorType *ot)
2137 {
2138         /* identifiers */
2139         ot->name= "Rotate UVs";
2140         ot->idname= "MESH_OT_uvs_rotate";
2141
2142         /* api callbacks */
2143         ot->exec= mesh_rotate_uvs;
2144         ot->poll= ED_operator_editmesh;
2145
2146         /* flags */
2147         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2148
2149         /* props */
2150         RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around.");
2151 }
2152
2153 //void MESH_OT_uvs_mirror(wmOperatorType *ot)
2154 void MESH_OT_uvs_reverse(wmOperatorType *ot)
2155 {
2156         /* identifiers */
2157         ot->name= "Reverse UVs";
2158         ot->idname= "MESH_OT_uvs_reverse";
2159
2160         /* api callbacks */
2161         ot->exec= mesh_reverse_uvs;
2162         ot->poll= ED_operator_editmesh;
2163
2164         /* flags */
2165         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2166
2167         /* props */
2168         //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around.");
2169 }
2170
2171 void MESH_OT_colors_rotate(wmOperatorType *ot)
2172 {
2173         /* identifiers */
2174         ot->name= "Rotate Colors";
2175         ot->idname= "MESH_OT_colors_rotate";
2176
2177         /* api callbacks */
2178         ot->exec= mesh_rotate_colors;
2179         ot->poll= ED_operator_editmesh;
2180
2181         /* flags */
2182         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2183
2184         /* props */
2185         RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around.");
2186 }
2187
2188 void MESH_OT_colors_reverse(wmOperatorType *ot)
2189 {
2190         /* identifiers */
2191         ot->name= "Reverse Colors";
2192         ot->idname= "MESH_OT_colors_reverse";
2193
2194         /* api callbacks */
2195         ot->exec= mesh_reverse_colors;
2196         ot->poll= ED_operator_editmesh;
2197
2198         /* flags */
2199         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2200
2201         /* props */
2202         //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around.");
2203 }
2204
2205
2206 static int merge_firstlast(BMEditMesh *em, int first, int uvmerge, wmOperator *wmop)
2207 {
2208         BMVert *mergevert;
2209         BMEditSelection *ese;
2210
2211         /* do sanity check in mergemenu in edit.c ?*/
2212         if(first == 0){
2213                 ese = em->bm->selected.last;
2214                 mergevert= (BMVert*)ese->data;
2215         }
2216         else{
2217                 ese = em->bm->selected.first;
2218                 mergevert = (BMVert*)ese->data;
2219         }
2220
2221         if (!BM_TestHFlag(mergevert, BM_SELECT))
2222                 return OPERATOR_CANCELLED;
2223         
2224         if (uvmerge) {
2225                 if (!EDBM_CallOpf(em, wmop, "pointmerge_facedata verts=%hv snapv=%e", BM_SELECT, mergevert))
2226                         return OPERATOR_CANCELLED;
2227         }
2228
2229         if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_SELECT, mergevert->co))
2230                 return OPERATOR_CANCELLED;
2231
2232         return OPERATOR_FINISHED;
2233 }
2234
2235 static int merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob, 
2236                         int target, int uvmerge, wmOperator *wmop)
2237 {
2238         BMIter iter;
2239         BMVert *v;
2240         float *vco=NULL, co[3], cent[3] = {0.0f, 0.0f, 0.0f};
2241
2242         if (target) {
2243                 vco = give_cursor(scene, v3d);
2244                 copy_v3_v3(co, vco);
2245                 mul_m4_v3(ob->imat, co);
2246         }
2247         else {
2248                 float fac;
2249                 int i = 0;
2250                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2251                         if (!BM_TestHFlag(v, BM_SELECT))
2252                                 continue;
2253                         VECADD(cent, cent, v->co);
2254                         i++;
2255                 }
2256                 
2257                 if (!i)
2258                         return OPERATOR_CANCELLED;
2259
2260                 fac = 1.0f / (float)i;
2261                 mul_v3_fl(cent, fac);
2262                 copy_v3_v3(co, cent);
2263                 vco = co;
2264         }
2265
2266         if (!vco)
2267                 return OPERATOR_CANCELLED;
2268         
2269         if (uvmerge) {
2270                 if (!EDBM_CallOpf(em, wmop, "vert_average_facedata verts=%hv", BM_SELECT))
2271                         return OPERATOR_CANCELLED;
2272         }
2273
2274         if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_SELECT, co))
2275                 return OPERATOR_CANCELLED;
2276
2277         return OPERATOR_FINISHED;
2278 }
2279
2280 static int merge_exec(bContext *C, wmOperator *op)
2281 {
2282         Scene *scene= CTX_data_scene(C);
2283         View3D *v3d = CTX_wm_view3d(C);
2284         Object *obedit= CTX_data_edit_object(C);
2285         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2286         int status= 0, uvs= RNA_boolean_get(op->ptr, "uvs");
2287
2288         switch(RNA_enum_get(op->ptr, "type")) {
2289                 case 3:
2290                         status = merge_target(em, scene, v3d, obedit, 0, uvs, op);
2291                         break;
2292                 case 4:
2293                         status = merge_target(em, scene, v3d, obedit, 1, uvs, op);
2294                         break;
2295                 case 1:
2296                         status = merge_firstlast(em, 0, uvs, op);
2297                         break;
2298                 case 6:
2299                         status = merge_firstlast(em, 1, uvs, op);
2300                         break;
2301                 case 5:
2302                         status = 1;
2303                         if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_SELECT))
2304                                 status = 0;
2305                         break;
2306         }
2307
2308         if(!status)
2309                 return OPERATOR_CANCELLED;
2310
2311         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2312         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2313
2314         return OPERATOR_FINISHED;
2315 }
2316
2317 static EnumPropertyItem merge_type_items[]= {
2318         {6, "FIRST", 0, "At First", ""},
2319         {1, "LAST", 0, "At Last", ""},
2320         {3, "CENTER", 0, "At Center", ""},
2321         {4, "CURSOR", 0, "At Cursor", ""},
2322         {5, "COLLAPSE", 0, "Collapse", ""},
2323         {0, NULL, 0, NULL, NULL}};
2324
2325 static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr),  PropertyRNA *UNUSED(prop), int *free)
2326 {       
2327         Object *obedit;
2328         EnumPropertyItem *item= NULL;
2329         int totitem= 0;
2330         
2331         if(!C) /* needed for docs */
2332                 return merge_type_items;
2333         
2334         obedit= CTX_data_edit_object(C);
2335         if(obedit && obedit->type == OB_MESH) {
2336                 BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2337
2338                 if(em->selectmode & SCE_SELECT_VERTEX) {
2339                         if(em->bm->selected.first && em->bm->selected.last &&
2340                                 ((BMEditSelection*)em->bm->selected.first)->type == BM_VERT && ((BMEditSelection*)em->bm->selected.last)->type == BM_VERT) {
2341                                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
2342                                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
2343                         }
2344                         else if(em->bm->selected.first && ((BMEditSelection*)em->bm->selected.first)->type == BM_VERT)
2345                                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
2346                         else if(em->bm->selected.last && ((BMEditSelection*)em->bm->selected.last)->type == BM_VERT)
2347                                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
2348                 }
2349
2350                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3);
2351                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4);
2352                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5);
2353                 RNA_enum_item_end(&item, &totitem);
2354
2355                 *free= 1;
2356
2357                 return item;
2358         }
2359         
2360         return NULL;
2361 }
2362
2363 void MESH_OT_merge(wmOperatorType *ot)
2364 {
2365         /* identifiers */
2366         ot->name= "Merge";
2367         ot->idname= "MESH_OT_merge";
2368
2369         /* api callbacks */
2370         ot->exec= merge_exec;
2371         ot->invoke= WM_menu_invoke;
2372         ot->poll= ED_operator_editmesh;
2373
2374         /* flags */
2375         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2376
2377         /* properties */
2378         ot->prop= RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use.");
2379         RNA_def_enum_funcs(ot->prop, merge_type_itemf);
2380         RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Move UVs according to merge.");
2381 }
2382
2383
2384 static int removedoublesflag_exec(bContext *C, wmOperator *op)
2385 {
2386         Object *obedit= CTX_data_edit_object(C);
2387         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2388         BMOperator bmop;
2389         /* int count; */ /* UNUSED */
2390
2391         EDBM_InitOpf(em, &bmop, op, "finddoubles verts=%hv dist=%f", 
2392                 BM_SELECT, RNA_float_get(op->ptr, "mergedist"));
2393         BMO_Exec_Op(em->bm, &bmop);
2394
2395         /* count = BMO_CountSlotMap(em->bm, &bmop, "targetmapout"); */ /* UNUSED */
2396
2397         if (!EDBM_CallOpf(em, op, "weldverts targetmap=%s", &bmop, "targetmapout")) {
2398                 BMO_Finish_Op(em->bm, &bmop);
2399                 return OPERATOR_CANCELLED;
2400         }
2401
2402         if (!EDBM_FinishOp(em, &bmop, op, 1))
2403                 return OPERATOR_CANCELLED;
2404
2405         /*we need a better way of reporting this, since this doesn't work
2406           with the last operator panel correctly.
2407         if(count)
2408         {
2409                 sprintf(msg, "Removed %d vertices", count);
2410                 BKE_report(op->reports, RPT_INFO, msg);
2411         }
2412         */
2413
2414         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2415         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2416
2417         return OPERATOR_FINISHED;
2418 }
2419
2420 void MESH_OT_remove_doubles(wmOperatorType *ot)
2421 {
2422         /* identifiers */
2423         ot->name= "Remove Doubles";
2424         ot->idname= "MESH_OT_remove_doubles";
2425
2426         /* api callbacks */
2427         ot->exec= removedoublesflag_exec;
2428         ot->poll= ED_operator_editmesh;
2429
2430         /* flags */
2431         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2432
2433         RNA_def_float(ot->srna, "mergedist", 0.0001f, 0.000001f, 50.0f, 
2434                 "Merge Distance", 
2435                 "Minimum distance between elements to merge.", 0.00001, 10.0);
2436 }
2437
2438 /************************ Vertex Path Operator *************************/
2439
2440 typedef struct PathNode {
2441         int u;
2442         int visited;
2443         ListBase edges;
2444 } PathNode;
2445
2446 typedef struct PathEdge {
2447         struct PathEdge *next, *prev;
2448         int v;
2449         float w;
2450 } PathEdge;
2451
2452
2453
2454 static int select_vertex_path_exec(bContext *C, wmOperator *op)
2455 {
2456         Object *ob = CTX_data_edit_object(C);
2457         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
2458         BMOperator bmop;
2459         BMEditSelection *sv, *ev;
2460
2461         /* get the type from RNA */
2462         int type = RNA_enum_get(op->ptr, "type");
2463
2464         sv = em->bm->selected.last;
2465         if( sv != NULL )
2466                 ev = sv->prev;
2467         else return OPERATOR_CANCELLED;
2468         if( ev == NULL )
2469                 return OPERATOR_CANCELLED;
2470
2471         if( sv->type != BM_VERT || ev->type != BM_VERT )
2472                 return OPERATOR_CANCELLED;
2473
2474         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2475         EDBM_InitOpf(em, &bmop, op, "vertexshortestpath startv=%e endv=%e type=%d", sv->data, ev->data, type);
2476
2477         /* execute the operator */
2478         BMO_Exec_Op(em->bm, &bmop);
2479
2480         /* DO NOT clear the existing selection */
2481         /* EDBM_clear_flag_all(em, BM_SELECT); */
2482
2483         /* select the output */
2484         BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_ALL);
2485
2486         /* finish the operator */
2487         if( !EDBM_FinishOp(em, &bmop, op, 1) )
2488                 return OPERATOR_CANCELLED;
2489
2490         EDBM_selectmode_flush(em);
2491
2492         /* dependencies graph and notification stuff */
2493 /*      DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
2494         WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob);
2495 */
2496         DAG_id_tag_update(ob->data, OB_RECALC_DATA);
2497         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2498
2499
2500         /* we succeeded */
2501         return OPERATOR_FINISHED;
2502 #if 0
2503         Object *obedit= CTX_data_edit_object(C);
2504         EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
2505         EditVert *eve, *s, *t;
2506         EditEdge *eed;
2507         EditSelection *ese;
2508         PathEdge *newpe, *currpe;
2509         PathNode *currpn;
2510         PathNode *Q;
2511         int v, *previous, pathvert, pnindex; /*pnindex redundant?*/
2512         int unbalanced, totnodes;
2513         short physical;
2514         float *cost;
2515         Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/
2516
2517         s = t = NULL;
2518
2519         ese = ((BMEditSelection*)em->selected.last);
2520         if(ese && ese->type == BM_VERT && ese->prev && ese->prev->type == BM_VERT) {
2521                 physical= pupmenu("Distance Method? %t|Edge Length%x1|Topological%x0");
2522
2523                 t = (EditVert*)ese->data;
2524                 s = (EditVert*)ese->prev->data;
2525
2526                 /*need to find out if t is actually reachable by s....*/
2527                 for(eve=em->verts.first; eve; eve=eve->next){
2528                         eve->f1 = 0;
2529                 }
2530
2531                 s->f1 = 1;
2532
2533                 unbalanced = 1;
2534                 totnodes = 1;
2535                 while(unbalanced){
2536                         unbalanced = 0;
2537                         for(eed=em->edges.first; eed; eed=eed->next){
2538                                 if(!eed->h){
2539                                         if(eed->v1->f1 && !eed->v2->f1){
2540                                                         eed->v2->f1 = 1;
2541                                                         totnodes++;
2542                                                         unbalanced = 1;
2543                                         }
2544                                         else if(eed->v2->f1 && !eed->v1->f1){
2545                                                         eed->v1->f1 = 1;
2546                                                         totnodes++;
2547                                                         unbalanced = 1;
2548                                         }
2549                                 }
2550                         }
2551                 }
2552
2553                 if(s->f1 && t->f1){ /* t can be reached by s */
2554                         Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes");
2555                         totnodes = 0;
2556                         for(eve=em->verts.first; eve; eve=eve->next){
2557                                 if(eve->f1){
2558                                         Q[totnodes].u = totnodes;
2559                                         Q[totnodes].edges.first = 0;
2560                                         Q[totnodes].edges.last = 0;
2561                                         Q[totnodes].visited = 0;
2562                                         eve->tmp.p = &(Q[totnodes]);
2563                                         totnodes++;
2564                                 }
2565                                 else eve->tmp.p = NULL;
2566                         }
2567
2568                         for(eed=em->edges.first; eed; eed=eed->next){
2569                                 if(!eed->h){
2570                                         if(eed->v1->f1){
2571                                                 currpn = ((PathNode*)eed->v1->tmp.p);
2572
2573                                                 newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
2574                                                 newpe->v = ((PathNode*)eed->v2->tmp.p)->u;
2575                                                 if(physical){
2576                                                                 newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
2577                                                 }
2578                                                 else newpe->w = 1;
2579                                                 newpe->next = 0;
2580                                                 newpe->prev = 0;
2581                                                 BLI_addtail(&(currpn->edges), newpe);
2582                                         }
2583                                         if(eed->v2->f1){
2584                                                 currpn = ((PathNode*)eed->v2->tmp.p);
2585                                                 newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
2586                                                 newpe->v = ((PathNode*)eed->v1->tmp.p)->u;
2587                                                 if(physical){
2588                                                                 newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
2589                                                 }
2590                                                 else newpe->w = 1;
2591                                                 newpe->next = 0;
2592                                                 newpe->prev = 0;
2593                                                 BLI_addtail(&(currpn->edges), newpe);
2594                                         }
2595                                 }
2596                         }
2597
2598                         heap = BLI_heap_new();
2599                         cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs");
2600                         previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices");
2601
2602                         for(v=0; v < totnodes; v++){
2603                                 cost[v] = 1000000;
2604                                 previous[v] = -1; /*array of indices*/
2605                         }
2606
2607                         pnindex = ((PathNode*)s->tmp.p)->u;
2608                         cost[pnindex] = 0;
2609                         BLI_heap_insert(heap,  0.0f, SET_INT_IN_POINTER(pnindex));
2610
2611                         while( !BLI_heap_empty(heap) ){
2612
2613                                 pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
2614                                 currpn = &(Q[pnindex]);
2615
2616                                 if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/
2617                                         break;
2618
2619                                 for(currpe=currpn->edges.first; currpe; currpe=currpe->next){
2620                                         if(!Q[currpe->v].visited){
2621                                                 if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){
2622                                                         cost[currpe->v] = cost[currpn->u] + currpe->w;
2623                                                         previous[currpe->v] = currpn->u;
2624                                                         Q[currpe->v].visited = 1;
2625                                                         BLI_heap_insert(heap, cost[currpe->v], SET_INT_IN_POINTER(currpe->v));
2626                                                 }
2627                                         }
2628                                 }
2629                         }
2630
2631                         pathvert = ((PathNode*)t->tmp.p)->u;
2632                         while(pathvert != -1){
2633                                 for(eve=em->verts.first; eve; eve=eve->next){
2634                                         if(eve->f1){
2635                                                 if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT;
2636                                         }
2637                                 }
2638                                 pathvert = previous[pathvert];
2639                         }
2640
2641                         for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges));
2642                         MEM_freeN(Q);
2643                         MEM_freeN(cost);
2644                         MEM_freeN(previous);
2645                         BLI_heap_free(heap, NULL);
2646                         EM_select_flush(em);
2647                 }
2648         }
2649         else {
2650                 BKE_mesh_end_editmesh(obedit->data, em);
2651                 BKE_report(op->reports, RPT_ERROR, "Path Selection requires that exactly two vertices be selected");
2652                 return OPERATOR_CANCELLED;
2653         }
2654
2655         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
2656         BKE_mesh_end_editmesh(obedit->data, em);
2657 #endif
2658 }
2659
2660 void MESH_OT_select_vertex_path(wmOperatorType *ot)
2661 {
2662         static const EnumPropertyItem type_items[] = {
2663                 {VPATH_SELECT_EDGE_LENGTH, "EDGE_LENGTH", 0, "Edge Length", NULL},
2664                 {VPATH_SELECT_TOPOLOGICAL, "TOPOLOGICAL", 0, "Topological", NULL},
2665                 {0, NULL, 0, NULL, NULL}};
2666
2667         /* identifiers */
2668         ot->name= "Select Vertex Path";
2669         ot->idname= "MESH_OT_select_vertex_path";
2670
2671         /* api callbacks */
2672         ot->exec= select_vertex_path_exec;
2673         ot->poll= ED_operator_editmesh;
2674
2675         /* flags */
2676         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2677
2678         /* properties */
2679         RNA_def_enum(ot->srna, "type", type_items, VPATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance.");
2680 }
2681 /********************** Rip Operator *************************/
2682
2683 /* helper to find edge for edge_rip */
2684 static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, const int mval[2])
2685 {
2686         float vec1[3], vec2[3], mvalf[2];
2687
2688         ED_view3d_project_float(ar, co1, vec1, mat);
2689         ED_view3d_project_float(ar, co2, vec2, mat);
2690         mvalf[0]= (float)mval[0];
2691         mvalf[1]= (float)mval[1];
2692
2693         return dist_to_line_segment_v2(mvalf, vec1, vec2);
2694 }
2695
2696 /* based on mouse cursor position, it defines how is being ripped */
2697 static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
2698 {
2699         Object *obedit= CTX_data_edit_object(C);
2700         ARegion *ar= CTX_wm_region(C);
2701         View3D *v3d = CTX_wm_view3d(C);
2702         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2703         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2704         BMOperator bmop;
2705         BMBVHTree *bvhtree;
2706         BMOIter siter;
2707         BMIter iter, eiter, liter;
2708         BMLoop *l;
2709         BMEdge *e, *e2, *closest = NULL;
2710         BMVert *v;
2711         int side = 0, i, singlesel = 0;
2712         float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
2713         float dist = FLT_MAX, d;
2714
2715         ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
2716
2717         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2718                 if (BM_TestHFlag(e, BM_SELECT))
2719                         BM_SetIndex(e, 1);
2720                 else BM_SetIndex(e, 0);
2721         }
2722
2723         /*handle case of one vert selected.  identify
2724           closest edge around that vert to mouse cursor,
2725           then rip two adjacent edges in the vert fan.*/
2726         if (em->bm->totvertsel == 1 && em->bm->totedgesel == 0 && em->bm->totfacesel == 0) {
2727                 singlesel = 1;
2728
2729                 /*find selected vert*/
2730                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2731                         if (BM_TestHFlag(v, BM_SELECT))
2732                                 break;
2733                 }
2734
2735                 /*this should be impossible, but sanity checks are a good thing*/
2736                 if (!v)
2737                         return OPERATOR_CANCELLED;
2738
2739                 /*find closest edge to mouse cursor*/
2740                 e2 = NULL;
2741                 BM_ITER(e, &iter, em->bm, BM_EDGES_OF_VERT, v) {
2742                         d = mesh_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, event->mval);
2743                         if (d < dist) {
2744                                 dist = d;
2745                                 e2 = e;
2746                         }
2747                 }
2748
2749                 if (!e2)
2750                         return OPERATOR_CANCELLED;
2751
2752                 /*rip two adjacent edges*/
2753                 if (BM_Edge_FaceCount(e2) == 1) {
2754                         l = e2->l;
2755                         e = BM_OtherFaceLoop(e2, l->f, v)->e;
2756
2757                         BM_SetIndex(e, 1);
2758                         BM_SetHFlag(e, BM_SELECT);
2759                 } else if (BM_Edge_FaceCount(e2) == 2) {
2760                         l = e2->l;
2761                         e = BM_OtherFaceLoop(e2, l->f, v)->e;
2762                         BM_SetIndex(e, 1);
2763                         BM_SetHFlag(e, BM_SELECT);
2764                         
2765                         l = e2->l->radial_next;
2766                         e = BM_OtherFaceLoop(e2, l->f, v)->e;
2767                         BM_SetIndex(e, 1);
2768                         BM_SetHFlag(e, BM_SELECT);
2769                 }
2770
2771                 dist = FLT_MAX;
2772         } else {
2773                 /*expand edge selection*/
2774                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2775                         e2 = NULL;
2776                         i = 0;
2777                         BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
2778                                 if (BM_GetIndex(e)) {
2779                                         e2 = e;
2780                                         i++;
2781                                 }
2782                         }
2783                         
2784                         if (i == 1 && e2->l) {
2785                                 l = BM_OtherFaceLoop(e2, e2->l->f, v);
2786                                 l = l->radial_next;
2787                                 l = BM_OtherFaceLoop(l->e, l->f, v);
2788
2789                                 if (l)
2790                                         BM_Select(em->bm, l->e, 1);
2791                         }
2792                 }
2793         }
2794
2795         if (!EDBM_InitOpf(em, &bmop, op, "edgesplit edges=%he", BM_SELECT)) {
2796                 return OPERATOR_CANCELLED;
2797         }
2798         
2799         BMO_Exec_Op(em->bm, &bmop);
2800
2801         /*build bvh tree for edge visibility tests*/
2802         bvhtree = BMBVH_NewBVH(em, 0, NULL, NULL);
2803
2804         for (i=0; i<2; i++) {
2805                 BMO_ITER(e, &siter, em->bm, &bmop, i ? "edgeout2":"edgeout1", BM_EDGE) {
2806                         float cent[3] = {0, 0, 0}, mid[3], vec[3];
2807
2808                         if (!BMBVH_EdgeVisible(bvhtree, e, ar, v3d, obedit) || !e->l)
2809                                 continue;
2810
2811                         /* method for calculating distance:
2812                          *
2813                          * for each edge: calculate face center, then made a vector
2814                          * from edge midpoint to face center.  offset edge midpoint
2815                          * by a small amount along this vector. */
2816                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, e->l->f) {
2817                                 add_v3_v3(cent, l->v->co);
2818                         }
2819                         mul_v3_fl(cent, 1.0f/(float)e->l->f->len);
2820
2821                         mid_v3_v3v3(mid, e->v1->co, e->v2->co);
2822                         sub_v3_v3v3(vec, cent, mid);
2823                         normalize_v3(vec);
2824                         mul_v3_fl(vec, 0.01f);
2825                         add_v3_v3v3(mid, mid, vec);
2826
2827                         /* yay we have our comparison point, now project it */
2828                         ED_view3d_project_float(ar, mid, mid, projectMat);
2829
2830                         d = len_squared_v2v2(fmval, mid);
2831
2832                         if (d < dist) {
2833                                 side = i;
2834                                 closest = e;
2835                                 dist = d;
2836                         }
2837                 }
2838         }
2839         
2840         EDBM_clear_flag_all(em, BM_SELECT);
2841         BMO_HeaderFlag_Buffer(em->bm, &bmop, side?"edgeout2":"edgeout1", BM_SELECT, BM_EDGE);
2842
2843         BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
2844                 if (BM_TestHFlag(e, BM_SELECT))
2845                         BM_SetIndex(e, 1);
2846                 else BM_SetIndex(e, 0);
2847         }
2848
2849         /*constrict edge selection again*/
2850         BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2851                 e2 = NULL;
2852                 i = 0;
2853                 BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
2854                         if (BM_GetIndex(e)) {
2855                                 e2 = e;
2856                                 i++;
2857                         }
2858                 }
2859                 
2860                 if (i == 1)  {
2861                         if (singlesel)
2862                                 BM_Select(em->bm, v, 0);
2863                         else
2864                                 BM_Select(em->bm, e2, 0);
2865                 }
2866         }
2867
2868         EDBM_selectmode_flush(em);
2869         
2870         if (!EDBM_FinishOp(em, &bmop, op, 1)) {
2871                 BMBVH_FreeBVH(bvhtree);
2872                 return OPERATOR_CANCELLED;
2873         }
2874         
2875         BMBVH_FreeBVH(bvhtree);
2876
2877         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2878         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2879
2880         return OPERATOR_FINISHED;
2881 }
2882
2883 void MESH_OT_rip(wmOperatorType *ot)
2884 {
2885         /* identifiers */
2886         ot->name= "Rip";
2887         ot->idname= "MESH_OT_rip";
2888
2889         /* api callbacks */
2890         ot->invoke= mesh_rip_invoke;
2891         ot->poll= EM_view3d_poll;
2892
2893         /* flags */
2894         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2895
2896         /* to give to transform */
2897         Transform_Properties(ot, P_PROPORTIONAL);
2898         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
2899 }
2900
2901 /************************ Shape Operators *************************/
2902
2903 /*BMESH_TODO this should be properly encapsulated in a bmop.  but later.*/
2904 static void shape_propagate(Object *obedit, BMEditMesh *em, wmOperator *op)
2905 {
2906         BMIter iter;
2907         BMVert *eve = NULL;
2908         float *co;
2909         int i, totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
2910
2911         if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
2912                 BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys");
2913                 return;
2914         }
2915         
2916         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2917                 if (!BM_TestHFlag(eve, BM_SELECT) || BM_TestHFlag(eve, BM_HIDDEN))
2918                         continue;
2919
2920                 for (i=0; i<totshape; i++) {
2921                         co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i);
2922                         copy_v3_v3(co, eve->co);
2923                 }
2924         }
2925
2926 #if 0
2927         //TAG Mesh Objects that share this data
2928         for(base = scene->base.first; base; base = base->next){
2929                 if(base->object && base->object->data == me){
2930                         base->object->recalc = OB_RECALC_DATA;
2931                 }
2932         }
2933 #endif
2934
2935         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
2936 }
2937
2938
2939 static int shape_propagate_to_all_exec(bContext *C, wmOperator *op)
2940 {
2941         Object *obedit= CTX_data_edit_object(C);
2942         Mesh *me= obedit->data;
2943         BMEditMesh *em= me->edit_btmesh;
2944
2945         shape_propagate(obedit, em, op);
2946
2947         DAG_id_tag_update(&me->id, OB_RECALC_DATA);
2948         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
2949
2950         return OPERATOR_FINISHED;
2951 }
2952
2953
2954 void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
2955 {
2956         /* identifiers */
2957         ot->name= "Shape Propagate";
2958         ot->description= "Apply selected vertex locations to all other shape keys.";
2959         ot->idname= "MESH_OT_shape_propagate_to_all";
2960
2961         /* api callbacks */
2962         ot->exec= shape_propagate_to_all_exec;
2963         ot->poll= ED_operator_editmesh;
2964
2965         /* flags */
2966         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2967 }
2968
2969 /*BMESH_TODO this should be properly encapsulated in a bmop.  but later.*/
2970 static int blend_from_shape_exec(bContext *C, wmOperator *op)
2971 {
2972         Object *obedit= CTX_data_edit_object(C);
2973         Mesh *me= obedit->data;
2974         BMEditMesh *em= me->edit_btmesh;
2975         BMVert *eve;
2976         BMIter iter;
2977         float co[3], *sco;
2978         float blend= RNA_float_get(op->ptr, "blend");
2979         int shape= RNA_enum_get(op->ptr, "shape");
2980         int add= RNA_boolean_get(op->ptr, "add");
2981         int totshape;
2982
2983         /*sanity check*/
2984         totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
2985         if (totshape == 0 || shape < 0 || shape >= totshape)
2986                 return OPERATOR_CANCELLED;
2987
2988         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2989                 if (!BM_TestHFlag(eve, BM_SELECT) || BM_TestHFlag(eve, BM_HIDDEN))
2990                         continue;
2991
2992                 sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
2993                 copy_v3_v3(co, sco);
2994
2995
2996                 if(add) {
2997                         mul_v3_fl(co, blend);
2998                         add_v3_v3v3(eve->co, eve->co, co);
2999                 }
3000                 else
3001                         interp_v3_v3v3(eve->co, eve->co, co, blend);
3002                 
3003                 copy_v3_v3(sco, co);
3004         }
3005
3006         DAG_id_tag_update(&me->id, OB_RECALC_DATA);
3007         WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
3008
3009         return OPERATOR_FINISHED;
3010 }
3011
3012 static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr),  PropertyRNA *UNUSED(prop), int *free)
3013 {       
3014         Object *obedit= CTX_data_edit_object(C);
3015         Mesh *me= (obedit) ? obedit->data : NULL;
3016         BMEditMesh *em = me->edit_btmesh;
3017         EnumPropertyItem *item= NULL;
3018         int totitem= 0;
3019
3020         if(obedit && obedit->type == OB_MESH && CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
3021                 EnumPropertyItem tmp= {0, "", 0, "", ""};
3022                 int a;
3023
3024                 for (a=0; a<em->bm->vdata.totlayer; a++) {
3025                         if (em->bm->vdata.layers[a].type != CD_SHAPEKEY)
3026                                 continue;
3027
3028                         tmp.value= totitem;
3029                         tmp.identifier= em->bm->vdata.layers[a].name;
3030                         tmp.name= em->bm->vdata.layers[a].name;
3031                         RNA_enum_item_add(&item, &totitem, &tmp);
3032
3033                         totitem++;
3034                 }
3035         }
3036
3037         RNA_enum_item_end(&item, &totitem);
3038         *free= 1;
3039
3040         return item;
3041 }
3042
3043 void MESH_OT_blend_from_shape(wmOperatorType *ot)
3044 {
3045         PropertyRNA *prop;
3046         static EnumPropertyItem shape_items[]= {{0, NULL, 0, NULL, NULL}};
3047
3048         /* identifiers */
3049         ot->name= "Blend From Shape";
3050         ot->description= "Blend in shape from a shape key.";
3051         ot->idname= "MESH_OT_blend_from_shape";
3052
3053         /* api callbacks */
3054         ot->exec= blend_from_shape_exec;
3055         ot->invoke= WM_operator_props_popup;
3056         ot->poll= ED_operator_editmesh;
3057
3058         /* flags */
3059         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3060
3061         /* properties */
3062         prop= RNA_def_enum(ot->srna, "shape", shape_items, 0, "Shape", "Shape key to use for blending.");
3063         RNA_def_enum_funcs(prop, shape_itemf);
3064         RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor.", -2.0f, 2.0f);
3065         RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather then blend between shapes.");
3066 }
3067
3068 /* BMESH_TODO - some way to select on an arbitrary axis */
3069 static int select_axis_exec(bContext *C, wmOperator *op)
3070 {
3071         Object *obedit= CTX_data_edit_object(C);
3072         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
3073         BMEditSelection *ese = em->bm->selected.last;
3074         int axis= RNA_enum_get(op->ptr, "axis");
3075         int mode= RNA_enum_get(op->ptr, "mode"); /* -1==aligned, 0==neg, 1==pos*/
3076
3077         if(ese==NULL)
3078                 return OPERATOR_CANCELLED;
3079
3080         if(ese->type==BM_VERT) {
3081                 BMVert *ev, *act_vert= (BMVert*)ese->data;
3082                 BMIter iter;
3083                 float value= act_vert->co[axis];
3084                 float limit=  CTX_data_tool_settings(C)->doublimit; // XXX
3085
3086                 if(mode==0)
3087                         value -= limit;
3088                 else if (mode==1) 
3089                         value += limit;
3090
3091                 BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
3092                         if(!BM_TestHFlag(ev, BM_HIDDEN)) {
3093                                 switch(mode) {
3094                                 case -1: /* aligned */
3095                                         if(fabs(ev->co[axis] - value) < limit)
3096                                                 BM_Select(em->bm, ev, 1);
3097                                         break;
3098                                 case 0: /* neg */
3099                                         if(ev->co[axis] > value)
3100                                                 BM_Select(em->bm, ev, 1);
3101                                         break;
3102                                 case 1: /* pos */
3103                                         if(ev->co[axis] < value)
3104                                                 BM_Select(em->bm, ev, 1);
3105                                         break;
3106                                 }
3107                         }
3108                 }
3109         }
3110
3111         EDBM_selectmode_flush(em);
3112         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
3113
3114         return OPERATOR_FINISHED;
3115 }
3116
3117 void MESH_OT_select_axis(wmOperatorType *ot)
3118 {
3119         static EnumPropertyItem axis_mode_items[] = {
3120                 {0,  "POSITIVE", 0, "Positive Axis", ""},
3121                 {1,  "NEGATIVE", 0, "Negative Axis", ""},
3122                 {-1, "ALIGNED",  0, "Aligned Axis", ""},
3123                 {0, NULL, 0, NULL, NULL}};
3124
3125         static EnumPropertyItem axis_items_xyz[] = {
3126                 {0, "X_AXIS", 0, "X Axis", ""},
3127                 {1, "Y_AXIS", 0, "Y Axis", ""},
3128                 {2, "Z_AXIS", 0, "Z Axis", ""},
3129                 {0, NULL, 0, NULL, NULL}};
3130
3131         /* identifiers */
3132         ot->name= "Select Axis";
3133         ot->description= "Select all data in the mesh on a single axis.";
3134         ot->idname= "MESH_OT_select_axis";
3135
3136         /* api callbacks */
3137         ot->exec= select_axis_exec;
3138         ot->poll= ED_operator_editmesh;
3139
3140         /* flags */
3141         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3142
3143         /* properties */
3144         RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting");
3145         RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on");
3146 }
3147
3148 static int solidify_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
3149 {
3150 #if 0
3151         Object *obedit= CTX_data_edit_object(C);
3152         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
3153         float nor[3] = {0,0,1};
3154
3155         float thickness= RNA_float_get(op->ptr, "thickness");
3156
3157         extrudeflag(obedit, em, SELECT, nor, 1);
3158         EM_make_hq_normals(em);
3159         EM_solidify(em, thickness);
3160
3161
3162         /* update vertex normals too */
3163         recalc_editnormals(em);
3164
3165         BKE_mesh_end_editmesh(obedit->data, em);
3166
3167         DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
3168         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
3169
3170         return OPERATOR_FINISHED;
3171 #endif
3172         return OPERATOR_CANCELLED;
3173 }
3174
3175
3176 void MESH_OT_solidify(wmOperatorType *ot)
3177 {
3178         PropertyRNA *prop;
3179         /* identifiers */
3180         ot->name= "Solidify";
3181         ot->description= "Create a solid skin by extruding, compensating for sharp angles.";
3182         ot->idname= "MESH_OT_solidify";
3183
3184         /* api callbacks */
3185         ot->exec= solidify_exec;
3186         ot->poll= ED_operator_editmesh;
3187
3188         /* flags */
3189         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3190
3191         prop= RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "thickness", "", -10.0f, 10.0f);
3192         RNA_def_property_ui_range(prop, -10, 10, 0.1, 4);
3193 }
3194
3195 #define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */
3196 #define TRAIL_FREEHAND 2
3197 #define TRAIL_MIXED    3 /* (1|2) */
3198 #define TRAIL_AUTO     4 
3199 #define TRAIL_MIDPOINTS 8
3200
3201 typedef struct CutCurve {
3202         float  x; 
3203         float  y;
3204 } CutCurve;
3205
3206 /* ******************************************************************** */
3207 /* Knife Subdivide Tool.  Subdivides edges intersected by a mouse trail
3208         drawn by user.
3209         
3210         Currently mapped to KKey when in MeshEdit mode.
3211         Usage:
3212                 Hit Shift K, Select Centers or Exact
3213                 Hold LMB down to draw path, hit RETKEY.
3214                 ESC cancels as expected.
3215    
3216         Contributed by Robert Wenzlaff (Det. Thorn).
3217
3218     2.5 revamp:
3219     - non modal (no menu before cutting)
3220     - exit on mouse release
3221     - polygon/segment drawing can become handled by WM cb later
3222
3223         bmesh port version
3224 */
3225
3226 #define KNIFE_EXACT             1
3227 #define KNIFE_MIDPOINT  2
3228 #define KNIFE_MULTICUT  3
3229
3230 static EnumPropertyItem knife_items[]= {
3231         {KNIFE_EXACT, "EXACT", 0, "Exact", ""},
3232         {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""},
3233         {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""},
3234         {0, NULL, 0, NULL, NULL}
3235 };
3236
3237 /* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */
3238
3239 static float bm_seg_intersect(BMEdge *e, CutCurve *c, int len, char mode,
3240                               struct GHash *gh, int *isected)
3241 {
3242 #define MAXSLOPE 100000
3243         float  x11, y11, x12=0, y12=0, x2max, x2min, y2max;
3244         float  y2min, dist, lastdist=0, xdiff2, xdiff1;
3245         float  m1, b1, m2, b2, x21, x22, y21, y22, xi;
3246         float  yi, x1min, x1max, y1max, y1min, perc=0; 
3247         float  *scr;
3248         float  threshold = 0.0;
3249         int  i;
3250         
3251         //threshold = 0.000001; /*tolerance for vertex intersection*/
3252         // XXX  threshold = scene->toolsettings->select_thresh / 100;
3253         
3254         /* Get screen coords of verts */
3255         scr = BLI_ghash_lookup(gh, e->v1);
3256         x21=scr[0];
3257         y21=scr[1];
3258         
3259         scr = BLI_ghash_lookup(gh, e->v2);
3260         x22=scr[0];
3261         y22=scr[1];
3262         
3263         xdiff2=(x22-x21);  
3264         if (xdiff2) {
3265                 m2=(y22-y21)/xdiff2;
3266                 b2= ((x22*y21)-(x21*y22))/xdiff2;
3267         }
3268         else {
3269                 m2=MAXSLOPE;  /* Verticle slope  */
3270                 b2=x22;      
3271         }
3272
3273         *isected = 0;
3274
3275         /*check for *exact* vertex intersection first*/
3276         if(mode!=KNIFE_MULTICUT){
3277                 for (i=0; i<len; i++){
3278                         if (i>0){
3279                                 x11=x12;
3280                                 y11=y12;
3281                         }
3282                         else {
3283                                 x11=c[i].x;
3284                                 y11=c[i].y;
3285                         }
3286                         x12=c[i].x;
3287                         y12=c[i].y;
3288                         
3289                         /*test e->v1*/
3290                         if((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)){
3291                                 perc = 0;
3292                                 *isected = 1;
3293                                 return(perc);
3294                         }
3295                         /*test e->v2*/