Assorted fixes - compile + drivers:
[blender.git] / source / blender / editors / object / object_vgroup.c
index 2b17a6cbe5482cbc4a015c6a8a0812c2aee47d7f..d9c21a9c9a53356266b1eece0b913f14e3cdcf17 100644 (file)
@@ -28,6 +28,7 @@
  */
 
 #include <string.h>
+#include <math.h>
 
 #include "MEM_guardedalloc.h"
 
@@ -68,6 +69,7 @@
 #include "ED_view3d.h"
 
 #include "UI_interface.h"
+#include "UI_resources.h"
 
 #include "object_intern.h"
 
@@ -166,6 +168,33 @@ void ED_vgroup_data_create(ID *id)
        }
 }
 
+/* returns true if the id type supports weights */
+int ED_vgroup_give_array(ID *id, MDeformVert **dvert_arr, int *dvert_tot)
+{
+       if(id) {
+               switch(GS(id->name)) {
+                       case ID_ME:
+                       {
+                               Mesh *me = (Mesh *)id;
+                               *dvert_arr= me->dvert;
+                               *dvert_tot= me->totvert;
+                               return TRUE;
+                       }
+                       case ID_LT:
+                       {
+                               Lattice *lt= (Lattice *)id;
+                               lt= (lt->editlatt)? lt->editlatt: lt;
+                               *dvert_arr= lt->dvert;
+                               *dvert_tot= lt->pntsu*lt->pntsv*lt->pntsw;
+                               return TRUE;
+                       }
+               }
+       }
+
+       *dvert_arr= NULL;
+       *dvert_tot= 0;
+       return FALSE;
+}
 /* for mesh in object mode
    lattice can be in editmode */
 void ED_vgroup_nr_vert_remove(Object *ob, int def_nr, int vertnum)
@@ -182,25 +211,18 @@ void ED_vgroup_nr_vert_remove(Object *ob, int def_nr, int vertnum)
 
        MDeformWeight *newdw;
        MDeformVert *dvert= NULL;
-       int i;
+       int i, tot;
 
        /* get the deform vertices corresponding to the
         * vertnum
         */
-       if(ob->type==OB_MESH) {
-               if(((Mesh*)ob->data)->dvert)
-                       dvert = ((Mesh*)ob->data)->dvert + vertnum;
-       }
-       else if(ob->type==OB_LATTICE) {
-               Lattice *lt= vgroup_edit_lattice(ob);
-               
-               if(lt->dvert)
-                       dvert = lt->dvert + vertnum;
-       }
-       
+       ED_vgroup_give_array(ob->data, &dvert, &tot);
+
        if(dvert==NULL)
                return;
        
+       dvert+= vertnum;
+
        /* for all of the deform weights in the
         * deform vert
         */
@@ -250,23 +272,16 @@ void ED_vgroup_nr_vert_add(Object *ob, int def_nr, int vertnum, float weight, in
         */
        MDeformVert *dv= NULL;
        MDeformWeight *newdw;
-       int     i;
+       int     i, tot;
 
        /* get the vert */
-       if(ob->type==OB_MESH) {
-               if(((Mesh*)ob->data)->dvert)
-                       dv = ((Mesh*)ob->data)->dvert + vertnum;
-       }
-       else if(ob->type==OB_LATTICE) {
-               Lattice *lt= vgroup_edit_lattice(ob);
-               
-               if(lt->dvert)
-                       dv = lt->dvert + vertnum;
-       }
+       ED_vgroup_give_array(ob->data, &dv, &tot);
        
        if(dv==NULL)
                return;
        
+       dv+= vertnum;
+
        /* Lets first check to see if this vert is
         * already in the weight group -- if so
         * lets update it
@@ -341,23 +356,19 @@ void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight,
         */
        int     def_nr;
 
+       MDeformVert *dv= NULL;
+       int tot;
+
        /* get the deform group number, exit if
         * it can't be found
         */
        def_nr = get_defgroup_num(ob, dg);
        if(def_nr < 0) return;
 
-       /* if there's no deform verts then
-        * create some
+       /* if there's no deform verts then create some,
         */
-       if(ob->type==OB_MESH) {
-               if(!((Mesh*)ob->data)->dvert)
-                       ED_vgroup_data_create(ob->data);
-       }
-       else if(ob->type==OB_LATTICE) {
-               if(!((Lattice*)ob->data)->dvert)
-                       ED_vgroup_data_create(ob->data);
-       }
+       if(ED_vgroup_give_array(ob->data, &dv, &tot) && dv==NULL)
+               ED_vgroup_data_create(ob->data);
 
        /* call another function to do the work
         */
@@ -405,20 +416,23 @@ static float get_vert_def_nr(Object *ob, int def_nr, int vertnum)
                        eve= BLI_findlink(&me->edit_mesh->verts, vertnum);
                        if(!eve) return 0.0f;
                        dvert= CustomData_em_get(&me->edit_mesh->vdata, eve->data, CD_MDEFORMVERT);
+                       vertnum= 0;
                }
                else
