Assorted fixes - compile + drivers:
[blender.git] / source / blender / editors / object / object_vgroup.c
index 3d3e29bcc228f5efc4677c1cc0a27d40f179bed5..d9c21a9c9a53356266b1eece0b913f14e3cdcf17 100644 (file)
  * Contributor(s): none yet.
  *
  * ***** END GPL LICENSE BLOCK *****
- * Creator-specific support for vertex deformation groups
- * Added: apply deform function (ton)
  */
 
 #include <string.h>
+#include <math.h>
 
 #include "MEM_guardedalloc.h"
 
 #include "BKE_global.h"
 #include "BKE_lattice.h"
 #include "BKE_mesh.h"
+#include "BKE_paint.h"
 #include "BKE_utildefines.h"
 
 #include "RNA_access.h"
+#include "RNA_define.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
 #include "ED_mesh.h"
 #include "ED_view3d.h"
 
+#include "UI_interface.h"
+#include "UI_resources.h"
+
 #include "object_intern.h"
 
-/* XXX */
-static void BIF_undo_push() {}
-static void error() {}
+/************************ Exported Functions **********************/
 
-static Lattice *def_get_lattice(Object *ob)
+static Lattice *vgroup_edit_lattice(Object *ob)
 {
        if(ob->type==OB_LATTICE) {
                Lattice *lt= ob->data;
-               if(lt->editlatt)
-                       return lt->editlatt;
-               return lt;
-       }
-       return NULL;
-}
-
-/* only in editmode */
-void sel_verts_defgroup (Object *obedit, int select)
-{
-       EditVert *eve;
-       Object *ob;
-       int i;
-       MDeformVert *dvert;
-
-       ob= obedit;
-
-       if (!ob)
-               return;
-
-       switch (ob->type){
-       case OB_MESH:
-       {
-               Mesh *me= ob->data;
-               EditMesh *em = BKE_mesh_get_editmesh(me);
-
-               for (eve=em->verts.first; eve; eve=eve->next){
-                       dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
-
-                       if (dvert && dvert->totweight){
-                               for (i=0; i<dvert->totweight; i++){
-                                       if (dvert->dw[i].def_nr == (ob->actdef-1)){
-                                               if (select) eve->f |= SELECT;
-                                               else eve->f &= ~SELECT;
-                                               
-                                               break;
-                                       }
-                               }
-                       }
-               }
-               /* this has to be called, because this function operates on vertices only */
-               if(select) EM_select_flush(em); // vertices to edges/faces
-               else EM_deselect_flush(em);
-
-               BKE_mesh_end_editmesh(me, em);
+               return (lt->editlatt)? lt->editlatt: lt;
        }
-               break;
-       case OB_LATTICE:
-       {
-               Lattice *lt= def_get_lattice(ob);
-               
-               if(lt->dvert) {
-                       BPoint *bp;
-                       int a, tot;
-                       
-                       dvert= lt->dvert;
 
-                       tot= lt->pntsu*lt->pntsv*lt->pntsw;
-                       for(a=0, bp= lt->def; a<tot; a++, bp++, dvert++) {
-                               for (i=0; i<dvert->totweight; i++){
-                                       if (dvert->dw[i].def_nr == (ob->actdef-1)) {
-                                               if(select) bp->f1 |= SELECT;
-                                               else bp->f1 &= ~SELECT;
-                                               
-                                               break;
-                                       }
-                               }
-                       }
-               }
-       }
-               break;
-               
-       default:
-               break;
-       }
+       return NULL;
 }
 
 /* check if deform vertex has defgroup index */
-MDeformWeight *get_defweight (MDeformVert *dv, int defgroup)
+MDeformWeight *ED_vgroup_weight_get(MDeformVert *dv, int defgroup)
 {
        int i;
        
-       if (!dv || defgroup<0)
+       if(!dv || defgroup<0)
                return NULL;
        
-       for (i=0; i<dv->totweight; i++){
-               if (dv->dw[i].def_nr == defgroup)
+       for(i=0; i<dv->totweight; i++)
+               if(dv->dw[i].def_nr == defgroup)
                        return dv->dw+i;
-       }
+
        return NULL;
 }
 
-/* Ensures that mv has a deform weight entry for
-   the specified defweight group */
+/* Ensures that mv has a deform weight entry for the specified defweight group */
 /* Note this function is mirrored in editmesh_tools.c, for use for editvertices */
