merge with 2.5 (not trunk, last merge message said that on accident) at r22252
[blender.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         return 'g';
340 #if 0
341         EditVert *eve, *v1, *v2, *v3, *v4;
342         EditEdge *eed;
343         EditFace *efa, *nextfa;
344         
345         if(em==NULL) return 0;
346         
347         /* selected edges with 1 or more selected face become faces */
348         /* selected faces each makes new faces */
349         /* always remove old faces, keeps volumes manifold */
350         /* select the new extrusion, deselect old */
351         
352         /* step 1; init, count faces in edges */
353         recalc_editnormals(em);
354         
355         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;      // new select flag
356
357         for(eed= em->edges.first; eed; eed= eed->next) {
358                 eed->f2= 0; // amount of unselected faces
359         }
360         for(efa= em->faces.first; efa; efa= efa->next) {
361                 if(efa->f & SELECT);
362                 else {
363                         efa->e1->f2++;
364                         efa->e2->f2++;
365                         efa->e3->f2++;
366                         if(efa->e4) efa->e4->f2++;
367                 }
368         }
369
370         /* step 2: make new faces from faces */
371         for(efa= em->faces.last; efa; efa= efa->prev) {
372                 if(efa->f & SELECT) {
373                         v1= addvertlist(em, efa->v1->co, efa->v1);
374                         v2= addvertlist(em, efa->v2->co, efa->v2);
375                         v3= addvertlist(em, efa->v3->co, efa->v3);
376                         
377                         v1->f1= v2->f1= v3->f1= 1;
378                         VECCOPY(v1->no, efa->n);
379                         VECCOPY(v2->no, efa->n);
380                         VECCOPY(v3->no, efa->n);
381                         if(efa->v4) {
382                                 v4= addvertlist(em, efa->v4->co, efa->v4); 
383                                 v4->f1= 1;
384                                 VECCOPY(v4->no, efa->n);
385                         }
386                         else v4= NULL;
387                         
388                         /* side faces, clockwise */
389                         addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL);
390                         addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL);
391                         if(efa->v4) {
392                                 addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL);
393                                 addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL);
394                         }
395                         else {
396                                 addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL);
397                         }
398                         /* top face */
399                         addfacelist(em, v1, v2, v3, v4, efa, NULL);
400                 }
401         }
402         
403         /* step 3: remove old faces */
404         efa= em->faces.first;
405         while(efa) {
406                 nextfa= efa->next;
407                 if(efa->f & SELECT) {
408                         BLI_remlink(&em->faces, efa);
409                         free_editface(em, efa);
410                 }
411                 efa= nextfa;
412         }
413
414         /* step 4: redo selection */
415         EM_clear_flag_all(em, SELECT);
416         
417         for(eve= em->verts.first; eve; eve= eve->next) {
418                 if(eve->f1)  eve->f |= SELECT;
419         }
420         
421         EM_select_flush(em);
422         
423         return 'n';
424 #endif
425 }
426
427
428 /* extrudes individual edges */
429 /* nor is filled with constraint vector */
430 short EDBM_Extrude_edges_indiv(BMEditMesh *em, short flag, float *nor) 
431 {
432 #if 0
433         EditVert *eve;
434         EditEdge *eed;
435         EditFace *efa;
436         
437         for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL;
438         for(eed= em->edges.first; eed; eed= eed->next) {
439                 eed->tmp.f = NULL;
440                 eed->f2= ((eed->f & flag)!=0);
441         }
442         
443         set_edge_directions_f2(em, 2);
444
445         /* sample for next loop */
446         for(efa= em->faces.first; efa; efa= efa->next) {
447                 efa->e1->tmp.f = efa;
448                 efa->e2->tmp.f = efa;
449                 efa->e3->tmp.f = efa;
450                 if(efa->e4) efa->e4->tmp.f = efa;
451         }
452         /* make the faces */
453         for(eed= em->edges.first; eed; eed= eed->next) {
454                 if(eed->f & flag) {
455                         if(eed->v1->tmp.v == NULL)
456                                 eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
457                         if(eed->v2->tmp.v == NULL)
458                                 eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
459
460                         if(eed->dir==1) 
461                                 addfacelist(em, eed->v1, eed->v2, 
462                                                         eed->v2->tmp.v, eed->v1->tmp.v, 
463                                                         eed->tmp.f, NULL);
464                         else 
465                                 addfacelist(em, eed->v2, eed->v1, 
466                                                         eed->v1->tmp.v, eed->v2->tmp.v, 
467                                                         eed->tmp.f, NULL);
468
469                         /* for transform */
470                         if(eed->tmp.f) {
471                                 efa = eed->tmp.f;
472                                 if (efa->f & SELECT) add_normal_aligned(nor, efa->n);
473                         }
474                 }
475         }
476         Normalize(nor);
477         
478         /* set correct selection */
479         EM_clear_flag_all(em, SELECT);
480         for(eve= em->verts.last; eve; eve= eve->prev) {
481                 if(eve->tmp.v) {
482                         eve->tmp.v->f |= flag;
483                 }
484         }
485
486         for(eed= em->edges.first; eed; eed= eed->next) {
487                 if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
488         }
489         
490         if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab
491 #endif
492         return 'n';  // n is for normal constraint
493 }
494
495 /* extrudes individual vertices */
496 short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) 
497 {
498         BMOperator bmop;
499         BMOIter siter;
500         BMVert *v;
501
502         EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", flag);
503
504         /*deselect original verts*/
505         BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "verts", BM_SELECT);
506
507         BMO_Exec_Op(em->bm, &bmop);
508
509         BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT);
510         if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
511
512         return 'g'; // g is grab
513 }
514
515 short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int flag, float *nor)
516 {
517         BMesh *bm = em->bm;
518         BMIter iter;
519         BMOIter siter;
520         BMOperator extop;
521         BMVert *vert;
522         BMEdge *edge;
523         BMFace *f;
524         ModifierData *md;
525         BMHeader *el;
526         
527         BMO_Init_Op(&extop, "extrudefaceregion");
528         BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein",
529                                flag, BM_VERT|BM_EDGE|BM_FACE);
530
531         BM_ITER(vert, &iter, bm, BM_VERTS_OF_MESH, NULL) {
532                 BM_Select(bm, vert, 0);
533         }
534
535         BM_ITER(edge, &iter, bm, BM_EDGES_OF_MESH, NULL) {
536                 BM_Select(bm, edge, 0);
537         }
538
539         BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
540                 BM_Select(bm, f, 0);
541         }
542
543         /* If a mirror modifier with clipping is on, we need to adjust some 
544          * of the cases above to handle edges on the line of symmetry.
545          */
546         md = obedit->modifiers.first;
547         for (; md; md=md->next) {
548                 if (md->type==eModifierType_Mirror) {
549                         MirrorModifierData *mmd = (MirrorModifierData*) md;     
550                 
551                         if(mmd->flag & MOD_MIR_CLIPPING) {
552                                 float mtx[4][4];
553                                 if (mmd->mirror_ob) {
554                                         float imtx[4][4];
555                                         Mat4Invert(imtx, mmd->mirror_ob->obmat);
556                                         Mat4MulMat4(mtx, obedit->obmat, imtx);
557                                 }
558
559                                 for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL);
560                                      edge; edge=BMIter_Step(&iter))
561                                 {
562                                         if(edge->head.flag & flag) {
563                                                 float co1[3], co2[3];
564
565                                                 VecCopyf(co1, edge->v1->co);
566                                                 VecCopyf(co2, edge->v2->co);
567
568                                                 if (mmd->mirror_ob) {
569                                                         VecMat4MulVecfl(co1, mtx, co1);
570                                                         VecMat4MulVecfl(co2, mtx, co2);
571                                                 }
572
573                                                 if (mmd->flag & MOD_MIR_AXIS_X)
574                                                         if ( (fabs(co1[0]) < mmd->tolerance) &&
575                                                                  (fabs(co2[0]) < mmd->tolerance) )
576                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
577
578                                                 if (mmd->flag & MOD_MIR_AXIS_Y)
579                                                         if ( (fabs(co1[1]) < mmd->tolerance) &&
580                                                                  (fabs(co2[1]) < mmd->tolerance) )
581                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
582
583                                                 if (mmd->flag & MOD_MIR_AXIS_Z)
584                                                         if ( (fabs(co1[2]) < mmd->tolerance) &&
585                                                                  (fabs(co2[2]) < mmd->tolerance) )
586                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
587                                         }
588                                 }
589                         }
590                 }
591         }
592
593         BMO_Exec_Op(bm, &extop);
594
595         nor[0] = nor[1] = nor[2] = 0.0f;
596         
597         BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) {
598                 BM_Select(bm, el, 1);
599
600                 if (el->type == BM_FACE) {
601                         f = (BMFace*)el;
602                         add_normal_aligned(nor, f->no);
603                 };
604         }
605
606         Normalize(nor);
607
608         BMO_Finish_Op(bm, &extop);
609
610         if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
611         return 'n'; // normal constraint 
612
613 }
614 short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, short flag, float *nor)
615 {
616                 BMIter iter;
617                 BMEdge *eed;
618                 
619                 /*ensure vert flags are consistent for edge selections*/
620                 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
621                 for ( ; eed; eed=BMIter_Step(&iter)) {
622                         if (BM_TestHFlag(eed, flag)) {
623                                 if (flag != BM_SELECT) {
624                                         BM_SetHFlag(eed->v1, flag);
625                                         BM_SetHFlag(eed->v2, flag);
626                                 } else {
627                                         BM_Select(em->bm, eed->v1, 1);
628                                         BM_Select(em->bm, eed->v2, 1);
629                                 }
630                         } else {
631                                 if (BM_TestHFlag(eed->v1, flag) && BM_TestHFlag(eed->v2, flag)) {
632                                         if (flag != BM_SELECT)
633                                                 BM_SetHFlag(eed, flag);
634                                         else BM_Select(em->bm, eed, 1);
635                                 }
636                         }
637                 }
638
639                 return EDBM_Extrude_edge(obedit, em, flag, nor);
640
641 }
642
643 static int extrude_repeat_mesh(bContext *C, wmOperator *op)
644 {
645         Object *obedit= CTX_data_edit_object(C);
646         Scene *scene = CTX_data_scene(C);
647         BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
648         RegionView3D *rv3d = CTX_wm_region_view3d(C);           
649                 
650         int steps = RNA_int_get(op->ptr,"steps");
651         
652         float offs = RNA_float_get(op->ptr,"offset");
653
654         float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
655         short a;
656
657         /* dvec */
658         dvec[0]= rv3d->persinv[2][0];
659         dvec[1]= rv3d->persinv[2][1];
660         dvec[2]= rv3d->persinv[2][2];
661         Normalize(dvec);
662         dvec[0]*= offs;
663         dvec[1]*= offs;
664         dvec[2]*= offs;
665
666         /* base correction */
667         Mat3CpyMat4(bmat, obedit->obmat);
668         Mat3Inv(tmat, bmat);
669         Mat3MulVecfl(tmat, dvec);
670
671         for(a=0; a<steps; a++) {
672                 EDBM_Extrude_edge(obedit, em, BM_SELECT, nor);
673                 //BMO_CallOpf(em->bm, "extrudefaceregion edgefacein=%hef", BM_SELECT);
674                 BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT);
675                 //extrudeflag(obedit, em, SELECT, nor);
676                 //translateflag(em, SELECT, dvec);
677         }
678         
679         EDBM_RecalcNormals(em);
680
681         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
682
683         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
684         return OPERATOR_FINISHED;
685 }
686
687 void MESH_OT_extrude_repeat(wmOperatorType *ot)
688 {
689         /* identifiers */
690         ot->name= "Extrude Repeat Mesh";
691         ot->idname= "MESH_OT_extrude_repeat";
692         
693         /* api callbacks */
694         ot->exec= extrude_repeat_mesh;
695         ot->poll= ED_operator_editmesh;
696         
697         /* flags */
698         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
699         
700         /* props */
701         RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX);
702         RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX);
703 }
704
705 /* generic extern called extruder */
706 int EDBM_Extrude_Mesh(Object *obedit, BMEditMesh *em, wmOperator *op, float *norin)
707 {
708         Scene *scene= NULL;             // XXX CTX!
709         short nr, transmode= 0;
710         float stacknor[3] = {0.0f, 0.0f, 0.0f};
711         float *nor = norin ? norin : stacknor;
712
713         nor[0] = nor[1] = nor[2] = 0.0f;
714         if(em->selectmode & SCE_SELECT_VERTEX) {
715                 if(em->bm->totvertsel==0) nr= 0;
716                 else if(em->bm->totvertsel==1) nr= 4;
717                 else if(em->bm->totedgesel==0) nr= 4;
718                 else if(em->bm->totfacesel==0) 
719                         nr= 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
720                 else if(em->bm->totfacesel==1)
721                         nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
722                 else 
723                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
724         }
725         else if(em->selectmode & SCE_SELECT_EDGE) {
726                 if (em->bm->totedgesel==0) nr = 0;
727                 
728                 nr = 1;
729                 /*else if (em->totedgesel==1) nr = 3;
730                 else if(em->totfacesel==0) nr = 3;
731                 else if(em->totfacesel==1)
732                         nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3");
733                 else
734                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
735                 */
736         }
737         else {
738                 if (em->bm->totfacesel == 0) nr = 0;
739                 else if (em->bm->totfacesel == 1) nr = 1;
740                 else
741                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
742         }
743                 
744         if(nr<1) return 'g';
745
746         if(nr==1 && em->selectmode & SCE_SELECT_VERTEX) 
747                 transmode= EDBM_Extrude_vert(obedit, em, SELECT, nor);
748         else if (nr == 1) transmode= EDBM_Extrude_edge(obedit, em, SELECT, nor);
749         else if(nr==4) transmode= EDBM_Extrude_verts_indiv(em, op, SELECT, nor);
750         else if(nr==3) transmode= EDBM_Extrude_edges_indiv(em, SELECT, nor);
751         else transmode= EDBM_Extrude_face_indiv(em, SELECT, nor);
752         
753         if(transmode==0) {
754                 BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
755         }
756         else {
757                 
758                         /* We need to force immediate calculation here because 
759                         * transform may use derived objects (which are now stale).
760                         *
761                         * This shouldn't be necessary, derived queries should be
762                         * automatically building this data if invalid. Or something.
763                         */
764 //              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
765                 object_handle_update(scene, obedit);
766
767                 /* individual faces? */
768 //              BIF_TransformSetUndo("Extrude");
769                 if(nr==2) {
770 //                      initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
771 //                      Transform();
772                 }
773                 else {
774 //                      initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
775                         if(transmode=='n') {
776                                 Mat4MulVecfl(obedit->obmat, nor);
777                                 VecSubf(nor, nor, obedit->obmat[3]);
778 //                              BIF_setSingleAxisConstraint(nor, "along normal");
779                         }
780 //                      Transform();
781                 }
782         }
783         
784         return transmode;
785 }
786
787 static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
788 {
789         Scene *scene= CTX_data_scene(C);
790         Object *obedit= CTX_data_edit_object(C);
791         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
792         int constraint_axis[3] = {0, 0, 1};
793         int tmode;
794
795         tmode = EDBM_Extrude_Mesh(obedit, em, op, NULL);
796
797         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
798         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
799
800         RNA_enum_set(op->ptr, "proportional", 0);
801         RNA_boolean_set(op->ptr, "mirror", 0);
802
803         if (tmode == 'n') {
804                 RNA_enum_set(op->ptr, "constraint_orientation", V3D_MANIP_NORMAL);
805                 RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
806         }
807         WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
808
809         return OPERATOR_FINISHED;
810 }
811
812 /* extrude without transform */
813 static int mesh_extrude_exec(bContext *C, wmOperator *op)
814 {
815         Object *obedit= CTX_data_edit_object(C);
816         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
817         
818         EDBM_Extrude_Mesh(obedit, em, op, NULL);
819         
820         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
821         
822         return OPERATOR_FINISHED;       
823 }
824
825
826 void MESH_OT_extrude(wmOperatorType *ot)
827 {
828         /* identifiers */
829         ot->name= "Extrude";
830         ot->idname= "MESH_OT_extrude";
831         
832         /* api callbacks */
833         ot->invoke= mesh_extrude_invoke;
834         ot->exec= mesh_extrude_exec;
835         ot->poll= ED_operator_editmesh;
836         
837         /* flags */
838         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
839
840         /* to give to transform */
841         Properties_Proportional(ot);
842         Properties_Constraints(ot);
843         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
844 }
845
846 /* ******************** (de)select all operator **************** */
847
848 void EDBM_toggle_select_all(BMEditMesh *em) /* exported for UV */
849 {
850         if(em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
851                 EDBM_clear_flag_all(em, SELECT);
852         else 
853                 EDBM_set_flag_all(em, SELECT);
854 }
855
856 static int toggle_select_all_exec(bContext *C, wmOperator *op)
857 {
858         Object *obedit= CTX_data_edit_object(C);
859         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
860         
861         EDBM_toggle_select_all(em);
862         
863         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
864
865         return OPERATOR_FINISHED;
866 }
867
868 void MESH_OT_select_all_toggle(wmOperatorType *ot)
869 {
870         /* identifiers */
871         ot->name= "Select/Deselect All";
872         ot->idname= "MESH_OT_select_all_toggle";
873         
874         /* api callbacks */
875         ot->exec= toggle_select_all_exec;
876         ot->poll= ED_operator_editmesh;
877         
878         /* flags */
879         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
880 }
881
882 /* *************** add-click-mesh (extrude) operator ************** */
883
884 static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
885 {
886         ViewContext vc;
887         BMVert *v1;
888         BMIter iter;
889         float min[3], max[3];
890         int done= 0;
891         
892         em_setup_viewcontext(C, &vc);
893         
894         INIT_MINMAX(min, max);
895         
896         BM_ITER_SELECT(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH, NULL)
897                 DO_MINMAX(v1->co, min, max);
898                 done= 1;
899         }
900
901         /* call extrude? */
902         if(done) {
903                 BMEdge *eed;
904                 float vec[3], cent[3], mat[3][3];
905                 float nor[3]= {0.0, 0.0, 0.0};
906                 
907                 /* check for edges that are half selected, use for rotation */
908                 done= 0;
909                 BM_ITER(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH, NULL) {
910                         if (BM_TestHFlag(eed->v1, BM_SELECT) ^ BM_TestHFlag(eed->v2, BM_SELECT)) {
911                                 if(BM_TestHFlag(eed->v1, BM_SELECT)) 
912                                         VecSubf(vec, eed->v1->co, eed->v2->co);
913                                 else 
914                                         VecSubf(vec, eed->v2->co, eed->v1->co);
915                                 VecAddf(nor, nor, vec);
916                                 done= 1;
917                         }
918                 }
919                 if(done) Normalize(nor);
920                 
921                 /* center */
922                 VecAddf(cent, min, max);
923                 VecMulf(cent, 0.5f);
924                 VECCOPY(min, cent);
925                 
926                 Mat4MulVecfl(vc.obedit->obmat, min);    // view space
927                 view3d_get_view_aligned_coordinate(&vc, min, event->mval);
928                 Mat4Invert(vc.obedit->imat, vc.obedit->obmat); 
929                 Mat4MulVecfl(vc.obedit->imat, min); // back in object space
930                 
931                 VecSubf(min, min, cent);
932                 
933                 /* calculate rotation */
934                 Mat3One(mat);
935                 if(done) {
936                         float dot;
937                         
938                         VECCOPY(vec, min);
939                         Normalize(vec);
940                         dot= INPR(vec, nor);
941
942                         if( fabs(dot)<0.999) {
943                                 float cross[3], si, q1[4];
944                                 
945                                 Crossf(cross, nor, vec);
946                                 Normalize(cross);
947                                 dot= 0.5f*saacos(dot);
948                                 si= (float)sin(dot);
949                                 q1[0]= (float)cos(dot);
950                                 q1[1]= cross[0]*si;
951                                 q1[2]= cross[1]*si;
952                                 q1[3]= cross[2]*si;
953                                 
954                                 QuatToMat3(q1, mat);
955                         }
956                 }
957                 
958
959                 EDBM_Extrude_edge(vc.obedit, vc.em, SELECT, nor);
960                 EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
961                         BM_SELECT, cent, mat);
962                 EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v",
963                         BM_SELECT, min);
964         }
965         else {
966                 float *curs= give_cursor(vc.scene, vc.v3d);
967                 BMOperator bmop;
968                 BMOIter oiter;
969                 
970                 VECCOPY(min, curs);
971
972                 view3d_get_view_aligned_coordinate(&vc, min, event->mval);
973                 Mat4Invert(vc.obedit->imat, vc.obedit->obmat); 
974                 Mat4MulVecfl(vc.obedit->imat, min); // back in object space
975                 
976                 EDBM_InitOpf(vc.em, &bmop, op, "makevert co=%v", min);
977                 BMO_Exec_Op(vc.em->bm, &bmop);
978
979                 BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) {
980                         BM_Select(vc.em->bm, v1, 1);
981                 }
982
983                 if (!EDBM_FinishOp(vc.em, &bmop, op, 1))
984                         return OPERATOR_CANCELLED;
985         }
986
987         //retopo_do_all();
988         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit); 
989         DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA);
990         
991         return OPERATOR_FINISHED;
992 }
993
994 void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
995 {
996         /* identifiers */
997         ot->name= "Duplicate or Extrude at 3D Cursor";
998         ot->idname= "MESH_OT_dupli_extrude_cursor";
999         
1000         /* api callbacks */
1001         ot->invoke= dupli_extrude_cursor;
1002         ot->poll= ED_operator_editmesh;
1003         
1004         /* flags */
1005         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1006 }
1007
1008 static int delete_mesh(Object *obedit, wmOperator *op, int event, Scene *scene)
1009 {
1010         BMEditMesh *bem = ((Mesh*)obedit->data)->edit_btmesh;
1011         
1012         if(event<1) return OPERATOR_CANCELLED;
1013
1014         if(event==10 ) {
1015                 //"Erase Vertices";
1016
1017                 if (!EDBM_CallOpf(bem, op, "del geom=%hv context=%i", BM_SELECT, DEL_VERTS))
1018                         return OPERATOR_CANCELLED;
1019         } 
1020         else if(event==11) {
1021                 //"Edge Loop"
1022                 if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_SELECT))
1023                         return OPERATOR_CANCELLED;
1024         }
1025         else if(event==7) {
1026                 //"Dissolve"
1027                 if (bem->selectmode & SCE_SELECT_FACE) {
1028                         if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf",BM_SELECT))
1029                                 return OPERATOR_CANCELLED;
1030                 } else if (bem->selectmode & SCE_SELECT_EDGE) {
1031                         if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he",BM_SELECT))
1032                                 return OPERATOR_CANCELLED;
1033                 } else if (bem->selectmode & SCE_SELECT_VERTEX) {
1034                         if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv",BM_SELECT))
1035                                 return OPERATOR_CANCELLED;
1036                 }
1037         }
1038         else if(event==4) {
1039                 //Edges and Faces
1040                 if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_SELECT, DEL_EDGESFACES))
1041                         return OPERATOR_CANCELLED;
1042         } 
1043         else if(event==1) {
1044                 //"Erase Edges"
1045                 if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_SELECT, DEL_EDGES))
1046                         return OPERATOR_CANCELLED;
1047         }
1048         else if(event==2) {
1049                 //"Erase Faces";
1050                 if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_SELECT, DEL_FACES))
1051                         return OPERATOR_CANCELLED;
1052         }
1053         else if(event==5) {
1054                 //"Erase Only Faces";
1055                 if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d",
1056                                   BM_SELECT, DEL_ONLYFACES))
1057                         return OPERATOR_CANCELLED;
1058         }
1059         
1060         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1061
1062         return OPERATOR_FINISHED;
1063 }
1064
1065 /* Note, these values must match delete_mesh() event values */
1066 static EnumPropertyItem prop_mesh_delete_types[] = {
1067         {7, "DISSOLVE",         0, "Dissolve", ""},
1068         {10,"VERT",             0, "Vertices", ""},
1069         {1, "EDGE",             0, "Edges", ""},
1070         {2, "FACE",             0, "Faces", ""},
1071         {11, "EDGE_LOOP", 0, "Edge Loop", ""},
1072         {4, "EDGE_FACE", 0, "Edges & Faces", ""},
1073         {5, "ONLY_FACE", 0, "Only Faces", ""},
1074         {0, NULL, 0, NULL, NULL}
1075 };
1076
1077 static int delete_mesh_exec(bContext *C, wmOperator *op)
1078 {
1079         Object *obedit= CTX_data_edit_object(C);
1080         Scene *scene = CTX_data_scene(C);
1081
1082         delete_mesh(obedit, op, RNA_enum_get(op->ptr, "type"), scene);
1083         
1084         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA|ND_GEOM_SELECT, obedit);
1085         
1086         return OPERATOR_FINISHED;
1087 }
1088
1089 void MESH_OT_delete(wmOperatorType *ot)
1090 {
1091         /* identifiers */
1092         ot->name= "Delete";
1093         ot->idname= "MESH_OT_delete";
1094         
1095         /* api callbacks */
1096         ot->invoke= WM_menu_invoke;
1097         ot->exec= delete_mesh_exec;
1098         
1099         ot->poll= ED_operator_editmesh;
1100         
1101         /* flags */
1102         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1103         
1104         /*props */
1105         RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
1106 }
1107
1108
1109 static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
1110 {
1111         BMOperator bmop;
1112         Object *obedit= CTX_data_edit_object(C);
1113         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1114         
1115         if (!EDBM_InitOpf(em, &bmop, op, "contextual_create geom=%hfev", BM_SELECT))
1116                 return OPERATOR_CANCELLED;
1117         
1118         BMO_Exec_Op(em->bm, &bmop);
1119         BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT);
1120
1121         if (!EDBM_FinishOp(em, &bmop, op, 1))
1122                 return OPERATOR_CANCELLED;
1123
1124         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1125         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);     
1126         
1127         return OPERATOR_FINISHED;
1128 }
1129
1130 void MESH_OT_edge_face_add(wmOperatorType *ot)
1131 {
1132         /* identifiers */
1133         ot->name= "Make Edge/Face";
1134         ot->idname= "MESH_OT_edge_face_add";
1135         
1136         /* api callbacks */
1137         ot->exec= addedgeface_mesh_exec;
1138         ot->poll= ED_operator_editmesh;
1139         
1140         /* flags */
1141         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1142         
1143 }
1144
1145 static EnumPropertyItem prop_mesh_edit_types[] = {
1146         {1, "VERT", 0, "Vertices", ""},
1147         {2, "EDGE", 0, "Edges", ""},
1148         {3, "FACE", 0, "Faces", ""},
1149         {0, NULL, 0, NULL, NULL}
1150 };
1151
1152 static int mesh_selection_type_exec(bContext *C, wmOperator *op)
1153 {               
1154         
1155         Object *obedit= CTX_data_edit_object(C);
1156         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1157         int type = RNA_enum_get(op->ptr,"type");
1158
1159         switch (type) {
1160                 case 1:
1161                         em->selectmode = SCE_SELECT_VERTEX;
1162                         break;
1163                 case 2:
1164                         em->selectmode = SCE_SELECT_EDGE;
1165                         break;
1166                 case 3:
1167                         em->selectmode = SCE_SELECT_FACE;
1168                         break;
1169         }
1170
1171         EDBM_selectmode_set(em);
1172         CTX_data_scene(C)->toolsettings->selectmode = em->selectmode;
1173
1174         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1175         
1176         return OPERATOR_FINISHED;
1177 }
1178
1179 void MESH_OT_selection_type(wmOperatorType *ot)
1180 {
1181         /* identifiers */
1182         ot->name= "Selection Mode";
1183         ot->idname= "MESH_OT_selection_type";
1184         
1185         /* api callbacks */
1186         ot->invoke= WM_menu_invoke;
1187         ot->exec= mesh_selection_type_exec;
1188         
1189         ot->poll= ED_operator_editmesh;
1190         
1191         /* flags */
1192         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1193         
1194         /* props */
1195         RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type");
1196         RNA_def_boolean(ot->srna, "inclusive", 0, "Inclusive", "Selects geometry around selected geometry, occording to selection mode");       
1197 }
1198
1199 /* ************************* SEAMS AND EDGES **************** */
1200
1201 static int editbmesh_mark_seam(bContext *C, wmOperator *op)
1202 {
1203         Scene *scene = CTX_data_scene(C);
1204         Object *obedit= CTX_data_edit_object(C);
1205         Mesh *me= ((Mesh *)obedit->data);
1206         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1207         BMesh *bm = em->bm;
1208         BMEdge *eed;
1209         BMIter iter;
1210         int clear = RNA_boolean_get(op->ptr, "clear");
1211         
1212         /* auto-enable seams drawing */
1213         if(clear==0) {
1214                 me->drawflag |= ME_DRAWSEAMS;
1215         }
1216
1217         if(clear) {
1218                 BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
1219                         BM_ClearHFlag(eed, BM_SEAM);
1220                 }
1221         }
1222         else {
1223                 BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
1224                         BM_SetHFlag(eed, BM_SEAM);
1225                 }
1226         }
1227
1228         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1229         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1230
1231         return OPERATOR_FINISHED;
1232 }
1233
1234 void MESH_OT_mark_seam(wmOperatorType *ot)
1235 {
1236         /* identifiers */
1237         ot->name= "Mark Seam";
1238         ot->idname= "MESH_OT_mark_seam";
1239         
1240         /* api callbacks */
1241         ot->exec= editbmesh_mark_seam;
1242         ot->poll= ED_operator_editmesh;
1243         
1244         /* flags */
1245         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1246         
1247         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1248 }
1249
1250 static int editbmesh_mark_sharp(bContext *C, wmOperator *op)
1251 {
1252         Scene *scene = CTX_data_scene(C);
1253         Object *obedit= CTX_data_edit_object(C);
1254         Mesh *me= ((Mesh *)obedit->data);
1255         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1256         BMesh *bm = em->bm;
1257         BMEdge *eed;
1258         BMIter iter;
1259         int clear = RNA_boolean_get(op->ptr, "clear");
1260
1261         /* auto-enable sharp edge drawing */
1262         if(clear == 0) {
1263                 me->drawflag |= ME_DRAWSHARP;
1264         }
1265
1266         if(!clear) {
1267                 BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
1268                         BM_SetHFlag(eed, BM_SHARP);
1269                 }
1270         } else {
1271                 BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
1272                         BM_ClearHFlag(eed, BM_SHARP);
1273                 }
1274         }
1275
1276
1277         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1278         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1279
1280         return OPERATOR_FINISHED;
1281 }
1282
1283 void MESH_OT_mark_sharp(wmOperatorType *ot)
1284 {
1285         /* identifiers */
1286         ot->name= "Mark Sharp";
1287         ot->idname= "MESH_OT_mark_sharp";
1288         
1289         /* api callbacks */
1290         ot->exec= editbmesh_mark_sharp;
1291         ot->poll= ED_operator_editmesh;
1292         
1293         /* flags */
1294         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1295         
1296         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1297 }
1298
1299
1300 static int editbmesh_vert_connect(bContext *C, wmOperator *op)
1301 {
1302         Scene *scene = CTX_data_scene(C);
1303         Object *obedit= CTX_data_edit_object(C);
1304         Mesh *me= ((Mesh *)obedit->data);
1305         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1306         BMesh *bm = em->bm;
1307         BMOperator bmop;
1308         int len = 0;
1309         
1310         BMO_InitOpf(bm, &bmop, "connectverts verts=%hv", BM_SELECT);
1311         BMO_Exec_Op(bm, &bmop);
1312         len = BMO_GetSlot(&bmop, "edgeout")->len;
1313         BMO_Finish_Op(bm, &bmop);
1314         
1315         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1316         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1317
1318         return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1319 }
1320
1321 void MESH_OT_vert_connect(wmOperatorType *ot)
1322 {
1323         /* identifiers */
1324         ot->name= "Vertex Connect";
1325         ot->idname= "MESH_OT_vert_connect";
1326         
1327         /* api callbacks */
1328         ot->exec= editbmesh_vert_connect;
1329         ot->poll= ED_operator_editmesh;
1330         
1331         /* flags */
1332         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1333 }
1334
1335 static int editbmesh_edge_split(bContext *C, wmOperator *op)
1336 {
1337         Scene *scene = CTX_data_scene(C);
1338         Object *obedit= CTX_data_edit_object(C);
1339         Mesh *me= ((Mesh *)obedit->data);
1340         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1341         BMesh *bm = em->bm;
1342         BMOperator bmop;
1343         int len = 0;
1344         
1345         BMO_InitOpf(bm, &bmop, "edgesplit edges=%he numcuts=%d", BM_SELECT, RNA_int_get(op->ptr,"number_cuts"));
1346         BMO_Exec_Op(bm, &bmop);
1347         len = BMO_GetSlot(&bmop, "outsplit")->len;
1348         BMO_Finish_Op(bm, &bmop);
1349         
1350         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1351         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1352
1353         return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1354 }
1355
1356 void MESH_OT_edge_split(wmOperatorType *ot)
1357 {
1358         /* identifiers */
1359         ot->name= "Edge Split";
1360         ot->idname= "MESH_OT_edge_split";
1361         
1362         /* api callbacks */
1363         ot->exec= editbmesh_edge_split;
1364         ot->poll= ED_operator_editmesh;
1365         
1366         /* flags */
1367         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1368
1369         RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX);
1370 }
1371
1372 /****************** add duplicate operator ***************/
1373
1374 static int mesh_duplicate_exec(bContext *C, wmOperator *op)
1375 {
1376         Scene *scene= CTX_data_scene(C);
1377         Object *ob= CTX_data_edit_object(C);
1378         BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh;
1379         BMOperator bmop;
1380
1381         EDBM_InitOpf(em, &bmop, op, "dupe geom=%hvef", BM_SELECT);
1382         
1383         BMO_Exec_Op(em->bm, &bmop);
1384         EDBM_clear_flag_all(em, BM_SELECT);
1385
1386         BMO_HeaderFlag_Buffer(em->bm, &bmop, "newout", BM_SELECT);
1387
1388         if (!EDBM_FinishOp(em, &bmop, op, 1))
1389                 return OPERATOR_CANCELLED;
1390
1391         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
1392         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
1393         
1394         return OPERATOR_FINISHED;
1395 }
1396
1397 static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
1398 {
1399         WM_cursor_wait(1);
1400         mesh_duplicate_exec(C, op);
1401         WM_cursor_wait(0);
1402         
1403         return OPERATOR_FINISHED;
1404 }
1405
1406 void MESH_OT_duplicate(wmOperatorType *ot)
1407 {
1408         /* identifiers */
1409         ot->name= "Duplicate";
1410         ot->idname= "MESH_OT_duplicate";
1411         
1412         /* api callbacks */
1413         ot->invoke= mesh_duplicate_invoke;
1414         ot->exec= mesh_duplicate_exec;
1415         
1416         ot->poll= ED_operator_editmesh;
1417         
1418         /* to give to transform */
1419         RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
1420 }
1421
1422 static int flip_normals(bContext *C, wmOperator *op)
1423 {
1424         Scene *scene = CTX_data_scene(C);
1425         Object *obedit= CTX_data_edit_object(C);
1426         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1427         
1428         if (!EDBM_CallOpf(em, op, "reversefaces facaes=%hf", BM_SELECT))
1429                 return OPERATOR_CANCELLED;
1430         
1431         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1432         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1433
1434         return OPERATOR_FINISHED;
1435 }
1436
1437 void MESH_OT_flip_normals(wmOperatorType *ot)
1438 {
1439         /* identifiers */
1440         ot->name= "Flip Normals";
1441         ot->idname= "MESH_OT_flip_normals";
1442         
1443         /* api callbacks */
1444         ot->exec= flip_normals;
1445         ot->poll= ED_operator_editmesh;
1446         
1447         /* flags */
1448         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1449 }
1450
1451 #define DIRECTION_CW    1
1452 #define DIRECTION_CCW   2
1453
1454 static const EnumPropertyItem direction_items[]= {
1455         {DIRECTION_CW, "CW", 0, "Clockwise", ""},
1456         {DIRECTION_CCW, "CCW", 0, "Counter Clockwise", ""},
1457         {0, NULL, 0, NULL, NULL}};
1458
1459 /* only accepts 1 selected edge, or 2 selected faces */
1460 static int edge_rotate_selected(bContext *C, wmOperator *op)
1461 {
1462         Scene *scene= CTX_data_scene(C);
1463         Object *obedit= CTX_data_edit_object(C);
1464         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1465         BMOperator bmop;
1466         BMOIter siter;
1467         BMEdge *eed;
1468         BMIter iter;
1469         int ccw = RNA_int_get(op->ptr, "direction") == 1; // direction == 2 when clockwise and ==1 for counter CW.
1470         short edgeCount = 0;
1471         
1472         if (!(em->bm->totfacesel == 2 || em->bm->totedgesel == 1)) {
1473                 BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
1474                 return OPERATOR_CANCELLED;
1475         }
1476
1477         /*first see if we have two adjacent faces*/
1478         BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1479                 if (BM_Edge_FaceCount(eed) == 2) {
1480                         if ((BM_TestHFlag(eed->loop->f, BM_SELECT) && BM_TestHFlag(((BMLoop*)eed->loop->radial.next->data)->f, BM_SELECT))
1481                              && !(BM_TestHFlag(eed->loop->f, BM_HIDDEN) || BM_TestHFlag(((BMLoop*)eed->loop->radial.next->data)->f, BM_HIDDEN)))
1482                         {
1483                                 break;
1484                         }
1485                 }
1486         }
1487         
1488         /*ok, we don't have two adjacent faces, but we do have two selected ones.
1489           that's an error condition.*/
1490         if (!eed && em->bm->totfacesel == 2) {
1491                 BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
1492                 return OPERATOR_CANCELLED;
1493         }
1494
1495         if (!eed) {
1496                 BM_ITER_SELECT(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL)
1497                         if (BM_TestHFlag(eed, BM_SELECT))
1498                                 break;
1499                 }
1500         }
1501
1502         /*this should never happen*/
1503         if (!eed)
1504                 return OPERATOR_CANCELLED;
1505         
1506         EDBM_InitOpf(em, &bmop, op, "edgerotate edges=%e ccw=%d", eed, ccw);
1507         BMO_Exec_Op(em->bm, &bmop);
1508
1509         BMO_HeaderFlag_Slot(em->bm, &bmop, "edgeout", BM_SELECT);
1510
1511         if (!EDBM_FinishOp(em, &bmop, op, 1))
1512                 return OPERATOR_CANCELLED;
1513
1514         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1515         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1516
1517         return OPERATOR_FINISHED;
1518 }
1519
1520 void MESH_OT_edge_rotate(wmOperatorType *ot)
1521 {
1522         /* identifiers */
1523         ot->name= "Rotate Selected Edge";
1524         ot->idname= "MESH_OT_edge_rotate";
1525
1526         /* api callbacks */
1527         ot->exec= edge_rotate_selected;
1528         ot->poll= ED_operator_editmesh;
1529
1530         /* flags */
1531         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1532
1533         /* props */
1534         RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "direction", "direction to rotate edge around.");
1535 }
1536
1537 /* swap is 0 or 1, if 1 it hides not selected */
1538 void EDBM_hide_mesh(BMEditMesh *em, int swap)
1539 {
1540         BMIter iter;
1541         BMHeader *h;
1542         int itermode;
1543
1544         if(em==NULL) return;
1545         
1546         if (em->selectmode & SCE_SELECT_VERTEX)
1547                 itermode = BM_VERTS_OF_MESH;
1548         else if (em->selectmode & SCE_SELECT_EDGE)
1549                 itermode = BM_EDGES_OF_MESH;
1550         else
1551                 itermode = BM_FACES_OF_MESH;
1552
1553         BM_ITER(h, &iter, em->bm, itermode, NULL) {
1554                 if (BM_TestHFlag(h, BM_SELECT) ^ swap)
1555                         BM_Hide(em->bm, h, 1);
1556         }
1557
1558         /*original hide flushing comment (OUTDATED): 
1559           hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
1560         /*  - vertex hidden, always means edge is hidden too
1561                 - edge hidden, always means face is hidden too
1562                 - face hidden, only set face hide
1563                 - then only flush back down what's absolute hidden
1564         */
1565
1566 }
1567
1568 static int hide_mesh_exec(bContext *C, wmOperator *op)
1569 {
1570         Object *obedit= CTX_data_edit_object(C);
1571         Scene *scene = CTX_data_scene(C);
1572         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1573         
1574         EDBM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
1575                 
1576         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1577         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
1578
1579         return OPERATOR_FINISHED;       
1580 }
1581
1582 void MESH_OT_hide(wmOperatorType *ot)
1583 {
1584         /* identifiers */
1585         ot->name= "Hide Selection";
1586         ot->idname= "MESH_OT_hide";
1587         
1588         /* api callbacks */
1589         ot->exec= hide_mesh_exec;
1590         ot->poll= ED_operator_editmesh;
1591         
1592         /* flags */
1593         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1594         
1595         /* props */
1596         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
1597 }
1598
1599
1600 void EDBM_reveal_mesh(BMEditMesh *em)
1601 {
1602         BMIter iter;
1603         BMHeader *ele;
1604         int i, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1605         int sels[3] = {1, !(em->selectmode & SCE_SELECT_VERTEX), !(em->selectmode & SCE_SELECT_VERTEX | SCE_SELECT_EDGE)};
1606
1607         for (i=0; i<3; i++) {
1608                 BM_ITER(ele, &iter, em->bm, types[i], NULL) {
1609                         if (BM_TestHFlag(ele, BM_HIDDEN)) {
1610                                 BM_Hide(em->bm, ele, 0);
1611
1612                                 if (sels[i])
1613                                         BM_Select(em->bm, ele, 1);
1614                         }
1615                 }
1616         }
1617
1618         EDBM_selectmode_flush(em);
1619 }
1620
1621 static int reveal_mesh_exec(bContext *C, wmOperator *op)
1622 {
1623         Object *obedit= CTX_data_edit_object(C);
1624         Scene *scene = CTX_data_scene(C);
1625         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1626         
1627         EDBM_reveal_mesh(em);
1628
1629         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1630         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
1631
1632         return OPERATOR_FINISHED;       
1633 }
1634
1635 void MESH_OT_reveal(wmOperatorType *ot)
1636 {
1637         /* identifiers */
1638         ot->name= "Reveal Hidden";
1639         ot->idname= "MESH_OT_reveal";
1640         
1641         /* api callbacks */
1642         ot->exec= reveal_mesh_exec;
1643         ot->poll= ED_operator_editmesh;
1644         
1645         /* flags */
1646         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1647 }
1648
1649 static int normals_make_consistent_exec(bContext *C, wmOperator *op)
1650 {
1651         Scene *scene = CTX_data_scene(C);
1652         Object *obedit= CTX_data_edit_object(C);
1653         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1654         
1655         if (!EDBM_CallOpf(em, op, "righthandfaces faces=%hf", BM_SELECT))
1656                 return OPERATOR_CANCELLED;
1657         
1658         if (RNA_boolean_get(op->ptr, "inside"))
1659                 EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT);
1660
1661         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1662         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); //TODO is this needed ?
1663
1664         return OPERATOR_FINISHED;       
1665 }
1666
1667 void MESH_OT_normals_make_consistent(wmOperatorType *ot)
1668 {
1669         /* identifiers */
1670         ot->name= "Make Normals Consistent";
1671         ot->idname= "MESH_OT_normals_make_consistent";
1672         
1673         /* api callbacks */
1674         ot->exec= normals_make_consistent_exec;
1675         ot->poll= ED_operator_editmesh;
1676         
1677         /* flags */
1678         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1679         
1680         RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
1681 }
1682