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