-MDeformWeight *verify_defweight (MDeformVert *dv, int defgroup)
+MDeformWeight *ED_vgroup_weight_verify(MDeformVert *dv, int defgroup)
 {
        MDeformWeight *newdw;
 
        /* do this check always, this function is used to check for it */
-       if (!dv || defgroup<0)
+       if(!dv || defgroup<0)
                return NULL;
        
-       newdw = get_defweight (dv, defgroup);
-       if (newdw)
+       newdw = ED_vgroup_weight_get(dv, defgroup);
+       if(newdw)
                return newdw;
        
-       newdw = MEM_callocN (sizeof(MDeformWeight)*(dv->totweight+1), "deformWeight");
-       if (dv->dw){
-               memcpy (newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
-               MEM_freeN (dv->dw);
+       newdw = MEM_callocN(sizeof(MDeformWeight)*(dv->totweight+1), "deformWeight");
+       if(dv->dw) {
+               memcpy(newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
+               MEM_freeN(dv->dw);
        }
        dv->dw=newdw;
        
@@ -200,16 +130,16 @@ MDeformWeight *verify_defweight (MDeformVert *dv, int defgroup)
        return dv->dw+(dv->totweight-1);
 }
 
-bDeformGroup *add_defgroup_name (Object *ob, char *name)
+bDeformGroup *ED_vgroup_add_name(Object *ob, char *name)
 {
-       bDeformGroup    *defgroup;
+       bDeformGroup *defgroup;
        
-       if (!ob)
+       if(!ob)
                return NULL;
        
-       defgroup = MEM_callocN (sizeof(bDeformGroup), "add deformGroup");
+       defgroup = MEM_callocN(sizeof(bDeformGroup), "add deformGroup");
 
-       BLI_strncpy (defgroup->name, name, 32);
+       BLI_strncpy(defgroup->name, name, 32);
 
        BLI_addtail(&ob->defbase, defgroup);
        unique_vertexgroup_name(defgroup, ob);
@@ -219,899 +149,1164 @@ bDeformGroup *add_defgroup_name (Object *ob, char *name)
        return defgroup;
 }
 
-void add_defgroup (Object *ob) 
+bDeformGroup *ED_vgroup_add(Object *ob) 
 {
-       add_defgroup_name (ob, "Group");
+       return ED_vgroup_add_name(ob, "Group");
 }
 
-
-void duplicate_defgroup ( Object *ob )
+void ED_vgroup_data_create(ID *id)
 {
-       bDeformGroup *dg, *cdg;
-       char name[32], s[32];
-       MDeformWeight *org, *cpy;
-       MDeformVert *dvert, *dvert_array=NULL;
-       int i, idg, icdg, dvert_tot=0;
-
-       if (ob->type != OB_MESH && ob->type != OB_LATTICE)
-               return;
-
-       dg = BLI_findlink (&ob->defbase, (ob->actdef-1));
-       if (!dg)
-               return;
-       
-       if (strstr(dg->name, "_copy")) {
-               BLI_strncpy (name, dg->name, 32); /* will be renamed _copy.001... etc */
-       } else {
-               BLI_snprintf (name, 32, "%s_copy", dg->name);
-               while (get_named_vertexgroup (ob, name)) {
-                       if ((strlen (name) + 6) > 32) {
-                               error ("Error: the name for the new group is > 32 characters");
-                               return;
-                       }
-                       strcpy (s, name);
-                       BLI_snprintf (name, 32, "%s_copy", s);
-               }
-       }               
+       /* create deform verts */
 
-       cdg = copy_defgroup (dg);
-       strcpy (cdg->name, name);
-       unique_vertexgroup_name(cdg, ob);
-       
-       BLI_addtail (&ob->defbase, cdg);
-
-       idg = (ob->actdef-1);
-       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;
+       if(GS(id->name)==ID_ME) {
+               Mesh *me= (Mesh *)id;
+               me->dvert= CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, 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;
+       else if(GS(id->name)==ID_LT) {
+               Lattice *lt= (Lattice *)id;
+               lt->dvert= MEM_callocN(sizeof(MDeformVert)*lt->pntsu*lt->pntsv*lt->pntsw, "lattice deformVert");
        }
-       
-       if (!dvert_array)
-               return;
+}
 
-       for (i = 0; i < dvert_tot; i++) {
-               dvert = dvert_array+i;
-               org = get_defweight (dvert, idg);
-               if (org) {
-                       float weight = org->weight;
-                       /* verify_defweight re-allocs org so need to store the weight first */
-                       cpy = verify_defweight (dvert, icdg);
-                       cpy->weight = weight;
+/* 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;
+                       }
                }
        }
-}
 
-static void del_defgroup_update_users(Object *ob, int id)
+       *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)
 {
-       ExplodeModifierData *emd;
-       ModifierData *md;
-       ParticleSystem *psys;
-       ClothModifierData *clmd;
-       ClothSimSettings *clsim;
-       int a;
-
-       /* these cases don't use names to refer to vertex groups, so when
-        * they get deleted the numbers get out of sync, this corrects that */
-
-       if(ob->soft) {
-               if(ob->soft->vertgroup == id)
-                       ob->soft->vertgroup= 0;
-               else if(ob->soft->vertgroup > id)
-                       ob->soft->vertgroup--;
-       }
+       /* This routine removes the vertex from the deform
+        * group with number def_nr.
+        *
+        * This routine is meant to be fast, so it is the
+        * responsibility of the calling routine to:
+        *   a) test whether ob is non-NULL
+        *   b) test whether ob is a mesh
+        *   c) calculate def_nr
+        */
 
-       for(md=ob->modifiers.first; md; md=md->next) {
-               if(md->type == eModifierType_Explode) {
-                       emd= (ExplodeModifierData*)md;
+       MDeformWeight *newdw;
+       MDeformVert *dvert= NULL;
+       int i, tot;
 
-                       if(emd->vgroup == id)
-                               emd->vgroup= 0;
-                       else if(emd->vgroup > id)
-                               emd->vgroup--;
-               }
-               else if(md->type == eModifierType_Cloth) {
-                       clmd= (ClothModifierData*)md;
-                       clsim= clmd->sim_parms;
+       /* get the deform vertices corresponding to the
+        * vertnum
+        */
+       ED_vgroup_give_array(ob->data, &dvert, &tot);
 
-                       if(clsim) {
-                               if(clsim->vgroup_mass == id)
-                                       clsim->vgroup_mass= 0;
-                               else if(clsim->vgroup_mass > id)
-                                       clsim->vgroup_mass--;
+       if(dvert==NULL)
+               return;
+       
+       dvert+= vertnum;
 
-                               if(clsim->vgroup_bend == id)
-                                       clsim->vgroup_bend= 0;
-                               else if(clsim->vgroup_bend > id)
-                                       clsim->vgroup_bend--;
+       /* for all of the deform weights in the
+        * deform vert
+        */
+       for(i=dvert->totweight - 1 ; i>=0 ; i--){
 
-                               if(clsim->vgroup_struct == id)
-                                       clsim->vgroup_struct= 0;
-                               else if(clsim->vgroup_struct > id)
-                                       clsim->vgroup_struct--;
+               /* if the def_nr is the same as the one
+                * for our weight group then remove it
+                * from this deform vert.
+                */
+               if(dvert->dw[i].def_nr == def_nr) {
+                       dvert->totweight--;
+        
+                       /* if there are still other deform weights
+                        * attached to this vert then remove this
+                        * deform weight, and reshuffle the others
+                        */
+                       if(dvert->totweight) {
+                               newdw = MEM_mallocN(sizeof(MDeformWeight)*(dvert->totweight), 
+                                                                        "deformWeight");
+                               if(dvert->dw){
+                                       memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*i);
+                                       memcpy(newdw+i, dvert->dw+i+1, 
+                                                       sizeof(MDeformWeight)*(dvert->totweight-i));
+                                       MEM_freeN(dvert->dw);
+                               }
+                               dvert->dw=newdw;
+                       }
+                       /* if there are no other deform weights
+                        * left then just remove the deform weight
+                        */
+                       else {
+                               MEM_freeN(dvert->dw);
+                               dvert->dw = NULL;
+                               break;
                        }
                }
        }
 
-       for(psys=ob->particlesystem.first; psys; psys=psys->next) {
-               for(a=0; a<PSYS_TOT_VG; a++)
-                       if(psys->vgroup[a] == id)
-                               psys->vgroup[a]= 0;
-                       else if(psys->vgroup[a] > id)
-                               psys->vgroup[a]--;
-       }
 }
 
-void del_defgroup_in_object_mode ( Object *ob )
+/* for Mesh in Object mode */
+/* allows editmode for Lattice */
+void ED_vgroup_nr_vert_add(Object *ob, int def_nr, int vertnum, float weight, int assignmode)
 {
-       bDeformGroup *dg;
-       MDeformVert *dvert, *dvert_array=NULL;
-       int i, e, dvert_tot=0;
-
-       if ((!ob) || (ob->type != OB_MESH && ob->type != OB_LATTICE))
-               return;
+       /* add the vert to the deform group with the
+        * specified number
+        */
+       MDeformVert *dv= NULL;
+       MDeformWeight *newdw;
+       int     i, tot;
 
-       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;
-       }
+       /* get the vert */
+       ED_vgroup_give_array(ob->data, &dv, &tot);
        
-       dg = BLI_findlink (&ob->defbase, (ob->actdef-1));
-       if (!dg)
+       if(dv==NULL)
                return;
        
-       if (dvert_array) {
-               for (i = 0; i < dvert_tot; i++) {
-                       dvert = dvert_array + i;
-                       if (dvert) {
-                               if (get_defweight (dvert, (ob->actdef-1)))
-                                       remove_vert_defgroup (ob, dg, i);
-                       }
-               }
+       dv+= vertnum;
 
-               for (i = 0; i < dvert_tot; i++) {
-                       dvert = dvert_array+i;
-                       if (dvert) {
-                               for (e = 0; e < dvert->totweight; e++) {
-                                       if (dvert->dw[e].def_nr > (ob->actdef-1))
-                                               dvert->dw[e].def_nr--;
-                               }
+       /* Lets first check to see if this vert is
+        * already in the weight group -- if so
+        * lets update it
+        */
+       for(i=0; i<dv->totweight; i++){
+               
+               /* if this weight cooresponds to the
+                * deform group, then add it using
+                * the assign mode provided
+                */
+               if(dv->dw[i].def_nr == def_nr){
+                       
+                       switch(assignmode) {
+                       case WEIGHT_REPLACE:
+                               dv->dw[i].weight=weight;
+                               break;
+                       case WEIGHT_ADD:
+                               dv->dw[i].weight+=weight;
+                               if(dv->dw[i].weight >= 1.0)
+                                       dv->dw[i].weight = 1.0;
+                               break;
+                       case WEIGHT_SUBTRACT:
+                               dv->dw[i].weight-=weight;
+                               /* if the weight is zero or less then
+                                * remove the vert from the deform group
+                                */
+                               if(dv->dw[i].weight <= 0.0)
+                                       ED_vgroup_nr_vert_remove(ob, def_nr, vertnum);
+                               break;
                        }
+                       return;
                }
        }
 
-       del_defgroup_update_users(ob, ob->actdef);
-
-       /* Update the active deform index if necessary */
-       if (ob->actdef == BLI_countlist(&ob->defbase))
-               ob->actdef--;
-  
-       /* Remove the group */
-       BLI_freelinkN (&ob->defbase, dg);
-}
-
-void del_defgroup (Object *ob)
-{
-       bDeformGroup    *defgroup;
-       int                             i;
-
-       if (!ob)
-               return;
-
-       if (!ob->actdef)
-               return;
+       /* if the vert wasn't in the deform group then
+        * we must take a different form of action ...
+        */
 
-       defgroup = BLI_findlink(&ob->defbase, ob->actdef-1);
-       if (!defgroup)
+       switch(assignmode) {
+       case WEIGHT_SUBTRACT:
+               /* if we are subtracting then we don't
+                * need to do anything
+                */
                return;
 
-       /* Make sure that no verts are using this group */
-       remove_verts_defgroup(ob, 1);
-
-       /* Make sure that any verts with higher indices are adjusted accordingly */
+       case WEIGHT_REPLACE:
+       case WEIGHT_ADD:
+               /* if we are doing an additive assignment, then
+                * we need to create the deform weight
+                */
+               newdw = MEM_callocN(sizeof(MDeformWeight)*(dv->totweight+1), 
+                                                        "deformWeight");
+               if(dv->dw){
+                       memcpy(newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
+                       MEM_freeN(dv->dw);
+               }
+               dv->dw=newdw;
+    
+               dv->dw[dv->totweight].weight=weight;
+               dv->dw[dv->totweight].def_nr=def_nr;
+    
+               dv->totweight++;
+               break;
+       }
+}
+
+/* called while not in editmode */
+void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
+{
+       /* add the vert to the deform group with the
+        * specified assign mode
+        */
+       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(ED_vgroup_give_array(ob->data, &dv, &tot) && dv==NULL)
+               ED_vgroup_data_create(ob->data);
+
+       /* call another function to do the work
+        */
+       ED_vgroup_nr_vert_add(ob, def_nr, vertnum, weight, assignmode);
+}
+
+/* mesh object mode, lattice can be in editmode */
+void ED_vgroup_vert_remove(Object *ob, bDeformGroup    *dg, int vertnum)
+{
+       /* This routine removes the vertex from the specified
+        * deform group.
+        */
+
+       int def_nr;
+
+       /* if the object is NULL abort
+        */
+       if(!ob)
+               return;
+
+       /* get the deform number that cooresponds
+        * to this deform group, and abort if it
+        * can not be found.
+        */
+       def_nr = get_defgroup_num(ob, dg);
+       if(def_nr < 0) return;
+
+       /* call another routine to do the work
+        */
+       ED_vgroup_nr_vert_remove(ob, def_nr, vertnum);
+}
+
+static float get_vert_def_nr(Object *ob, int def_nr, int vertnum)
+{
+       MDeformVert *dvert= NULL;
+       EditVert *eve;
+       Mesh *me;
+       int i;
+
+       /* get the deform vertices corresponding to the vertnum */
        if(ob->type==OB_MESH) {
+               me= ob->data;
+
+               if(me->edit_mesh) {
+                       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;
+       }
+       else if(ob->type==OB_LATTICE) {
+               Lattice *lt= vgroup_edit_lattice(ob);
+               
+               if(lt->dvert)
+                       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;
+
+       return 0.0f;
+}
+
+float ED_vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum)
+{
+       int def_nr;
+
+       if(!ob) return 0.0f;
+
+       def_nr = get_defgroup_num(ob, dg);
+       if(def_nr < 0) return 0.0f;
+
+       return get_vert_def_nr(ob, def_nr, vertnum);
+}
+
+void ED_vgroup_select_by_name(Object *ob, char *name)
+{
+       bDeformGroup *curdef;
+       int actdef= 1;
+       
+       for(curdef = ob->defbase.first; curdef; curdef=curdef->next, actdef++){
+               if(!strcmp(curdef->name, name)) {
+                       ob->actdef= actdef;
+                       return;
+               }
+       }
+
+       ob->actdef=0;   // this signals on painting to create a new one, if a bone in posemode is selected */
+}
+
+/********************** Operator Implementations *********************/
+
+/* only in editmode */
+static void vgroup_select_verts(Object *ob, int select)
+{
+       EditVert *eve;
+       MDeformVert *dvert;
+       int i;
+
+       if(ob->type == OB_MESH) {
                Mesh *me= ob->data;
                EditMesh *em = BKE_mesh_get_editmesh(me);
-               EditVert *eve;
-               MDeformVert *dvert;
-               
-               for (eve=em->verts.first; eve; eve=eve->next){
+
+               for(eve=em->verts.first; eve; eve=eve->next){
                        dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
 
-                       if (dvert)
-                               for (i=0; i<dvert->totweight; i++)
-                                       if (dvert->dw[i].def_nr > (ob->actdef-1))
-                                               dvert->dw[i].def_nr--;
+                       if(dvert && dvert->totweight){
+                               for(i=0; i<dvert->totweight; i++){
+                                       if(dvert->dw[i].def_nr == (ob->actdef-1)){
+                                               if(select) eve->f |= SELECT;
+                                               else eve->f &= ~SELECT;
+                                               
+                                               break;
+                                       }
+                               }
+                       }
                }
+               /* this has to be called, because this function operates on vertices only */
+               if(select) EM_select_flush(em); // vertices to edges/faces
+               else EM_deselect_flush(em);
+
                BKE_mesh_end_editmesh(me, em);
        }
-       else if(ob->type==OB_LATTICE) {
-               Lattice *lt= def_get_lattice(ob);
-               BPoint *bp;
-               MDeformVert *dvert= lt->dvert;
-               int a, tot;
+       else if(ob->type == OB_LATTICE) {
+               Lattice *lt= vgroup_edit_lattice(ob);
                
-               if (dvert) {
+               if(lt->dvert) {
+                       BPoint *bp;
+                       int a, tot;
+                       
+                       dvert= lt->dvert;
+
                        tot= lt->pntsu*lt->pntsv*lt->pntsw;
                        for(a=0, bp= lt->def; a<tot; a++, bp++, dvert++) {
-                               for (i=0; i<dvert->totweight; i++){
-                                       if (dvert->dw[i].def_nr > (ob->actdef-1))
-                                               dvert->dw[i].def_nr--;
+                               for(i=0; i<dvert->totweight; i++){
+                                       if(dvert->dw[i].def_nr == (ob->actdef-1)) {
+                                               if(select) bp->f1 |= SELECT;
+                                               else bp->f1 &= ~SELECT;
+                                               
+                                               break;
+                                       }
                                }
                        }
                }
        }
+}
 
-       del_defgroup_update_users(ob, ob->actdef);
+static void vgroup_duplicate(Object *ob)
+{
+       bDeformGroup *dg, *cdg;
+       char name[32], s[32];
+       MDeformWeight *org, *cpy;
+       MDeformVert *dvert, *dvert_array=NULL;
+       int i, idg, icdg, dvert_tot=0;
 
-       /* Update the active deform index if necessary */
-       if (ob->actdef==BLI_countlist(&ob->defbase))
-               ob->actdef--;
+       dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
+       if(!dg)
+               return;
        
-       /* Remove the group */
-       BLI_freelinkN (&ob->defbase, defgroup);
+       if(strstr(dg->name, "_copy")) {
+               BLI_strncpy(name, dg->name, 32); /* will be renamed _copy.001... etc */
+       }
+       else {
+               BLI_snprintf(name, 32, "%s_copy", dg->name);
+               while(get_named_vertexgroup(ob, name)) {
+                       if((strlen(name) + 6) > 32) {
+                               printf("Internal error: the name for the new vertex group is > 32 characters");
+                               return;
+                       }
+                       strcpy(s, name);
+                       BLI_snprintf(name, 32, "%s_copy", s);
+               }
+       }               
+
+       cdg = copy_defgroup(dg);
+       strcpy(cdg->name, name);
+       unique_vertexgroup_name(cdg, ob);
        
-       /* remove all dverts */
-       if(ob->actdef==0) {
-               if(ob->type==OB_MESH) {
-                       Mesh *me= ob->data;
-                       CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
-                       me->dvert= NULL;
+       BLI_addtail(&ob->defbase, cdg);
+
+       idg = (ob->actdef-1);
+       ob->actdef = BLI_countlist(&ob->defbase);
+       icdg = (ob->actdef-1);
+
+       ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
+       
+       if(!dvert_array)
+               return;
+
+       for(i = 0; i < dvert_tot; i++) {
+               dvert = dvert_array+i;
+               org = ED_vgroup_weight_get(dvert, idg);
+               if(org) {
+                       float weight = org->weight;
+                       /* ED_vgroup_weight_verify re-allocs org so need to store the weight first */
+                       cpy = ED_vgroup_weight_verify(dvert, icdg);
+                       cpy->weight = weight;
                }
-               else if(ob->type==OB_LATTICE) {
-                       Lattice *lt= def_get_lattice(ob);
-                       if (lt->dvert) {
-                               MEM_freeN(lt->dvert);
-                               lt->dvert= NULL;
+       }
+}
+
+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);
+                               }
                        }
                }
        }
 }
 
-void del_all_defgroups (Object *ob)
+static void vgroup_levels(Object *ob, float offset, float gain)
 {
-       /* Sanity check */
-       if (ob == NULL)
-               return;
+       bDeformGroup *dg;
+       MDeformWeight *dw;
+       MDeformVert *dvert, *dvert_array=NULL;
+       int i, def_nr, dvert_tot=0;
        
-       /* Remove all DVerts */
-       if (ob->type==OB_MESH) {
-               Mesh *me= ob->data;
-               CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
-               me->dvert= NULL;
-       }
-       else if(ob->type==OB_LATTICE) {
-               Lattice *lt= def_get_lattice(ob);
-               if (lt->dvert) {
-                       MEM_freeN(lt->dvert);
-                       lt->dvert= NULL;
-               }
-       }
+       ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
        
-       /* Remove all DefGroups */
-       BLI_freelistN(&ob->defbase);
+       dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
        
-       /* Fix counters/indices */
-       ob->actdef= 0;
+       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);
+                       }
+               }
+       }
 }
 
-void create_dverts(ID *id)
+/* TODO - select between groups */
+static void vgroup_normalize_all(Object *ob, int lock_active)
 {
-       /* create deform verts
-        */
+       MDeformWeight *dw, *dw_act;
+       MDeformVert *dvert, *dvert_array=NULL;
+       int i, dvert_tot=0;
+       float tot_weight;
 
-       if( GS(id->name)==ID_ME) {
-               Mesh *me= (Mesh *)id;
-               me->dvert= CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert);
-       }
-       else if( GS(id->name)==ID_LT) {
-               Lattice *lt= (Lattice *)id;
-               lt->dvert= MEM_callocN(sizeof(MDeformVert)*lt->pntsu*lt->pntsv*lt->pntsw, "lattice deformVert");
+       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);
+                                       }
+                               }
+                       }
+               }
        }
 }
 
-/* for mesh in object mode
-   lattice can be in editmode */
-void remove_vert_def_nr (Object *ob, int def_nr, int vertnum)
+
+static void vgroup_invert(Object *ob, int auto_assign, int auto_remove)
 {
-       /* This routine removes the vertex from the deform
-        * group with number def_nr.
-        *
-        * This routine is meant to be fast, so it is the
-        * responsibility of the calling routine to:
-        *   a) test whether ob is non-NULL
-        *   b) test whether ob is a mesh
-        *   c) calculate def_nr
-        */
+       bDeformGroup *dg;
+       MDeformWeight *dw;
+       MDeformVert *dvert, *dvert_array=NULL;
+       int i, def_nr, dvert_tot=0;
 
-       MDeformWeight *newdw;
-       MDeformVert *dvert= NULL;
-       int i;
+       ED_vgroup_give_array(ob->data, &dvert_array, &dvert_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= def_get_lattice(ob);
-               
-               if(lt->dvert)
-                       dvert = lt->dvert + vertnum;
+       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);
+                               }
+                       }
+               }
        }
