whitespace only, no functional change mixed tabs/spaces --> tabs.
[blender.git] / source / blender / editors / mesh / editmesh_tools.c
index b907171afb46496e6ee008ec9dff52f53bc54a90..dc1023952a6f31f45076707d82e65704f1cf2c24 100644 (file)
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/editors/mesh/editmesh_tools.c
+ *  \ingroup edmesh
+ */
+
+
 /*
 
 editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise in mods.c
@@ -37,8 +42,6 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise
 #include <math.h>
 #include <float.h>
 
-#include "MEM_guardedalloc.h"
-
 #include "BLO_sys_types.h" // for intptr_t support
 
 #include "DNA_meshdata_types.h"
@@ -47,31 +50,29 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise
 #include "DNA_scene_types.h"
 #include "DNA_key_types.h"
 
+#include "MEM_guardedalloc.h"
+
 #include "RNA_define.h"
 #include "RNA_access.h"
 
 #include "BLI_blenlib.h"
 #include "BLI_math.h"
+#include "BLI_utildefines.h"
 #include "BLI_editVert.h"
 #include "BLI_rand.h"
 #include "BLI_ghash.h"
 #include "BLI_linklist.h"
 #include "BLI_heap.h"
+#include "BLI_scanfill.h"
 
 #include "BKE_context.h"
-#include "BKE_customdata.h"
 #include "BKE_depsgraph.h"
 #include "BKE_global.h"
 #include "BKE_key.h"
-#include "BKE_library.h"
 #include "BKE_mesh.h"
-#include "BKE_object.h"
-#include "BKE_utildefines.h"
 #include "BKE_bmesh.h"
 #include "BKE_report.h"
 
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
@@ -80,12 +81,13 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise
 #include "ED_screen.h"
 #include "ED_transform.h"
 #include "ED_view3d.h"
+#include "ED_object.h"
 
 
 #include "mesh_intern.h"
 
 /* XXX */
-static void waitcursor(int val) {}
+static void waitcursor(int UNUSED(val)) {}
 #define add_numbut(a, b, c, d, e, f, g) {}
 
 /* XXX */
@@ -484,18 +486,24 @@ static int removedoublesflag_exec(bContext *C, wmOperator *op)
 
        int count = removedoublesflag(em,1,0,RNA_float_get(op->ptr, "limit"));
        
-       if(count)
-               BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count);
+       if(count) {
+               recalc_editnormals(em);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+               DAG_id_tag_update(obedit->data, 0);
+               WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+       }
+
+       BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s.", count, (count==1)?"ex":"ices");
 
        BKE_mesh_end_editmesh(obedit->data, em);
+
        return OPERATOR_FINISHED;
 }
 
 void MESH_OT_remove_doubles(wmOperatorType *ot)
 {
+       PropertyRNA *prop;
+
        /* identifiers */
        ot->name= "Remove Doubles";
        ot->description= "Remove duplicate vertices";
@@ -508,12 +516,13 @@ void MESH_OT_remove_doubles(wmOperatorType *ot)
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
-       RNA_def_float(ot->srna, "limit", 0.0001f, 0.000001f, 50.0f, "Merge Threshold", "Minimum distance between merged verts", 0.00001f, 2.0f);
+       prop= RNA_def_float(ot->srna, "limit", 0.0001f, 0.000001f, 50.0f, "Merge Threshold", "Minimum distance between merged verts", 0.00001f, 2.0f);
+       RNA_def_property_ui_range(prop,  0.000001f, 50.0f, 0.001, 5);
 }
 
 // XXX is this needed?
 /* called from buttons */
-static void xsortvert_flag__doSetX(void *userData, EditVert *eve, int x, int y, int index)
+static void xsortvert_flag__doSetX(void *userData, EditVert *UNUSED(eve), int x, int UNUSED(y), int index)
 {
        xvertsort *sortblock = userData;
 
@@ -521,7 +530,7 @@ static void xsortvert_flag__doSetX(void *userData, EditVert *eve, int x, int y,
 }
 
 /* all verts with (flag & 'flag') are sorted */
-void xsortvert_flag(bContext *C, int flag)
+static void xsortvert_flag(bContext *C, int flag)
 {
        ViewContext vc;
        EditVert *eve;
@@ -553,14 +562,37 @@ void xsortvert_flag(bContext *C, int flag)
                }
        }
 
-       addlisttolist(&vc.em->verts, &tbase);
+       BLI_movelisttolist(&vc.em->verts, &tbase);
 
        MEM_freeN(sortblock);
 
 }
 
+static int mesh_vertices_sort_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       xsortvert_flag(C, SELECT);
+       return OPERATOR_FINISHED;
+}
+
+void MESH_OT_vertices_sort(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Vertex Sort";
+       ot->description= "Sort vertex order";
+       ot->idname= "MESH_OT_vertices_sort";
+
+       /* api callbacks */
+       ot->exec= mesh_vertices_sort_exec;
+
+       ot->poll= EM_view3d_poll; /* uses view relative X axis to sort verts */
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
 /* called from buttons */
-void hashvert_flag(EditMesh *em, int flag)
+static void hashvert_flag(EditMesh *em, int flag)
 {
        /* switch vertex order using hash table */
        EditVert *eve;
@@ -611,14 +643,39 @@ void hashvert_flag(EditMesh *em, int flag)
                sb++;
        }
 
-       addlisttolist(&em->verts, &tbase);
+       BLI_movelisttolist(&em->verts, &tbase);
 
        MEM_freeN(sortblock);
 
 }
 
