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