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