+static int mesh_vertices_randomize_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+       hashvert_flag(em, SELECT);
+       return OPERATOR_FINISHED;
+}
+
+void MESH_OT_vertices_randomize(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Vertex Randomize";
+       ot->description= "Randomize vertex order";
+       ot->idname= "MESH_OT_vertices_randomize";
+
+       /* api callbacks */
+       ot->exec= mesh_vertices_randomize_exec;
+
+       ot->poll= ED_operator_editmesh;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
 /* generic extern called extruder */
-void extrude_mesh(Scene *scene, Object *obedit, EditMesh *em, wmOperator *op, short type)
+static void extrude_mesh(Object *obedit, EditMesh *em, wmOperator *op, short type)
 {
        float nor[3]= {0.0, 0.0, 0.0};
        short transmode= 0;
@@ -633,7 +690,7 @@ void extrude_mesh(Scene *scene, Object *obedit, EditMesh *em, wmOperator *op, sh
        EM_stats_update(em);
 
        if(transmode==0) {
-               BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
+               BKE_report(op->reports, RPT_WARNING, "Not a valid selection for extrude");
        }
        else {
                EM_fgon_flags(em);
@@ -644,7 +701,7 @@ void extrude_mesh(Scene *scene, Object *obedit, EditMesh *em, wmOperator *op, sh
                        * This shouldn't be necessary, derived queries should be
                        * automatically building this data if invalid. Or something.
                        */
-               DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+               DAG_id_tag_update(obedit->data, 0);
 
                /* individual faces? */
 //             BIF_TransformSetUndo("Extrude");
@@ -666,17 +723,16 @@ void extrude_mesh(Scene *scene, Object *obedit, EditMesh *em, wmOperator *op, sh
 }
 
 // XXX should be a menu item
-static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 {
-       Scene *scene= CTX_data_scene(C);
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
        
-       extrude_mesh(scene, obedit, em, op, RNA_int_get(op->ptr, "type"));
+       extrude_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type"));
 
        BKE_mesh_end_editmesh(obedit->data, em);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        return OPERATOR_FINISHED;
@@ -685,20 +741,19 @@ static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
 /* extrude without transform */
 static int mesh_extrude_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene= CTX_data_scene(C);
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
 
-       extrude_mesh(scene, obedit, em, op, RNA_int_get(op->ptr, "type"));
+       extrude_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type"));
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        BKE_mesh_end_editmesh(obedit->data, em);
        return OPERATOR_FINISHED;
 }
 
-EnumPropertyItem extrude_items[] = {
+static EnumPropertyItem extrude_items[] = {
                {1, "REGION", 0, "Region", ""},
                {2, "FACES", 0, "Individual Faces", ""},
                {3, "EDGES", 0, "Only Edges", ""},
@@ -706,7 +761,7 @@ EnumPropertyItem extrude_items[] = {
                {0, NULL, 0, NULL, NULL}};
 
 
-static EnumPropertyItem *extrude_itemf(bContext *C, PointerRNA *ptr, int *free)
+static EnumPropertyItem *mesh_extrude_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
 {
        EnumPropertyItem *item= NULL;
        Object *obedit= CTX_data_edit_object(C);
@@ -714,7 +769,7 @@ static EnumPropertyItem *extrude_itemf(bContext *C, PointerRNA *ptr, int *free)
 
        int totitem= 0;
 
-       if(!obedit)
+       if(obedit==NULL || obedit->type != OB_MESH)
                return extrude_items;
 
        em = BKE_mesh_get_editmesh(obedit->data);
@@ -794,11 +849,11 @@ void MESH_OT_extrude(wmOperatorType *ot)
        /* properties */
        prop= RNA_def_enum(ot->srna, "type", extrude_items, 0, "Type", "");
        RNA_def_property_flag(prop, PROP_HIDDEN);
-       RNA_def_enum_funcs(prop, extrude_itemf);
+       RNA_def_enum_funcs(prop, mesh_extrude_itemf);
        ot->prop= prop;
 }
 
-static int split_mesh(bContext *C, wmOperator *op)
+static int split_mesh(bContext *C, wmOperator *UNUSED(op))
 {
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
@@ -813,7 +868,7 @@ static int split_mesh(bContext *C, wmOperator *op)
 
        WM_cursor_wait(0);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        BKE_mesh_end_editmesh(obedit->data, em);
@@ -873,7 +928,7 @@ static int extrude_repeat_mesh(bContext *C, wmOperator *op)
 
        EM_fgon_flags(em);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        BKE_mesh_end_editmesh(obedit->data, em);
@@ -889,7 +944,7 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot)
 
        /* api callbacks */
        ot->exec= extrude_repeat_mesh;
-       ot->poll= ED_operator_editmesh;
+       ot->poll= ED_operator_editmesh_region_view3d;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -925,7 +980,7 @@ static int spin_mesh(bContext *C, wmOperator *op, float *dvec, int steps, float
        cent[2]-= obedit->obmat[3][2];
        mul_m3_v3(imat, cent);
 
-       phi= degr*M_PI/360.0;
+       phi= degr*(float)M_PI/360.0f;
        phi/= steps;
        if(ts->editbutflag & B_CLOCKWISE) phi= -phi;
 
@@ -977,7 +1032,7 @@ static int spin_mesh(bContext *C, wmOperator *op, float *dvec, int steps, float
 
                EM_fgon_flags(em);
 
-               DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+               DAG_id_tag_update(obedit->data, 0);
        }
 
        BKE_mesh_end_editmesh(obedit->data, em);
@@ -991,18 +1046,18 @@ static int spin_mesh_exec(bContext *C, wmOperator *op)
 
        ok= spin_mesh(C, op, NULL, RNA_int_get(op->ptr,"steps"), RNA_float_get(op->ptr,"degrees"), RNA_boolean_get(op->ptr,"dupli"));
        if(ok==0) {
-               BKE_report(op->reports, RPT_ERROR, "No valid vertices are selected");
+               BKE_report(op->reports, RPT_WARNING, "No valid vertices are selected");
                return OPERATOR_CANCELLED;
        }
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        return OPERATOR_FINISHED;
 }
 
 /* get center and axis, in global coords */
-static int spin_mesh_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int spin_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 {
        Scene *scene = CTX_data_scene(C);
        View3D *v3d = CTX_wm_view3d(C);
@@ -1030,11 +1085,11 @@ void MESH_OT_spin(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
        /* props */
-       RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, INT_MAX);
+       RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 128);
        RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates");
        RNA_def_float(ot->srna, "degrees", 90.0f, -FLT_MAX, FLT_MAX, "Degrees", "Degrees", -360.0f, 360.0f);
 
-       RNA_def_float_vector(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
+       RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
        RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX);
 
 }
@@ -1077,7 +1132,7 @@ static int screw_mesh_exec(bContext *C, wmOperator *op)
                }
        }
        if(v1==NULL || v2==NULL) {
-               BKE_report(op->reports, RPT_ERROR, "You have to select a string of connected vertices too");
+               BKE_report(op->reports, RPT_WARNING, "You have to select a string of connected vertices too");
                BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_CANCELLED;
        }
@@ -1089,28 +1144,26 @@ static int screw_mesh_exec(bContext *C, wmOperator *op)
 
        VECCOPY(nor, obedit->obmat[2]);
 
-       if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.000) {
-               dvec[0]= -dvec[0];
-               dvec[1]= -dvec[1];
-               dvec[2]= -dvec[2];
+       if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.0f) {
+               negate_v3(dvec);
        }
 
        if(spin_mesh(C, op, dvec, turns*steps, 360.0f*turns, 0)) {
-               DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+               DAG_id_tag_update(obedit->data, 0);
                WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
                BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_FINISHED;
        }
        else {
-               BKE_report(op->reports, RPT_ERROR, "No valid vertices are selected");
+               BKE_report(op->reports, RPT_WARNING, "No valid vertices are selected");
                BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_CANCELLED;
        }
 }
 
 /* get center and axis, in global coords */
-static int screw_mesh_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int screw_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 {
        Scene *scene = CTX_data_scene(C);
        View3D *v3d = CTX_wm_view3d(C);
@@ -1141,7 +1194,7 @@ void MESH_OT_screw(wmOperatorType *ot)
        RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 256);
        RNA_def_int(ot->srna, "turns", 1, 0, INT_MAX, "Turns", "Turns", 0, 256);
 
-       RNA_def_float_vector(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
+       RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
        RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX);
 }
 
@@ -1191,19 +1244,19 @@ static void erase_vertices(EditMesh *em, ListBase *l)
        }
 }
 