-       
-       if(dvert==NULL)
+}
+
+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;
-       
-       /* for all of the deform weights in the
-        * deform vert
-        */
-       for (i=dvert->totweight - 1 ; i>=0 ; i--){
 
-               /* if the def_nr is the same as the one
-                * for our weight group then remove it
-                * from this deform vert.
-                */
-               if (dvert->dw[i].def_nr == def_nr) {
-                       dvert->totweight--;
-        
-                       /* if there are still other deform weights
-                        * attached to this vert then remove this
-                        * deform weight, and reshuffle the others
-                        */
-                       if (dvert->totweight) {
-                               newdw = MEM_mallocN (sizeof(MDeformWeight)*(dvert->totweight), 
-                                                                        "deformWeight");
-                               if (dvert->dw){
-                                       memcpy (newdw, dvert->dw, sizeof(MDeformWeight)*i);
-                                       memcpy (newdw+i, dvert->dw+i+1, 
-                                                       sizeof(MDeformWeight)*(dvert->totweight-i));
-                                       MEM_freeN (dvert->dw);
+       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;
                                }
-                               dvert->dw=newdw;
                        }
-                       /* if there are no other deform weights
-                        * left then just remove the deform weight
-                        */
-                       else {
-                               MEM_freeN (dvert->dw);
-                               dvert->dw = NULL;
-                               break;
+               }
+
+               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);
        }
