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