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