-
 }
 
-/* for Mesh in Object mode */
-/* allows editmode for Lattice */
-void add_vert_defnr (Object *ob, int def_nr, int vertnum, 
-                           float weight, int assignmode)
+static void vgroup_clean(Object *ob, float eul, int keep_single)
 {
-       /* add the vert to the deform group with the
-        * specified number
-        */
-       MDeformVert *dv= NULL;
-       MDeformWeight *newdw;
-       int     i;
+       bDeformGroup *dg;
+       MDeformWeight *dw;
+       MDeformVert *dvert, *dvert_array=NULL;
+       int i, def_nr, dvert_tot=0;
 
-       /* 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= def_get_lattice(ob);
-               
-               if(lt->dvert)
-                       dv = lt->dvert + vertnum;
+       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);
+                       }
+               }
        }
-       
-       if(dv==NULL)
-               return;
-       
-       /* Lets first check to see if this vert is
-        * already in the weight group -- if so
-        * lets update it
-        */
-       for (i=0; i<dv->totweight; i++){
-               
-               /* if this weight cooresponds to the
-                * deform group, then add it using
-                * the assign mode provided
-                */
-               if (dv->dw[i].def_nr == def_nr){
-                       
-                       switch (assignmode) {
-                       case WEIGHT_REPLACE:
-                               dv->dw[i].weight=weight;
-                               break;
-                       case WEIGHT_ADD:
-                               dv->dw[i].weight+=weight;
-                               if (dv->dw[i].weight >= 1.0)
-                                       dv->dw[i].weight = 1.0;
-                               break;
-                       case WEIGHT_SUBTRACT:
-                               dv->dw[i].weight-=weight;
-                               /* if the weight is zero or less then
-                                * remove the vert from the deform group
-                                */
-                               if (dv->dw[i].weight <= 0.0)
-                                       remove_vert_def_nr(ob, def_nr, vertnum);
-                               break;
+}
+
+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);
+
                        }
-                       return;
                }
        }
+}
 
