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