194a3ea9ebea9a181b80fdfb72070744ffc02114
[blender-staging.git] / source / blender / editors / mesh / bmesh_tools.c
1  /* $Id: bmesh_tools.c
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2004 by Blender Foundation.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): Joseph Eagar
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "MEM_guardedalloc.h"
35 #include "PIL_time.h"
36
37 #include "BLO_sys_types.h" // for intptr_t support
38
39 #include "DNA_mesh_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_modifier_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_view3d_types.h"
47 #include "DNA_key_types.h"
48 #include "DNA_windowmanager_types.h"
49
50 #include "RNA_types.h"
51 #include "RNA_define.h"
52 #include "RNA_access.h"
53
54 #include "BLI_blenlib.h"
55 #include "BLI_arithb.h"
56 #include "BLI_editVert.h"
57 #include "BLI_rand.h"
58 #include "BLI_ghash.h"
59 #include "BLI_linklist.h"
60 #include "BLI_heap.h"
61
62 #include "BKE_context.h"
63 #include "BKE_customdata.h"
64 #include "BKE_depsgraph.h"
65 #include "BKE_global.h"
66 #include "BKE_library.h"
67 #include "BKE_mesh.h"
68 #include "BKE_object.h"
69 #include "BKE_utildefines.h"
70 #include "BKE_bmesh.h"
71 #include "BKE_report.h"
72 #include "BKE_tessmesh.h"
73
74 #include "BIF_gl.h"
75 #include "BIF_glutil.h"
76
77 #include "WM_api.h"
78 #include "WM_types.h"
79
80 #include "ED_mesh.h"
81 #include "ED_view3d.h"
82 #include "ED_util.h"
83 #include "ED_screen.h"
84 #include "ED_transform.h"
85
86 #include "UI_interface.h"
87
88 #include "mesh_intern.h"
89 #include "bmesh.h"
90
91 static void add_normal_aligned(float *nor, float *add)
92 {
93         if( INPR(nor, add) < -0.9999f)
94                 VecSubf(nor, nor, add);
95         else
96                 VecAddf(nor, nor, add);
97 }
98
99
100 static int subdivide_exec(bContext *C, wmOperator *op)
101 {
102         Scene *scene = CTX_data_scene(C);
103         Object *obedit= CTX_data_edit_object(C);
104         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
105         int cuts= RNA_int_get(op->ptr,"number_cuts");
106         float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness");
107         float fractal= RNA_float_get(op->ptr, "fractal")/100;
108         int flag= 0;
109
110         if(smooth != 0.0f)
111                 flag |= B_SMOOTH;
112         if(fractal != 0.0f)
113                 flag |= B_FRACTAL;
114
115         BM_esubdivideflag(obedit, em->bm, BM_SELECT, smooth, fractal, scene->toolsettings->editbutflag|flag, cuts, 0);
116
117         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
118         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
119
120         return OPERATOR_FINISHED;
121 }
122
123 void MESH_OT_subdivide(wmOperatorType *ot)
124 {
125         /* identifiers */
126         ot->name= "Subdivide";
127         ot->idname= "MESH_OT_subdivide";
128
129         /* api callbacks */
130         ot->exec= subdivide_exec;
131         ot->poll= ED_operator_editmesh;
132
133         /* flags */
134         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
135
136         /* properties */
137         RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX);
138         RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
139         RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1000.0f, "Smoothness", "Smoothness factor.", 0.0f, FLT_MAX);
140 }
141
142 #if 0
143 static int subdivide_exec(bContext *C, wmOperator *op)
144 {
145         Object *obedit= CTX_data_edit_object(C);
146         Scene *scene = CTX_data_scene(C);
147         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
148         
149         BM_esubdivideflag(obedit, em->bm, 1, 0.0, scene->toolsettings->editbutflag, 1, 0);
150                 
151         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
152
153         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
154
155         return OPERATOR_FINISHED;       
156 }
157
158 void MESH_OT_subdivide(wmOperatorType *ot)
159 {
160         /* identifiers */
161         ot->name= "Subdivide";
162         ot->idname= "MESH_OT_subdivide";
163         
164         /* api callbacks */
165         ot->exec= subdivide_exec;
166         ot->poll= ED_operator_editmesh;
167         
168         /* flags */
169         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
170 }
171
172 static int subdivide_multi_exec(bContext *C, wmOperator *op)
173 {
174         Object *obedit= CTX_data_edit_object(C);
175         Scene *scene = CTX_data_scene(C);
176         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
177         
178         BM_esubdivideflag(obedit, em->bm, 1, 0.0, scene->toolsettings->editbutflag, RNA_int_get(op->ptr,"number_cuts"), 0);
179                 
180         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
181         
182         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
183
184         return OPERATOR_FINISHED;       
185 }
186
187 void MESH_OT_subdivide_multi(wmOperatorType *ot)
188 {
189         /* identifiers */
190         ot->name= "Subdivide Multi";
191         ot->idname= "MESH_OT_subdivide_multi";
192         
193         /* api callbacks */
194         ot->exec= subdivide_multi_exec;
195         ot->poll= ED_operator_editmesh;
196         
197         /* flags */
198         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
199         
200         /* props */
201         RNA_def_int(ot->srna, "number_cuts", 4, 1, 100, "Number of Cuts", "", 1, INT_MAX);
202 }
203
204 static int subdivide_multi_fractal_exec(bContext *C, wmOperator *op)
205 {
206         Object *obedit= CTX_data_edit_object(C);
207         Scene *scene = CTX_data_scene(C);
208         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
209
210         BM_esubdivideflag(obedit, em->bm, 1, -(RNA_float_get(op->ptr, "random_factor")/100), scene->toolsettings->editbutflag, RNA_int_get(op->ptr, "number_cuts"), 0);
211                 
212         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
213         
214         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
215
216         return OPERATOR_FINISHED;       
217 }
218
219 void MESH_OT_subdivide_multi_fractal(wmOperatorType *ot)
220 {
221         /* identifiers */
222         ot->name= "Subdivide Multi Fractal";
223         ot->idname= "MESH_OT_subdivide_multi_fractal";
224         
225         /* api callbacks */
226         ot->exec= subdivide_multi_fractal_exec;
227         ot->poll= ED_operator_editmesh;
228
229         /* flags */
230         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
231         
232         /* properties */
233         RNA_def_int(ot->srna, "number_cuts", 4, 1, 100, "Number of Cuts", "", 1, INT_MAX);
234         RNA_def_float(ot->srna, "random_factor", 5.0, 0.0f, FLT_MAX, "Random Factor", "", 0.0f, 1000.0f);
235 }
236
237 static int subdivide_smooth_exec(bContext *C, wmOperator *op)
238 {
239         Object *obedit= CTX_data_edit_object(C);
240         Scene *scene = CTX_data_scene(C);
241         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
242
243         BM_esubdivideflag(obedit, em->bm, 1, 0.292f*RNA_float_get(op->ptr, "smoothness"), scene->toolsettings->editbutflag | B_SMOOTH, 1, 0);
244                 
245         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
246         
247         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
248
249         return OPERATOR_FINISHED;       
250 }
251
252 void MESH_OT_subdivide_smooth(wmOperatorType *ot)
253 {
254         /* identifiers */
255         ot->name= "Subdivide Smooth";
256         ot->idname= "MESH_OT_subdivide_smooth";
257         
258         /* api callbacks */
259         ot->exec= subdivide_smooth_exec;
260         ot->poll= ED_operator_editmesh;
261
262         /* flags */
263         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
264         
265         /* props */
266         RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1000.0f, "Smoothness", "", 0.0f, FLT_MAX);
267 }
268
269 static int subdivs_invoke(bContext *C, wmOperator *op, wmEvent *event)
270 {
271         uiPopupMenu *pup;
272         uiLayout *layout;
273
274         pup= uiPupMenuBegin(C, "Subdivision Type", 0);
275         layout= uiPupMenuLayout(pup);
276         uiItemsEnumO(layout, "MESH_OT_subdivs", "type");
277         uiPupMenuEnd(C, pup);
278         
279         return OPERATOR_CANCELLED;
280 }
281
282 static int subdivs_exec(bContext *C, wmOperator *op)
283 {       
284         switch(RNA_int_get(op->ptr, "type"))
285         {
286                 case 0: // simple
287                         subdivide_exec(C,op);
288                         break;
289                 case 1: // multi
290                         subdivide_multi_exec(C,op);
291                         break;
292                 case 2: // fractal;
293                         subdivide_multi_fractal_exec(C,op);
294                         break;
295                 case 3: //smooth
296                         subdivide_smooth_exec(C,op);
297                         break;
298         }
299                                          
300         return OPERATOR_FINISHED;
301 }
302
303 void MESH_OT_subdivs(wmOperatorType *ot)
304 {
305         static EnumPropertyItem type_items[]= {
306                 {0, "SIMPLE", 0, "Simple", ""},
307                 {1, "MULTI", 0, "Multi", ""},
308                 {2, "FRACTAL", 0, "Fractal", ""},
309                 {3, "SMOOTH", 0, "Smooth", ""},
310                 {0, NULL, NULL}};
311
312         /* identifiers */
313         ot->name= "subdivs";
314         ot->idname= "MESH_OT_subdivs";
315         
316         /* api callbacks */
317         ot->invoke= subdivs_invoke;
318         ot->exec= subdivs_exec;
319         
320         ot->poll= ED_operator_editmesh;
321         
322         /* flags */
323         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
324         
325         /*props */
326         RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
327         
328         /* this is temp, the ops are different, but they are called from subdivs, so all the possible props should be here as well*/
329         RNA_def_int(ot->srna, "number_cuts", 4, 1, 10, "Number of Cuts", "", 1, INT_MAX);
330         RNA_def_float(ot->srna, "random_factor", 5.0, 0.0f, FLT_MAX, "Random Factor", "", 0.0f, 1000.0f);
331         RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1000.0f, "Smoothness", "", 0.0f, FLT_MAX);            
332 }
333 #endif
334
335 /* individual face extrude */
336 /* will use vertex normals for extrusion directions, so *nor is unaffected */
337 short EDBM_Extrude_face_indiv(BMEditMesh *em, short flag, float *nor)
338 {
339 #if 0
340         EditVert *eve, *v1, *v2, *v3, *v4;
341         EditEdge *eed;
342         EditFace *efa, *nextfa;
343         
344         if(em==NULL) return 0;
345         
346         /* selected edges with 1 or more selected face become faces */
347         /* selected faces each makes new faces */
348         /* always remove old faces, keeps volumes manifold */
349         /* select the new extrusion, deselect old */
350         
351         /* step 1; init, count faces in edges */
352         recalc_editnormals(em);
353         
354         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;      // new select flag
355
356         for(eed= em->edges.first; eed; eed= eed->next) {
357                 eed->f2= 0; // amount of unselected faces
358         }
359         for(efa= em->faces.first; efa; efa= efa->next) {
360                 if(efa->f & SELECT);
361                 else {
362                         efa->e1->f2++;
363                         efa->e2->f2++;
364                         efa->e3->f2++;
365                         if(efa->e4) efa->e4->f2++;
366                 }
367         }
368
369         /* step 2: make new faces from faces */
370         for(efa= em->faces.last; efa; efa= efa->prev) {
371                 if(efa->f & SELECT) {
372                         v1= addvertlist(em, efa->v1->co, efa->v1);
373                         v2= addvertlist(em, efa->v2->co, efa->v2);
374                         v3= addvertlist(em, efa->v3->co, efa->v3);
375                         
376                         v1->f1= v2->f1= v3->f1= 1;
377                         VECCOPY(v1->no, efa->n);
378                         VECCOPY(v2->no, efa->n);
379                         VECCOPY(v3->no, efa->n);
380                         if(efa->v4) {
381                                 v4= addvertlist(em, efa->v4->co, efa->v4); 
382                                 v4->f1= 1;
383                                 VECCOPY(v4->no, efa->n);
384                         }
385                         else v4= NULL;
386                         
387                         /* side faces, clockwise */
388                         addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL);
389                         addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL);
390                         if(efa->v4) {
391                                 addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL);
392                                 addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL);
393                         }
394                         else {
395                                 addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL);
396                         }
397                         /* top face */
398                         addfacelist(em, v1, v2, v3, v4, efa, NULL);
399                 }
400         }
401         
402         /* step 3: remove old faces */
403         efa= em->faces.first;
404         while(efa) {
405                 nextfa= efa->next;
406                 if(efa->f & SELECT) {
407                         BLI_remlink(&em->faces, efa);
408                         free_editface(em, efa);
409                 }
410                 efa= nextfa;
411         }
412
413         /* step 4: redo selection */
414         EM_clear_flag_all(em, SELECT);
415         
416         for(eve= em->verts.first; eve; eve= eve->next) {
417                 if(eve->f1)  eve->f |= SELECT;
418         }
419         
420         EM_select_flush(em);
421         
422         return 'n';
423 #endif
424 }
425
426
427 /* extrudes individual edges */
428 /* nor is filled with constraint vector */
429 short EDBM_Extrude_edges_indiv(BMEditMesh *em, short flag, float *nor) 
430 {
431 #if 0
432         EditVert *eve;
433         EditEdge *eed;
434         EditFace *efa;
435         
436         for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL;
437         for(eed= em->edges.first; eed; eed= eed->next) {
438                 eed->tmp.f = NULL;
439                 eed->f2= ((eed->f & flag)!=0);
440         }
441         
442         set_edge_directions_f2(em, 2);
443
444         /* sample for next loop */
445         for(efa= em->faces.first; efa; efa= efa->next) {
446                 efa->e1->tmp.f = efa;
447                 efa->e2->tmp.f = efa;
448                 efa->e3->tmp.f = efa;
449                 if(efa->e4) efa->e4->tmp.f = efa;
450         }
451         /* make the faces */
452         for(eed= em->edges.first; eed; eed= eed->next) {
453                 if(eed->f & flag) {
454                         if(eed->v1->tmp.v == NULL)
455                                 eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
456                         if(eed->v2->tmp.v == NULL)
457                                 eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
458
459                         if(eed->dir==1) 
460                                 addfacelist(em, eed->v1, eed->v2, 
461                                                         eed->v2->tmp.v, eed->v1->tmp.v, 
462                                                         eed->tmp.f, NULL);
463                         else 
464                                 addfacelist(em, eed->v2, eed->v1, 
465                                                         eed->v1->tmp.v, eed->v2->tmp.v, 
466                                                         eed->tmp.f, NULL);
467
468                         /* for transform */
469                         if(eed->tmp.f) {
470                                 efa = eed->tmp.f;
471                                 if (efa->f & SELECT) add_normal_aligned(nor, efa->n);
472                         }
473                 }
474         }
475         Normalize(nor);
476         
477         /* set correct selection */
478         EM_clear_flag_all(em, SELECT);
479         for(eve= em->verts.last; eve; eve= eve->prev) {
480                 if(eve->tmp.v) {
481                         eve->tmp.v->f |= flag;
482                 }
483         }
484
485         for(eed= em->edges.first; eed; eed= eed->next) {
486                 if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
487         }
488         
489         if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab
490 #endif
491         return 'n';  // n is for normal constraint
492 }
493
494 /* extrudes individual vertices */
495 short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) 
496 {
497         BMOperator bmop;
498         BMOIter siter;
499         BMVert *v;
500
501         EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", flag);
502
503         /*deselect original verts*/
504         v = BMO_IterNew(&siter, em->bm, &bmop, "verts", BM_VERT);
505         for (; v; v=BMO_IterStep(&siter)) {
506                 BM_Select(em->bm, v, 0);
507         }
508
509         BMO_Exec_Op(em->bm, &bmop);
510
511         v = BMO_IterNew(&siter, em->bm, &bmop, "vertout", BM_VERT);
512         for (; v; v=BMO_IterStep(&siter)) {
513                 BM_Select(em->bm, v, 1);
514         }
515
516         if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
517
518         return 'g'; // g is grab
519 }
520
521 short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int flag, float *nor)
522 {
523         BMesh *bm = em->bm;
524         BMIter iter;
525         BMOIter siter;
526         BMOperator extop;
527         BMVert *vert;
528         BMEdge *edge;
529         BMFace *f;
530         ModifierData *md;
531         BMHeader *el;
532         
533         BMO_Init_Op(&extop, "extrudefaceregion");
534         BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein",
535                                flag, BM_VERT|BM_EDGE|BM_FACE);
536
537         BM_ITER(vert, &iter, bm, BM_VERTS_OF_MESH, NULL) {
538                 BM_Select(bm, vert, 0);
539         }
540
541         BM_ITER(edge, &iter, bm, BM_EDGES_OF_MESH, NULL) {
542                 BM_Select(bm, edge, 0);
543         }
544
545         BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
546                 BM_Select(bm, f, 0);
547         }
548
549         /* If a mirror modifier with clipping is on, we need to adjust some 
550          * of the cases above to handle edges on the line of symmetry.
551          */
552         md = obedit->modifiers.first;
553         for (; md; md=md->next) {
554                 if (md->type==eModifierType_Mirror) {
555                         MirrorModifierData *mmd = (MirrorModifierData*) md;     
556                 
557                         if(mmd->flag & MOD_MIR_CLIPPING) {
558                                 float mtx[4][4];
559                                 if (mmd->mirror_ob) {
560                                         float imtx[4][4];
561                                         Mat4Invert(imtx, mmd->mirror_ob->obmat);
562                                         Mat4MulMat4(mtx, obedit->obmat, imtx);
563                                 }
564
565                                 for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL);
566                                      edge; edge=BMIter_Step(&iter))
567                                 {
568                                         if(edge->head.flag & flag) {
569                                                 float co1[3], co2[3];
570
571                                                 VecCopyf(co1, edge->v1->co);
572                                                 VecCopyf(co2, edge->v2->co);
573
574                                                 if (mmd->mirror_ob) {
575                                                         VecMat4MulVecfl(co1, mtx, co1);
576                                                         VecMat4MulVecfl(co2, mtx, co2);
577                                                 }
578
579                                                 if (mmd->flag & MOD_MIR_AXIS_X)
580                                                         if ( (fabs(co1[0]) < mmd->tolerance) &&
581                                                                  (fabs(co2[0]) < mmd->tolerance) )
582                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
583
584                                                 if (mmd->flag & MOD_MIR_AXIS_Y)
585                                                         if ( (fabs(co1[1]) < mmd->tolerance) &&
586                                                                  (fabs(co2[1]) < mmd->tolerance) )
587                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
588
589                                                 if (mmd->flag & MOD_MIR_AXIS_Z)
590                                                         if ( (fabs(co1[2]) < mmd->tolerance) &&
591                                                                  (fabs(co2[2]) < mmd->tolerance) )
592                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
593                                         }
594                                 }
595                         }
596                 }
597         }
598
599         BMO_Exec_Op(bm, &extop);
600
601         nor[0] = nor[1] = nor[2] = 0.0f;
602         
603         BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) {
604                 BM_Select(bm, el, 1);
605
606                 if (el->type == BM_FACE) {
607                         f = (BMFace*)el;
608                         add_normal_aligned(nor, f->no);
609                 };
610         }
611
612         Normalize(nor);
613
614         BMO_Finish_Op(bm, &extop);
615
616         if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
617         return 'n'; // normal constraint 
618
619 }
620 short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, short flag, float *nor)
621 {
622                 BMIter iter;
623                 BMEdge *eed;
624                 
625                 /*ensure vert flags are consistent for edge selections*/
626                 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
627                 for ( ; eed; eed=BMIter_Step(&iter)) {
628                         if (BM_TestHFlag(eed, flag)) {
629                                 if (flag != BM_SELECT) {
630                                         BM_SetHFlag(eed->v1, flag);
631                                         BM_SetHFlag(eed->v2, flag);
632                                 } else {
633                                         BM_Select(em->bm, eed->v1, 1);
634                                         BM_Select(em->bm, eed->v2, 1);
635                                 }
636                         } else {
637                                 if (BM_TestHFlag(eed->v1, flag) && BM_TestHFlag(eed->v2, flag)) {
638                                         if (flag != BM_SELECT)
639                                                 BM_SetHFlag(eed, flag);
640                                         else BM_Select(em->bm, eed, 1);
641                                 }
642                         }
643                 }
644
645                 return EDBM_Extrude_edge(obedit, em, flag, nor);
646
647 }
648
649 static int extrude_repeat_mesh(bContext *C, wmOperator *op)
650 {
651         Object *obedit= CTX_data_edit_object(C);
652         Scene *scene = CTX_data_scene(C);
653         BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
654         RegionView3D *rv3d = CTX_wm_region_view3d(C);           
655                 
656         int steps = RNA_int_get(op->ptr,"steps");
657         
658         float offs = RNA_float_get(op->ptr,"offset");
659
660         float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
661         short a;
662
663         /* dvec */
664         dvec[0]= rv3d->persinv[2][0];
665         dvec[1]= rv3d->persinv[2][1];
666         dvec[2]= rv3d->persinv[2][2];
667         Normalize(dvec);
668         dvec[0]*= offs;
669         dvec[1]*= offs;
670         dvec[2]*= offs;
671
672         /* base correction */
673         Mat3CpyMat4(bmat, obedit->obmat);
674         Mat3Inv(tmat, bmat);
675         Mat3MulVecfl(tmat, dvec);
676
677         for(a=0; a<steps; a++) {
678                 EDBM_Extrude_edge(obedit, em, BM_SELECT, nor);
679                 //BMO_CallOpf(em->bm, "extrudefaceregion edgefacein=%hef", BM_SELECT);
680                 BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT);
681                 //extrudeflag(obedit, em, SELECT, nor);
682                 //translateflag(em, SELECT, dvec);
683         }
684         
685         EDBM_RecalcNormals(em);
686
687         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
688
689         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
690         return OPERATOR_FINISHED;
691 }
692
693 void MESH_OT_extrude_repeat(wmOperatorType *ot)
694 {
695         /* identifiers */
696         ot->name= "Extrude Repeat Mesh";
697         ot->idname= "MESH_OT_extrude_repeat";
698         
699         /* api callbacks */
700         ot->exec= extrude_repeat_mesh;
701         ot->poll= ED_operator_editmesh;
702         
703         /* flags */
704         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
705         
706         /* props */
707         RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX);
708         RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX);
709 }
710
711 /* generic extern called extruder */
712 int EDBM_Extrude_Mesh(Object *obedit, BMEditMesh *em, wmOperator *op, float *norin)
713 {
714         Scene *scene= NULL;             // XXX CTX!
715         short nr, transmode= 0;
716         float stacknor[3] = {0.0f, 0.0f, 0.0f};
717         float *nor = norin ? norin : stacknor;
718
719         nor[0] = nor[1] = nor[2] = 0.0f;
720         if(em->selectmode & SCE_SELECT_VERTEX) {
721                 if(em->bm->totvertsel==0) nr= 0;
722                 else if(em->bm->totvertsel==1) nr= 4;
723                 else if(em->bm->totedgesel==0) nr= 4;
724                 else if(em->bm->totfacesel==0) 
725                         nr= 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
726                 else if(em->bm->totfacesel==1)
727                         nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
728                 else 
729                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
730         }
731         else if(em->selectmode & SCE_SELECT_EDGE) {
732                 if (em->bm->totedgesel==0) nr = 0;
733                 
734                 nr = 1;
735                 /*else if (em->totedgesel==1) nr = 3;
736                 else if(em->totfacesel==0) nr = 3;
737                 else if(em->totfacesel==1)
738                         nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3");
739                 else
740                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
741                 */
742         }
743         else {
744                 if (em->bm->totfacesel == 0) nr = 0;
745                 else if (em->bm->totfacesel == 1) nr = 1;
746                 else
747                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
748         }
749                 
750         if(nr<1) return 'g';
751
752         if(nr==1 && em->selectmode & SCE_SELECT_VERTEX) 
753                 transmode= EDBM_Extrude_vert(obedit, em, SELECT, nor);
754         else if (nr == 1) transmode= EDBM_Extrude_edge(obedit, em, SELECT, nor);
755         else if(nr==4) transmode= EDBM_Extrude_verts_indiv(em, op, SELECT, nor);
756         else if(nr==3) transmode= EDBM_Extrude_edges_indiv(em, SELECT, nor);
757         else transmode= EDBM_Extrude_face_indiv(em, SELECT, nor);
758         
759         if(transmode==0) {
760                 BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
761         }
762         else {
763                 
764                         /* We need to force immediate calculation here because 
765                         * transform may use derived objects (which are now stale).
766                         *
767                         * This shouldn't be necessary, derived queries should be
768                         * automatically building this data if invalid. Or something.
769                         */
770 //              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
771                 object_handle_update(scene, obedit);
772
773                 /* individual faces? */
774 //              BIF_TransformSetUndo("Extrude");
775                 if(nr==2) {
776 //                      initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
777 //                      Transform();
778                 }
779                 else {
780 //                      initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
781                         if(transmode=='n') {
782                                 Mat4MulVecfl(obedit->obmat, nor);
783                                 VecSubf(nor, nor, obedit->obmat[3]);
784 //                              BIF_setSingleAxisConstraint(nor, "along normal");
785                         }
786 //                      Transform();
787                 }
788         }
789         
790         return transmode;
791 }
792
793 static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
794 {
795         Scene *scene= CTX_data_scene(C);
796         Object *obedit= CTX_data_edit_object(C);
797         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
798         int constraint_axis[3] = {0, 0, 1};
799         int tmode;
800
801         tmode = EDBM_Extrude_Mesh(obedit, em, op, NULL);
802
803         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
804         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
805
806         RNA_enum_set(op->ptr, "proportional", 0);
807         RNA_boolean_set(op->ptr, "mirror", 0);
808
809         if (tmode == 'n') {
810                 RNA_enum_set(op->ptr, "constraint_orientation", V3D_MANIP_NORMAL);
811                 RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
812         }
813         WM_operator_name_call(C, "TFM_OT_translation", WM_OP_INVOKE_REGION_WIN, op->ptr);
814
815         return OPERATOR_FINISHED;
816 }
817
818 /* extrude without transform */
819 static int mesh_extrude_exec(bContext *C, wmOperator *op)
820 {
821         Object *obedit= CTX_data_edit_object(C);
822         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
823         
824         EDBM_Extrude_Mesh(obedit, em, op, NULL);
825         
826         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
827         
828         return OPERATOR_FINISHED;       
829 }
830
831
832 void MESH_OT_extrude(wmOperatorType *ot)
833 {
834         /* identifiers */
835         ot->name= "Extrude";
836         ot->idname= "MESH_OT_extrude";
837         
838         /* api callbacks */
839         ot->invoke= mesh_extrude_invoke;
840         ot->exec= mesh_extrude_exec;
841         ot->poll= ED_operator_editmesh;
842         
843         /* flags */
844         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
845
846         /* to give to transform */
847         Properties_Proportional(ot);
848         Properties_Constraints(ot);
849         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
850 }
851
852 /* ******************** (de)select all operator **************** */
853
854 void EDBM_toggle_select_all(BMEditMesh *em) /* exported for UV */
855 {
856         if(em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
857                 EDBM_clear_flag_all(em, SELECT);
858         else 
859                 EDBM_set_flag_all(em, SELECT);
860 }
861
862 static int toggle_select_all_exec(bContext *C, wmOperator *op)
863 {
864         Object *obedit= CTX_data_edit_object(C);
865         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
866         
867         EDBM_toggle_select_all(em);
868         
869         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
870
871         return OPERATOR_FINISHED;
872 }
873
874 void MESH_OT_select_all_toggle(wmOperatorType *ot)
875 {
876         /* identifiers */
877         ot->name= "Select/Deselect All";
878         ot->idname= "MESH_OT_select_all_toggle";
879         
880         /* api callbacks */
881         ot->exec= toggle_select_all_exec;
882         ot->poll= ED_operator_editmesh;
883         
884         /* flags */
885         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
886 }
887
888 /* *************** add-click-mesh (extrude) operator ************** */
889
890 static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
891 {
892         ViewContext vc;
893         BMVert *eve, *v1;
894         BMIter iter;
895         float min[3], max[3];
896         int done= 0;
897         
898         em_setup_viewcontext(C, &vc);
899         
900         INIT_MINMAX(min, max);
901         
902         BM_ITER(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH, NULL) {
903                 if(BM_TestHFlag(v1, BM_SELECT)) {
904                         DO_MINMAX(v1->co, min, max);
905                         done= 1;
906                 }
907         }
908
909         /* call extrude? */
910         if(done) {
911                 BMEdge *eed;
912                 float vec[3], cent[3], mat[3][3];
913                 float nor[3]= {0.0, 0.0, 0.0};
914                 
915                 /* check for edges that are half selected, use for rotation */
916                 done= 0;
917                 BM_ITER(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH, NULL) {
918                         if (BM_TestHFlag(eed->v1, BM_SELECT) ^ BM_TestHFlag(eed->v2, BM_SELECT)) {
919                                 if(BM_TestHFlag(eed->v1, BM_SELECT)) 
920                                         VecSubf(vec, eed->v1->co, eed->v2->co);
921                                 else 
922                                         VecSubf(vec, eed->v2->co, eed->v1->co);
923                                 VecAddf(nor, nor, vec);
924                                 done= 1;
925                         }
926                 }
927                 if(done) Normalize(nor);
928                 
929                 /* center */
930                 VecAddf(cent, min, max);
931                 VecMulf(cent, 0.5f);
932                 VECCOPY(min, cent);
933                 
934                 Mat4MulVecfl(vc.obedit->obmat, min);    // view space
935                 view3d_get_view_aligned_coordinate(&vc, min, event->mval);
936                 Mat4Invert(vc.obedit->imat, vc.obedit->obmat); 
937                 Mat4MulVecfl(vc.obedit->imat, min); // back in object space
938                 
939                 VecSubf(min, min, cent);
940                 
941                 /* calculate rotation */
942                 Mat3One(mat);
943                 if(done) {
944                         float dot;
945                         
946                         VECCOPY(vec, min);
947                         Normalize(vec);
948                         dot= INPR(vec, nor);
949
950                         if( fabs(dot)<0.999) {
951                                 float cross[3], si, q1[4];
952                                 
953                                 Crossf(cross, nor, vec);
954                                 Normalize(cross);
955                                 dot= 0.5f*saacos(dot);
956                                 si= (float)sin(dot);
957                                 q1[0]= (float)cos(dot);
958                                 q1[1]= cross[0]*si;
959                                 q1[2]= cross[1]*si;
960                                 q1[3]= cross[2]*si;
961                                 
962                                 QuatToMat3(q1, mat);
963                         }
964                 }
965                 
966
967                 EDBM_Extrude_edge(vc.obedit, vc.em, SELECT, nor);
968                 EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
969                         BM_SELECT, cent, mat);
970                 EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v",
971                         BM_SELECT, min);
972         }
973         else {
974                 float *curs= give_cursor(vc.scene, vc.v3d);
975                 BMOperator bmop;
976                 BMOIter oiter;
977                 
978                 VECCOPY(min, curs);
979
980                 view3d_get_view_aligned_coordinate(&vc, min, event->mval);
981                 Mat4Invert(vc.obedit->imat, vc.obedit->obmat); 
982                 Mat4MulVecfl(vc.obedit->imat, min); // back in object space
983                 
984                 EDBM_InitOpf(vc.em, &bmop, op, "makevert co=%v", min);
985                 BMO_Exec_Op(vc.em->bm, &bmop);
986
987                 BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) {
988                         BM_Select(vc.em->bm, v1, 1);
989                 }
990
991                 if (!EDBM_FinishOp(vc.em, &bmop, op, 1))
992                         return OPERATOR_CANCELLED;
993         }
994
995         //retopo_do_all();
996         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit); 
997         DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA);
998         
999         return OPERATOR_FINISHED;
1000 }
1001
1002 void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
1003 {
1004         /* identifiers */
1005         ot->name= "Duplicate or Extrude at 3D Cursor";
1006         ot->idname= "MESH_OT_dupli_extrude_cursor";
1007         
1008         /* api callbacks */
1009         ot->invoke= dupli_extrude_cursor;
1010         ot->poll= ED_operator_editmesh;
1011         
1012         /* flags */
1013         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1014 }
1015
1016 static int delete_mesh(Object *obedit, wmOperator *op, int event, Scene *scene)
1017 {
1018         BMEditMesh *bem = ((Mesh*)obedit->data)->edit_btmesh;
1019         
1020         if(event<1) return OPERATOR_CANCELLED;
1021
1022         if(event==10 ) {
1023                 //"Erase Vertices";
1024
1025                 if (!EDBM_CallOpf(bem, op, "del geom=%hv context=%i", BM_SELECT, DEL_VERTS))
1026                         return OPERATOR_CANCELLED;
1027         } 
1028         else if(event==11) {
1029                 //"Edge Loop"
1030                 if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_SELECT))
1031                         return OPERATOR_CANCELLED;
1032         }
1033         else if(event==7) {
1034                 //"Dissolve"
1035                 if (bem->selectmode & SCE_SELECT_FACE) {
1036                         if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf",BM_SELECT))
1037                                 return OPERATOR_CANCELLED;
1038                 } else if (bem->selectmode & SCE_SELECT_EDGE) {
1039                         if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he",BM_SELECT))
1040                                 return OPERATOR_CANCELLED;
1041                 } else if (bem->selectmode & SCE_SELECT_VERTEX) {
1042                         if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv",BM_SELECT))
1043                                 return OPERATOR_CANCELLED;
1044                 }
1045         }
1046         else if(event==4) {
1047                 //Edges and Faces
1048                 if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_SELECT, DEL_EDGESFACES))
1049                         return OPERATOR_CANCELLED;
1050         } 
1051         else if(event==1) {
1052                 //"Erase Edges"
1053                 if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_SELECT, DEL_EDGES))
1054                         return OPERATOR_CANCELLED;
1055         }
1056         else if(event==2) {
1057                 //"Erase Faces";
1058                 if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_SELECT, DEL_FACES))
1059                         return OPERATOR_CANCELLED;
1060         }
1061         else if(event==5) {
1062                 //"Erase Only Faces";
1063                 if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d",
1064                                   BM_SELECT, DEL_ONLYFACES))
1065                         return OPERATOR_CANCELLED;
1066         }
1067         
1068         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1069
1070         return OPERATOR_FINISHED;
1071 }
1072
1073 /* Note, these values must match delete_mesh() event values */
1074 static EnumPropertyItem prop_mesh_delete_types[] = {
1075         {7, "DISSOLVE",         0, "Dissolve", ""},
1076         {10,"VERT",             0, "Vertices", ""},
1077         {1, "EDGE",             0, "Edges", ""},
1078         {2, "FACE",             0, "Faces", ""},
1079         {11, "EDGE_LOOP", 0, "Edge Loop", ""},
1080         {4, "EDGE_FACE", 0, "Edges & Faces", ""},
1081         {5, "ONLY_FACE", 0, "Only Faces", ""},
1082         {0, NULL, 0, NULL, NULL}
1083 };
1084
1085 static int delete_mesh_exec(bContext *C, wmOperator *op)
1086 {
1087         Object *obedit= CTX_data_edit_object(C);
1088         Scene *scene = CTX_data_scene(C);
1089
1090         delete_mesh(obedit, op, RNA_enum_get(op->ptr, "type"), scene);
1091         
1092         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA|ND_GEOM_SELECT, obedit);
1093         
1094         return OPERATOR_FINISHED;
1095 }
1096
1097 void MESH_OT_delete(wmOperatorType *ot)
1098 {
1099         /* identifiers */
1100         ot->name= "Delete";
1101         ot->idname= "MESH_OT_delete";
1102         
1103         /* api callbacks */
1104         ot->invoke= WM_menu_invoke;
1105         ot->exec= delete_mesh_exec;
1106         
1107         ot->poll= ED_operator_editmesh;
1108         
1109         /* flags */
1110         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1111         
1112         /*props */
1113         RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
1114 }
1115
1116
1117 static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
1118 {
1119         BMOperator bmop;
1120         Object *obedit= CTX_data_edit_object(C);
1121         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1122         
1123         if (!EDBM_InitOpf(em, &bmop, op, "contextual_create geom=%hfev", BM_SELECT))
1124                 return OPERATOR_CANCELLED;
1125         
1126         BMO_Exec_Op(em->bm, &bmop);
1127         BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT);
1128
1129         if (!EDBM_FinishOp(em, &bmop, op, 1))
1130                 return OPERATOR_CANCELLED;
1131
1132         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1133         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);     
1134         
1135         return OPERATOR_FINISHED;
1136 }
1137
1138 void MESH_OT_edge_face_add(wmOperatorType *ot)
1139 {
1140         /* identifiers */
1141         ot->name= "Make Edge/Face";
1142         ot->idname= "MESH_OT_edge_face_add";
1143         
1144         /* api callbacks */
1145         ot->exec= addedgeface_mesh_exec;
1146         ot->poll= ED_operator_editmesh;
1147         
1148         /* flags */
1149         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1150         
1151 }
1152
1153 static EnumPropertyItem prop_mesh_edit_types[] = {
1154         {1, "VERT", 0, "Vertices", ""},
1155         {2, "EDGE", 0, "Edges", ""},
1156         {3, "FACE", 0, "Faces", ""},
1157         {0, NULL, 0, NULL, NULL}
1158 };
1159
1160 static int mesh_selection_type_exec(bContext *C, wmOperator *op)
1161 {               
1162         
1163         Object *obedit= CTX_data_edit_object(C);
1164         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1165         int type = RNA_enum_get(op->ptr,"type");
1166
1167         switch (type) {
1168                 case 1:
1169                         em->selectmode = SCE_SELECT_VERTEX;
1170                         break;
1171                 case 2:
1172                         em->selectmode = SCE_SELECT_EDGE;
1173                         break;
1174                 case 3:
1175                         em->selectmode = SCE_SELECT_FACE;
1176                         break;
1177         }
1178
1179         EDBM_selectmode_set(em);
1180         CTX_data_scene(C)->toolsettings->selectmode = em->selectmode;
1181
1182         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1183         
1184         return OPERATOR_FINISHED;
1185 }
1186
1187 void MESH_OT_selection_type(wmOperatorType *ot)
1188 {
1189         /* identifiers */
1190         ot->name= "Selection Mode";
1191         ot->idname= "MESH_OT_selection_type";
1192         
1193         /* api callbacks */
1194         ot->invoke= WM_menu_invoke;
1195         ot->exec= mesh_selection_type_exec;
1196         
1197         ot->poll= ED_operator_editmesh;
1198         
1199         /* flags */
1200         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1201         
1202         /* props */
1203         RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type");
1204         RNA_def_boolean(ot->srna, "inclusive", 0, "Inclusive", "Selects geometry around selected geometry, occording to selection mode");       
1205 }
1206
1207 /* ************************* SEAMS AND EDGES **************** */
1208
1209 static int editbmesh_mark_seam(bContext *C, wmOperator *op)
1210 {
1211         Scene *scene = CTX_data_scene(C);
1212         Object *obedit= CTX_data_edit_object(C);
1213         Mesh *me= ((Mesh *)obedit->data);
1214         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1215         BMesh *bm = em->bm;
1216         BMEdge *eed;
1217         BMIter iter;
1218         int clear = RNA_boolean_get(op->ptr, "clear");
1219         
1220         /* auto-enable seams drawing */
1221         if(clear==0) {
1222                 me->drawflag |= ME_DRAWSEAMS;
1223         }
1224
1225         if(clear) {
1226                 BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
1227                         if (BM_TestHFlag(eed, BM_HIDDEN) == 0 &&
1228                             BM_TestHFlag(eed, BM_SELECT) != 0)
1229                         {
1230                                 BM_ClearHFlag(eed, BM_SEAM);
1231                         }
1232                 }
1233         }
1234         else {
1235                 BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
1236                         if (BM_TestHFlag(eed, BM_HIDDEN) == 0 &&
1237                             BM_TestHFlag(eed, BM_SELECT) != 0)
1238                         {
1239                                 BM_SetHFlag(eed, BM_SEAM);
1240                         }
1241                 }
1242         }
1243
1244         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1245         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1246
1247         return OPERATOR_FINISHED;
1248 }
1249
1250 void MESH_OT_mark_seam(wmOperatorType *ot)
1251 {
1252         /* identifiers */
1253         ot->name= "Mark Seam";
1254         ot->idname= "MESH_OT_mark_seam";
1255         
1256         /* api callbacks */
1257         ot->exec= editbmesh_mark_seam;
1258         ot->poll= ED_operator_editmesh;
1259         
1260         /* flags */
1261         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1262         
1263         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1264 }
1265
1266 static int editbmesh_mark_sharp(bContext *C, wmOperator *op)
1267 {
1268         Scene *scene = CTX_data_scene(C);
1269         Object *obedit= CTX_data_edit_object(C);
1270         Mesh *me= ((Mesh *)obedit->data);
1271         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1272         BMesh *bm = em->bm;
1273         BMEdge *eed;
1274         BMIter iter;
1275         int clear = RNA_boolean_get(op->ptr, "clear");
1276
1277         /* auto-enable sharp edge drawing */
1278         if(clear == 0) {
1279                 me->drawflag |= ME_DRAWSHARP;
1280         }
1281
1282         if(!clear) {
1283                 BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
1284                         if (BM_TestHFlag(eed, BM_HIDDEN) == 0 &&
1285                             BM_TestHFlag(eed, BM_SELECT) != 0)
1286                         {
1287                                 BM_SetHFlag(eed, BM_SHARP);
1288                         }
1289                 }
1290         } else {
1291                 BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
1292                         if (BM_TestHFlag(eed, BM_HIDDEN) == 0 &&
1293                             BM_TestHFlag(eed, BM_SELECT) != 0)
1294                         {
1295                                 BM_ClearHFlag(eed, BM_SHARP);
1296                         }
1297                 }
1298         }
1299
1300
1301         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1302         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1303
1304         return OPERATOR_FINISHED;
1305 }
1306
1307 void MESH_OT_mark_sharp(wmOperatorType *ot)
1308 {
1309         /* identifiers */
1310         ot->name= "Mark Sharp";
1311         ot->idname= "MESH_OT_mark_sharp";
1312         
1313         /* api callbacks */
1314         ot->exec= editbmesh_mark_sharp;
1315         ot->poll= ED_operator_editmesh;
1316         
1317         /* flags */
1318         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1319         
1320         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1321 }
1322
1323
1324 static int editbmesh_vert_connect(bContext *C, wmOperator *op)
1325 {
1326         Scene *scene = CTX_data_scene(C);
1327         Object *obedit= CTX_data_edit_object(C);
1328         Mesh *me= ((Mesh *)obedit->data);
1329         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1330         BMesh *bm = em->bm;
1331         BMOperator bmop;
1332         int len = 0;
1333         
1334         BMO_InitOpf(bm, &bmop, "connectverts verts=%hv", BM_SELECT);
1335         BMO_Exec_Op(bm, &bmop);
1336         len = BMO_GetSlot(&bmop, "edgeout")->len;
1337         BMO_Finish_Op(bm, &bmop);
1338         
1339         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1340         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1341
1342         return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1343 }
1344
1345 void MESH_OT_vert_connect(wmOperatorType *ot)
1346 {
1347         /* identifiers */
1348         ot->name= "Vertex Connect";
1349         ot->idname= "MESH_OT_vert_connect";
1350         
1351         /* api callbacks */
1352         ot->exec= editbmesh_vert_connect;
1353         ot->poll= ED_operator_editmesh;
1354         
1355         /* flags */
1356         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1357 }
1358
1359 static int editbmesh_edge_split(bContext *C, wmOperator *op)
1360 {
1361         Scene *scene = CTX_data_scene(C);
1362         Object *obedit= CTX_data_edit_object(C);
1363         Mesh *me= ((Mesh *)obedit->data);
1364         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1365         BMesh *bm = em->bm;
1366         BMOperator bmop;
1367         int len = 0;
1368         
1369         BMO_InitOpf(bm, &bmop, "edgesplit edges=%he numcuts=%d", BM_SELECT, RNA_int_get(op->ptr,"number_cuts"));
1370         BMO_Exec_Op(bm, &bmop);
1371         len = BMO_GetSlot(&bmop, "outsplit")->len;
1372         BMO_Finish_Op(bm, &bmop);
1373         
1374         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1375         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1376
1377         return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1378 }
1379
1380 void MESH_OT_edge_split(wmOperatorType *ot)
1381 {
1382         /* identifiers */
1383         ot->name= "Edge Split";
1384         ot->idname= "MESH_OT_edge_split";
1385         
1386         /* api callbacks */
1387         ot->exec= editbmesh_edge_split;
1388         ot->poll= ED_operator_editmesh;
1389         
1390         /* flags */
1391         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1392
1393         RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX);
1394 }