-       /* if the vert wasn't in the deform group then
-        * we must take a different form of action ...
-        */
+static void vgroup_delete_update_users(Object *ob, int id)
+{
+       ExplodeModifierData *emd;
+       ModifierData *md;
+       ParticleSystem *psys;
+       ClothModifierData *clmd;
+       ClothSimSettings *clsim;
+       int a;
 
-       switch (assignmode) {
-       case WEIGHT_SUBTRACT:
-               /* if we are subtracting then we don't
-                * need to do anything
-                */
-               return;
+       /* these cases don't use names to refer to vertex groups, so when
+        * they get deleted the numbers get out of sync, this corrects that */
+
+       if(ob->soft) {
+               if(ob->soft->vertgroup == id)
+                       ob->soft->vertgroup= 0;
+               else if(ob->soft->vertgroup > id)
+                       ob->soft->vertgroup--;
+       }
+
+       for(md=ob->modifiers.first; md; md=md->next) {
+               if(md->type == eModifierType_Explode) {
+                       emd= (ExplodeModifierData*)md;
+
+                       if(emd->vgroup == id)
+                               emd->vgroup= 0;
+                       else if(emd->vgroup > id)
+                               emd->vgroup--;
+               }
+               else if(md->type == eModifierType_Cloth) {
+                       clmd= (ClothModifierData*)md;
+                       clsim= clmd->sim_parms;
+
+                       if(clsim) {
+                               if(clsim->vgroup_mass == id)
+                                       clsim->vgroup_mass= 0;
+                               else if(clsim->vgroup_mass > id)
+                                       clsim->vgroup_mass--;
+
+                               if(clsim->vgroup_bend == id)
+                                       clsim->vgroup_bend= 0;
+                               else if(clsim->vgroup_bend > id)
+                                       clsim->vgroup_bend--;
 
-       case WEIGHT_REPLACE:
-       case WEIGHT_ADD:
-               /* if we are doing an additive assignment, then
-                * we need to create the deform weight
-                */
-               newdw = MEM_callocN (sizeof(MDeformWeight)*(dv->totweight+1), 
-                                                        "deformWeight");
-               if (dv->dw){
-                       memcpy (newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
-                       MEM_freeN (dv->dw);
+                               if(clsim->vgroup_struct == id)
+                                       clsim->vgroup_struct= 0;
+                               else if(clsim->vgroup_struct > id)
+                                       clsim->vgroup_struct--;
+                       }
                }
-               dv->dw=newdw;
-    
-               dv->dw[dv->totweight].weight=weight;
-               dv->dw[dv->totweight].def_nr=def_nr;
-    
-               dv->totweight++;
-               break;
+       }
+
+       for(psys=ob->particlesystem.first; psys; psys=psys->next) {
+               for(a=0; a<PSYS_TOT_VG; a++)
+                       if(psys->vgroup[a] == id)
+                               psys->vgroup[a]= 0;
+                       else if(psys->vgroup[a] > id)
+                               psys->vgroup[a]--;
        }
 }
 
-/* called while not in editmode */
-void add_vert_to_defgroup (Object *ob, bDeformGroup *dg, int vertnum, 
-                           float weight, int assignmode)
+static void vgroup_delete_object_mode(Object *ob)
 {
-       /* add the vert to the deform group with the
-        * specified assign mode
-        */
-       int     def_nr;
+       bDeformGroup *dg;
+       MDeformVert *dvert, *dvert_array=NULL;
+       int i, e, dvert_tot=0;
+       
+       dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
+       if(!dg)
+               return;
+       
+       ED_vgroup_give_array(ob->data, &dvert_array, &dvert_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(dvert_array) {
+               for(i = 0; i < dvert_tot; i++) {
+                       dvert = dvert_array + i;
+                       if(dvert) {
+                               if(ED_vgroup_weight_get(dvert, (ob->actdef-1)))
+                                       ED_vgroup_vert_remove(ob, dg, i);
+                       }
+               }
 
-       /* if there's no deform verts then
-        * create some
-        */
-       if(ob->type==OB_MESH) {
-               if (!((Mesh*)ob->data)->dvert)
-                       create_dverts(ob->data);
-       }
-       else if(ob->type==OB_LATTICE) {
-               if (!((Lattice*)ob->data)->dvert)
-                       create_dverts(ob->data);
+               for(i = 0; i < dvert_tot; i++) {
+                       dvert = dvert_array+i;
+                       if(dvert) {
+                               for(e = 0; e < dvert->totweight; e++) {
+                                       if(dvert->dw[e].def_nr > (ob->actdef-1))
+                                               dvert->dw[e].def_nr--;
+                               }
+                       }
+               }
        }
 
-       /* call another function to do the work
-        */
-       add_vert_defnr (ob, def_nr, vertnum, weight, assignmode);
+       vgroup_delete_update_users(ob, ob->actdef);
+
+       /* Update the active deform index if necessary */
+       if(ob->actdef == BLI_countlist(&ob->defbase))
+               ob->actdef--;
+  
+       /* Remove the group */
+       BLI_freelinkN(&ob->defbase, dg);
 }
 
-/* Only available in editmode */
-void assign_verts_defgroup (Object *ob, float weight)
+/* only in editmode */
+/* removes from active defgroup, if allverts==0 only selected vertices */
+static void vgroup_active_remove_verts(Object *ob, int allverts)
 {
        EditVert *eve;
-       bDeformGroup *dg, *eg;
-       MDeformWeight *newdw;
        MDeformVert *dvert;
-       int     i, done;
-
-       if (!ob)
-               return;
+       MDeformWeight *newdw;
+       bDeformGroup *dg, *eg;
+       int     i;
 
        dg=BLI_findlink(&ob->defbase, ob->actdef-1);
-       if (!dg){
-               error ("No vertex group is active");
+       if(!dg)
                return;
-       }
 
-       switch (ob->type){
-       case OB_MESH:
-       {
+       if(ob->type == OB_MESH) {
                Mesh *me= ob->data;
                EditMesh *em = BKE_mesh_get_editmesh(me);
 
-               if (!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT))
-                       EM_add_data_layer(em, &em->vdata, CD_MDEFORMVERT);
-
-               /* Go through the list of editverts and assign them */
-               for (eve=em->verts.first; eve; eve=eve->next){
+               for(eve=em->verts.first; eve; eve=eve->next){
                        dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
-
-                       if (dvert && (eve->f & 1)){
-                               done=0;
-                               /* See if this vert already has a reference to this group */
-                               /*              If so: Change its weight */
-                               done=0;
-                               for (i=0; i<dvert->totweight; i++){
-                                       eg = BLI_findlink (&ob->defbase, dvert->dw[i].def_nr);
-                                       /* Find the actual group */
-                                       if (eg==dg){
-                                               dvert->dw[i].weight= weight;
-                                               done=1;
-                                               break;
-                                       }
-                               }
-                               /*              If not: Add the group and set its weight */
-                               if (!done){
-                                       newdw = MEM_callocN (sizeof(MDeformWeight)*(dvert->totweight+1), "deformWeight");
-                                       if (dvert->dw){
-                                               memcpy (newdw, dvert->dw, sizeof(MDeformWeight)*dvert->totweight);
-                                               MEM_freeN (dvert->dw);
+               
+                       if(dvert && dvert->dw && ((eve->f & 1) || allverts)){
+                               for(i=0; i<dvert->totweight; i++){
+                                       /* Find group */
+                                       eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr);
+                                       if(eg == dg){
+                                               dvert->totweight--;
+                                               if(dvert->totweight){
+                                                       newdw = MEM_mallocN(sizeof(MDeformWeight)*(dvert->totweight), "deformWeight");
+                                                       
+                                                       if(dvert->dw){
+                                                               memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*i);
+                                                               memcpy(newdw+i, dvert->dw+i+1, sizeof(MDeformWeight)*(dvert->totweight-i));
+                                                               MEM_freeN(dvert->dw);
+                                                       }
+                                                       dvert->dw=newdw;
+                                               }
+                                               else{
+                                                       MEM_freeN(dvert->dw);
+                                                       dvert->dw=NULL;
+                                                       break;
+                                               }
                                        }
-                                       dvert->dw=newdw;
-
-                                       dvert->dw[dvert->totweight].weight= weight;
-                                       dvert->dw[dvert->totweight].def_nr= ob->actdef-1;
-
-                                       dvert->totweight++;
-
                                }
                        }
                }
                BKE_mesh_end_editmesh(me, em);
        }
-               break;
-       case OB_LATTICE:
-               {
-                       Lattice *lt= def_get_lattice(ob);
+       else if(ob->type == OB_LATTICE) {
+               Lattice *lt= vgroup_edit_lattice(ob);
+               
+               if(lt->dvert) {
                        BPoint *bp;
-                       int a, tot;
-                       
-                       if(lt->dvert==NULL)
-                               create_dverts(&lt->id);
-                       
-                       tot= lt->pntsu*lt->pntsv*lt->pntsw;
+                       int a, tot= lt->pntsu*lt->pntsv*lt->pntsw;
+                               
                        for(a=0, bp= lt->def; a<tot; a++, bp++) {
-                               if(bp->f1 & SELECT)
-                                       add_vert_defnr (ob, ob->actdef-1, a, weight, WEIGHT_REPLACE);
+                               if(allverts || (bp->f1 & SELECT))
+                                       ED_vgroup_vert_remove(ob, dg, a);
                        }
                }
-               break;
-       default:
-               printf ("Assigning deformation groups to unknown object type\n");
-               break;
        }
-
 }
 
-/* mesh object mode, lattice can be in editmode */
-void remove_vert_defgroup (Object *ob, bDeformGroup    *dg, int vertnum)
+static void vgroup_delete_edit_mode(Object *ob)
 {
-       /* This routine removes the vertex from the specified
-        * deform group.
-        */
-
-       int def_nr;
+       bDeformGroup *defgroup;
+       int i;
 
-       /* if the object is NULL abort
-        */
-       if (!ob)
+       if(!ob->actdef)
                return;
 
-       /* get the deform number that cooresponds
-        * to this deform group, and abort if it
-        * can not be found.
-        */
-       def_nr = get_defgroup_num(ob, dg);
-       if (def_nr < 0) return;
-
-       /* call another routine to do the work
-        */
-       remove_vert_def_nr (ob, def_nr, vertnum);
-}
+       defgroup = BLI_findlink(&ob->defbase, ob->actdef-1);
+       if(!defgroup)
+               return;
 
-/* for mesh in object mode lattice can be in editmode */
-static float get_vert_def_nr (Object *ob, int def_nr, int vertnum)
-{
-       MDeformVert *dvert= NULL;
-       int i;
+       /* Make sure that no verts are using this group */
+       vgroup_active_remove_verts(ob, 1);
 
-       /* get the deform vertices corresponding to the
-        * vertnum
-        */
+       /* Make sure that any verts with higher indices are adjusted accordingly */
        if(ob->type==OB_MESH) {
-               if( ((Mesh*)ob->data)->dvert )
-                       dvert = ((Mesh*)ob->data)->dvert + vertnum;
+               Mesh *me= ob->data;
+               EditMesh *em = BKE_mesh_get_editmesh(me);
+               EditVert *eve;
+               MDeformVert *dvert;
+               
+               for(eve=em->verts.first; eve; eve=eve->next){
+                       dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+
+                       if(dvert)
+                               for(i=0; i<dvert->totweight; i++)
+                                       if(dvert->dw[i].def_nr > (ob->actdef-1))
+                                               dvert->dw[i].def_nr--;
+               }
+               BKE_mesh_end_editmesh(me, em);
        }
        else if(ob->type==OB_LATTICE) {
-               Lattice *lt= def_get_lattice(ob);
+               Lattice *lt= vgroup_edit_lattice(ob);
+               BPoint *bp;
+               MDeformVert *dvert= lt->dvert;
+               int a, tot;
                
-               if(lt->dvert)
-                       dvert = lt->dvert + vertnum;
+               if(dvert) {
+                       tot= lt->pntsu*lt->pntsv*lt->pntsw;
+                       for(a=0, bp= lt->def; a<tot; a++, bp++, dvert++) {
+                               for(i=0; i<dvert->totweight; i++){
+                                       if(dvert->dw[i].def_nr > (ob->actdef-1))
+                                               dvert->dw[i].def_nr--;
+                               }
+                       }
+               }
        }
+
+       vgroup_delete_update_users(ob, ob->actdef);
+
+       /* Update the active deform index if necessary */
+       if(ob->actdef==BLI_countlist(&ob->defbase))
+               ob->actdef--;
        
-       if(dvert==NULL)
-               return 0.0f;
+       /* Remove the group */
+       BLI_freelinkN (&ob->defbase, defgroup);
        
-       for(i=dvert->totweight-1 ; i>=0 ; i--)
-               if(dvert->dw[i].def_nr == def_nr)
-                       return dvert->dw[i].weight;
-
-       return 0.0f;
+       /* remove all dverts */
+       if(ob->actdef==0) {
+               if(ob->type==OB_MESH) {
+                       Mesh *me= ob->data;
+                       CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
+                       me->dvert= NULL;
+               }
+               else if(ob->type==OB_LATTICE) {
+                       Lattice *lt= vgroup_edit_lattice(ob);
+                       if(lt->dvert) {
+                               MEM_freeN(lt->dvert);
+                               lt->dvert= NULL;
+                       }
+               }
+       }
 }
 
-/* mesh object mode, lattice can be in editmode */
-float get_vert_defgroup (Object *ob, bDeformGroup *dg, int vertnum)
+static int vgroup_object_in_edit_mode(Object *ob)
 {
-       int def_nr;
-
-       if(!ob)
-               return 0.0f;
+       if(ob->type == OB_MESH)
+               return (((Mesh*)ob->data)->edit_mesh != NULL);
+       else if(ob->type == OB_LATTICE)
+               return (((Lattice*)ob->data)->editlatt != NULL);
+       
+       return 0;
+}
 
-       def_nr = get_defgroup_num(ob, dg);
-       if(def_nr < 0) return 0.0f;
+static void vgroup_delete(Object *ob)
+{
+       if(vgroup_object_in_edit_mode(ob))
+               vgroup_delete_edit_mode(ob);
+       else
+               vgroup_delete_object_mode(ob);
+}
 
-       return get_vert_def_nr (ob, def_nr, vertnum);
+static void vgroup_delete_all(Object *ob)
+{
+       /* Remove all DVerts */
+       if(ob->type==OB_MESH) {
+               Mesh *me= ob->data;
+               CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
+               me->dvert= NULL;
+       }
+       else if(ob->type==OB_LATTICE) {
+               Lattice *lt= vgroup_edit_lattice(ob);
+               if(lt->dvert) {
+                       MEM_freeN(lt->dvert);
+                       lt->dvert= NULL;
+               }
+       }
+       
+       /* Remove all DefGroups */
+       BLI_freelistN(&ob->defbase);
+       
+       /* Fix counters/indices */
+       ob->actdef= 0;
 }
 
-/* Only available in editmode */
-/* removes from active defgroup, if allverts==0 only selected vertices */
-void remove_verts_defgroup (Object *ob, int allverts)
+/* only in editmode */
+static void vgroup_assign_verts(Object *ob, float weight)
 {
        EditVert *eve;
-       MDeformVert *dvert;
-       MDeformWeight *newdw;
        bDeformGroup *dg, *eg;
-       int     i;
-
-       if (!ob)
-               return;
+       MDeformWeight *newdw;
+       MDeformVert *dvert;
+       int     i, done;
 
        dg=BLI_findlink(&ob->defbase, ob->actdef-1);
-       if (!dg){
-               error ("No vertex group is active");
+       if(!dg)
                return;
-       }
 
-       switch (ob->type){
-       case OB_MESH:
-       {
+       if(ob->type == OB_MESH) {
                Mesh *me= ob->data;
                EditMesh *em = BKE_mesh_get_editmesh(me);
 
-               for (eve=em->verts.first; eve; eve=eve->next){
+               if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT))
+                       EM_add_data_layer(em, &em->vdata, CD_MDEFORMVERT);
+
+               /* Go through the list of editverts and assign them */
+               for(eve=em->verts.first; eve; eve=eve->next){
                        dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
-               
-                       if (dvert && dvert->dw && ((eve->f & 1) || allverts)){
-                               for (i=0; i<dvert->totweight; i++){
-                                       /* Find group */
-                                       eg = BLI_findlink (&ob->defbase, dvert->dw[i].def_nr);
-                                       if (eg == dg){
-                                               dvert->totweight--;
-                                               if (dvert->totweight){
-                                                       newdw = MEM_mallocN (sizeof(MDeformWeight)*(dvert->totweight), "deformWeight");
-                                                       
-                                                       if (dvert->dw){
-                                                               memcpy (newdw, dvert->dw, sizeof(MDeformWeight)*i);
-                                                               memcpy (newdw+i, dvert->dw+i+1, sizeof(MDeformWeight)*(dvert->totweight-i));
-                                                               MEM_freeN (dvert->dw);
-                                                       }
-                                                       dvert->dw=newdw;
-                                               }
-                                               else{
-                                                       MEM_freeN (dvert->dw);
-                                                       dvert->dw=NULL;
-                                                       break;
-                                               }
+
+                       if(dvert && (eve->f & 1)){
+                               done=0;
+                               /* See if this vert already has a reference to this group */
+                               /*              If so: Change its weight */
+                               done=0;
+                               for(i=0; i<dvert->totweight; i++){
+                                       eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr);
+                                       /* Find the actual group */
+                                       if(eg==dg){
+                                               dvert->dw[i].weight= weight;
+                                               done=1;
+                                               break;
+                                       }
+                               }
+                               /*              If not: Add the group and set its weight */
+                               if(!done){
+                                       newdw = MEM_callocN(sizeof(MDeformWeight)*(dvert->totweight+1), "deformWeight");
+                                       if(dvert->dw){
+                                               memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*dvert->totweight);
+                                               MEM_freeN(dvert->dw);
                                        }
+                                       dvert->dw=newdw;
+
+                                       dvert->dw[dvert->totweight].weight= weight;
+                                       dvert->dw[dvert->totweight].def_nr= ob->actdef-1;
+
+                                       dvert->totweight++;
+
                                }
                        }
                }
                BKE_mesh_end_editmesh(me, em);
        }
-               break;
-       case OB_LATTICE:
-       {
-               Lattice *lt= def_get_lattice(ob);
+       else if(ob->type == OB_LATTICE) {
+               Lattice *lt= vgroup_edit_lattice(ob);
+               BPoint *bp;
+               int a, tot;
                
-               if(lt->dvert) {
-                       BPoint *bp;
-                       int a, tot= lt->pntsu*lt->pntsv*lt->pntsw;
-                               
-                       for(a=0, bp= lt->def; a<tot; a++, bp++) {
-                               if(allverts || (bp->f1 & SELECT))
-                                       remove_vert_defgroup (ob, dg, a);
-                       }
-               }
-       }
-               break;
+               if(lt->dvert==NULL)
+                       ED_vgroup_data_create(&lt->id);
                
-       default:
-               printf ("Removing deformation groups from unknown object type\n");
-               break;
+               tot= lt->pntsu*lt->pntsv*lt->pntsw;
+               for(a=0, bp= lt->def; a<tot; a++, bp++) {
+                       if(bp->f1 & SELECT)
+                               ED_vgroup_nr_vert_add(ob, ob->actdef-1, a, weight, WEIGHT_REPLACE);
+               }
        }
 }
 
-/* Only available in editmode */
+/* only in editmode */
 /* removes from all defgroup, if allverts==0 only selected vertices */
-void remove_verts_defgroups(Object *ob, int allverts)
+static void vgroup_remove_verts(Object *ob, int allverts)
 {
        int actdef, defCount;
-
-       if (ob == NULL) return;
        
        actdef= ob->actdef;
        defCount= BLI_countlist(&ob->defbase);
        
-       if (defCount == 0) {
-               error("Object has no vertex groups");
+       if(defCount == 0)
                return;
-       }
        
-       /* To prevent code redundancy, we just use remove_verts_defgroup, but that
+       /* To prevent code redundancy, we just use vgroup_active_remove_verts, but that
         * only operates on the active vgroup. So we iterate through all groups, by changing
         * active group index
         */
-       for (ob->actdef= 1; ob->actdef <= defCount; ob->actdef++)
-               remove_verts_defgroup(ob, allverts);
+       for(ob->actdef= 1; ob->actdef <= defCount; ob->actdef++)
+               vgroup_active_remove_verts(ob, allverts);
                
        ob->actdef= actdef;
 }
 
-void vertexgroup_select_by_name(Object *ob, char *name)
-{
-       bDeformGroup *curdef;
-       int actdef= 1;
-       
-       if(ob==NULL) return;
-       
-       for (curdef = ob->defbase.first; curdef; curdef=curdef->next, actdef++){
-               if (!strcmp(curdef->name, name)) {
-                       ob->actdef= actdef;
-                       return;
-               }
-       }
-       ob->actdef=0;   // this signals on painting to create a new one, if a bone in posemode is selected */
-}
+/********************** vertex group operators *********************/
 
-/* This function provides a shortcut for adding/removing verts from 
- * vertex groups. It is called by the Ctrl-G hotkey in EditMode for Meshes
- * and Lattices. (currently only restricted to those two)
- * It is only responsible for 
- */
-void vgroup_assign_with_menu(Scene *scene, Object *ob)
+static int vertex_group_poll(bContext *C)
 {
-       VPaint *wp= scene->toolsettings->wpaint;
-       int defCount;
-       int mode= 0;
-       
-       /* prevent crashes */
-       if (wp==NULL || ob==NULL) return;
-       
-       defCount= BLI_countlist(&ob->defbase);
-       
-       /* give user choices of adding to current/new or removing from current */
-// XXX if (defCount && ob->actdef)
-//             mode = pupmenu("Vertex Groups %t|Add Selected to New Group %x1|Add Selected to Active Group %x2|Remove Selected from Active Group %x3|Remove Selected from All Groups %x4");
-//     else
-//             mode= pupmenu("Vertex Groups %t|Add Selected to New Group %x1");
-       
-       /* handle choices */
-       switch (mode) {
-               case 1: /* add to new group */
-                       add_defgroup(ob);
-                       assign_verts_defgroup(ob, wp->brush->alpha);
-                       BIF_undo_push("Assign to vertex group");
-                       break;
-               case 2: /* add to current group */
-                       assign_verts_defgroup(ob, wp->brush->alpha);
-                       BIF_undo_push("Assign to vertex group");
-                       break;
-               case 3: /* remove from current group */
-                       remove_verts_defgroup(ob, 0);
-                       BIF_undo_push("Remove from vertex group");
-                       break;
-               case 4: /* remove from all groups */
-                       remove_verts_defgroups(ob, 0);
-                       BIF_undo_push("Remove from all vertex groups");
-                       break;
-       }
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       ID *data= (ob)? ob->data: NULL;
+       return (ob && !ob->id.lib && ELEM(ob->type, OB_MESH, OB_LATTICE) && data && !data->lib);
 }
 
-/* This function provides a shortcut for commonly used vertex group 
- * functions - change weight (not implemented), change active group, delete active group,
- * when Ctrl-Shift-G is used in EditMode, for Meshes and Lattices (only for now).
- */
-void vgroup_operation_with_menu(Object *ob)
+static int vertex_group_poll_edit(bContext *C)
 {
-       int defCount;
-       int mode= 0;
-       
-       /* prevent crashes and useless cases */
-       if (ob==NULL) return;
-       
-       defCount= BLI_countlist(&ob->defbase);
-       if (defCount == 0) return;
-       
-       /* give user choices of adding to current/new or removing from current */
-// XXX if (ob->actdef)
-//             mode = pupmenu("Vertex Groups %t|Change Active Group%x1|Delete Active Group%x2|Delete All Groups%x3");
-//     else
-//             mode= pupmenu("Vertex Groups %t|Change Active Group%x1|Delete All Groups%x3");
-       
-       /* handle choices */
-       switch (mode) {
-               case 1: /* change active group*/
-                       {
-                               char *menustr= NULL; // XXX get_vertexgroup_menustr(ob);
-                               short nr;
-                               
-                               if (menustr) {
-// XXX                                 nr= pupmenu(menustr);
-                                       
-                                       if ((nr >= 1) && (nr <= defCount)) 
-                                               ob->actdef= nr;
-                                               
-                                       MEM_freeN(menustr);
-                               }
-                       }
-                       break;
-               case 2: /* delete active group  */
-                       {
-                               del_defgroup(ob);
-                               BIF_undo_push("Delete vertex group");
-                       }
-                       break;
-               case 3: /* delete all groups */
-                       {
-                               del_all_defgroups(ob);
-                               BIF_undo_push("Delete all vertex groups");
-                       }
-                       break;
-       }
-}
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       ID *data= (ob)? ob->data: NULL;
 
-/********************** vertex group operators *********************/
+       if(!(ob && !ob->id.lib && data && !data->lib))
+               return 0;
+
+       return vgroup_object_in_edit_mode(ob);
+}
 
 static int vertex_group_add_exec(bContext *C, wmOperator *op)
 {
        Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
-       Scene *scene= CTX_data_scene(C);
-
-       if(!ob)
-               return OPERATOR_CANCELLED;
 
-       add_defgroup(ob);
-       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
+       ED_vgroup_add(ob);
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
        
        return OPERATOR_FINISHED;
 }
@@ -1123,6 +1318,7 @@ void OBJECT_OT_vertex_group_add(wmOperatorType *ot)
        ot->idname= "OBJECT_OT_vertex_group_add";
        
        /* api callbacks */
+       ot->poll= vertex_group_poll;
        ot->exec= vertex_group_add_exec;
 
        /* flags */
@@ -1132,20 +1328,15 @@ void OBJECT_OT_vertex_group_add(wmOperatorType *ot)
 static int vertex_group_remove_exec(bContext *C, wmOperator *op)
 {
        Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
-       Scene *scene= CTX_data_scene(C);
 
-       if(!ob)
-               return OPERATOR_CANCELLED;
+       if(RNA_boolean_get(op->ptr, "all"))
+               vgroup_delete_all(ob);
+       else
+               vgroup_delete(ob);
 
-       if(scene->obedit == ob) {
-               del_defgroup(ob);
-               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
-       }
-       else {
-               del_defgroup_in_object_mode(ob);
-               DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
-       }
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
        
        return OPERATOR_FINISHED;
 }
@@ -1157,24 +1348,27 @@ void OBJECT_OT_vertex_group_remove(wmOperatorType *ot)
        ot->idname= "OBJECT_OT_vertex_group_remove";
        
        /* api callbacks */
+       ot->poll= vertex_group_poll;
        ot->exec= vertex_group_remove_exec;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups.");
 }
 
 static int vertex_group_assign_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene= CTX_data_scene(C);
        ToolSettings *ts= CTX_data_tool_settings(C);
        Object *ob= CTX_data_edit_object(C);
 
-       if(!ob)
-               return OPERATOR_CANCELLED;
+       if(RNA_boolean_get(op->ptr, "new"))
+               ED_vgroup_add(ob);
 
-       assign_verts_defgroup(ob, ts->vgroup_weight);
-       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
+       vgroup_assign_verts(ob, ts->vgroup_weight);
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
        
        return OPERATOR_FINISHED;
 }
@@ -1186,24 +1380,24 @@ void OBJECT_OT_vertex_group_assign(wmOperatorType *ot)
        ot->idname= "OBJECT_OT_vertex_group_assign";
        
        /* api callbacks */
+       ot->poll= vertex_group_poll_edit;
        ot->exec= vertex_group_assign_exec;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_boolean(ot->srna, "new", 0, "New", "Assign vertex to new vertex group.");
 }
 
 static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene= CTX_data_scene(C);
        Object *ob= CTX_data_edit_object(C);
 
-       if(!ob)
-               return OPERATOR_CANCELLED;
+       vgroup_remove_verts(ob, 0);
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
 
-       remove_verts_defgroup(ob, 0);
-       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
-       
        return OPERATOR_FINISHED;
 }
 
@@ -1212,23 +1406,27 @@ void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot)
        /* identifiers */
        ot->name= "Remove from Vertex Group";
        ot->idname= "OBJECT_OT_vertex_group_remove_from";
-       
+
        /* api callbacks */
+       ot->poll= vertex_group_poll_edit;
        ot->exec= vertex_group_remove_from_exec;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups.");
 }
 
 static int vertex_group_select_exec(bContext *C, wmOperator *op)
 {
        Object *ob= CTX_data_edit_object(C);
 
-       if(!ob)
+       if(!ob || ob->id.lib)
                return OPERATOR_CANCELLED;
 
-       sel_verts_defgroup(ob, 1); /* runs countall() */
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
+       vgroup_select_verts(ob, 1);
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
 
        return OPERATOR_FINISHED;
 }
@@ -1238,8 +1436,9 @@ void OBJECT_OT_vertex_group_select(wmOperatorType *ot)
        /* identifiers */
        ot->name= "Select Vertex Group";
        ot->idname= "OBJECT_OT_vertex_group_select";
-       
+
        /* api callbacks */
+       ot->poll= vertex_group_poll_edit;
        ot->exec= vertex_group_select_exec;
 
        /* flags */
@@ -1250,11 +1449,8 @@ static int vertex_group_deselect_exec(bContext *C, wmOperator *op)
 {
        Object *ob= CTX_data_edit_object(C);
 
-       if(!ob)
-               return OPERATOR_CANCELLED;
-
-       sel_verts_defgroup(ob, 0); /* runs countall() */
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
+       vgroup_select_verts(ob, 0);
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
 
        return OPERATOR_FINISHED;
 }
@@ -1264,8 +1460,9 @@ void OBJECT_OT_vertex_group_deselect(wmOperatorType *ot)
        /* identifiers */
        ot->name= "Deselect Vertex Group";
        ot->idname= "OBJECT_OT_vertex_group_deselect";
-       
+
        /* api callbacks */
+       ot->poll= vertex_group_poll_edit;
        ot->exec= vertex_group_deselect_exec;
 
        /* flags */
@@ -1274,16 +1471,13 @@ void OBJECT_OT_vertex_group_deselect(wmOperatorType *ot)
 
 static int vertex_group_copy_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene= CTX_data_scene(C);
        Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
 
-       if(!ob)
-               return OPERATOR_CANCELLED;
+       vgroup_duplicate(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);
 
-       duplicate_defgroup(ob);
-       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
-       
        return OPERATOR_FINISHED;
 }
 
@@ -1292,39 +1486,227 @@ void OBJECT_OT_vertex_group_copy(wmOperatorType *ot)
        /* identifiers */
        ot->name= "Copy Vertex Group";
        ot->idname= "OBJECT_OT_vertex_group_copy";
-       
+
        /* api callbacks */
+       ot->poll= vertex_group_poll;
        ot->exec= vertex_group_copy_exec;
 
        /* flags */
        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);
        Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
-    Base *base;
+       Base *base;
        int retval= OPERATOR_CANCELLED;
 
-       if(!ob)
-               return retval;
-
-    for(base=scene->base.first; base; base= base->next) {
-        if(base->object->type==ob->type) {
-            if(base->object!=ob && base->object->data==ob->data) {
-                BLI_freelistN(&base->object->defbase);
-                BLI_duplicatelist(&base->object->defbase, &ob->defbase);
-                base->object->actdef= ob->actdef;
+       for(base=scene->base.first; base; base= base->next) {
+               if(base->object->type==ob->type) {
+                       if(base->object!=ob && base->object->data==ob->data) {
+                               BLI_freelistN(&base->object->defbase);
+                               BLI_duplicatelist(&base->object->defbase, &ob->defbase);
+                               base->object->actdef= ob->actdef;
 
-                DAG_object_flush_update(scene, base->object, OB_RECALC_DATA);
-                               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, base->object);
+                               DAG_id_flush_update(&base->object->id, OB_RECALC_DATA);
+                               WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, base->object);
+                               WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
 
                                retval = OPERATOR_FINISHED;
-            }
-        }
-    }
-       
+                       }
+               }
+       }
+
        return retval;
 }
 
@@ -1333,11 +1715,76 @@ 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;
        ot->exec= vertex_group_copy_to_linked_exec;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
+static EnumPropertyItem vgroup_items[]= {
+       {0, NULL, 0, NULL, NULL}};
+
+static int set_active_group_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       int nr= RNA_enum_get(op->ptr, "group");
+
+       ob->actdef= nr+1;
+
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+
+       return OPERATOR_FINISHED;
+}
+
+static EnumPropertyItem *vgroup_itemf(bContext *C, PointerRNA *ptr, int *free)
+{      
+       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(!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;
+}
+
+void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
+{
+       PropertyRNA *prop;
+
+       /* 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;
+       ot->exec= set_active_group_exec;
+       ot->invoke= WM_menu_invoke;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* properties */
+       prop= RNA_def_enum(ot->srna, "group", vgroup_items, 0, "Group", "Vertex group to set as active.");
+       RNA_def_enum_funcs(prop, vgroup_itemf);
+}
+