part 1 of cleaning up my little array macro library to be a formal API. also removed...
[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 #include "BLI_array.h"
62
63 #include "BKE_context.h"
64 #include "BKE_customdata.h"
65 #include "BKE_depsgraph.h"
66 #include "BKE_global.h"
67 #include "BKE_library.h"
68 #include "BKE_mesh.h"
69 #include "BKE_object.h"
70 #include "BKE_utildefines.h"
71 #include "BKE_bmesh.h"
72 #include "BKE_report.h"
73 #include "BKE_tessmesh.h"
74
75 #include "BIF_gl.h"
76 #include "BIF_glutil.h"
77
78 #include "WM_api.h"
79 #include "WM_types.h"
80
81 #include "ED_mesh.h"
82 #include "ED_view3d.h"
83 #include "ED_util.h"
84 #include "ED_screen.h"
85 #include "ED_transform.h"
86
87 #include "UI_interface.h"
88
89 #include "mesh_intern.h"
90 #include "bmesh.h"
91
92 static void add_normal_aligned(float *nor, float *add)
93 {
94         if( INPR(nor, add) < -0.9999f)
95                 VecSubf(nor, nor, add);
96         else
97                 VecAddf(nor, nor, add);
98 }
99
100
101 static int subdivide_exec(bContext *C, wmOperator *op)
102 {
103         ToolSettings *ts = CTX_data_tool_settings(C);
104         Object *obedit= CTX_data_edit_object(C);
105         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
106         int cuts= RNA_int_get(op->ptr,"number_cuts");
107         float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness");
108         float fractal= RNA_float_get(op->ptr, "fractal")/100;
109         int flag= 0;
110
111         if(smooth != 0.0f)
112                 flag |= B_SMOOTH;
113         if(fractal != 0.0f)
114                 flag |= B_FRACTAL;
115
116         BM_esubdivideflag(obedit, em->bm, BM_SELECT, 
117                           smooth, fractal, 
118                           ts->editbutflag|flag, 
119                           cuts, 0, RNA_enum_get(op->ptr, "quadcorner"), 
120                           RNA_boolean_get(op->ptr, "tess_single_edge"),
121                           RNA_boolean_get(op->ptr, "gridfill"));
122
123         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
124         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
125
126         return OPERATOR_FINISHED;
127 }
128
129 /* Note, these values must match delete_mesh() event values */
130 static EnumPropertyItem prop_mesh_cornervert_types[] = {
131         {SUBD_INNERVERT,     "INNERVERT", 0,      "Inner Vert", ""},
132         {SUBD_PATH,          "PATH", 0,           "Path", ""},
133         {SUBD_STRAIGHT_CUT,  "STRAIGHT_CUT", 0,   "Straight Cut", ""},
134         {SUBD_FAN,           "FAN", 0,            "Fan", ""},
135         {0, NULL, 0, NULL, NULL}
136 };
137
138 void MESH_OT_subdivide(wmOperatorType *ot)
139 {
140         /* identifiers */
141         ot->name= "Subdivide";
142         ot->description= "Subdivide selected edges.";
143         ot->idname= "MESH_OT_subdivide";
144
145         /* api callbacks */
146         ot->exec= subdivide_exec;
147         ot->poll= ED_operator_editmesh;
148
149         /* flags */
150         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
151
152         /* properties */
153         RNA_def_int(ot->srna, "number_cuts", 1, 1, 20, "Number of Cuts", "", 1, INT_MAX);
154         RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
155         RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1000.0f, "Smoothness", "Smoothness factor.", 0.0f, FLT_MAX);
156
157         /*props */
158         RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_STRAIGHT_CUT, "Quad Corner Type", "Method used for subdividing two adjacent edges in a quad");
159         RNA_def_boolean(ot->srna, "tess_single_edge", 0, "Tesselate Single Edge", "Adds triangles to single edges belonging to triangles or quads");
160         RNA_def_boolean(ot->srna, "gridfill", 1, "Grid Fill", "Fill Fully Selected Triangles and Quads With A Grid");
161 }
162
163 /* individual face extrude */
164 /* will use vertex normals for extrusion directions, so *nor is unaffected */
165 short EDBM_Extrude_face_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) 
166 {
167         BMOIter siter;
168         BMIter liter;
169         BMFace *f;
170         BMLoop *l;
171         BMOperator bmop;
172
173         EDBM_InitOpf(em, &bmop, op, "extrude_face_indiv faces=%hf", flag);
174
175         /*deselect original verts*/
176         EDBM_clear_flag_all(em, BM_SELECT);
177
178         BMO_Exec_Op(em->bm, &bmop);
179         
180         BMO_ITER(f, &siter, em->bm, &bmop, "faceout", BM_FACE) {
181                 BM_Select(em->bm, f, 1);
182
183                 /*set face vertex normals to face normal*/
184                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
185                         VECCOPY(l->v->no, f->no);
186                 }
187         }
188
189         if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
190
191         return 's'; // s is shrink/fatten
192 }
193
194 #if 0
195 short EDBM_Extrude_face_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) 
196         EditVert *eve, *v1, *v2, *v3, *v4;
197         EditEdge *eed;
198         EditFace *efa, *nextfa;
199         
200         if(em==NULL) return 0;
201         
202         /* selected edges with 1 or more selected face become faces */
203         /* selected faces each makes new faces */
204         /* always remove old faces, keeps volumes manifold */
205         /* select the new extrusion, deselect old */
206         
207         /* step 1; init, count faces in edges */
208         recalc_editnormals(em);
209         
210         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;      // new select flag
211
212         for(eed= em->edges.first; eed; eed= eed->next) {
213                 eed->f2= 0; // amount of unselected faces
214         }
215         for(efa= em->faces.first; efa; efa= efa->next) {
216                 if(efa->f & SELECT);
217                 else {
218                         efa->e1->f2++;
219                         efa->e2->f2++;
220                         efa->e3->f2++;
221                         if(efa->e4) efa->e4->f2++;
222                 }
223         }
224
225         /* step 2: make new faces from faces */
226         for(efa= em->faces.last; efa; efa= efa->prev) {
227                 if(efa->f & SELECT) {
228                         v1= addvertlist(em, efa->v1->co, efa->v1);
229                         v2= addvertlist(em, efa->v2->co, efa->v2);
230                         v3= addvertlist(em, efa->v3->co, efa->v3);
231                         
232                         v1->f1= v2->f1= v3->f1= 1;
233                         VECCOPY(v1->no, efa->n);
234                         VECCOPY(v2->no, efa->n);
235                         VECCOPY(v3->no, efa->n);
236                         if(efa->v4) {
237                                 v4= addvertlist(em, efa->v4->co, efa->v4); 
238                                 v4->f1= 1;
239                                 VECCOPY(v4->no, efa->n);
240                         }
241                         else v4= NULL;
242                         
243                         /* side faces, clockwise */
244                         addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL);
245                         addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL);
246                         if(efa->v4) {
247                                 addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL);
248                                 addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL);
249                         }
250                         else {
251                                 addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL);
252                         }
253                         /* top face */
254                         addfacelist(em, v1, v2, v3, v4, efa, NULL);
255                 }
256         }
257         
258         /* step 3: remove old faces */
259         efa= em->faces.first;
260         while(efa) {
261                 nextfa= efa->next;
262                 if(efa->f & SELECT) {
263                         BLI_remlink(&em->faces, efa);
264                         free_editface(em, efa);
265                 }
266                 efa= nextfa;
267         }
268
269         /* step 4: redo selection */
270         EM_clear_flag_all(em, SELECT);
271         
272         for(eve= em->verts.first; eve; eve= eve->next) {
273                 if(eve->f1)  eve->f |= SELECT;
274         }
275         
276         EM_select_flush(em);
277         
278         return 'n';
279 }
280 #endif
281
282 /* extrudes individual edges */
283 short EDBM_Extrude_edges_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) 
284 {
285         BMOperator bmop;
286
287         EDBM_InitOpf(em, &bmop, op, "extrude_edge_only edges=%he", flag);
288
289         /*deselect original verts*/
290         EDBM_clear_flag_all(em, BM_SELECT);
291
292         BMO_Exec_Op(em->bm, &bmop);
293         BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_VERT|BM_EDGE);
294
295         if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
296
297         return 'n'; // n is normal grab
298 }
299
300 #if 0
301 /* nor is filled with constraint vector */
302 short EDBM_Extrude_edges_indiv(BMEditMesh *em, short flag, float *nor) 
303 {
304         EditVert *eve;
305         EditEdge *eed;
306         EditFace *efa;
307         
308         for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL;
309         for(eed= em->edges.first; eed; eed= eed->next) {
310                 eed->tmp.f = NULL;
311                 eed->f2= ((eed->f & flag)!=0);
312         }
313         
314         set_edge_directions_f2(em, 2);
315
316         /* sample for next loop */
317         for(efa= em->faces.first; efa; efa= efa->next) {
318                 efa->e1->tmp.f = efa;
319                 efa->e2->tmp.f = efa;
320                 efa->e3->tmp.f = efa;
321                 if(efa->e4) efa->e4->tmp.f = efa;
322         }
323         /* make the faces */
324         for(eed= em->edges.first; eed; eed= eed->next) {
325                 if(eed->f & flag) {
326                         if(eed->v1->tmp.v == NULL)
327                                 eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
328                         if(eed->v2->tmp.v == NULL)
329                                 eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
330
331                         if(eed->dir==1) 
332                                 addfacelist(em, eed->v1, eed->v2, 
333                                                         eed->v2->tmp.v, eed->v1->tmp.v, 
334                                                         eed->tmp.f, NULL);
335                         else 
336                                 addfacelist(em, eed->v2, eed->v1, 
337                                                         eed->v1->tmp.v, eed->v2->tmp.v, 
338                                                         eed->tmp.f, NULL);
339
340                         /* for transform */
341                         if(eed->tmp.f) {
342                                 efa = eed->tmp.f;
343                                 if (efa->f & SELECT) add_normal_aligned(nor, efa->n);
344                         }
345                 }
346         }
347         Normalize(nor);
348         
349         /* set correct selection */
350         EM_clear_flag_all(em, SELECT);
351         for(eve= em->verts.last; eve; eve= eve->prev) {
352                 if(eve->tmp.v) {
353                         eve->tmp.v->f |= flag;
354                 }
355         }
356
357         for(eed= em->edges.first; eed; eed= eed->next) {
358                 if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
359         }
360         
361         if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab
362         return 'n';  // n is for normal constraint
363 }
364 #endif
365
366 /* extrudes individual vertices */
367 short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) 
368 {
369         BMOperator bmop;
370
371         EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", flag);
372
373         /*deselect original verts*/
374         BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "verts", BM_SELECT, BM_VERT);
375
376         BMO_Exec_Op(em->bm, &bmop);
377         BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_VERT);
378
379         if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
380
381         return 'g'; // g is grab
382 }
383
384 short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int flag, float *nor)
385 {
386         BMesh *bm = em->bm;
387         BMIter iter;
388         BMOIter siter;
389         BMOperator extop;
390         BMVert *vert;
391         BMEdge *edge;
392         BMFace *f;
393         ModifierData *md;
394         BMHeader *el;
395         
396         BMO_Init_Op(&extop, "extrudefaceregion");
397         BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein",
398                                flag, BM_VERT|BM_EDGE|BM_FACE);
399
400         BM_ITER(vert, &iter, bm, BM_VERTS_OF_MESH, NULL) {
401                 BM_Select(bm, vert, 0);
402         }
403
404         BM_ITER(edge, &iter, bm, BM_EDGES_OF_MESH, NULL) {
405                 BM_Select(bm, edge, 0);
406         }
407
408         BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
409                 BM_Select(bm, f, 0);
410         }
411
412         /* If a mirror modifier with clipping is on, we need to adjust some 
413          * of the cases above to handle edges on the line of symmetry.
414          */
415         md = obedit->modifiers.first;
416         for (; md; md=md->next) {
417                 if (md->type==eModifierType_Mirror) {
418                         MirrorModifierData *mmd = (MirrorModifierData*) md;     
419                 
420                         if(mmd->flag & MOD_MIR_CLIPPING) {
421                                 float mtx[4][4];
422                                 if (mmd->mirror_ob) {
423                                         float imtx[4][4];
424                                         Mat4Invert(imtx, mmd->mirror_ob->obmat);
425                                         Mat4MulMat4(mtx, obedit->obmat, imtx);
426                                 }
427
428                                 for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL);
429                                      edge; edge=BMIter_Step(&iter))
430                                 {
431                                         if(edge->head.flag & flag) {
432                                                 float co1[3], co2[3];
433
434                                                 VecCopyf(co1, edge->v1->co);
435                                                 VecCopyf(co2, edge->v2->co);
436
437                                                 if (mmd->mirror_ob) {
438                                                         VecMat4MulVecfl(co1, mtx, co1);
439                                                         VecMat4MulVecfl(co2, mtx, co2);
440                                                 }
441
442                                                 if (mmd->flag & MOD_MIR_AXIS_X)
443                                                         if ( (fabs(co1[0]) < mmd->tolerance) &&
444                                                                  (fabs(co2[0]) < mmd->tolerance) )
445                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
446
447                                                 if (mmd->flag & MOD_MIR_AXIS_Y)
448                                                         if ( (fabs(co1[1]) < mmd->tolerance) &&
449                                                                  (fabs(co2[1]) < mmd->tolerance) )
450                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
451
452                                                 if (mmd->flag & MOD_MIR_AXIS_Z)
453                                                         if ( (fabs(co1[2]) < mmd->tolerance) &&
454                                                                  (fabs(co2[2]) < mmd->tolerance) )
455                                                                 BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
456                                         }
457                                 }
458                         }
459                 }
460         }
461
462         BMO_Exec_Op(bm, &extop);
463
464         nor[0] = nor[1] = nor[2] = 0.0f;
465         
466         BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) {
467                 BM_Select(bm, el, 1);
468
469                 if (el->type == BM_FACE) {
470                         f = (BMFace*)el;
471                         add_normal_aligned(nor, f->no);
472                 };
473         }
474
475         Normalize(nor);
476
477         BMO_Finish_Op(bm, &extop);
478
479         if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
480         return 'n'; // normal constraint 
481
482 }
483 short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, short flag, float *nor)
484 {
485                 BMIter iter;
486                 BMEdge *eed;
487                 
488                 /*ensure vert flags are consistent for edge selections*/
489                 eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
490                 for ( ; eed; eed=BMIter_Step(&iter)) {
491                         if (BM_TestHFlag(eed, flag)) {
492                                 if (flag != BM_SELECT) {
493                                         BM_SetHFlag(eed->v1, flag);
494                                         BM_SetHFlag(eed->v2, flag);
495                                 } else {
496                                         BM_Select(em->bm, eed->v1, 1);
497                                         BM_Select(em->bm, eed->v2, 1);
498                                 }
499                         } else {
500                                 if (BM_TestHFlag(eed->v1, flag) && BM_TestHFlag(eed->v2, flag)) {
501                                         if (flag != BM_SELECT)
502                                                 BM_SetHFlag(eed, flag);
503                                         else BM_Select(em->bm, eed, 1);
504                                 }
505                         }
506                 }
507
508                 return EDBM_Extrude_edge(obedit, em, flag, nor);
509
510 }
511
512 static int extrude_repeat_mesh(bContext *C, wmOperator *op)
513 {
514         Object *obedit= CTX_data_edit_object(C);
515         Scene *scene = CTX_data_scene(C);
516         BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
517         RegionView3D *rv3d = CTX_wm_region_view3d(C);           
518                 
519         int steps = RNA_int_get(op->ptr,"steps");
520         
521         float offs = RNA_float_get(op->ptr,"offset");
522         float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
523         short a;
524
525         /* dvec */
526         dvec[0]= rv3d->persinv[2][0];
527         dvec[1]= rv3d->persinv[2][1];
528         dvec[2]= rv3d->persinv[2][2];
529         Normalize(dvec);
530         dvec[0]*= offs;
531         dvec[1]*= offs;
532         dvec[2]*= offs;
533
534         /* base correction */
535         Mat3CpyMat4(bmat, obedit->obmat);
536         Mat3Inv(tmat, bmat);
537         Mat3MulVecfl(tmat, dvec);
538
539         for(a=0; a<steps; a++) {
540                 EDBM_Extrude_edge(obedit, em, BM_SELECT, nor);
541                 //BMO_CallOpf(em->bm, "extrudefaceregion edgefacein=%hef", BM_SELECT);
542                 BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT);
543                 //extrudeflag(obedit, em, SELECT, nor);
544                 //translateflag(em, SELECT, dvec);
545         }
546         
547         EDBM_RecalcNormals(em);
548
549         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
550         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
551
552         return OPERATOR_FINISHED;
553 }
554
555 void MESH_OT_extrude_repeat(wmOperatorType *ot)
556 {
557         /* identifiers */
558         ot->name= "Extrude Repeat Mesh";
559         ot->description= "Extrude selected vertices, edges or faces repeatedly.";
560         ot->idname= "MESH_OT_extrude_repeat";
561         
562         /* api callbacks */
563         ot->exec= extrude_repeat_mesh;
564         ot->poll= ED_operator_editmesh;
565         
566         /* flags */
567         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
568         
569         /* props */
570         RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX);
571         RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX);
572 }
573
574 /* generic extern called extruder */
575 int EDBM_Extrude_Mesh(Object *obedit, BMEditMesh *em, wmOperator *op, float *norin)
576 {
577         Scene *scene= NULL;             // XXX CTX!
578         short nr, transmode= 0;
579         float stacknor[3] = {0.0f, 0.0f, 0.0f};
580         float *nor = norin ? norin : stacknor;
581
582         nor[0] = nor[1] = nor[2] = 0.0f;
583
584         if(em->selectmode & SCE_SELECT_VERTEX) {
585                 if(em->bm->totvertsel==0) nr= 0;
586                 else if(em->bm->totvertsel==1) nr= 4;
587                 else if(em->bm->totedgesel==0) nr= 4;
588                 else if(em->bm->totfacesel==0) 
589                         nr= 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
590                 else if(em->bm->totfacesel==1)
591                         nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
592                 else 
593                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
594         }
595         else if(em->selectmode & SCE_SELECT_EDGE) {
596                 if (em->bm->totedgesel==0) nr = 0;
597                 
598                 nr = 1;
599                 /*else if (em->totedgesel==1) nr = 3;
600                 else if(em->totfacesel==0) nr = 3;
601                 else if(em->totfacesel==1)
602                         nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3");
603                 else
604                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
605                 */
606         }
607         else {
608                 if (em->bm->totfacesel == 0) nr = 0;
609                 else if (em->bm->totfacesel == 1) nr = 1;
610                 else
611                         nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
612         }
613
614         if(nr<1) return 'g';
615
616         if(nr==1 && em->selectmode & SCE_SELECT_VERTEX) 
617                 transmode= EDBM_Extrude_vert(obedit, em, SELECT, nor);
618         else if (nr == 1) transmode= EDBM_Extrude_edge(obedit, em, SELECT, nor);
619         else if(nr==4) transmode= EDBM_Extrude_verts_indiv(em, op, SELECT, nor);
620         else if(nr==3) transmode= EDBM_Extrude_edges_indiv(em, op, SELECT, nor);
621         else transmode= EDBM_Extrude_face_indiv(em, op, SELECT, nor);
622         
623         if(transmode==0) {
624                 BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
625         }
626         else {
627                 
628                         /* We need to force immediate calculation here because 
629                         * transform may use derived objects (which are now stale).
630                         *
631                         * This shouldn't be necessary, derived queries should be
632                         * automatically building this data if invalid. Or something.
633                         */
634 //              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
635                 object_handle_update(scene, obedit);
636
637                 /* individual faces? */
638 //              BIF_TransformSetUndo("Extrude");
639                 if(nr==2) {
640 //                      initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
641 //                      Transform();
642                 }
643                 else {
644 //                      initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
645                         if(transmode=='n') {
646                                 Mat4MulVecfl(obedit->obmat, nor);
647                                 VecSubf(nor, nor, obedit->obmat[3]);
648 //                              BIF_setSingleAxisConstraint(nor, "along normal");
649                         }
650 //                      Transform();
651                 }
652         }
653         
654         return transmode;
655 }
656
657 /* extrude without transform */
658 static int mesh_extrude_region_exec(bContext *C, wmOperator *op)
659 {
660         Object *obedit= CTX_data_edit_object(C);
661         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
662         
663         EDBM_Extrude_Mesh(obedit, em, op, NULL);
664         
665         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
666         
667         return OPERATOR_FINISHED;       
668 }
669
670 static int mesh_extrude_region_invoke(bContext *C, wmOperator *op, wmEvent *event)
671 {
672         Scene *scene= CTX_data_scene(C);
673         Object *obedit= CTX_data_edit_object(C);
674         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
675         float nor[3];
676         int constraint_axis[3] = {0, 0, 1};
677         int tmode;
678
679         tmode = EDBM_Extrude_edge(obedit, em, BM_SELECT, nor);
680
681         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
682         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
683
684         RNA_enum_set(op->ptr, "proportional", 0);
685         RNA_boolean_set(op->ptr, "mirror", 0);
686
687         if (tmode == 'n') {
688                 RNA_enum_set(op->ptr, "constraint_orientation", V3D_MANIP_NORMAL);
689                 RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
690         }
691         WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
692
693         return OPERATOR_FINISHED;
694 }
695
696 void MESH_OT_extrude_region(wmOperatorType *ot)
697 {
698         /* identifiers */
699         ot->name= "Extrude Region";
700         ot->idname= "MESH_OT_extrude_region";
701         
702         /* api callbacks */
703         ot->invoke= mesh_extrude_region_invoke;
704         ot->exec= mesh_extrude_region_exec;
705         ot->poll= ED_operator_editmesh;
706         
707         /* flags */
708         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
709
710         /* to give to transform */
711         Properties_Proportional(ot);
712         Properties_Constraints(ot);
713         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
714 }
715
716 static int mesh_extrude_verts_exec(bContext *C, wmOperator *op)
717 {
718         Object *obedit= CTX_data_edit_object(C);
719         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
720         float nor[3];
721
722         EDBM_Extrude_verts_indiv(em, op, BM_SELECT, nor);
723         
724         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
725         
726         return OPERATOR_FINISHED;       
727 }
728
729 static int mesh_extrude_verts_invoke(bContext *C, wmOperator *op, wmEvent *event)
730 {
731         Scene *scene= CTX_data_scene(C);
732         Object *obedit= CTX_data_edit_object(C);
733         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
734         float nor[3];
735         int constraint_axis[3] = {0, 0, 1};
736         int tmode;
737
738         tmode = EDBM_Extrude_verts_indiv(em, op, BM_SELECT, nor);
739
740         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
741         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
742
743         RNA_enum_set(op->ptr, "proportional", 0);
744         RNA_boolean_set(op->ptr, "mirror", 0);
745
746         if (tmode == 'n') {
747                 RNA_enum_set(op->ptr, "constraint_orientation", V3D_MANIP_NORMAL);
748                 RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
749         }
750         WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
751
752         return OPERATOR_FINISHED;
753 }
754
755 void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
756 {
757         /* identifiers */
758         ot->name= "Extrude Only Vertices";
759         ot->idname= "MESH_OT_extrude_verts_indiv";
760         
761         /* api callbacks */
762         ot->invoke= mesh_extrude_verts_invoke;
763         ot->exec= mesh_extrude_verts_exec;
764         ot->poll= ED_operator_editmesh;
765         
766         /* flags */
767         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
768
769         /* to give to transform */
770         Properties_Proportional(ot);
771         Properties_Constraints(ot);
772         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
773 }
774
775 static int mesh_extrude_edges_exec(bContext *C, wmOperator *op)
776 {
777         Object *obedit= CTX_data_edit_object(C);
778         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
779         float nor[3];
780
781         EDBM_Extrude_edges_indiv(em, op, BM_SELECT, nor);
782         
783         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
784         
785         return OPERATOR_FINISHED;       
786 }
787
788 static int mesh_extrude_edges_invoke(bContext *C, wmOperator *op, wmEvent *event)
789 {
790         Scene *scene= CTX_data_scene(C);
791         Object *obedit= CTX_data_edit_object(C);
792         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
793         float nor[3];
794         int constraint_axis[3] = {0, 0, 1};
795         int tmode;
796
797         tmode = EDBM_Extrude_edges_indiv(em, op, BM_SELECT, nor);
798
799         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
800         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
801
802         RNA_enum_set(op->ptr, "proportional", 0);
803         RNA_boolean_set(op->ptr, "mirror", 0);
804
805         /*if (tmode == 'n') {
806                 RNA_enum_set(op->ptr, "constraint_orientation", V3D_MANIP_NORMAL);
807                 RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
808         }*/
809         WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
810
811         return OPERATOR_FINISHED;
812 }
813
814 void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
815 {
816         /* identifiers */
817         ot->name= "Extrude Only Edges";
818         ot->idname= "MESH_OT_extrude_edges_indiv";
819         
820         /* api callbacks */
821         ot->invoke= mesh_extrude_edges_invoke;
822         ot->exec= mesh_extrude_edges_exec;
823         ot->poll= ED_operator_editmesh;
824         
825         /* flags */
826         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
827
828         /* to give to transform */
829         Properties_Proportional(ot);
830         Properties_Constraints(ot);
831         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
832 }
833
834 static int mesh_extrude_faces_exec(bContext *C, wmOperator *op)
835 {
836         Object *obedit= CTX_data_edit_object(C);
837         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
838         float nor[3];
839
840         EDBM_Extrude_face_indiv(em, op, BM_SELECT, nor);
841         
842         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
843         
844         return OPERATOR_FINISHED;       
845 }
846
847 static int mesh_extrude_faces_invoke(bContext *C, wmOperator *op, wmEvent *event)
848 {
849         Scene *scene= CTX_data_scene(C);
850         Object *obedit= CTX_data_edit_object(C);
851         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
852         float nor[3];
853         int constraint_axis[3] = {0, 0, 1};
854         int tmode;
855
856         tmode = EDBM_Extrude_face_indiv(em, op, BM_SELECT, nor);
857
858         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
859         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
860
861         RNA_enum_set(op->ptr, "proportional", 0);
862         RNA_boolean_set(op->ptr, "mirror", 0);
863         
864         if (tmode == 's') {
865                 WM_operator_name_call(C, "TFM_OT_shrink_fatten", WM_OP_INVOKE_REGION_WIN, op->ptr);
866         } else {
867                 if (tmode == 'n') {
868                         RNA_enum_set(op->ptr, "constraint_orientation", V3D_MANIP_NORMAL);
869                         RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
870                 }
871                 WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
872         }
873         return OPERATOR_FINISHED;
874 }
875
876 void MESH_OT_extrude_faces_indiv(wmOperatorType *ot)
877 {
878         /* identifiers */
879         ot->name= "Extrude Individual Faces";
880         ot->idname= "MESH_OT_extrude_faces_indiv";
881         
882         /* api callbacks */
883         ot->invoke= mesh_extrude_faces_invoke;
884         ot->exec= mesh_extrude_faces_exec;
885         ot->poll= ED_operator_editmesh;
886         
887         /* flags */
888         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
889
890         /* to give to transform */
891         Properties_Proportional(ot);
892         Properties_Constraints(ot);
893         RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
894 }
895
896 int extrude_menu_invoke(bContext *C, wmOperator *op, wmEvent *event)
897 {
898         Object *obedit= CTX_data_edit_object(C);
899         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
900         uiPopupMenu *pup;
901         uiLayout *layout;
902
903         if(em->selectmode & SCE_SELECT_VERTEX) {
904                 if(em->bm->totvertsel==0) {
905                         return OPERATOR_CANCELLED;
906                 } else if(em->bm->totvertsel==1) {
907                         WM_operator_name_call(C, "MESH_OT_extrude_verts_indiv", WM_OP_INVOKE_REGION_WIN, op->ptr);
908                 } else if(em->bm->totedgesel==0) {
909                         WM_operator_name_call(C, "MESH_OT_extrude_verts_indiv", WM_OP_INVOKE_REGION_WIN, op->ptr);
910                 } else if(em->bm->totfacesel==0) {
911                         // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
912                         pup= uiPupMenuBegin(C, "Extrude", 0);
913                         layout= uiPupMenuLayout(pup);
914                         uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
915                         
916                         uiItemO(layout, "Only Edges", 0, "MESH_OT_extrude_edges_indiv");
917                         uiItemO(layout, "Only Verts", 0, "MESH_OT_extrude_verts_indiv");
918                         
919                         uiPupMenuEnd(C, pup);
920                 } else if(em->bm->totfacesel==1) {
921                         // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
922                         pup= uiPupMenuBegin(C, "Extrude", 0);
923                         layout= uiPupMenuLayout(pup);
924                         uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
925                         
926                         uiItemO(layout, "Region", 0, "MESH_OT_extrude_region");
927                         uiItemO(layout, "Only Edges", 0, "MESH_OT_extrude_edges_indiv");
928                         uiItemO(layout, "Only Verts", 0, "MESH_OT_extrude_verts_indiv");
929                         
930                         uiPupMenuEnd(C, pup);
931                 } else  {
932                         // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
933                         pup= uiPupMenuBegin(C, "Extrude", 0);
934                         layout= uiPupMenuLayout(pup);
935                         uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
936                         
937                         uiItemO(layout, "Region", 0, "MESH_OT_extrude_region");
938                         uiItemO(layout, "Individual Faces", 0, "MESH_OT_extrude_faces_indiv");
939                         uiItemO(layout, "Only Edges", 0, "MESH_OT_extrude_edges_indiv");
940                         uiItemO(layout, "Only Verts", 0, "MESH_OT_extrude_verts_indiv");
941                         
942                         uiPupMenuEnd(C, pup);
943                 }
944         } else if (em->selectmode & SCE_SELECT_EDGE) {
945                 if (em->bm->totedge==0)
946                         return OPERATOR_CANCELLED;
947                 else if (em->bm->totedgesel==1)
948                         WM_operator_name_call(C, "MESH_OT_extrude_edges_indiv", WM_OP_INVOKE_REGION_WIN, op->ptr);
949                 else if (em->bm->totfacesel==0) {
950                         WM_operator_name_call(C, "MESH_OT_extrude_edges_indiv", WM_OP_INVOKE_REGION_WIN, op->ptr);
951                 } else if (em->bm->totfacesel==1) {
952                         // pupmenu("Extrude %t|Region %x1|Only Edges%x3");
953                         pup= uiPupMenuBegin(C, "Extrude", 0);
954                         layout= uiPupMenuLayout(pup);
955                         uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
956                         
957                         uiItemO(layout, "Region", 0, "MESH_OT_extrude_region");
958                         uiItemO(layout, "Only Edges", 0, "MESH_OT_extrude_edges_indiv");
959                         
960                         uiPupMenuEnd(C, pup);
961                 } else {
962                         // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
963                         pup= uiPupMenuBegin(C, "Extrude", 0);
964                         layout= uiPupMenuLayout(pup);
965                         uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
966                         
967                         uiItemO(layout, "Region", 0, "MESH_OT_extrude_region");
968                         uiItemO(layout, "Individual Faces", 0, "MESH_OT_extrude_faces_indiv");
969                         uiItemO(layout, "Only Edges", 0, "MESH_OT_extrude_edges_indiv");
970                         
971                         uiPupMenuEnd(C, pup);
972                 }
973
974         } else if (em->selectmode & SCE_SELECT_FACE) {
975                 if (em->bm->totfacesel==0)
976                         return OPERATOR_CANCELLED;
977                 else if (em->bm->totfacesel==1)
978                         WM_operator_name_call(C, "MESH_OT_extrude_region", WM_OP_INVOKE_REGION_WIN, op->ptr);
979                 else {
980                         // pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
981                         pup= uiPupMenuBegin(C, "Extrude", 0);
982                         layout= uiPupMenuLayout(pup);
983                         uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
984                         
985                         uiItemO(layout, "Region", 0, "MESH_OT_extrude_region");
986                         uiItemO(layout, "Individual Faces", 0, "MESH_OT_extrude_faces_indiv");
987                         
988                         uiPupMenuEnd(C, pup);
989                 }
990         }
991
992         return OPERATOR_CANCELLED;
993 }
994
995 void MESH_OT_extrude(wmOperatorType *ot)
996 {
997         /* identifiers */
998         ot->name= "Extrude";
999         ot->description= "Extrude selected vertices, edges or faces.";
1000         ot->idname= "MESH_OT_extrude";
1001         
1002         /* api callbacks */
1003         ot->invoke= extrude_menu_invoke;
1004         ot->poll= ED_operator_editmesh;
1005 }
1006
1007 /* ******************** (de)select all operator **************** */
1008
1009 void EDBM_toggle_select_all(BMEditMesh *em) /* exported for UV */
1010 {
1011         if(em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
1012                 EDBM_clear_flag_all(em, SELECT);
1013         else 
1014                 EDBM_set_flag_all(em, SELECT);
1015 }
1016
1017 static int toggle_select_all_exec(bContext *C, wmOperator *op)
1018 {
1019         Object *obedit= CTX_data_edit_object(C);
1020         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1021         
1022         EDBM_toggle_select_all(em);
1023         
1024         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1025
1026         return OPERATOR_FINISHED;
1027 }
1028
1029 void MESH_OT_select_all_toggle(wmOperatorType *ot)
1030 {
1031         /* identifiers */
1032         ot->name= "Select/Deselect All";
1033         ot->idname= "MESH_OT_select_all_toggle";
1034         ot->description= "(de)select all vertices, edges or faces.";
1035         
1036         /* api callbacks */
1037         ot->exec= toggle_select_all_exec;
1038         ot->poll= ED_operator_editmesh;
1039         
1040         /* flags */
1041         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1042 }
1043
1044 /* *************** add-click-mesh (extrude) operator ************** */
1045
1046 static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
1047 {
1048         ViewContext vc;
1049         BMVert *v1;
1050         BMIter iter;
1051         float min[3], max[3];
1052         int done= 0;
1053         
1054         em_setup_viewcontext(C, &vc);
1055         
1056         INIT_MINMAX(min, max);
1057         
1058         BM_ITER_SELECT(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH, NULL)
1059                 DO_MINMAX(v1->co, min, max);
1060                 done= 1;
1061         }
1062
1063         /* call extrude? */
1064         if(done) {
1065                 BMEdge *eed;
1066                 float vec[3], cent[3], mat[3][3];
1067                 float nor[3]= {0.0, 0.0, 0.0};
1068                 
1069                 /* check for edges that are half selected, use for rotation */
1070                 done= 0;
1071                 BM_ITER(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH, NULL) {
1072                         if (BM_TestHFlag(eed->v1, BM_SELECT) ^ BM_TestHFlag(eed->v2, BM_SELECT)) {
1073                                 if(BM_TestHFlag(eed->v1, BM_SELECT)) 
1074                                         VecSubf(vec, eed->v1->co, eed->v2->co);
1075                                 else 
1076                                         VecSubf(vec, eed->v2->co, eed->v1->co);
1077                                 VecAddf(nor, nor, vec);
1078                                 done= 1;
1079                         }
1080                 }
1081                 if(done) Normalize(nor);
1082                 
1083                 /* center */
1084                 VecAddf(cent, min, max);
1085                 VecMulf(cent, 0.5f);
1086                 VECCOPY(min, cent);
1087                 
1088                 Mat4MulVecfl(vc.obedit->obmat, min);    // view space
1089                 view3d_get_view_aligned_coordinate(&vc, min, event->mval);
1090                 Mat4Invert(vc.obedit->imat, vc.obedit->obmat); 
1091                 Mat4MulVecfl(vc.obedit->imat, min); // back in object space
1092                 
1093                 VecSubf(min, min, cent);
1094                 
1095                 /* calculate rotation */
1096                 Mat3One(mat);
1097                 if(done) {
1098                         float dot;
1099                         
1100                         VECCOPY(vec, min);
1101                         Normalize(vec);
1102                         dot= INPR(vec, nor);
1103
1104                         if( fabs(dot)<0.999) {
1105                                 float cross[3], si, q1[4];
1106                                 
1107                                 Crossf(cross, nor, vec);
1108                                 Normalize(cross);
1109                                 dot= 0.5f*saacos(dot);
1110                                 si= (float)sin(dot);
1111                                 q1[0]= (float)cos(dot);
1112                                 q1[1]= cross[0]*si;
1113                                 q1[2]= cross[1]*si;
1114                                 q1[3]= cross[2]*si;
1115                                 
1116                                 QuatToMat3(q1, mat);
1117                         }
1118                 }
1119                 
1120
1121                 EDBM_Extrude_edge(vc.obedit, vc.em, SELECT, nor);
1122                 EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
1123                         BM_SELECT, cent, mat);
1124                 EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v",
1125                         BM_SELECT, min);
1126         }
1127         else {
1128                 float *curs= give_cursor(vc.scene, vc.v3d);
1129                 BMOperator bmop;
1130                 BMOIter oiter;
1131                 
1132                 VECCOPY(min, curs);
1133
1134                 view3d_get_view_aligned_coordinate(&vc, min, event->mval);
1135                 Mat4Invert(vc.obedit->imat, vc.obedit->obmat); 
1136                 Mat4MulVecfl(vc.obedit->imat, min); // back in object space
1137                 
1138                 EDBM_InitOpf(vc.em, &bmop, op, "makevert co=%v", min);
1139                 BMO_Exec_Op(vc.em->bm, &bmop);
1140
1141                 BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) {
1142                         BM_Select(vc.em->bm, v1, 1);
1143                 }
1144
1145                 if (!EDBM_FinishOp(vc.em, &bmop, op, 1))
1146                         return OPERATOR_CANCELLED;
1147         }
1148
1149         //retopo_do_all();
1150         WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data); 
1151         DAG_id_flush_update(vc.obedit->data, OB_RECALC_DATA);
1152         
1153         return OPERATOR_FINISHED;
1154 }
1155
1156 void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
1157 {
1158         /* identifiers */
1159         ot->name= "Duplicate or Extrude at 3D Cursor";
1160         ot->idname= "MESH_OT_dupli_extrude_cursor";
1161         
1162         /* api callbacks */
1163         ot->invoke= dupli_extrude_cursor;
1164         ot->description= "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor.";
1165         ot->poll= ED_operator_editmesh;
1166         
1167         /* flags */
1168         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1169 }
1170
1171 static int delete_mesh(bContext *C, Object *obedit, wmOperator *op, int event, Scene *scene)
1172 {
1173         BMEditMesh *bem = ((Mesh*)obedit->data)->edit_btmesh;
1174         
1175         if(event<1) return OPERATOR_CANCELLED;
1176
1177         if(event==10 ) {
1178                 //"Erase Vertices";
1179
1180                 if (!EDBM_CallOpf(bem, op, "del geom=%hv context=%i", BM_SELECT, DEL_VERTS))
1181                         return OPERATOR_CANCELLED;
1182         } 
1183         else if(event==11) {
1184                 //"Edge Loop"
1185                 if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_SELECT))
1186                         return OPERATOR_CANCELLED;
1187         }
1188         else if(event==7) {
1189                 //"Dissolve"
1190                 if (bem->selectmode & SCE_SELECT_FACE) {
1191                         if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf",BM_SELECT))
1192                                 return OPERATOR_CANCELLED;
1193                 } else if (bem->selectmode & SCE_SELECT_EDGE) {
1194                         if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he",BM_SELECT))
1195                                 return OPERATOR_CANCELLED;
1196                 } else if (bem->selectmode & SCE_SELECT_VERTEX) {
1197                         if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv",BM_SELECT))
1198                                 return OPERATOR_CANCELLED;
1199                 }
1200         }
1201         else if(event==4) {
1202                 //Edges and Faces
1203                 if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_SELECT, DEL_EDGESFACES))
1204                         return OPERATOR_CANCELLED;
1205         } 
1206         else if(event==1) {
1207                 //"Erase Edges"
1208                 if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_SELECT, DEL_EDGES))
1209                         return OPERATOR_CANCELLED;
1210         }
1211         else if(event==2) {
1212                 //"Erase Faces";
1213                 if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_SELECT, DEL_FACES))
1214                         return OPERATOR_CANCELLED;
1215         }
1216         else if(event==5) {
1217                 //"Erase Only Faces";
1218                 if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d",
1219                                   BM_SELECT, DEL_ONLYFACES))
1220                         return OPERATOR_CANCELLED;
1221         }
1222         
1223         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1224         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1225
1226         return OPERATOR_FINISHED;
1227 }
1228
1229 /* Note, these values must match delete_mesh() event values */
1230 static EnumPropertyItem prop_mesh_delete_types[] = {
1231         {7, "DISSOLVE",         0, "Dissolve", ""},
1232         {10,"VERT",             0, "Vertices", ""},
1233         {1, "EDGE",             0, "Edges", ""},
1234         {2, "FACE",             0, "Faces", ""},
1235         {11, "EDGE_LOOP", 0, "Edge Loop", ""},
1236         {4, "EDGE_FACE", 0, "Edges & Faces", ""},
1237         {5, "ONLY_FACE", 0, "Only Faces", ""},
1238         {0, NULL, 0, NULL, NULL}
1239 };
1240
1241 static int delete_mesh_exec(bContext *C, wmOperator *op)
1242 {
1243         Object *obedit= CTX_data_edit_object(C);
1244         Scene *scene = CTX_data_scene(C);
1245
1246         delete_mesh(C, obedit, op, RNA_enum_get(op->ptr, "type"), scene);
1247         
1248         WM_event_add_notifier(C, NC_GEOM|ND_DATA|ND_SELECT, obedit);
1249         
1250         return OPERATOR_FINISHED;
1251 }
1252
1253 void MESH_OT_delete(wmOperatorType *ot)
1254 {
1255         /* identifiers */
1256         ot->name= "Delete";
1257         ot->description= "Delete selected vertices, edges or faces.";
1258         ot->idname= "MESH_OT_delete";
1259         
1260         /* api callbacks */
1261         ot->invoke= WM_menu_invoke;
1262         ot->exec= delete_mesh_exec;
1263         
1264         ot->poll= ED_operator_editmesh;
1265         
1266         /* flags */
1267         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1268         
1269         /*props */
1270         RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
1271 }
1272
1273
1274 static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
1275 {
1276         BMOperator bmop;
1277         Object *obedit= CTX_data_edit_object(C);
1278         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1279         
1280         if (!EDBM_InitOpf(em, &bmop, op, "contextual_create geom=%hfev", BM_SELECT))
1281                 return OPERATOR_CANCELLED;
1282         
1283         BMO_Exec_Op(em->bm, &bmop);
1284         BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT, BM_FACE);
1285
1286         if (!EDBM_FinishOp(em, &bmop, op, 1))
1287                 return OPERATOR_CANCELLED;
1288
1289         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1290         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1291         
1292         return OPERATOR_FINISHED;
1293 }
1294
1295 void MESH_OT_edge_face_add(wmOperatorType *ot)
1296 {
1297         /* identifiers */
1298         ot->name= "Make Edge/Face";
1299         ot->description= "Add an edge or face to selected.";
1300         ot->idname= "MESH_OT_edge_face_add";
1301         
1302         /* api callbacks */
1303         ot->exec= addedgeface_mesh_exec;
1304         ot->poll= ED_operator_editmesh;
1305         
1306         /* flags */
1307         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1308         
1309 }
1310
1311 static EnumPropertyItem prop_mesh_edit_types[] = {
1312         {1, "VERT", 0, "Vertices", ""},
1313         {2, "EDGE", 0, "Edges", ""},
1314         {3, "FACE", 0, "Faces", ""},
1315         {0, NULL, 0, NULL, NULL}
1316 };
1317
1318 static int mesh_selection_type_exec(bContext *C, wmOperator *op)
1319 {               
1320         
1321         Object *obedit= CTX_data_edit_object(C);
1322         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1323         int type = RNA_enum_get(op->ptr,"type");
1324
1325         switch (type) {
1326                 case 1:
1327                         em->selectmode = SCE_SELECT_VERTEX;
1328                         break;
1329                 case 2:
1330                         em->selectmode = SCE_SELECT_EDGE;
1331                         break;
1332                 case 3:
1333                         em->selectmode = SCE_SELECT_FACE;
1334                         break;
1335         }
1336
1337         EDBM_selectmode_set(em);
1338         CTX_data_tool_settings(C)->selectmode = em->selectmode;
1339
1340         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
1341         
1342         return OPERATOR_FINISHED;
1343 }
1344
1345 void MESH_OT_selection_type(wmOperatorType *ot)
1346 {
1347         /* identifiers */
1348         ot->name= "Selection Mode";
1349         ot->description= "Set the selection mode type.";
1350         ot->idname= "MESH_OT_selection_type";
1351         
1352         /* api callbacks */
1353         ot->invoke= WM_menu_invoke;
1354         ot->exec= mesh_selection_type_exec;
1355         
1356         ot->poll= ED_operator_editmesh;
1357         
1358         /* flags */
1359         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1360         
1361         /* props */
1362         RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type");
1363         RNA_def_boolean(ot->srna, "inclusive", 0, "Inclusive", "Selects geometry around selected geometry, occording to selection mode");       
1364 }
1365
1366 /* ************************* SEAMS AND EDGES **************** */
1367
1368 static int editbmesh_mark_seam(bContext *C, wmOperator *op)
1369 {
1370         Scene *scene = CTX_data_scene(C);
1371         Object *obedit= CTX_data_edit_object(C);
1372         Mesh *me= ((Mesh *)obedit->data);
1373         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1374         BMesh *bm = em->bm;
1375         BMEdge *eed;
1376         BMIter iter;
1377         int clear = RNA_boolean_get(op->ptr, "clear");
1378         
1379         /* auto-enable seams drawing */
1380         if(clear==0) {
1381                 me->drawflag |= ME_DRAWSEAMS;
1382         }
1383
1384         if(clear) {
1385                 BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
1386                         BM_ClearHFlag(eed, BM_SEAM);
1387                 }
1388         }
1389         else {
1390                 BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
1391                         BM_SetHFlag(eed, BM_SEAM);
1392                 }
1393         }
1394
1395         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1396         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1397
1398         return OPERATOR_FINISHED;
1399 }
1400
1401 void MESH_OT_mark_seam(wmOperatorType *ot)
1402 {
1403         /* identifiers */
1404         ot->name= "Mark Seam";
1405         ot->idname= "MESH_OT_mark_seam";
1406         ot->description= "(un)mark selected edges as a seam.";
1407         
1408         /* api callbacks */
1409         ot->exec= editbmesh_mark_seam;
1410         ot->poll= ED_operator_editmesh;
1411         
1412         /* flags */
1413         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1414         
1415         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1416 }
1417
1418 static int editbmesh_mark_sharp(bContext *C, wmOperator *op)
1419 {
1420         Scene *scene = CTX_data_scene(C);
1421         Object *obedit= CTX_data_edit_object(C);
1422         Mesh *me= ((Mesh *)obedit->data);
1423         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1424         BMesh *bm = em->bm;
1425         BMEdge *eed;
1426         BMIter iter;
1427         int clear = RNA_boolean_get(op->ptr, "clear");
1428
1429         /* auto-enable sharp edge drawing */
1430         if(clear == 0) {
1431                 me->drawflag |= ME_DRAWSHARP;
1432         }
1433
1434         if(!clear) {
1435                 BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
1436                         BM_SetHFlag(eed, BM_SHARP);
1437                 }
1438         } else {
1439                 BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
1440                         BM_ClearHFlag(eed, BM_SHARP);
1441                 }
1442         }
1443
1444
1445         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1446         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1447
1448         return OPERATOR_FINISHED;
1449 }
1450
1451 void MESH_OT_mark_sharp(wmOperatorType *ot)
1452 {
1453         /* identifiers */
1454         ot->name= "Mark Sharp";
1455         ot->idname= "MESH_OT_mark_sharp";
1456         ot->description= "(un)mark selected edges as sharp.";
1457         
1458         /* api callbacks */
1459         ot->exec= editbmesh_mark_sharp;
1460         ot->poll= ED_operator_editmesh;
1461         
1462         /* flags */
1463         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1464         
1465         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1466 }
1467
1468
1469 static int editbmesh_vert_connect(bContext *C, wmOperator *op)
1470 {
1471         Scene *scene = CTX_data_scene(C);
1472         Object *obedit= CTX_data_edit_object(C);
1473         Mesh *me= ((Mesh *)obedit->data);
1474         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1475         BMesh *bm = em->bm;
1476         BMOperator bmop;
1477         int len = 0;
1478         
1479         BMO_InitOpf(bm, &bmop, "connectverts verts=%hv", BM_SELECT);
1480         BMO_Exec_Op(bm, &bmop);
1481         len = BMO_GetSlot(&bmop, "edgeout")->len;
1482         BMO_Finish_Op(bm, &bmop);
1483         
1484         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1485         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1486
1487         return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1488 }
1489
1490 void MESH_OT_vert_connect(wmOperatorType *ot)
1491 {
1492         /* identifiers */
1493         ot->name= "Vertex Connect";
1494         ot->idname= "MESH_OT_vert_connect";
1495         
1496         /* api callbacks */
1497         ot->exec= editbmesh_vert_connect;
1498         ot->poll= ED_operator_editmesh;
1499         
1500         /* flags */
1501         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1502 }
1503
1504 static int editbmesh_edge_split(bContext *C, wmOperator *op)
1505 {
1506         Scene *scene = CTX_data_scene(C);
1507         Object *obedit= CTX_data_edit_object(C);
1508         Mesh *me= ((Mesh *)obedit->data);
1509         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1510         BMesh *bm = em->bm;
1511         BMOperator bmop;
1512         int len = 0;
1513         
1514         BMO_InitOpf(bm, &bmop, "edgesplit edges=%he numcuts=%d", BM_SELECT, RNA_int_get(op->ptr,"number_cuts"));
1515         BMO_Exec_Op(bm, &bmop);
1516         len = BMO_GetSlot(&bmop, "outsplit")->len;
1517         BMO_Finish_Op(bm, &bmop);
1518         
1519         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1520         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1521
1522         return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1523 }
1524
1525 void MESH_OT_edge_split(wmOperatorType *ot)
1526 {
1527         /* identifiers */
1528         ot->name= "Edge Split";
1529         ot->idname= "MESH_OT_edge_split";
1530         
1531         /* api callbacks */
1532         ot->exec= editbmesh_edge_split;
1533         ot->poll= ED_operator_editmesh;
1534         
1535         /* flags */
1536         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1537
1538         RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX);
1539 }
1540
1541 /****************** add duplicate operator ***************/
1542
1543 static int mesh_duplicate_exec(bContext *C, wmOperator *op)
1544 {
1545         Scene *scene= CTX_data_scene(C);
1546         Object *ob= CTX_data_edit_object(C);
1547         BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh;
1548         BMOperator bmop;
1549
1550         EDBM_InitOpf(em, &bmop, op, "dupe geom=%hvef", BM_SELECT);
1551         
1552         BMO_Exec_Op(em->bm, &bmop);
1553         EDBM_clear_flag_all(em, BM_SELECT);
1554
1555         BMO_HeaderFlag_Buffer(em->bm, &bmop, "newout", BM_SELECT, BM_ALL);
1556
1557         if (!EDBM_FinishOp(em, &bmop, op, 1))
1558                 return OPERATOR_CANCELLED;
1559
1560         DAG_id_flush_update(ob->data, OB_RECALC_DATA);
1561         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
1562         
1563         return OPERATOR_FINISHED;
1564 }
1565
1566 static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
1567 {
1568         WM_cursor_wait(1);
1569         mesh_duplicate_exec(C, op);
1570         WM_cursor_wait(0);
1571         
1572         return OPERATOR_FINISHED;
1573 }
1574
1575 void MESH_OT_duplicate(wmOperatorType *ot)
1576 {
1577         /* identifiers */
1578         ot->name= "Duplicate";
1579         ot->description= "Duplicate selected vertices, edges or faces.";
1580         ot->idname= "MESH_OT_duplicate";
1581         
1582         /* api callbacks */
1583         ot->invoke= mesh_duplicate_invoke;
1584         ot->exec= mesh_duplicate_exec;
1585         
1586         ot->poll= ED_operator_editmesh;
1587         
1588         /* to give to transform */
1589         RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
1590 }
1591
1592 static int flip_normals(bContext *C, wmOperator *op)
1593 {
1594         Scene *scene = CTX_data_scene(C);
1595         Object *obedit= CTX_data_edit_object(C);
1596         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1597         
1598         if (!EDBM_CallOpf(em, op, "reversefaces facaes=%hf", BM_SELECT))
1599                 return OPERATOR_CANCELLED;
1600         
1601         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1602         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1603
1604         return OPERATOR_FINISHED;
1605 }
1606
1607 void MESH_OT_flip_normals(wmOperatorType *ot)
1608 {
1609         /* identifiers */
1610         ot->name= "Flip Normals";
1611         ot->description= "Flip the direction of selected face's vertex and face normals";
1612         ot->idname= "MESH_OT_flip_normals";
1613         
1614         /* api callbacks */
1615         ot->exec= flip_normals;
1616         ot->poll= ED_operator_editmesh;
1617         
1618         /* flags */
1619         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1620 }
1621
1622 //#define DIRECTION_CW  1
1623 //#define DIRECTION_CCW 2
1624
1625 static const EnumPropertyItem direction_items[]= {
1626         {DIRECTION_CW, "CW", 0, "Clockwise", ""},
1627         {DIRECTION_CCW, "CCW", 0, "Counter Clockwise", ""},
1628         {0, NULL, 0, NULL, NULL}};
1629
1630 /* only accepts 1 selected edge, or 2 selected faces */
1631 static int edge_rotate_selected(bContext *C, wmOperator *op)
1632 {
1633         Scene *scene= CTX_data_scene(C);
1634         Object *obedit= CTX_data_edit_object(C);
1635         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1636         BMOperator bmop;
1637         BMEdge *eed;
1638         BMIter iter;
1639         int ccw = RNA_int_get(op->ptr, "direction") == 1; // direction == 2 when clockwise and ==1 for counter CW.
1640         short edgeCount = 0;
1641         
1642         if (!(em->bm->totfacesel == 2 || em->bm->totedgesel == 1)) {
1643                 BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
1644                 return OPERATOR_CANCELLED;
1645         }
1646
1647         /*first see if we have two adjacent faces*/
1648         BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1649                 if (BM_Edge_FaceCount(eed) == 2) {
1650                         if ((BM_TestHFlag(eed->loop->f, BM_SELECT) && BM_TestHFlag(((BMLoop*)eed->loop->radial.next->data)->f, BM_SELECT))
1651                              && !(BM_TestHFlag(eed->loop->f, BM_HIDDEN) || BM_TestHFlag(((BMLoop*)eed->loop->radial.next->data)->f, BM_HIDDEN)))
1652                         {
1653                                 break;
1654                         }
1655                 }
1656         }
1657         
1658         /*ok, we don't have two adjacent faces, but we do have two selected ones.
1659           that's an error condition.*/
1660         if (!eed && em->bm->totfacesel == 2) {
1661                 BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
1662                 return OPERATOR_CANCELLED;
1663         }
1664
1665         if (!eed) {
1666                 BM_ITER_SELECT(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL)
1667                         if (BM_TestHFlag(eed, BM_SELECT))
1668                                 break;
1669                 }
1670         }
1671
1672         /*this should never happen*/
1673         if (!eed)
1674                 return OPERATOR_CANCELLED;
1675         
1676         EDBM_InitOpf(em, &bmop, op, "edgerotate edges=%e ccw=%d", eed, ccw);
1677         BMO_Exec_Op(em->bm, &bmop);
1678
1679         BMO_HeaderFlag_Buffer(em->bm, &bmop, "edgeout", BM_SELECT, BM_EDGE);
1680
1681         if (!EDBM_FinishOp(em, &bmop, op, 1))
1682                 return OPERATOR_CANCELLED;
1683
1684         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1685         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1686
1687         return OPERATOR_FINISHED;
1688 }
1689
1690 void MESH_OT_edge_rotate(wmOperatorType *ot)
1691 {
1692         /* identifiers */
1693         ot->name= "Rotate Selected Edge";
1694         ot->description= "Rotate selected edge or adjoining faces.";
1695         ot->idname= "MESH_OT_edge_rotate";
1696
1697         /* api callbacks */
1698         ot->exec= edge_rotate_selected;
1699         ot->poll= ED_operator_editmesh;
1700
1701         /* flags */
1702         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1703
1704         /* props */
1705         RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "direction", "direction to rotate edge around.");
1706 }
1707
1708 /* pinning code */
1709
1710 /* swap is 0 or 1, if 1 it pins not selected */
1711 void EDBM_pin_mesh(BMEditMesh *em, int swap)
1712 {
1713         BMIter iter;
1714         BMHeader *h;
1715         int itermode;
1716
1717         if(em==NULL) return;
1718         
1719         if (em->selectmode & SCE_SELECT_VERTEX)
1720                 itermode = BM_VERTS_OF_MESH;
1721         else if (em->selectmode & SCE_SELECT_EDGE)
1722                 itermode = BM_EDGES_OF_MESH;
1723         else
1724                 itermode = BM_FACES_OF_MESH;
1725
1726         BM_ITER(h, &iter, em->bm, itermode, NULL) {
1727                 if (BM_TestHFlag(h, BM_SELECT) ^ swap)
1728                         BM_Pin(em->bm, h, 1);
1729         }
1730
1731         EDBM_selectmode_flush(em);
1732 }
1733
1734 static int pin_mesh_exec(bContext *C, wmOperator *op)
1735 {
1736         Object *obedit= CTX_data_edit_object(C);
1737         Scene *scene = CTX_data_scene(C);
1738         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1739         Mesh *me= ((Mesh *)obedit->data);
1740
1741         me->drawflag |= ME_DRAW_PINS;
1742         
1743         EDBM_pin_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
1744                 
1745         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1746         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1747
1748         return OPERATOR_FINISHED;       
1749 }
1750
1751 void MESH_OT_pin(wmOperatorType *ot)
1752 {
1753         /* identifiers */
1754         ot->name= "Pin Selection";
1755         ot->idname= "MESH_OT_pin";
1756         
1757         /* api callbacks */
1758         ot->exec= pin_mesh_exec;
1759         ot->poll= ED_operator_editmesh;
1760         ot->description= "Pin (un)selected vertices, edges or faces.";
1761
1762         /* flags */
1763         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1764         
1765         /* props */
1766         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Pin unselected rather than selected.");
1767 }
1768
1769 /* swap is 0 or 1, if 1 it unhides not selected */
1770 void EDBM_unpin_mesh(BMEditMesh *em, int swap)
1771 {
1772         BMIter iter;
1773         BMHeader *ele;
1774         int i, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1775         int sels[3] = {1, !(em->selectmode & SCE_SELECT_VERTEX), !(em->selectmode & SCE_SELECT_VERTEX | SCE_SELECT_EDGE)};
1776         int itermode;
1777         
1778         if(em==NULL) return;
1779         
1780         if (em->selectmode & SCE_SELECT_VERTEX)
1781                 itermode = BM_VERTS_OF_MESH;
1782         else if (em->selectmode & SCE_SELECT_EDGE)
1783                 itermode = BM_EDGES_OF_MESH;
1784         else
1785                 itermode = BM_FACES_OF_MESH;
1786
1787         BM_ITER(ele, &iter, em->bm, itermode, NULL) {
1788                 if (BM_TestHFlag(ele, BM_SELECT) ^ swap)
1789                         BM_Pin(em->bm, ele, 0);
1790         }
1791
1792         EDBM_selectmode_flush(em);
1793 }
1794
1795 static int unpin_mesh_exec(bContext *C, wmOperator *op)
1796 {
1797         Object *obedit= CTX_data_edit_object(C);
1798         Scene *scene = CTX_data_scene(C);
1799         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1800         Mesh *me= ((Mesh *)obedit->data);
1801         
1802         EDBM_unpin_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
1803
1804         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1805         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1806
1807         return OPERATOR_FINISHED;       
1808 }
1809
1810 void MESH_OT_unpin(wmOperatorType *ot)
1811 {
1812         /* identifiers */
1813         ot->name= "Unpin Selection";
1814         ot->idname= "MESH_OT_unpin";
1815         ot->description= "Unpin (un)selected vertices, edges or faces.";
1816         
1817         /* api callbacks */
1818         ot->exec= unpin_mesh_exec;
1819         ot->poll= ED_operator_editmesh;
1820         
1821         /* flags */
1822         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1823
1824         /* props */
1825         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Unpin unselected rather than selected.");
1826 }
1827
1828
1829 /* swap is 0 or 1, if 1 it hides not selected */
1830 void EDBM_hide_mesh(BMEditMesh *em, int swap)
1831 {
1832         BMIter iter;
1833         BMHeader *h;
1834         int itermode;
1835
1836         if(em==NULL) return;
1837         
1838         if (em->selectmode & SCE_SELECT_VERTEX)
1839                 itermode = BM_VERTS_OF_MESH;
1840         else if (em->selectmode & SCE_SELECT_EDGE)
1841                 itermode = BM_EDGES_OF_MESH;
1842         else
1843                 itermode = BM_FACES_OF_MESH;
1844
1845         BM_ITER(h, &iter, em->bm, itermode, NULL) {
1846                 if (BM_TestHFlag(h, BM_SELECT) ^ swap)
1847                         BM_Hide(em->bm, h, 1);
1848         }
1849
1850         /*original hide flushing comment (OUTDATED): 
1851           hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
1852         /*  - vertex hidden, always means edge is hidden too
1853                 - edge hidden, always means face is hidden too
1854                 - face hidden, only set face hide
1855                 - then only flush back down what's absolute hidden
1856         */
1857
1858 }
1859
1860 static int hide_mesh_exec(bContext *C, wmOperator *op)
1861 {
1862         Object *obedit= CTX_data_edit_object(C);
1863         Scene *scene = CTX_data_scene(C);
1864         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1865         
1866         EDBM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
1867                 
1868         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1869         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1870
1871         return OPERATOR_FINISHED;       
1872 }
1873
1874 void MESH_OT_hide(wmOperatorType *ot)
1875 {
1876         /* identifiers */
1877         ot->name= "Hide Selection";
1878         ot->idname= "MESH_OT_hide";
1879         
1880         /* api callbacks */
1881         ot->exec= hide_mesh_exec;
1882         ot->poll= ED_operator_editmesh;
1883          ot->description= "Hide (un)selected vertices, edges or faces.";
1884
1885         /* flags */
1886         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1887         
1888         /* props */
1889         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
1890 }
1891
1892
1893 void EDBM_reveal_mesh(BMEditMesh *em)
1894 {
1895         BMIter iter;
1896         BMHeader *ele;
1897         int i, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1898         int sels[3] = {1, !(em->selectmode & SCE_SELECT_VERTEX), !(em->selectmode & SCE_SELECT_VERTEX | SCE_SELECT_EDGE)};
1899
1900         for (i=0; i<3; i++) {
1901                 BM_ITER(ele, &iter, em->bm, types[i], NULL) {
1902                         if (BM_TestHFlag(ele, BM_HIDDEN)) {
1903                                 BM_Hide(em->bm, ele, 0);
1904
1905                                 if (sels[i])
1906                                         BM_Select(em->bm, ele, 1);
1907                         }
1908                 }
1909         }
1910
1911         EDBM_selectmode_flush(em);
1912 }
1913
1914 static int reveal_mesh_exec(bContext *C, wmOperator *op)
1915 {
1916         Object *obedit= CTX_data_edit_object(C);
1917         Scene *scene = CTX_data_scene(C);
1918         BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
1919         
1920         EDBM_reveal_mesh(em);
1921
1922         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1923         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1924
1925         return OPERATOR_FINISHED;       
1926 }
1927
1928 void MESH_OT_reveal(wmOperatorType *ot)
1929 {
1930         /* identifiers */
1931         ot->name= "Reveal Hidden";
1932         ot->idname= "MESH_OT_reveal";
1933         ot->description= "Reveal all hidden vertices, edges and faces.";
1934         
1935         /* api callbacks */
1936         ot->exec= reveal_mesh_exec;
1937         ot->poll= ED_operator_editmesh;
1938         
1939         /* flags */
1940         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1941 }
1942
1943 static int normals_make_consistent_exec(bContext *C, wmOperator *op)
1944 {
1945         Scene *scene = CTX_data_scene(C);
1946         Object *obedit= CTX_data_edit_object(C);
1947         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1948         
1949         if (!EDBM_CallOpf(em, op, "righthandfaces faces=%hf", BM_SELECT))
1950                 return OPERATOR_CANCELLED;
1951         
1952         if (RNA_boolean_get(op->ptr, "inside"))
1953                 EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT);
1954
1955         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1956         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1957
1958         return OPERATOR_FINISHED;       
1959 }
1960
1961 void MESH_OT_normals_make_consistent(wmOperatorType *ot)
1962 {
1963         /* identifiers */
1964         ot->name= "Make Normals Consistent";
1965         ot->description= "Make face and vertex normals point either outside or inside the mesh";
1966         ot->idname= "MESH_OT_normals_make_consistent";
1967         
1968         /* api callbacks */
1969         ot->exec= normals_make_consistent_exec;
1970         ot->poll= ED_operator_editmesh;
1971         
1972         /* flags */
1973         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1974         
1975         RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
1976 }
1977
1978
1979
1980 static int do_smooth_vertex(bContext *C, wmOperator *op)
1981 {
1982         Scene *scene = CTX_data_scene(C);
1983         Object *obedit= CTX_data_edit_object(C);
1984         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
1985         ModifierData *md;
1986         int mirrx=0, mirry=0, mirrz=0;
1987         int i, repeat;
1988
1989         /* if there is a mirror modifier with clipping, flag the verts that
1990          * are within tolerance of the plane(s) of reflection 
1991          */
1992         for(md=obedit->modifiers.first; md; md=md->next) {
1993                 if(md->type==eModifierType_Mirror) {
1994                         MirrorModifierData *mmd = (MirrorModifierData*) md;     
1995                 
1996                         if(mmd->flag & MOD_MIR_CLIPPING) {
1997                                 if (mmd->flag & MOD_MIR_AXIS_X)
1998                                         mirrx = 1;
1999                                 if (mmd->flag & MOD_MIR_AXIS_Y)
2000                                         mirry = 1;
2001                                 if (mmd->flag & MOD_MIR_AXIS_Z)
2002                                         mirrz = 1;
2003                         }
2004                 }
2005         }
2006
2007         repeat = RNA_int_get(op->ptr,"repeat");
2008         if (!repeat)
2009                 repeat = 1;
2010         
2011         for (i=0; i<repeat; i++) {
2012                 if (!EDBM_CallOpf(em, op, "vertexsmooth verts=%hv mirror_clip_x=%d mirror_clip_y=%d mirror_clip_z=%d",
2013                                   BM_SELECT, mirrx, mirry, mirrz))
2014                 {
2015                         return OPERATOR_CANCELLED;
2016                 }
2017         }
2018
2019         //BMESH_TODO: need to handle the x-axis editing option here properly.
2020         //should probably make a helper function for that? I dunno.
2021
2022         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2023         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2024
2025         return OPERATOR_FINISHED;
2026 }       
2027         
2028 void MESH_OT_vertices_smooth(wmOperatorType *ot)
2029 {
2030         /* identifiers */
2031         ot->name= "Smooth Vertex";
2032         ot->description= "Flatten angles of selected vertices.";
2033         ot->idname= "MESH_OT_vertices_smooth";
2034         
2035         /* api callbacks */
2036         ot->exec= do_smooth_vertex;
2037         ot->poll= ED_operator_editmesh;
2038         
2039         /* flags */
2040         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2041
2042         RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
2043 }
2044
2045
2046 static int bm_test_exec(bContext *C, wmOperator *op)
2047 {
2048         Scene *scene = CTX_data_scene(C);
2049         Object *obedit= CTX_data_edit_object(C);
2050         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2051 #if 1
2052         if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_SELECT))
2053                 return OPERATOR_CANCELLED;
2054
2055 #else //uv island walker test
2056         BMIter iter, liter;
2057         BMFace *f;
2058         BMLoop *l, *l2;
2059         MLoopUV *luv;
2060         BMWalker walker;
2061         int i=0;
2062
2063         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2064                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
2065                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2066                 }
2067         }
2068
2069         BMW_Init(&walker, em->bm, BMW_UVISLAND, 0);
2070
2071         BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2072                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
2073                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2074                         if (luv->flag & MLOOPUV_VERTSEL) {
2075                                 l2 = BMW_Begin(&walker, l);
2076                                 for (; l2; l2=BMW_Step(&walker)) {
2077                                         luv = CustomData_bmesh_get(&em->bm->ldata, l2->head.data, CD_MLOOPUV);
2078                                         luv->flag |= MLOOPUV_VERTSEL;
2079                                 }                               
2080                         }
2081                 }
2082         }
2083
2084         BMW_End(&walker);
2085 #endif
2086         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2087         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2088
2089         return OPERATOR_FINISHED;
2090 }       
2091         
2092 void MESH_OT_bm_test(wmOperatorType *ot)
2093 {
2094         /* identifiers */
2095         ot->name= "BMesh Test Operator";
2096         ot->idname= "MESH_OT_bm_test";
2097         
2098         /* api callbacks */
2099         ot->exec= bm_test_exec;
2100         ot->poll= ED_operator_editmesh;
2101         
2102         /* flags */
2103         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2104
2105         //RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
2106 }
2107
2108 /********************** Smooth/Solid Operators *************************/
2109
2110 void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
2111 {
2112         BMIter iter;
2113         BMFace *efa;
2114
2115         if(em==NULL) return;
2116         
2117         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2118                 if (BM_TestHFlag(efa, BM_SELECT)) {
2119                         if (smooth)
2120                                 BM_SetHFlag(efa, BM_SMOOTH);
2121                         else
2122                                 BM_ClearHFlag(efa, BM_SMOOTH);
2123                 }
2124         }
2125 }
2126
2127 static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *op)
2128 {
2129         Scene *scene= CTX_data_scene(C);
2130         Object *obedit= CTX_data_edit_object(C);
2131         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2132
2133         mesh_set_smooth_faces(em, 1);
2134
2135         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2136         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2137
2138         return OPERATOR_FINISHED;
2139 }
2140
2141 void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
2142 {
2143         /* identifiers */
2144         ot->name= "Shade Smooth";
2145          ot->description= "Display faces smooth (using vertex normals).";
2146         ot->idname= "MESH_OT_faces_shade_smooth";
2147
2148         /* api callbacks */
2149         ot->exec= mesh_faces_shade_smooth_exec;
2150         ot->poll= ED_operator_editmesh;
2151
2152         /* flags */
2153         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2154 }
2155
2156 static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *op)
2157 {
2158         Scene *scene = CTX_data_scene(C);
2159         Object *obedit= CTX_data_edit_object(C);
2160         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2161
2162         mesh_set_smooth_faces(em, 0);
2163
2164         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2165         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2166
2167         return OPERATOR_FINISHED;
2168 }
2169
2170 void MESH_OT_faces_shade_flat(wmOperatorType *ot)
2171 {
2172         /* identifiers */
2173         ot->name= "Shade Flat";
2174         ot->description= "Display faces flat.";
2175         ot->idname= "MESH_OT_faces_shade_flat";
2176
2177         /* api callbacks */
2178         ot->exec= mesh_faces_shade_flat_exec;
2179         ot->poll= ED_operator_editmesh;
2180
2181         /* flags */
2182         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2183 }
2184
2185
2186 /********************** UV/Color Operators *************************/
2187
2188
2189 static const EnumPropertyItem axis_items[]= {
2190         {OPUVC_AXIS_X, "X", 0, "X", ""},
2191         {OPUVC_AXIS_Y, "Y", 0, "Y", ""},
2192         {0, NULL, 0, NULL, NULL}};
2193
2194 static int mesh_rotate_uvs(bContext *C, wmOperator *op)
2195 {
2196         Scene *scene = CTX_data_scene(C);
2197         Object *ob = CTX_data_edit_object(C);
2198         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
2199         BMOperator bmop;
2200
2201         /* get the direction from RNA */
2202         int dir = RNA_enum_get(op->ptr, "direction");
2203
2204         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2205         EDBM_InitOpf(em, &bmop, op, "meshrotateuvs faces=%hf dir=%d", BM_SELECT, dir);
2206
2207         /* execute the operator */
2208         BMO_Exec_Op(em->bm, &bmop);
2209
2210         /* finish the operator */
2211         if( !EDBM_FinishOp(em, &bmop, op, 1) )
2212                 return OPERATOR_CANCELLED;
2213
2214
2215         /* dependencies graph and notification stuff */
2216         DAG_id_flush_update(ob->data, OB_RECALC_DATA);
2217         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2218
2219         /* we succeeded */
2220         return OPERATOR_FINISHED;
2221 }
2222
2223 static int mesh_reverse_uvs(bContext *C, wmOperator *op)
2224 {
2225         Scene *scene = CTX_data_scene(C);
2226         Object *ob = CTX_data_edit_object(C);
2227         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
2228         BMOperator bmop;
2229
2230         /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
2231         EDBM_InitOpf(em, &bmop, op, "meshreverseuvs faces=%hf", BM_SELECT);
2232
2233         /* execute the operator */
2234         BMO_Exec_Op(em->bm, &bmop);
2235
2236         /* finish the operator */
2237         if( !EDBM_FinishOp(em, &bmop, op, 1) )
2238                 return OPERATOR_CANCELLED;
2239
2240         /* dependencies graph and notification stuff */
2241         DAG_id_flush_update(ob->data, OB_RECALC_DATA);
2242         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2243
2244         /* we succeeded */
2245         return OPERATOR_FINISHED;
2246 }
2247
2248 static int mesh_rotate_colors(bContext *C, wmOperator *op)
2249 {
2250 #if 0
2251         Scene *scene= CTX_data_scene(C);
2252         Object *obedit= CTX_data_edit_object(C);
2253         EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
2254
2255         EditFace *efa;
2256         short change = 0;
2257         MCol tmpcol, *mcol;
2258         int dir= RNA_enum_get(op->ptr, "direction");
2259
2260         if (!EM_vertColorCheck(em)) {
2261                 BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers.");
2262                 BKE_mesh_end_editmesh(obedit->data, em);
2263                 return OPERATOR_CANCELLED;
2264         }
2265
2266         for(efa=em->faces.first; efa; efa=efa->next) {
2267                 if (efa->f & SELECT) {
2268                         mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
2269                         tmpcol= mcol[0];
2270
2271                         if (dir == DIRECTION_CCW) {
2272                                 if(efa->v4) {
2273                                         mcol[0]= mcol[3];
2274                                         mcol[3]= mcol[2];
2275                                 } else {
2276                                         mcol[0]= mcol[2];
2277                                 }
2278                                 mcol[2]= mcol[1];
2279                                 mcol[1]= tmpcol;
2280                         } else {
2281                                 mcol[0]= mcol[1];
2282                                 mcol[1]= mcol[2];
2283
2284                                 if(efa->v4) {
2285                                         mcol[2]= mcol[3];
2286                                         mcol[3]= tmpcol;
2287                                 }
2288                                 else
2289                                         mcol[2]= tmpcol;
2290                         }
2291                         change = 1;
2292                 }
2293         }
2294
2295         BKE_mesh_end_editmesh(obedit->data, em);
2296
2297         if(!change)
2298                 return OPERATOR_CANCELLED;
2299
2300         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2301         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2302
2303         return OPERATOR_FINISHED;
2304 #endif
2305 }
2306
2307
2308 static int mesh_mirror_colors(bContext *C, wmOperator *op)
2309 {
2310 #if 0
2311         Scene *scene= CTX_data_scene(C);
2312         Object *obedit= CTX_data_edit_object(C);
2313         EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
2314
2315         EditFace *efa;
2316         short change = 0;
2317         MCol tmpcol, *mcol;
2318         int axis= RNA_enum_get(op->ptr, "axis");
2319
2320         if (!EM_vertColorCheck(em)) {
2321                 BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers");
2322                 BKE_mesh_end_editmesh(obedit->data, em);
2323                 return OPERATOR_CANCELLED;
2324         }
2325
2326         for(efa=em->faces.first; efa; efa=efa->next) {
2327                 if (efa->f & SELECT) {
2328                         mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
2329                         if (axis == AXIS_Y) {
2330                                 tmpcol= mcol[1];
2331                                 mcol[1]= mcol[2];
2332                                 mcol[2]= tmpcol;
2333
2334                                 if(efa->v4) {
2335                                         tmpcol= mcol[0];
2336                                         mcol[0]= mcol[3];
2337                                         mcol[3]= tmpcol;
2338                                 }
2339                         } else {
2340                                 tmpcol= mcol[0];
2341                                 mcol[0]= mcol[1];
2342                                 mcol[1]= tmpcol;
2343
2344                                 if(efa->v4) {
2345                                         tmpcol= mcol[2];
2346                                         mcol[2]= mcol[3];
2347                                         mcol[3]= tmpcol;
2348                                 }
2349                         }
2350                         change = 1;
2351                 }
2352         }
2353
2354         BKE_mesh_end_editmesh(obedit->data, em);
2355
2356         if(!change)
2357                 return OPERATOR_CANCELLED;
2358
2359         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2360         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2361
2362 #endif
2363         return OPERATOR_FINISHED;
2364 }
2365
2366 void MESH_OT_uvs_rotate(wmOperatorType *ot)
2367 {
2368         /* identifiers */
2369         ot->name= "Rotate UVs";
2370         ot->idname= "MESH_OT_uvs_rotate";
2371
2372         /* api callbacks */
2373         ot->exec= mesh_rotate_uvs;
2374         ot->poll= ED_operator_editmesh;
2375
2376         /* flags */
2377         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2378
2379         /* props */
2380         RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around.");
2381 }
2382
2383 //void MESH_OT_uvs_mirror(wmOperatorType *ot)
2384 void MESH_OT_uvs_reverse(wmOperatorType *ot)
2385 {
2386         /* identifiers */
2387         ot->name= "Reverse UVs";
2388         ot->idname= "MESH_OT_uvs_reverse";
2389
2390         /* api callbacks */
2391         ot->exec= mesh_reverse_uvs;
2392         ot->poll= ED_operator_editmesh;
2393
2394         /* flags */
2395         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2396
2397         /* props */
2398         //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around.");
2399 }
2400
2401 void MESH_OT_colors_rotate(wmOperatorType *ot)
2402 {
2403         /* identifiers */
2404         ot->name= "Rotate Colors";
2405         ot->idname= "MESH_OT_colors_rotate";
2406
2407         /* api callbacks */
2408         ot->exec= mesh_rotate_colors;
2409         ot->poll= ED_operator_editmesh;
2410
2411         /* flags */
2412         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2413
2414         /* props */
2415         RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around.");
2416 }
2417
2418 void MESH_OT_colors_mirror(wmOperatorType *ot)
2419 {
2420         /* identifiers */
2421         ot->name= "Mirror Colors";
2422         ot->idname= "MESH_OT_colors_mirror";
2423
2424         /* api callbacks */
2425         ot->exec= mesh_mirror_colors;
2426         ot->poll= ED_operator_editmesh;
2427
2428         /* flags */
2429         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2430
2431         /* props */
2432         RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around.");
2433 }
2434
2435
2436 static int merge_firstlast(BMEditMesh *em, int first, int uvmerge, wmOperator *wmop)
2437 {
2438         BMVert *mergevert;
2439         BMEditSelection *ese;
2440
2441         /* do sanity check in mergemenu in edit.c ?*/
2442         if(first == 0){
2443                 ese = em->bm->selected.last;
2444                 mergevert= (BMVert*)ese->data;
2445         }
2446         else{
2447                 ese = em->bm->selected.first;
2448                 mergevert = (BMVert*)ese->data;
2449         }
2450
2451         if (!BM_TestHFlag(mergevert, BM_SELECT))
2452                 return OPERATOR_CANCELLED;
2453         
2454         if (uvmerge) {
2455                 if (!EDBM_CallOpf(em, wmop, "pointmerge_facedata verts=%hv snapv=%e", BM_SELECT, mergevert))
2456                         return OPERATOR_CANCELLED;
2457         }
2458
2459         if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_SELECT, mergevert->co))
2460                 return OPERATOR_CANCELLED;
2461
2462         return OPERATOR_FINISHED;
2463 }
2464
2465 static int merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob, 
2466                         int target, int uvmerge, wmOperator *wmop)
2467 {
2468         BMIter iter;
2469         BMVert *v;
2470         float *vco, co[3], cent[3] = {0.0f, 0.0f, 0.0f}, fac;
2471         int i;
2472
2473         if (target) {
2474                 vco = give_cursor(scene, v3d);
2475                 VECCOPY(co, vco);
2476                 Mat4MulVecfl(ob->imat, co);
2477         } else {
2478                 i = 0;
2479                 BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2480                         if (!BM_TestHFlag(v, BM_SELECT))
2481                                 continue;
2482                         VECADD(cent, cent, v->co);
2483                         i++;
2484                 }
2485                 
2486                 if (!i)
2487                         return OPERATOR_CANCELLED;
2488
2489                 fac = 1.0f / (float)i;
2490                 VECMUL(cent, fac);
2491                 VECCOPY(co, cent);
2492         }
2493
2494         if (!co)
2495                 return OPERATOR_CANCELLED;
2496         
2497         if (uvmerge) {
2498                 if (!EDBM_CallOpf(em, wmop, "vert_average_facedata verts=%hv", BM_SELECT))
2499                         return OPERATOR_CANCELLED;
2500         }
2501
2502         if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_SELECT, co))
2503                 return OPERATOR_CANCELLED;
2504
2505         return OPERATOR_FINISHED;
2506 }
2507
2508 static int merge_exec(bContext *C, wmOperator *op)
2509 {
2510         Scene *scene= CTX_data_scene(C);
2511         View3D *v3d = CTX_wm_view3d(C);
2512         Object *obedit= CTX_data_edit_object(C);
2513         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2514         int status= 0, uvs= RNA_boolean_get(op->ptr, "uvs");
2515
2516         switch(RNA_enum_get(op->ptr, "type")) {
2517                 case 3:
2518                         status = merge_target(em, scene, v3d, obedit, 0, uvs, op);
2519                         break;
2520                 case 4:
2521                         status = merge_target(em, scene, v3d, obedit, 1, uvs, op);
2522                         break;
2523                 case 1:
2524                         status = merge_firstlast(em, 0, uvs, op);
2525                         break;
2526                 case 6:
2527                         status = merge_firstlast(em, 1, uvs, op);
2528                         break;
2529                 case 5:
2530                         status = 1;
2531                         if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_SELECT))
2532                                 status = 0;
2533                         break;
2534         }
2535
2536         if(!status)
2537                 return OPERATOR_CANCELLED;
2538
2539         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2540         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2541
2542         return OPERATOR_FINISHED;
2543 }
2544
2545 static EnumPropertyItem merge_type_items[]= {
2546         {6, "FIRST", 0, "At First", ""},
2547         {1, "LAST", 0, "At Last", ""},
2548         {3, "CENTER", 0, "At Center", ""},
2549         {4, "CURSOR", 0, "At Cursor", ""},
2550         {5, "COLLAPSE", 0, "Collapse", ""},
2551         {0, NULL, 0, NULL, NULL}};
2552
2553 static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *ptr, int *free)
2554 {       
2555         Object *obedit;
2556         EnumPropertyItem *item= NULL;
2557         int totitem= 0;
2558         
2559         if(!C) /* needed for docs */
2560                 return merge_type_items;
2561         
2562         obedit= CTX_data_edit_object(C);
2563         if(obedit && obedit->type == OB_MESH) {
2564                 BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2565
2566                 if(em->selectmode & SCE_SELECT_VERTEX) {
2567                         if(em->bm->selected.first && em->bm->selected.last &&
2568                                 ((BMEditSelection*)em->bm->selected.first)->type == BM_VERT && ((BMEditSelection*)em->bm->selected.last)->type == BM_VERT) {
2569                                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
2570                                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
2571                         }
2572                         else if(em->bm->selected.first && ((BMEditSelection*)em->bm->selected.first)->type == BM_VERT)
2573                                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
2574                         else if(em->bm->selected.last && ((BMEditSelection*)em->bm->selected.last)->type == BM_VERT)
2575                                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
2576                 }
2577
2578                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3);
2579                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4);
2580                 RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5);
2581                 RNA_enum_item_end(&item, &totitem);
2582
2583                 *free= 1;
2584
2585                 return item;
2586         }
2587         
2588         return NULL;
2589 }
2590
2591 void MESH_OT_merge(wmOperatorType *ot)
2592 {
2593         PropertyRNA *prop;
2594
2595         /* identifiers */
2596         ot->name= "Merge";
2597         ot->idname= "MESH_OT_merge";
2598
2599         /* api callbacks */
2600         ot->exec= merge_exec;
2601         ot->invoke= WM_menu_invoke;
2602         ot->poll= ED_operator_editmesh;
2603
2604         /* flags */
2605         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2606
2607         /* properties */
2608         prop= RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use.");
2609         RNA_def_enum_funcs(prop, merge_type_itemf);
2610         RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Move UVs according to merge.");
2611 }
2612
2613
2614 static int removedoublesflag_exec(bContext *C, wmOperator *op)
2615 {
2616         Object *obedit= CTX_data_edit_object(C);
2617         Scene *scene = CTX_data_scene(C);
2618         BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
2619         BMOperator bmop;
2620         char msg[100];
2621         int count;
2622
2623         EDBM_InitOpf(em, &bmop, op, "finddoubles verts=%hv dist=%f", 
2624                 BM_SELECT, RNA_float_get(op->ptr, "mergedist"));
2625         BMO_Exec_Op(em->bm, &bmop);
2626
2627         count = BMO_CountSlotMap(em->bm, &bmop, "targetmapout");
2628
2629         if (!EDBM_CallOpf(em, op, "weldverts targetmap=%s", &bmop, "targetmapout")) {
2630                 BMO_Finish_Op(em->bm, &bmop);
2631                 return OPERATOR_CANCELLED;
2632         }
2633
2634         if (!EDBM_FinishOp(em, &bmop, op, 1))
2635                 return OPERATOR_CANCELLED;
2636
2637         /*we need a better way of reporting this, since this doesn't work
2638           with the last operator panel correctly.
2639         if(count)
2640         {
2641                 sprintf(msg, "Removed %d vertices", count);
2642                 BKE_report(op->reports, RPT_INFO, msg);
2643         }
2644         */
2645
2646         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2647         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2648
2649         return OPERATOR_FINISHED;
2650 }
2651
2652 void MESH_OT_remove_doubles(wmOperatorType *ot)
2653 {
2654         /* identifiers */
2655         ot->name= "Remove Doubles";
2656         ot->idname= "MESH_OT_remove_doubles";
2657
2658         /* api callbacks */
2659         ot->exec= removedoublesflag_exec;
2660         ot->poll= ED_operator_editmesh;
2661
2662         /* flags */
2663         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2664
2665         RNA_def_float(ot->srna, "mergedist", 0.0001, 0.0001, 100.0, 
2666                 "Merge Distance", 
2667                 "Minimum distance between elements to merge.", 0.00001, 10.0);
2668 }