-void delete_mesh(Object *obedit, EditMesh *em, wmOperator *op, int event)
+static void delete_mesh(EditMesh *em, wmOperator *op, int event)
 {
        EditFace *efa, *nextvl;
        EditVert *eve,*nextve;
        EditEdge *eed,*nexted;
        int count;
-       char *str="Erase";
+       /* const char *str="Erase"; */
 
 
        if(event<1) return;
 
        if(event==10 ) {
-               str= "Erase Vertices";
+               /* str= "Erase Vertices"; */
                erase_edges(em, &em->edges);
                erase_faces(em, &em->faces);
                erase_vertices(em, &em->verts);
@@ -1212,10 +1265,10 @@ void delete_mesh(Object *obedit, EditMesh *em, wmOperator *op, int event)
                if(!EdgeLoopDelete(em, op))
                        return;
 
-               str= "Erase Edge Loop";
+               /* str= "Erase Edge Loop"; */
        }
        else if(event==4) {
-               str= "Erase Edges & Faces";
+               /* str= "Erase Edges & Faces"; */
                efa= em->faces.first;
                while(efa) {
                        nextvl= efa->next;
@@ -1257,7 +1310,7 @@ void delete_mesh(Object *obedit, EditMesh *em, wmOperator *op, int event)
                }
        }
        else if(event==1) {
-               str= "Erase Edges";
+               /* str= "Erase Edges"; */
                // faces first
                efa= em->faces.first;
                while(efa) {
@@ -1302,18 +1355,18 @@ void delete_mesh(Object *obedit, EditMesh *em, wmOperator *op, int event)
 
        }
        else if(event==2) {
-               str="Erase Faces";
+               /* str="Erase Faces"; */
                delfaceflag(em, SELECT);
        }
        else if(event==3) {
-               str= "Erase All";
+               /* str= "Erase All"; */
                if(em->verts.first) free_vertlist(em, &em->verts);
                if(em->edges.first) free_edgelist(em, &em->edges);
                if(em->faces.first) free_facelist(em, &em->faces);
                if(em->selected.first) BLI_freelistN(&(em->selected));
        }
        else if(event==5) {
-               str= "Erase Only Faces";
+               /* str= "Erase Only Faces"; */
                efa= em->faces.first;
                while(efa) {
                        nextvl= efa->next;
@@ -1349,9 +1402,9 @@ static int delete_mesh_exec(bContext *C, wmOperator *op)
        if(type==6)
                return WM_operator_name_call(C, "MESH_OT_delete_edgeloop", WM_OP_EXEC_DEFAULT, NULL);
 
-       delete_mesh(obedit, em, op, type);
+       delete_mesh(em, op, type);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        BKE_mesh_end_editmesh(obedit->data, em);
@@ -1421,7 +1474,7 @@ static void alter_co(float *co, EditEdge *edge, float smooth, float fractal, int
                vec1[2]+= fac*nor2[2];
 
                /* falloff for multi subdivide */
-               smooth *= sqrt(fabs(1.0f - 2.0f*fabs(0.5f-perc)));
+               smooth *= sqrtf(fabs(1.0f - 2.0f*fabsf(0.5f-perc)));
 
                vec1[0]*= smooth*len;
                vec1[1]*= smooth*len;
@@ -1519,6 +1572,7 @@ static void facecopy(EditMesh *em, EditFace *source, EditFace *target)
        if (target->v4)
                interp_weights_face_v3( w[3],v1, v2, v3, v4, target->v4->co);
 
+       CustomData_em_validate_data(&em->fdata, target->data, target->v4 ? 4 : 3);
        CustomData_em_interp(&em->fdata, &source->data, NULL, (float*)w, 1, target->data);
 }
 
@@ -1683,7 +1737,7 @@ static void fill_quad_double_op(EditMesh *em, EditFace *efa, struct GHash *gh, i
        EditEdge *cedge[2]={NULL, NULL};
        EditVert *v[4], **verts[2];
        EditFace *hold;
-       short start=0, end, left, right, vertsize,i;
+       short start=0, /*end,*/ left, /* right,*/ vertsize,i;
 
        v[0] = efa->v1;
        v[1] = efa->v2;
@@ -1704,9 +1758,9 @@ static void fill_quad_double_op(EditMesh *em, EditFace *efa, struct GHash *gh, i
        // the array to the correct direction
 
        if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
-       end     = (start+1)%4;
+       /* end  = (start+1)%4; */ /* UNUSED */
        left   = (start+2)%4;
-       right  = (start+3)%4;
+       /* right  = (start+3)%4; */ /* UNUSED */
        if(verts[1][0] != v[left]) {flipvertarray(verts[1],numcuts+2);}
        /*
        We should have something like this now
@@ -2619,15 +2673,15 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
                                        eve->f2= 0;
                                        switch(mmd->axis){
                                                case 0:
-                                                       if (fabs(eve->co[0]) < mmd->tolerance)
+                                                       if (fabsf(eve->co[0]) < mmd->tolerance)
                                                                eve->f2 |= 1;
                                                        break;
                                                case 1:
-                                                       if (fabs(eve->co[1]) < mmd->tolerance)
+                                                       if (fabsf(eve->co[1]) < mmd->tolerance)
                                                                eve->f2 |= 2;
                                                        break;
                                                case 2:
-                                                       if (fabs(eve->co[2]) < mmd->tolerance)
+                                                       if (fabsf(eve->co[2]) < mmd->tolerance)
                                                                eve->f2 |= 4;
                                                        break;
                                        }
@@ -2759,7 +2813,7 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
                }
        }
 
-//     DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+//     DAG_id_tag_update(obedit->data, 0);
        // Now for each face in the mesh we need to figure out How many edges were cut
        // and which filling method to use for that face
        for(ef = em->faces.first;ef;ef = ef->next) {
@@ -2943,6 +2997,13 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float
                }
        }
 
+       //third pass: unhide edges that have both verts visible
+       //(these were missed if all faces were hidden, bug #21976)
+       for(eed=em->edges.first; eed; eed=eed->next){
+               if(eed->v1->h == 0 && eed->v2->h == 0)
+                       eed->h &= ~1;
+       }
+
        // Free the ghash and call MEM_freeN on all the value entries to return
        // that memory
        BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
@@ -3090,21 +3151,21 @@ static void givequadverts(EditFace *efa, EditFace *efa1, EditVert **v1, EditVert
 
        if VTEST(efa1, 1, efa) {
                *v3= efa1->v1;
-               *v4= efa1->v2;
+               *v4= (efa1->v2 == *v2)? efa1->v3: efa1->v2;
                vindex[2]= 0;
-               vindex[3]= 1;
+               vindex[3]= (efa1->v2 == *v2)? 2: 1;
        }
        else if VTEST(efa1, 2, efa) {
                *v3= efa1->v2;
-               *v4= efa1->v3;
+               *v4= (efa1->v3 == *v2)? efa1->v1: efa1->v3;
                vindex[2]= 1;
-               vindex[3]= 2;
+               vindex[3]= (efa1->v3 == *v2)? 0: 2;
        }
        else if VTEST(efa1, 3, efa) {
                *v3= efa1->v3;
-               *v4= efa1->v1;
+               *v4= (efa1->v1 == *v2)? efa1->v2: efa1->v1;
                vindex[2]= 2;
-               vindex[3]= 0;
+               vindex[3]= (efa1->v1 == *v2)? 1: 0;
        }
        else
                *v3= *v4= NULL;
@@ -3163,13 +3224,13 @@ static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert
        normal_tri_v3( noA2,v1->co, v3->co, v4->co);
 
        if(noA1[0] == noA2[0] && noA1[1] == noA2[1] && noA1[2] == noA2[2]) normalADiff = 0.0;
-       else normalADiff = RAD2DEG(angle_v2v2(noA1, noA2));
+       else normalADiff = RAD2DEGF(angle_v2v2(noA1, noA2));
                //if(!normalADiff) normalADiff = 179;
        normal_tri_v3( noB1,v2->co, v3->co, v4->co);
        normal_tri_v3( noB2,v4->co, v1->co, v2->co);
 
        if(noB1[0] == noB2[0] && noB1[1] == noB2[1] && noB1[2] == noB2[2]) normalBDiff = 0.0;
-       else normalBDiff = RAD2DEG(angle_v2v2(noB1, noB2));
+       else normalBDiff = RAD2DEGF(angle_v2v2(noB1, noB2));
                //if(!normalBDiff) normalBDiff = 179;
 
        measure += (normalADiff/360) + (normalBDiff/360);
@@ -3184,10 +3245,10 @@ static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert
        diff = 0.0;
 
        diff = (
-               fabs(RAD2DEG(angle_v2v2(edgeVec1, edgeVec2)) - 90) +
-               fabs(RAD2DEG(angle_v2v2(edgeVec2, edgeVec3)) - 90) +
-               fabs(RAD2DEG(angle_v2v2(edgeVec3, edgeVec4)) - 90) +
-               fabs(RAD2DEG(angle_v2v2(edgeVec4, edgeVec1)) - 90)) / 360;
+               fabsf(RAD2DEGF(angle_v2v2(edgeVec1, edgeVec2)) - 90) +
+               fabsf(RAD2DEGF(angle_v2v2(edgeVec2, edgeVec3)) - 90) +
+               fabsf(RAD2DEGF(angle_v2v2(edgeVec3, edgeVec4)) - 90) +
+               fabsf(RAD2DEGF(angle_v2v2(edgeVec4, edgeVec1)) - 90)) / 360;
        if(!diff) return 0.0;
 
        measure +=  diff;
@@ -3209,7 +3270,7 @@ static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert
        return measure;
 }
 
-#define T2QUV_LIMIT 0.005
+#define T2QUV_LIMIT 0.005f
 #define T2QCOL_LIMIT 3
 static int compareFaceAttribs(EditMesh *em, EditFace *f1, EditFace *f2, EditEdge *eed)
 {
@@ -3413,7 +3474,7 @@ void join_triangles(EditMesh *em)
                                efaa= (EVPtr *)eed->tmp.p;
                                v1 = v2 = v3 = v4 = NULL;
                                givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
-                               if((v1 && v2 && v3 && v4) && (exist_face(em, v1, v2, v3, v4)==0)){ /*exist_face is very slow! Needs to be adressed.*/
+                               if((v1 && v2 && v3 && v4) && (exist_face(em, v1, v2, v3, v4)==0)){ /*exist_face is very slow! Needs to be addressed.*/
                                        /*flag for delete*/
                                        eed->f1 |= T2QDELETE;
                                        /*create new quad and select*/
@@ -3449,7 +3510,7 @@ void join_triangles(EditMesh *em)
 #define FACE_MARKCLEAR(f) (f->f1 = 1)
 
 /* quick hack, basically a copy of beautify_fill */
-void edge_flip(EditMesh *em)
+static void edge_flip(EditMesh *em)
 {
        EditVert *v1, *v2, *v3, *v4;
        EditEdge *eed, *nexted;
@@ -3550,7 +3611,7 @@ static const EnumPropertyItem direction_items[]= {
 #define AXIS_X         1
 #define AXIS_Y         2
 
-static const EnumPropertyItem axis_items[]= {
+static const EnumPropertyItem axis_items_xy[]= {
        {AXIS_X, "X", 0, "X", ""},
        {AXIS_Y, "Y", 0, "Y", ""},
        {0, NULL, 0, NULL, NULL}};
@@ -3770,7 +3831,7 @@ static int edge_rotate_selected(bContext *C, wmOperator *op)
                }
                else
                {
-                       BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
+                       BKE_report(op->reports, RPT_WARNING, "Select one edge or two adjacent faces");
                        BKE_mesh_end_editmesh(obedit->data, em);
                        return OPERATOR_CANCELLED;
                }
@@ -3785,7 +3846,7 @@ static int edge_rotate_selected(bContext *C, wmOperator *op)
                }
        }
        else  {
-               BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
+               BKE_report(op->reports, RPT_WARNING, "Select one edge or two adjacent faces");
                BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_CANCELLED;
        }
@@ -3795,7 +3856,7 @@ static int edge_rotate_selected(bContext *C, wmOperator *op)
 
        BKE_mesh_end_editmesh(obedit->data, em);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        return OPERATOR_FINISHED;
@@ -3824,7 +3885,7 @@ void MESH_OT_edge_rotate(wmOperatorType *ot)
 
   /* XXX old bevel not ported yet */
 
-void bevel_menu(EditMesh *em)
+static void bevel_menu(EditMesh *em)
 {
        BME_Mesh *bm;
        BME_TransData_Head *td;
@@ -4197,7 +4258,7 @@ useless:
                        return 0;
                }
 
-               if(me->drawflag & ME_DRAW_EDGELEN) {
+               if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
                        if(!(tempsv->up->f & SELECT)) {
                                tempsv->up->f |= SELECT;
                                tempsv->up->f2 |= 16;
@@ -4646,11 +4707,11 @@ useless:
                } else {
                        draw = 0;
                }
-//             DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+//             DAG_id_tag_update(obedit->data, 0);
        }
 
 
-       if(me->drawflag & ME_DRAW_EDGELEN) {
+       if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
                look = vertlist;
                while(look) {
                        tempsv  = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
@@ -4666,7 +4727,7 @@ useless:
 
        if(!immediate)
                EM_automerge(0);
-//     DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+//     DAG_id_tag_update(obedit->data, 0);
 //     scrarea_queue_winredraw(curarea);
 
        //BLI_ghash_free(edgesgh, freeGHash, NULL);
@@ -4698,7 +4759,7 @@ useless:
 }
 #endif // END OF XXX
 
-int EdgeLoopDelete(EditMesh *em, wmOperator *op)
+int EdgeLoopDelete(EditMesh *UNUSED(em), wmOperator *UNUSED(op))
 {
 #if 0 //XXX won't work with new edgeslide
 
@@ -4717,7 +4778,7 @@ int EdgeLoopDelete(EditMesh *em, wmOperator *op)
        EM_select_more(em);
        removedoublesflag(em, 1,0, 0.001);
        EM_select_flush(em);
-       //      DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       //      DAG_id_tag_update(obedit->data, 0);
        return 1;
 #endif
        return 0;
@@ -4871,12 +4932,12 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
        }
 
        if(efa) {
-               BKE_report(op->reports, RPT_ERROR, "Can't perform ripping with faces selected this way");
+               BKE_report(op->reports, RPT_WARNING, "Can't perform ripping with faces selected this way");
                BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_CANCELLED;
        }
        if(sefa==NULL) {
-               BKE_report(op->reports, RPT_ERROR, "No proper selection or faces included");
+               BKE_report(op->reports, RPT_WARNING, "No proper selection or faces included");
                BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_CANCELLED;
        }
@@ -4941,7 +5002,7 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
        }
 
        if(seed==NULL) {        // never happens?
-               BKE_report(op->reports, RPT_ERROR, "No proper edge found to start");
+               BKE_report(op->reports, RPT_WARNING, "No proper edge found to start");
                BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_CANCELLED;
        }
@@ -5026,7 +5087,7 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
                }
        }
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        BKE_mesh_end_editmesh(obedit->data, em);
@@ -5071,7 +5132,7 @@ static void shape_propagate(Object *obedit, EditMesh *em, wmOperator *op)
        if(me->key){
                ky = me->key;
        } else {
-               BKE_report(op->reports, RPT_ERROR, "Object Has No Key");
+               BKE_report(op->reports, RPT_WARNING, "Object Has No Key");
                return;
        }
 
@@ -5086,7 +5147,7 @@ static void shape_propagate(Object *obedit, EditMesh *em, wmOperator *op)
                        }
                }
        } else {
-               BKE_report(op->reports, RPT_ERROR, "Object Has No Blendshapes");
+               BKE_report(op->reports, RPT_WARNING, "Object Has No Blendshapes");
                return;
        }
 
@@ -5099,7 +5160,7 @@ static void shape_propagate(Object *obedit, EditMesh *em, wmOperator *op)
        }
 #endif
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        return;
 }
 