-                       dvert = me->dvert + vertnum;
+                       dvert = me->dvert;
        }
        else if(ob->type==OB_LATTICE) {
                Lattice *lt= vgroup_edit_lattice(ob);
                
                if(lt->dvert)
-                       dvert = lt->dvert + vertnum;
+                       dvert = lt->dvert;
        }
        
        if(dvert==NULL)
                return 0.0f;
        
+       dvert += vertnum;
+       
        for(i=dvert->totweight-1 ; i>=0 ; i--)
                if(dvert->dw[i].def_nr == def_nr)
                        return dvert->dw[i].weight;
@@ -547,16 +561,7 @@ static void vgroup_duplicate(Object *ob)
        ob->actdef = BLI_countlist(&ob->defbase);
        icdg = (ob->actdef-1);
 
-       if(ob->type == OB_MESH) {
-               Mesh *me = get_mesh(ob);
-               dvert_array= me->dvert;
-               dvert_tot= me->totvert;
-       }
-       else if(ob->type == OB_LATTICE) {
-               Lattice *lt= (Lattice *)ob->data;
-               dvert_array= lt->dvert;
-               dvert_tot= lt->pntsu*lt->pntsv*lt->pntsw;
-       }
+       ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
        
        if(!dvert_array)
                return;
@@ -573,6 +578,331 @@ static void vgroup_duplicate(Object *ob)
        }
 }
 
