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