@@ -5112,7 +5173,7 @@ static int shape_propagate_to_all_exec(bContext *C, wmOperator *op)
 
        shape_propagate(obedit, em, op);
 
-       DAG_id_flush_update(&me->id, OB_RECALC_DATA);
+       DAG_id_tag_update(&me->id, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
 
        return OPERATOR_FINISHED;
@@ -5141,27 +5202,38 @@ static int blend_from_shape_exec(bContext *C, wmOperator *op)
        Key *key= me->key;
        EditMesh *em= BKE_mesh_get_editmesh(me);
        EditVert *eve;
-       KeyBlock *kb;
-       float *data, co[3];
+       KeyBlock *kb, *refkb= NULL;
+       float *data, *refdata= NULL, co[3];
        float blend= RNA_float_get(op->ptr, "blend");
        int shape= RNA_enum_get(op->ptr, "shape");
-       int add= RNA_int_get(op->ptr, "add");
+       int add= RNA_boolean_get(op->ptr, "add");
        int blended= 0;
 
        if(key && (kb= BLI_findlink(&key->block, shape))) {
                data= kb->data;
 
+               if(add) {
+                       refkb= BLI_findlink(&key->block, kb->relative);
+                       if(refkb)
+                               refdata = refkb->data;
+               }
+
                for(eve=em->verts.first; eve; eve=eve->next){
                        if(eve->f & SELECT) {
                                if(eve->keyindex >= 0 && eve->keyindex < kb->totelem) {
-                                       VECCOPY(co, data + eve->keyindex*3);
+                                       copy_v3_v3(co, data + eve->keyindex*3);
 
                                        if(add) {
-                                               mul_v3_fl(co, blend);
-                                               add_v3_v3(eve->co, co);
+                                               /* in add mode, we add relative shape key offset */
+                                               if(refdata && eve->keyindex < refkb->totelem)
+                                                       sub_v3_v3v3(co, co, refdata + eve->keyindex*3);
+
+                                               madd_v3_v3fl(eve->co, co, blend);
                                        }
-                                       else
+                                       else {
+                                               /* in blend mode, we interpolate to the shape key */
                                                interp_v3_v3v3(eve->co, eve->co, co, blend);
+                                       }
 
                                        blended= 1;
                                }
@@ -5174,13 +5246,13 @@ static int blend_from_shape_exec(bContext *C, wmOperator *op)
        if(!blended)
                return OPERATOR_CANCELLED;
 
-       DAG_id_flush_update(&me->id, OB_RECALC_DATA);
+       DAG_id_tag_update(&me->id, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
 
        return OPERATOR_FINISHED;
 }
 
-static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *ptr, int *free)
+static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
 {      
        Object *obedit= CTX_data_edit_object(C);
        Mesh *me= (obedit) ? obedit->data : NULL;
@@ -5233,7 +5305,7 @@ void MESH_OT_blend_from_shape(wmOperatorType *ot)
        prop= RNA_def_enum(ot->srna, "shape", shape_items, 0, "Shape", "Shape key to use for blending.");
        RNA_def_enum_funcs(prop, shape_itemf);
        RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor.", -2.0f, 2.0f);
-       RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather then blend between shapes.");
+       RNA_def_boolean(ot->srna, "add", 0, "Add", "Add rather then blend between shapes.");
 }
 
 /************************ Merge Operator *************************/
@@ -5342,7 +5414,7 @@ static void freecollections(ListBase *allcollections)
 
 /*Begin UV Edge Collapse Code
        Like Edge subdivide, Edge Collapse should handle UV's intelligently, but since UV's are a per-face attribute, normal edge collapse will fail
-       in areas such as the boundries of 'UV islands'. So for each edge collection we need to build a set of 'welded' UV vertices and edges for it.
+       in areas such as the boundaries of 'UV islands'. So for each edge collection we need to build a set of 'welded' UV vertices and edges for it.
        The welded UV edges can then be sorted and collapsed.
 */
 typedef struct wUV{
@@ -5675,7 +5747,7 @@ static int collapseEdges(EditMesh *em)
        CollectedEdge *curredge;
        Collection *edgecollection;
 
-       int totedges, groupcount, mergecount,vcount;
+       int totedges, mergecount,vcount /*, groupcount*/;
        float avgcount[3];
 
        allcollections.first = 0;
@@ -5684,7 +5756,7 @@ static int collapseEdges(EditMesh *em)
        mergecount = 0;
 
        build_edgecollection(em, &allcollections);
-       groupcount = BLI_countlist(&allcollections);
+       /*groupcount = BLI_countlist(&allcollections);*/ /*UNUSED*/
 
 
        for(edgecollection = allcollections.first; edgecollection; edgecollection = edgecollection->next){
@@ -5837,6 +5909,7 @@ static int merge_exec(bContext *C, wmOperator *op)
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
        int count= 0, uvs= RNA_boolean_get(op->ptr, "uvs");
+       EditSelection *ese;
 
        switch(RNA_enum_get(op->ptr, "type")) {
                case 3:
@@ -5846,10 +5919,21 @@ static int merge_exec(bContext *C, wmOperator *op)
                        count = merge_target(C, em, 1, uvs);
                        break;
                case 1:
-                       count = merge_firstlast(em, 0, uvs);
+                       ese= (EditSelection *)em->selected.last;
+                       if(ese && ese->type == EDITVERT) {
+                               count = merge_firstlast(em, 0, uvs);
+                       } else {
+                               BKE_report(op->reports, RPT_WARNING, "no last selected vertex set");
+                       }
                        break;
                case 6:
-                       count = merge_firstlast(em, 1, uvs);
+                       ese= (EditSelection *)em->selected.first;
+                       if(ese && ese->type == EDITVERT) {
+                               count = merge_firstlast(em, 1, uvs);
+                       }
+                       else {
+                               BKE_report(op->reports, RPT_WARNING, "no last selected vertex set");
+                       }
                        break;
                case 5:
                        count = collapseEdges(em);
@@ -5859,12 +5943,13 @@ static int merge_exec(bContext *C, wmOperator *op)
        if(!count)
                return OPERATOR_CANCELLED;
 
+       recalc_editnormals(em);
        
        BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s.", count, (count==1)?"ex":"ices");
 
        BKE_mesh_end_editmesh(obedit->data, em);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        return OPERATOR_FINISHED;
@@ -5878,7 +5963,7 @@ static EnumPropertyItem merge_type_items[]= {
        {5, "COLLAPSE", 0, "Collapse", ""},
        {0, NULL, 0, NULL, NULL}};
 
-static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *ptr, int *free)
+static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
 {      
        Object *obedit= CTX_data_edit_object(C);
        EnumPropertyItem *item= NULL;
@@ -5961,7 +6046,6 @@ static int select_vertex_path_exec(bContext *C, wmOperator *op)
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
        EditVert *eve, *s, *t;
        EditEdge *eed;
-       EditSelection *ese;
        PathEdge *newpe, *currpe;
        PathNode *currpn;
        PathNode *Q;
@@ -5972,17 +6056,24 @@ static int select_vertex_path_exec(bContext *C, wmOperator *op)
        Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/
 
        s = t = NULL;
+       for(eve=em->verts.first; eve; eve=eve->next) {
+               if(eve->f&SELECT) {
+                       if(s == NULL) s= eve;
+                       else if(t == NULL) t= eve;
+                       else {
+                               /* more than two vertices are selected,
+                                  show warning message and cancel operator */
+                               s = t = NULL;
+                               break;
+                       }
 
-       ese = ((EditSelection*)em->selected.last);
-       if(ese && ese->type == EDITVERT && ese->prev && ese->prev->type == EDITVERT) {
-               t = (EditVert*)ese->data;
-               s = (EditVert*)ese->prev->data;
+               }
 
                /*need to find out if t is actually reachable by s....*/
-               for(eve=em->verts.first; eve; eve=eve->next){
-                       eve->f1 = 0;
-               }
+               eve->f1 = 0;
+       }
 
+       if(s != NULL && t != NULL) {
                s->f1 = 1;
 
                unbalanced = 1;
@@ -6103,7 +6194,7 @@ static int select_vertex_path_exec(bContext *C, wmOperator *op)
        }
        else {
                BKE_mesh_end_editmesh(obedit->data, em);
-               BKE_report(op->reports, RPT_ERROR, "Path Selection requires that exactly two vertices be selected");
+               BKE_report(op->reports, RPT_WARNING, "Path Selection requires that exactly two vertices be selected");
                return OPERATOR_CANCELLED;
        }
 
@@ -6138,7 +6229,7 @@ void MESH_OT_select_vertex_path(wmOperatorType *ot)
 
 /********************** Region/Loop Operators *************************/
 
-static int region_to_loop(bContext *C, wmOperator *op)
+static int region_to_loop(bContext *C, wmOperator *UNUSED(op))
 {
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
@@ -6319,7 +6410,7 @@ static int loop_bisect(EditMesh *em, Collection *edgecollection){
        else return(2);
 }
 
-static int loop_to_region(bContext *C, wmOperator *op)
+static int loop_to_region(bContext *C, wmOperator *UNUSED(op))
 {
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
@@ -6388,7 +6479,7 @@ static int mesh_rotate_uvs(bContext *C, wmOperator *op)
        int dir= RNA_enum_get(op->ptr, "direction");
 
        if (!EM_texFaceCheck(em)) {
-               BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
+               BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
                BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_CANCELLED;
        }
@@ -6444,7 +6535,7 @@ static int mesh_rotate_uvs(bContext *C, wmOperator *op)
        if(!change)
                return OPERATOR_CANCELLED;
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        return OPERATOR_FINISHED;
@@ -6462,7 +6553,7 @@ static int mesh_mirror_uvs(bContext *C, wmOperator *op)
        int axis= RNA_enum_get(op->ptr, "axis");
 
        if (!EM_texFaceCheck(em)) {
-               BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
+               BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
                BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_CANCELLED;
        }
@@ -6533,7 +6624,7 @@ static int mesh_mirror_uvs(bContext *C, wmOperator *op)
        if(!change)
                return OPERATOR_CANCELLED;
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        return OPERATOR_FINISHED;
@@ -6550,7 +6641,7 @@ static int mesh_rotate_colors(bContext *C, wmOperator *op)
        int dir= RNA_enum_get(op->ptr, "direction");
 
        if (!EM_vertColorCheck(em)) {
-               BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers.");
+               BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers.");
                BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_CANCELLED;
        }
@@ -6589,7 +6680,7 @@ static int mesh_rotate_colors(bContext *C, wmOperator *op)
        if(!change)
                return OPERATOR_CANCELLED;
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        return OPERATOR_FINISHED;
@@ -6607,7 +6698,7 @@ static int mesh_mirror_colors(bContext *C, wmOperator *op)
        int axis= RNA_enum_get(op->ptr, "axis");
 
        if (!EM_vertColorCheck(em)) {
-               BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers");
+               BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers");
                BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_CANCELLED;
        }
@@ -6645,7 +6736,7 @@ static int mesh_mirror_colors(bContext *C, wmOperator *op)
        if(!change)
                return OPERATOR_CANCELLED;
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        return OPERATOR_FINISHED;
@@ -6684,7 +6775,7 @@ void MESH_OT_uvs_mirror(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
        /* props */
-       RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around.");
+       RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror UVs around.");
 }
 
 void MESH_OT_colors_rotate(wmOperatorType *ot)
@@ -6720,7 +6811,7 @@ void MESH_OT_colors_mirror(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
        /* props */
-       RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around.");
+       RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror colors around.");
 }
 
 /********************** Subdivide Operator *************************/
@@ -6743,7 +6834,7 @@ static int subdivide_exec(bContext *C, wmOperator *op)
 
        esubdivideflag(obedit, em, 1, smooth, fractal, ts->editbutflag|flag, cuts, corner_cut_pattern, 0);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        return OPERATOR_FINISHED;
@@ -6765,7 +6856,7 @@ void MESH_OT_subdivide(wmOperatorType *ot)
 
        /* properties */
        RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
-       RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor.", 0.0f, 1000.0f);
+       RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor.", 0.0f, 1.0f);
        RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
        RNA_def_enum(ot->srna, "corner_cut_pattern", corner_type_items, SUBDIV_CORNER_INNERVERT, "Corner Cut Pattern", "Topology pattern to use to fill a face after cutting across its corner");
 }
@@ -6997,7 +7088,7 @@ static void fill_mesh(EditMesh *em)
                }
        }
 
-       if(BLI_edgefill(0, em->mat_nr)) {
+       if(BLI_edgefill(em->mat_nr)) {
                efa= fillfacebase.first;
                while(efa) {
                        /* normals default pointing up */
@@ -7016,7 +7107,7 @@ static void fill_mesh(EditMesh *em)
 
 }
 
-static int fill_mesh_exec(bContext *C, wmOperator *op)
+static int fill_mesh_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
@@ -7025,7 +7116,7 @@ static int fill_mesh_exec(bContext *C, wmOperator *op)
 
        BKE_mesh_end_editmesh(obedit->data, em);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        return OPERATOR_FINISHED;
@@ -7047,7 +7138,7 @@ void MESH_OT_fill(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
-static int beautify_fill_exec(bContext *C, wmOperator *op)
+static int beautify_fill_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
@@ -7056,7 +7147,7 @@ static int beautify_fill_exec(bContext *C, wmOperator *op)
 
        BKE_mesh_end_editmesh(obedit->data, em);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        return OPERATOR_FINISHED;
@@ -7077,16 +7168,194 @@ void MESH_OT_beautify_fill(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
+/* ********************** SORT FACES ******************* */
+
+static void permutate(void *list, int num, int size, int *index)
+{
+       void *buf;
+       int len;
+       int i;
+
+       len = num * size;
+
+       buf = MEM_mallocN(len, "permutate");
+       memcpy(buf, list, len);
+       
+       for (i = 0; i < num; i++) {
+               memcpy((char *)list + (i * size), (char *)buf + (index[i] * size), size);
+       }
+       MEM_freeN(buf);
+}
+
+/* sort faces on view axis */
+static float *face_sort_floats;
+static int float_sort(const void *v1, const void *v2)
+{
+       float x1, x2;
+       
+       x1 = face_sort_floats[((int *) v1)[0]];
+       x2 = face_sort_floats[((int *) v2)[0]];
+       
+       if( x1 > x2 ) return 1;
+       else if( x1 < x2 ) return -1;
+       return 0;
+}
+
+
+static int sort_faces_exec(bContext *C, wmOperator *op)
+{
+       RegionView3D *rv3d= ED_view3d_context_rv3d(C);
+       View3D *v3d= CTX_wm_view3d(C);
+       Object *ob= CTX_data_edit_object(C);
+       Scene *scene= CTX_data_scene(C);
+       Mesh *me;
+       CustomDataLayer *layer;
+       int i, *index;
+       int event;
+       float reverse = 1;
+       // XXX int ctrl= 0;
+       
+       if (!v3d) return OPERATOR_CANCELLED;
+
+       /* This operator work in Object Mode, not in edit mode.
+        * After talk with Campbell we agree that there is no point to port this to EditMesh right now.
+        * so for now, we just exit_editmode and enter_editmode at the end of this function.
+        */
+       ED_object_exit_editmode(C, EM_FREEDATA);
+
+       me= ob->data;
+       if(me->totface==0) {
+               ED_object_enter_editmode(C, 0);
+               return OPERATOR_FINISHED;
+       }
+
+       event= RNA_enum_get(op->ptr, "type");
+
+       // XXX
+       //if(ctrl)
+       //      reverse = -1;
+       
+       /* create index list */
+       index= (int *)MEM_mallocN(sizeof(int) * me->totface, "sort faces");
+       for (i = 0; i < me->totface; i++) {
+               index[i] = i;
+       }
+       
+       face_sort_floats = (float *) MEM_mallocN(sizeof(float) * me->totface, "sort faces float");
+
+       /* sort index list instead of faces itself 
+        * and apply this permutation to all face layers
+        */
+       if (event == 5) {
+               /* Random */
+               for(i=0; i<me->totface; i++) {
+                       face_sort_floats[i] = BLI_frand();
+               }
+               qsort(index, me->totface, sizeof(int), float_sort);             
+       } else {
+               MFace *mf;
+               float vec[3];
+               float mat[4][4];
+               float cur[3];
+               
+               if (event == 1)
+                       mul_m4_m4m4(mat, OBACT->obmat, rv3d->viewmat); /* apply the view matrix to the object matrix */
+               else if (event == 2) { /* sort from cursor */
+                       if( v3d && v3d->localvd ) {
+                               VECCOPY(cur, v3d->cursor);
+                       } else {
+                               VECCOPY(cur, scene->cursor);
+                       }
+                       invert_m4_m4(mat, OBACT->obmat);
+                       mul_m4_v3(mat, cur);
+               }
+               
+               mf= me->mface;
+
+               for(i=0; i<me->totface; i++, mf++) {
+                       if (event==3) {
+                               face_sort_floats[i] = ((float)mf->mat_nr)*reverse;
+                       } else if (event==4) {
+                               /*selected first*/
+                               if (mf->flag & ME_FACE_SEL)
+                                       face_sort_floats[i] = 0.0;
+                               else
+                                       face_sort_floats[i] = reverse;
+                       } else {
+                               /* find the faces center */
+                               add_v3_v3v3(vec, (me->mvert+mf->v1)->co, (me->mvert+mf->v2)->co);
+                               if (mf->v4) {
+                                       add_v3_v3(vec, (me->mvert+mf->v3)->co);
+                                       add_v3_v3(vec, (me->mvert+mf->v4)->co);
+                                       mul_v3_fl(vec, 0.25f);
+                               } else {
+                                       add_v3_v3(vec, (me->mvert+mf->v3)->co);
+                                       mul_v3_fl(vec, 1.0f/3.0f);
+                               } /* done */
+                               
+                               if (event == 1) { /* sort on view axis */
+                                       mul_m4_v3(mat, vec);
+                                       face_sort_floats[i] = vec[2] * reverse;
+                               } else if(event == 2) { /* distance from cursor*/
+                                       face_sort_floats[i] = len_v3v3(cur, vec) * reverse; /* back to front */
+                               }
+                       }
+               }
+               qsort(index, me->totface, sizeof(int), float_sort);
+       }
+       
+       MEM_freeN(face_sort_floats);
+       for(i = 0; i < me->fdata.totlayer; i++) {
+               layer = &me->fdata.layers[i];
+               permutate(layer->data, me->totface, CustomData_sizeof(layer->type), index);
+       }
+
+       MEM_freeN(index);
+       DAG_id_tag_update(ob->data, 0);
+
+       /* Return to editmode. */
+       ED_object_enter_editmode(C, 0);
+
+       return OPERATOR_FINISHED;
+}
+
+void MESH_OT_sort_faces(wmOperatorType *ot)
+{
+       static EnumPropertyItem type_items[]= {
+               { 1, "VIEW_AXIS", 0, "View Axis", "" },
+               { 2, "CURSOR_DISTANCE", 0, "Cursor Distance", "" },
+               { 3, "MATERIAL", 0, "Material", "" },
+               { 4, "SELECTED", 0, "Selected", "" },
+               { 5, "RANDOMIZE", 0, "Randomize", "" },
+               { 0, NULL, 0, NULL, NULL }};
+
+       /* identifiers */
+       ot->name= "Sort Faces"; // XXX (Ctrl to reverse)%t|
+       ot->description= "The faces of the active Mesh Object are sorted, based on the current view.";
+       ot->idname= "MESH_OT_sort_faces";
+
+       /* api callbacks */
+       ot->invoke= WM_menu_invoke;
+       ot->exec= sort_faces_exec;
+       ot->poll= ED_operator_editmesh;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* properties */
+       ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
+}
+
 /********************** Quad/Tri Operators *************************/
 
-static int quads_convert_to_tris_exec(bContext *C, wmOperator *op)
+static int quads_convert_to_tris_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
 
        convert_to_triface(em,0);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        BKE_mesh_end_editmesh(obedit->data, em);
@@ -7108,17 +7377,14 @@ void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
-static int tris_convert_to_quads_exec(bContext *C, wmOperator *op)
+static int tris_convert_to_quads_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
 
-       /* recalc outside so that joining doesn't create a hole */
-       EM_recalc_normal_direction(em, 0, 1);
-       
        join_triangles(em);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        BKE_mesh_end_editmesh(obedit->data, em);
@@ -7140,14 +7406,14 @@ void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
-static int edge_flip_exec(bContext *C, wmOperator *op)
+static int edge_flip_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
 
        edge_flip(em);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        BKE_mesh_end_editmesh(obedit->data, em);
@@ -7183,9 +7449,11 @@ static void mesh_set_smooth_faces(EditMesh *em, short smooth)
                        else efa->flag &= ~ME_SMOOTH;
                }
        }
+
+       recalc_editnormals(em);
 }
 
-static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *op)
+static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
@@ -7194,7 +7462,7 @@ static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *op)
 
        BKE_mesh_end_editmesh(obedit->data, em);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        return OPERATOR_FINISHED;
@@ -7215,14 +7483,14 @@ void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
-static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *op)
+static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
 
        mesh_set_smooth_faces(em, 0);
 
-       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       DAG_id_tag_update(obedit->data, 0);
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
        return OPERATOR_FINISHED;
@@ -7301,7 +7569,7 @@ void MESH_OT_select_axis(wmOperatorType *ot)
                {-1, "ALIGNED",  0, "Aligned Axis", ""},
                {0, NULL, 0, NULL, NULL}};
        
-       static EnumPropertyItem axis_items[] = {
+       static EnumPropertyItem axis_items_xyz[] = {
                {0, "X_AXIS", 0, "X Axis", ""},
                {1, "Y_AXIS", 0, "Y Axis", ""},
                {2, "Z_AXIS", 0, "Z Axis", ""},
@@ -7321,6 +7589,6 @@ void MESH_OT_select_axis(wmOperatorType *ot)
 
        /* properties */
        RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting");
-       RNA_def_enum(ot->srna, "axis", axis_items, 0, "Axis", "Select the axis to compare each vertex on");
+       RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on");
 }