+static void vgroup_normalize(Object *ob)
+{
+       bDeformGroup *dg;
+       MDeformWeight *dw;
+       MDeformVert *dvert, *dvert_array=NULL;
+       int i, def_nr, dvert_tot=0;
+
+       ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
+
+       dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
+
+       if(dg) {
+               float weight_max = 0.0f;
+
+               def_nr= ob->actdef-1;
+
+               for(i = 0; i < dvert_tot; i++) {
+                       dvert = dvert_array+i;
+                       dw = ED_vgroup_weight_get(dvert, def_nr);
+                       if(dw) {
+                               weight_max = MAX2(dw->weight, weight_max);
+                       }
+               }
+
+               if(weight_max > 0.0f) {
+                       for(i = 0; i < dvert_tot; i++) {
+                               dvert = dvert_array+i;
+                               dw = ED_vgroup_weight_get(dvert, def_nr);
+                               if(dw) {
+                                       dw->weight /= weight_max;
+                                       
+                                       /* incase of division errors with very low weights */
+                                       CLAMP(dw->weight, 0.0f, 1.0f);
+                               }
+                       }
+               }
+       }
+}
+
+static void vgroup_levels(Object *ob, float offset, float gain)
+{
+       bDeformGroup *dg;
+       MDeformWeight *dw;
+       MDeformVert *dvert, *dvert_array=NULL;
+       int i, def_nr, dvert_tot=0;
+       
+       ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
+       
+       dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
+       
+       if(dg) {
+               def_nr= ob->actdef-1;
+               
+               for(i = 0; i < dvert_tot; i++) {
+                       dvert = dvert_array+i;
+                       dw = ED_vgroup_weight_get(dvert, def_nr);
+                       if(dw) {
+                               dw->weight = gain * (dw->weight + offset);
+                               
+                               CLAMP(dw->weight, 0.0f, 1.0f);
+                       }
+               }
+       }
+}
+
+/* TODO - select between groups */
+static void vgroup_normalize_all(Object *ob, int lock_active)
+{
+       MDeformWeight *dw, *dw_act;
+       MDeformVert *dvert, *dvert_array=NULL;
+       int i, dvert_tot=0;
+       float tot_weight;
+
+       ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
+
+       if(dvert_array) {
+               if(lock_active) {
+                       int def_nr= ob->actdef-1;
+
+                       for(i = 0; i < dvert_tot; i++) {
+                               float lock_iweight= 1.0f;
+                               int j;
+
+                               tot_weight= 0.0f;
+                               dw_act= NULL;
+                               dvert = dvert_array+i;
+
+                               j= dvert->totweight;
+                               while(j--) {
+                                       dw= dvert->dw + j;
+
+                                       if(dw->def_nr==def_nr) {
+                                               dw_act= dw;
+                                               lock_iweight = (1.0f - dw_act->weight);
+                                       }
+                                       else {
+                                               tot_weight += dw->weight;
+                                       }
+                               }
+
+                               if(tot_weight) {
+                                       j= dvert->totweight;
+                                       while(j--) {
+                                               dw= dvert->dw + j;
+                                               if(dw == dw_act) {
+                                                       if (dvert->totweight==1) {
+                                                               dw_act->weight= 1.0f; /* no other weights, set to 1.0 */
+                                                       }
+                                               } else {
+                                                       if(dw->weight > 0.0f)
+                                                               dw->weight = (dw->weight / tot_weight) * lock_iweight;
+                                               }
+
+                                               /* incase of division errors with very low weights */
+                                               CLAMP(dw->weight, 0.0f, 1.0f);
+                                       }
+                               }
+                       }
+               }
+               else {
+                       for(i = 0; i < dvert_tot; i++) {
+                               int j;
+                               tot_weight= 0.0f;
+                               dvert = dvert_array+i;
+
+                               j= dvert->totweight;
+                               while(j--) {
+                                       dw= dvert->dw + j;
+                                       tot_weight += dw->weight;
+                               }
+
+                               if(tot_weight) {
+                                       j= dvert->totweight;
+                                       while(j--) {
+                                               dw= dvert->dw + j;
+                                               dw->weight /= tot_weight;
+
+                                               /* incase of division errors with very low weights */
+                                               CLAMP(dw->weight, 0.0f, 1.0f);
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+
+static void vgroup_invert(Object *ob, int auto_assign, int auto_remove)
+{
+       bDeformGroup *dg;
+       MDeformWeight *dw;
+       MDeformVert *dvert, *dvert_array=NULL;
+       int i, def_nr, dvert_tot=0;
+
+       ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
+
+       dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
+
+       if(dg) {
+               def_nr= ob->actdef-1;
+
+
+               for(i = 0; i < dvert_tot; i++) {
+                       dvert = dvert_array+i;
+
+                       if(auto_assign) {
+                               dw= ED_vgroup_weight_verify(dvert, def_nr);
+                       } else {
+                               dw= ED_vgroup_weight_get(dvert, def_nr);
+                       }
+
+                       if(dw) {
+                               dw->weight = 1.0f-dw->weight;
+
+                               if(auto_remove && dw->weight <= 0.0f) {
+                                       /* could have a faster function for this */
+                                       ED_vgroup_nr_vert_remove(ob, def_nr, i);
+                               }
+                       }
+               }
+       }
+}
+
+static void vgroup_blend(Object *ob)
+{
+       bDeformGroup *dg;
+       MDeformWeight *dw;
+       MDeformVert *dvert_array=NULL, *dvert;
+       int i, def_nr, dvert_tot=0;
+
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)ob->data));
+       // ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
+
+       if(em==NULL)
+               return;
+
+       dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
+
+       if(dg) {
+               int sel1, sel2;
+               int i1, i2;
+
+               EditEdge *eed;
+               EditVert *eve;
+               float *vg_weights;
+               float *vg_users;
+
+               def_nr= ob->actdef-1;
+
+               i= 0;
+               for(eve= em->verts.first; eve; eve= eve->next)
+                       eve->tmp.l= i++;
+
+               dvert_tot= i;
+
+               vg_weights= MEM_callocN(sizeof(float)*dvert_tot, "vgroup_blend_f");
+               vg_users= MEM_callocN(sizeof(int)*dvert_tot, "vgroup_blend_i");
+
+               for(eed= em->edges.first; eed; eed= eed->next) {
+                       sel1= eed->v1->f & SELECT;
+                       sel2= eed->v2->f & SELECT;
+
+                       if(sel1 != sel2) {
+                               /* i1 is always the selected one */
+                               if(sel1==TRUE && sel2==FALSE) {
+                                       i1= eed->v1->tmp.l;
+                                       i2= eed->v2->tmp.l;
+                                       eve= eed->v2;
+                               }
+                               else {
+                                       i2= eed->v1->tmp.l;
+                                       i1= eed->v2->tmp.l;
+                                       eve= eed->v1;
+                               }
+
+                               vg_users[i1]++;
+
+                               /* TODO, we may want object mode blending */
+                               if(em)  dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+                               else    dvert= dvert_array+i2;
+
+                               dw= ED_vgroup_weight_get(dvert, def_nr);
+
+                               if(dw) {
+                                       vg_weights[i1] += dw->weight;
+                               }
+                       }
+               }
+
+               i= 0;
+               for(eve= em->verts.first; eve; eve= eve->next) {
+                       if(eve->f & SELECT && vg_users[i] > 0) {
+                               /* TODO, we may want object mode blending */
+                               if(em)  dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+                               else    dvert= dvert_array+i;
+
+                               dw= ED_vgroup_weight_verify(dvert, def_nr);
+                               dw->weight= vg_weights[i] / (float)vg_users[i];
+                       }
+
+                       i++;
+               }
+               MEM_freeN(vg_weights);
+               MEM_freeN(vg_users);
+       }
+}
+
+static void vgroup_clean(Object *ob, float eul, int keep_single)
+{
+       bDeformGroup *dg;
+       MDeformWeight *dw;
+       MDeformVert *dvert, *dvert_array=NULL;
+       int i, def_nr, dvert_tot=0;
+
+       ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
+
+       /* only the active group */
+       dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
+       if(dg) {
+               def_nr= ob->actdef-1;
+
+               for(i = 0; i < dvert_tot; i++) {
+                       dvert = dvert_array+i;
+
+                       dw= ED_vgroup_weight_get(dvert, def_nr);
+
+                       if(dw) {
+                               if(dw->weight <= eul)
+                                       if(keep_single==FALSE || dvert->totweight > 1)
+                                               ED_vgroup_nr_vert_remove(ob, def_nr, i);
+                       }
+               }
+       }
+}
+
+static void vgroup_clean_all(Object *ob, float eul, int keep_single)
+{
+
+       MDeformWeight *dw;
+       MDeformVert *dvert, *dvert_array=NULL;
+       int i, dvert_tot=0;
+
+       ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
+
+       if(dvert_array) {
+               for(i = 0; i < dvert_tot; i++) {
+                       int j;
+                       dvert = dvert_array+i;
+                       j= dvert->totweight;
+
+                       while(j--) {
+
+                               if(keep_single && dvert->totweight == 1)
+                                       break;
+
+                               dw= dvert->dw + j;
+
+                               if(dw->weight <= eul)
+                                       ED_vgroup_nr_vert_remove(ob, dw->def_nr, i);
+
+                       }
+               }
+       }
+}
+
 static void vgroup_delete_update_users(Object *ob, int id)
 {
        ExplodeModifierData *emd;
@@ -638,22 +968,13 @@ static void vgroup_delete_object_mode(Object *ob)
        bDeformGroup *dg;
        MDeformVert *dvert, *dvert_array=NULL;
        int i, e, dvert_tot=0;
-
-       if(ob->type == OB_MESH) {
-               Mesh *me = get_mesh(ob);
-               dvert_array= me->dvert;
-               dvert_tot= me->totvert;
-       }
-       else if(ob->type == OB_LATTICE) {
-               Lattice *lt= (Lattice *)ob->data;
-               dvert_array= lt->dvert;
-               dvert_tot= lt->pntsu*lt->pntsv*lt->pntsw;
-       }
        
        dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
        if(!dg)
                return;
        
+       ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
+
        if(dvert_array) {
                for(i = 0; i < dvert_tot; i++) {
                        dvert = dvert_array + i;
@@ -873,6 +1194,8 @@ static void vgroup_assign_verts(Object *ob, float weight)
        int     i, done;
 
        dg=BLI_findlink(&ob->defbase, ob->actdef-1);
+       if(!dg)
+               return;
 
        if(ob->type == OB_MESH) {
                Mesh *me= ob->data;
@@ -1172,6 +1495,195 @@ void OBJECT_OT_vertex_group_copy(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
+static int vertex_group_levels_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       
+       float offset= RNA_float_get(op->ptr,"offset");
+       float gain= RNA_float_get(op->ptr,"gain");
+       
+       vgroup_levels(ob, offset, gain);
+       
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+       
+       return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_vertex_group_levels(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Vertex Group Levels";
+       ot->idname= "OBJECT_OT_vertex_group_levels";
+       
+       /* api callbacks */
+       ot->poll= vertex_group_poll;
+       ot->exec= vertex_group_levels_exec;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       RNA_def_float(ot->srna, "offset", 0.f, -1.0, 1.0, "Offset", "Value to add to weights.", -1.0f, 1.f);
+       RNA_def_float(ot->srna, "gain", 1.f, 0.f, FLT_MAX, "Gain", "Value to multiply weights by.", 0.0f, 10.f);
+}
+
+static int vertex_group_normalize_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+
+       vgroup_normalize(ob);
+
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+
+       return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Normalize Vertex Group";
+       ot->idname= "OBJECT_OT_vertex_group_normalize";
+
+       /* api callbacks */
+       ot->poll= vertex_group_poll;
+       ot->exec= vertex_group_normalize_exec;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       int lock_active= RNA_boolean_get(op->ptr,"lock_active");
+
+       vgroup_normalize_all(ob, lock_active);
+
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+
+       return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Normalize All Vertex Groups";
+       ot->idname= "OBJECT_OT_vertex_group_normalize_all";
+
+       /* api callbacks */
+       ot->poll= vertex_group_poll;
+       ot->exec= vertex_group_normalize_all_exec;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       RNA_def_boolean(ot->srna, "lock_active", TRUE, "Lock Active", "Keep the values of the active group while normalizing others.");
+}
+
+static int vertex_group_invert_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       int auto_assign= RNA_boolean_get(op->ptr,"auto_assign");
+       int auto_remove= RNA_boolean_get(op->ptr,"auto_remove");
+
+       vgroup_invert(ob, auto_assign, auto_remove);
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+
+       return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Invert Vertex Group";
+       ot->idname= "OBJECT_OT_vertex_group_invert";
+
+       /* api callbacks */
+       ot->poll= vertex_group_poll;
+       ot->exec= vertex_group_invert_exec;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       RNA_def_boolean(ot->srna, "auto_assign", TRUE, "Add Weights", "Add verts from groups that have zero weight before inverting.");
+       RNA_def_boolean(ot->srna, "auto_remove", TRUE, "Remove Weights", "Remove verts from groups that have zero weight after inverting.");
+}
+
+
+static int vertex_group_blend_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+
+       vgroup_blend(ob);
+
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+
+       return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_vertex_group_blend(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Blend Vertex Group";
+       ot->idname= "OBJECT_OT_vertex_group_blend";
+       ot->description= "";
+
+       /* api callbacks */
+       ot->poll= vertex_group_poll;
+       ot->exec= vertex_group_blend_exec;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
+static int vertex_group_clean_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+
+       float limit= RNA_float_get(op->ptr,"limit");
+       int all_groups= RNA_boolean_get(op->ptr,"all_groups");
+       int keep_single= RNA_boolean_get(op->ptr,"keep_single");
+
+       if(all_groups)  vgroup_clean_all(ob, limit, keep_single);
+       else                    vgroup_clean(ob, limit, keep_single);
+
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+
+       return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_vertex_group_clean(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Clean Vertex Group";
+       ot->idname= "OBJECT_OT_vertex_group_clean";
+       ot->description= "Remove Vertex Group assignments which aren't required.";
+
+       /* api callbacks */
+       ot->poll= vertex_group_poll;
+       ot->exec= vertex_group_clean_exec;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, 1.0, "Limit", "Remove weights under this limit.", 0.001f, 0.99f);
+       RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Clean all vertex groups.");
+       RNA_def_boolean(ot->srna, "keep_single", FALSE, "Keep Single", "Keep verts assigned to at least one group when cleaning.");
+}
+
+
 static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *op)
 {
        Scene *scene= CTX_data_scene(C);
@@ -1203,6 +1715,7 @@ void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot)
        /* identifiers */
        ot->name= "Copy Vertex Group to Linked";
        ot->idname= "OBJECT_OT_vertex_group_copy_to_linked";
+       ot->description= "Copy Vertex Groups to all users of the same Geometry data.";
 
        /* api callbacks */
        ot->poll= vertex_group_poll;
@@ -1230,24 +1743,24 @@ static int set_active_group_exec(bContext *C, wmOperator *op)
 
 static EnumPropertyItem *vgroup_itemf(bContext *C, PointerRNA *ptr, int *free)
 {      
-       Object *ob;
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
        EnumPropertyItem tmp = {0, "", 0, "", ""};
        EnumPropertyItem *item= NULL;
        bDeformGroup *def;
        int a, totitem= 0;
        
-       if(!C || !(ob = CTX_data_pointer_get_type(C, "object", &RNA_Object).data)) /* needed for docs */
+       if(!ob)
                return vgroup_items;
        
        for(a=0, def=ob->defbase.first; def; def=def->next, a++) {
                tmp.value= a;
+               tmp.icon= ICON_GROUP_VERTEX;
                tmp.identifier= def->name;
                tmp.name= def->name;
                RNA_enum_item_add(&item, &totitem, &tmp);
        }
 
        RNA_enum_item_end(&item, &totitem);
-
        *free= 1;
 
        return item;
@@ -1260,6 +1773,7 @@ void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
        /* identifiers */
        ot->name= "Set Active Vertex Group";
        ot->idname= "OBJECT_OT_vertex_group_set_active";
+       ot->description= "Set the active vertex group.";
 
        /* api callbacks */
        ot->poll= vertex_group_poll;
@@ -1274,48 +1788,3 @@ void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
        RNA_def_enum_funcs(prop, vgroup_itemf);
 }
 
-static int vertex_group_menu_exec(bContext *C, wmOperator *op)
-{
-       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
-       uiPopupMenu *pup;
-       uiLayout *layout;
-
-       pup= uiPupMenuBegin(C, "Vertex Groups", 0);
-       layout= uiPupMenuLayout(pup);
-       uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
-
-       if(vgroup_object_in_edit_mode(ob)) {
-               uiItemBooleanO(layout, "Assign to New Group", 0, "OBJECT_OT_vertex_group_assign", "new", 1);
-
-               if(BLI_countlist(&ob->defbase) && ob->actdef) {
-                       uiItemO(layout, "Assign to Group", 0, "OBJECT_OT_vertex_group_assign");
-                       uiItemO(layout, "Remove from Group", 0, "OBJECT_OT_vertex_group_remove_from");
-                       uiItemBooleanO(layout, "Remove from All", 0, "OBJECT_OT_vertex_group_remove_from", "all", 1);
-               }
-       }
-
-       if(BLI_countlist(&ob->defbase) && ob->actdef) {
-               if(vgroup_object_in_edit_mode(ob))
-                       uiItemS(layout);
-
-               uiItemO(layout, "Set Active Group", 0, "OBJECT_OT_vertex_group_set_active");
-               uiItemO(layout, "Remove Group", 0, "OBJECT_OT_vertex_group_remove");
-               uiItemBooleanO(layout, "Remove All Groups", 0, "OBJECT_OT_vertex_group_remove", "all", 1);
-       }
-
-       uiPupMenuEnd(C, pup);
-
-       return OPERATOR_FINISHED;
-}
-
-void OBJECT_OT_vertex_group_menu(wmOperatorType *ot)
-{
-       /* identifiers */
-       ot->name= "Vertex Group Menu";
-       ot->idname= "OBJECT_OT_vertex_group_menu";
-
-       /* api callbacks */
-       ot->poll= vertex_group_poll;
-       ot->exec= vertex_group_menu_exec;
-}
-