Blender V2.61 - r43446

object_vgroup.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <string.h>
00034 #include <stddef.h>
00035 #include <math.h>
00036 #include <assert.h>
00037 
00038 #include "MEM_guardedalloc.h"
00039 
00040 #include "DNA_cloth_types.h"
00041 #include "DNA_curve_types.h"
00042 #include "DNA_lattice_types.h"
00043 #include "DNA_meshdata_types.h"
00044 #include "DNA_modifier_types.h"
00045 #include "DNA_object_types.h"
00046 #include "DNA_object_force.h"
00047 #include "DNA_scene_types.h"
00048 #include "DNA_particle_types.h"
00049 
00050 #include "BLI_math.h"
00051 #include "BLI_blenlib.h"
00052 #include "BLI_editVert.h"
00053 #include "BLI_utildefines.h"
00054 
00055 #include "BKE_context.h"
00056 #include "BKE_customdata.h"
00057 #include "BKE_deform.h"
00058 #include "BKE_depsgraph.h"
00059 #include "BKE_global.h"
00060 #include "BKE_mesh.h"
00061 #include "BKE_report.h"
00062 #include "BKE_DerivedMesh.h"
00063 
00064 #include "RNA_access.h"
00065 #include "RNA_define.h"
00066 
00067 #include "WM_api.h"
00068 #include "WM_types.h"
00069 
00070 #include "ED_object.h"
00071 #include "ED_mesh.h"
00072 
00073 #include "UI_resources.h"
00074 
00075 #include "object_intern.h"
00076 
00077 /************************ Exported Functions **********************/
00078 static void vgroup_remap_update_users(Object *ob, int *map);
00079 static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *defgroup);
00080 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg);
00081 static void vgroup_delete_all(Object *ob);
00082 
00083 static Lattice *vgroup_edit_lattice(Object *ob)
00084 {
00085     Lattice *lt= ob->data;
00086     BLI_assert(ob->type==OB_LATTICE);
00087     return (lt->editlatt)? lt->editlatt->latt: lt;
00088 }
00089 
00090 int ED_vgroup_object_is_edit_mode(Object *ob)
00091 {
00092     if(ob->type == OB_MESH)
00093         return (((Mesh*)ob->data)->edit_mesh != NULL);
00094     else if(ob->type == OB_LATTICE)
00095         return (((Lattice*)ob->data)->editlatt != NULL);
00096 
00097     return 0;
00098 }
00099 
00100 bDeformGroup *ED_vgroup_add_name(Object *ob, const char *name)
00101 {
00102     bDeformGroup *defgroup;
00103 
00104     if(!ob || !OB_TYPE_SUPPORT_VGROUP(ob->type))
00105         return NULL;
00106     
00107     defgroup = MEM_callocN(sizeof(bDeformGroup), "add deformGroup");
00108 
00109     BLI_strncpy(defgroup->name, name, sizeof(defgroup->name));
00110 
00111     BLI_addtail(&ob->defbase, defgroup);
00112     defgroup_unique_name(defgroup, ob);
00113 
00114     ob->actdef = BLI_countlist(&ob->defbase);
00115 
00116     return defgroup;
00117 }
00118 
00119 bDeformGroup *ED_vgroup_add(Object *ob) 
00120 {
00121     return ED_vgroup_add_name(ob, "Group");
00122 }
00123 
00124 void ED_vgroup_delete(Object *ob, bDeformGroup *defgroup) 
00125 {
00126     bDeformGroup *dg = (bDeformGroup *)ob->defbase.first;
00127 
00128     while (dg) {
00129         if (dg == defgroup)
00130             break;
00131         dg = dg->next;
00132     }
00133 
00134     if (dg == NULL)
00135         return;
00136 
00137     if(ED_vgroup_object_is_edit_mode(ob))
00138         vgroup_delete_edit_mode(ob, dg);
00139     else
00140         vgroup_delete_object_mode(ob, dg);
00141 }
00142 
00143 void ED_vgroup_clear(Object *ob)
00144 {
00145     bDeformGroup *dg= (bDeformGroup *)ob->defbase.first;
00146     int edit_mode= ED_vgroup_object_is_edit_mode(ob);
00147 
00148     while (dg) {
00149         bDeformGroup *next_dg= dg->next;
00150 
00151         if(edit_mode)
00152             vgroup_delete_edit_mode(ob, dg);
00153         else
00154             vgroup_delete_object_mode(ob, dg);
00155 
00156         dg= next_dg;
00157     }
00158 }
00159 
00160 int ED_vgroup_data_create(ID *id)
00161 {
00162     /* create deform verts */
00163 
00164     if(GS(id->name)==ID_ME) {
00165         Mesh *me= (Mesh *)id;
00166         me->dvert= CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert);
00167         return TRUE;
00168     }
00169     else if(GS(id->name)==ID_LT) {
00170         Lattice *lt= (Lattice *)id;
00171         lt->dvert= MEM_callocN(sizeof(MDeformVert)*lt->pntsu*lt->pntsv*lt->pntsw, "lattice deformVert");
00172         return TRUE;
00173     }
00174     else {
00175         return FALSE;
00176     }
00177 }
00178 
00179 static int ED_vgroup_give_parray(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, const short use_vert_sel)
00180 {
00181     *dvert_tot = 0;
00182     *dvert_arr = NULL;
00183 
00184     if(id) {
00185         switch(GS(id->name)) {
00186             case ID_ME:
00187             {
00188                 Mesh *me = (Mesh *)id;
00189 
00190                 if(me->edit_mesh) {
00191                     EditMesh *em = me->edit_mesh;
00192                     EditVert *eve;
00193                     int i;
00194 
00195                     if (!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
00196                         return 0;
00197                     }
00198 
00199                     i= BLI_countlist(&em->verts);
00200 
00201                     *dvert_arr= MEM_mallocN(sizeof(void*)*i, "vgroup parray from me");
00202                     *dvert_tot = i;
00203 
00204                     i = 0;
00205 
00206                     if (use_vert_sel) {
00207                         for (eve=em->verts.first; eve; eve=eve->next, i++) {
00208                             (*dvert_arr)[i] = (eve->f & SELECT) ?
00209                                                CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT) : NULL;
00210                         }
00211                     }
00212                     else {
00213                         for (eve=em->verts.first; eve; eve=eve->next, i++) {
00214                             (*dvert_arr)[i] = CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
00215                         }
00216                     }
00217 
00218                     return 1;
00219                 }
00220                 else if(me->dvert) {
00221                     MVert *mvert= me->mvert;
00222                     MDeformVert *dvert= me->dvert;
00223                     int i;
00224 
00225                     *dvert_tot= me->totvert;
00226                     *dvert_arr= MEM_mallocN(sizeof(void*)*me->totvert, "vgroup parray from me");
00227 
00228                     if (use_vert_sel) {
00229                         for (i=0; i<me->totvert; i++) {
00230                             (*dvert_arr)[i] = (mvert[i].flag & SELECT) ?
00231                                                &dvert[i] : NULL;
00232                         }
00233                     }
00234                     else {
00235                         for (i=0; i<me->totvert; i++) {
00236                             (*dvert_arr)[i] = me->dvert + i;
00237                         }
00238                     }
00239 
00240                     return 1;
00241                 }
00242                 else {
00243                     return 0;
00244                 }
00245             }
00246             case ID_LT:
00247             {
00248                 int i=0;
00249 
00250                 Lattice *lt= (Lattice *)id;
00251                 lt= (lt->editlatt)? lt->editlatt->latt: lt;
00252 
00253                 if(lt->dvert) {
00254                     BPoint *def= lt->def;
00255                     *dvert_tot= lt->pntsu*lt->pntsv*lt->pntsw;
00256                     *dvert_arr= MEM_mallocN(sizeof(void*)*(*dvert_tot), "vgroup parray from me");
00257 
00258                     if (use_vert_sel) {
00259                         for (i=0; i<*dvert_tot; i++) {
00260                             (*dvert_arr)[i] = (def->f1 & SELECT) ?
00261                                                &lt->dvert[i] : NULL;
00262                         }
00263                     }
00264                     else {
00265                         for (i=0; i<*dvert_tot; i++) {
00266                             (*dvert_arr)[i] = lt->dvert + i;
00267                         }
00268                     }
00269 
00270                     return 1;
00271                 }
00272                 else {
00273                     return 0;
00274                 }
00275             }
00276         }
00277     }
00278 
00279     return 0;
00280 }
00281 
00282 /* returns true if the id type supports weights */
00283 int ED_vgroup_give_array(ID *id, MDeformVert **dvert_arr, int *dvert_tot)
00284 {
00285     if(id) {
00286         switch(GS(id->name)) {
00287             case ID_ME:
00288             {
00289                 Mesh *me = (Mesh *)id;
00290                 *dvert_arr= me->dvert;
00291                 *dvert_tot= me->totvert;
00292                 return TRUE;
00293             }
00294             case ID_LT:
00295             {
00296                 Lattice *lt= (Lattice *)id;
00297                 lt= (lt->editlatt)? lt->editlatt->latt: lt;
00298                 *dvert_arr= lt->dvert;
00299                 *dvert_tot= lt->pntsu*lt->pntsv*lt->pntsw;
00300                 return TRUE;
00301             }
00302         }
00303     }
00304 
00305     *dvert_arr= NULL;
00306     *dvert_tot= 0;
00307     return FALSE;
00308 }
00309 
00310 /* matching index only */
00311 int ED_vgroup_copy_array(Object *ob, Object *ob_from)
00312 {
00313     MDeformVert **dvert_array_from, **dvf;
00314     MDeformVert **dvert_array, **dv;
00315     int dvert_tot_from;
00316     int dvert_tot;
00317     int i;
00318     int defbase_tot_from= BLI_countlist(&ob_from->defbase);
00319     int defbase_tot= BLI_countlist(&ob->defbase);
00320     short new_vgroup= FALSE;
00321 
00322     ED_vgroup_give_parray(ob_from->data, &dvert_array_from, &dvert_tot_from, FALSE);
00323     ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, FALSE);
00324 
00325     if((dvert_array == NULL) && (dvert_array_from != NULL) && ED_vgroup_data_create(ob->data)) {
00326         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, FALSE);
00327         new_vgroup= TRUE;
00328     }
00329 
00330     if(ob==ob_from || dvert_tot==0 || (dvert_tot != dvert_tot_from) || dvert_array_from==NULL || dvert_array==NULL) {
00331         if (dvert_array) MEM_freeN(dvert_array);
00332         if (dvert_array_from) MEM_freeN(dvert_array_from);
00333 
00334         if(new_vgroup == TRUE) {
00335             /* free the newly added vgroup since it wasn't compatible */
00336             vgroup_delete_all(ob);
00337         }
00338         return 0;
00339     }
00340 
00341     /* do the copy */
00342     BLI_freelistN(&ob->defbase);
00343     BLI_duplicatelist(&ob->defbase, &ob_from->defbase);
00344     ob->actdef= ob_from->actdef;
00345 
00346     if(defbase_tot_from < defbase_tot) {
00347         /* correct vgroup indices because the number of vgroups is being reduced. */
00348         int *remap= MEM_mallocN(sizeof(int) * (defbase_tot + 1), __func__);
00349         for(i=0; i<=defbase_tot_from; i++) remap[i]= i;
00350         for(; i<=defbase_tot; i++) remap[i]= 0; /* can't use these, so disable */
00351 
00352         vgroup_remap_update_users(ob, remap);
00353         MEM_freeN(remap);
00354     }
00355 
00356     dvf= dvert_array_from;
00357     dv= dvert_array;
00358 
00359     for(i=0; i<dvert_tot; i++, dvf++, dv++) {
00360         if((*dv)->dw)
00361             MEM_freeN((*dv)->dw);
00362 
00363         *(*dv)= *(*dvf);
00364 
00365         if((*dv)->dw)
00366             (*dv)->dw= MEM_dupallocN((*dv)->dw);
00367     }
00368 
00369     MEM_freeN(dvert_array);
00370     MEM_freeN(dvert_array_from);
00371 
00372     return 1;
00373 }
00374 
00375 
00376 /* for Mesh in Object mode */
00377 /* allows editmode for Lattice */
00378 static void ED_vgroup_nr_vert_add(Object *ob,
00379                                   const int def_nr, const int vertnum,
00380                                   const float weight, const int assignmode)
00381 {
00382     /* add the vert to the deform group with the
00383      * specified number
00384      */
00385     MDeformVert *dvert= NULL;
00386     int tot;
00387 
00388     /* get the vert */
00389     ED_vgroup_give_array(ob->data, &dvert, &tot);
00390     
00391     if(dvert==NULL)
00392         return;
00393 
00394     /* check that vertnum is valid before trying to get the relevant dvert */
00395     if ((vertnum < 0) || (vertnum >= tot))
00396         return;
00397 
00398 
00399     if (dvert) {
00400         MDeformVert *dv= &dvert[vertnum];
00401         MDeformWeight *dw;
00402 
00403         /* Lets first check to see if this vert is
00404          * already in the weight group -- if so
00405          * lets update it
00406          */
00407 
00408         dw= defvert_find_index(dv, def_nr);
00409 
00410         if (dw) {
00411             switch(assignmode) {
00412             case WEIGHT_REPLACE:
00413                 dw->weight = weight;
00414                 break;
00415             case WEIGHT_ADD:
00416                 dw->weight += weight;
00417                 if(dw->weight >= 1.0f)
00418                     dw->weight = 1.0f;
00419                 break;
00420             case WEIGHT_SUBTRACT:
00421                 dw->weight -= weight;
00422                 /* if the weight is zero or less then
00423                  * remove the vert from the deform group
00424                  */
00425                 if(dw->weight <= 0.0f) {
00426                     defvert_remove_group(dv, dw);
00427                 }
00428                 break;
00429             }
00430         }
00431         else {
00432             /* if the vert wasn't in the deform group then
00433              * we must take a different form of action ...
00434              */
00435 
00436             switch(assignmode) {
00437             case WEIGHT_SUBTRACT:
00438                 /* if we are subtracting then we don't
00439                  * need to do anything
00440                  */
00441                 return;
00442 
00443             case WEIGHT_REPLACE:
00444             case WEIGHT_ADD:
00445                 /* if we are doing an additive assignment, then
00446                  * we need to create the deform weight
00447                  */
00448 
00449                 /* we checked if the vertex was added before so no need to test again, simply add */
00450                 defvert_add_index_notest(dv, def_nr, weight);
00451             }
00452         }
00453     }
00454 }
00455 
00456 /* called while not in editmode */
00457 void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
00458 {
00459     /* add the vert to the deform group with the
00460      * specified assign mode
00461      */
00462     const int def_nr= BLI_findindex(&ob->defbase, dg);
00463 
00464     MDeformVert *dv= NULL;
00465     int tot;
00466 
00467     /* get the deform group number, exit if
00468      * it can't be found
00469      */
00470     if(def_nr < 0) return;
00471 
00472     /* if there's no deform verts then create some,
00473      */
00474     if(ED_vgroup_give_array(ob->data, &dv, &tot) && dv==NULL)
00475         ED_vgroup_data_create(ob->data);
00476 
00477     /* call another function to do the work
00478      */
00479     ED_vgroup_nr_vert_add(ob, def_nr, vertnum, weight, assignmode);
00480 }
00481 
00482 /* mesh object mode, lattice can be in editmode */
00483 void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
00484 {
00485     /* This routine removes the vertex from the specified
00486      * deform group.
00487      */
00488 
00489     /* TODO, this is slow in a loop, better pass def_nr directly, but leave for later... - campbell */
00490     const int def_nr= BLI_findindex(&ob->defbase, dg);
00491 
00492     if(def_nr != -1) {
00493         MDeformVert *dvert= NULL;
00494         int tot;
00495 
00496         /* get the deform vertices corresponding to the
00497          * vertnum
00498          */
00499         ED_vgroup_give_array(ob->data, &dvert, &tot);
00500 
00501         if(dvert) {
00502             MDeformVert *dv= &dvert[vertnum];
00503             MDeformWeight *dw;
00504 
00505             dw= defvert_find_index(dv, def_nr);
00506             defvert_remove_group(dv, dw); /* dw can be NULL */
00507         }
00508     }
00509 }
00510 
00511 static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
00512 {
00513     MDeformVert *dv= NULL;
00514     EditVert *eve;
00515     Mesh *me;
00516 
00517     /* get the deform vertices corresponding to the vertnum */
00518     if(ob->type==OB_MESH) {
00519         me= ob->data;
00520 
00521         if(me->edit_mesh) {
00522             eve= BLI_findlink(&me->edit_mesh->verts, vertnum);
00523             if(!eve) {
00524                 return 0.0f;
00525             }
00526             dv= CustomData_em_get(&me->edit_mesh->vdata, eve->data, CD_MDEFORMVERT);
00527         }
00528         else {
00529             if(vertnum >= me->totvert) {
00530                 return 0.0f;
00531             }
00532             dv = &me->dvert[vertnum];
00533         }
00534     }
00535     else if(ob->type==OB_LATTICE) {
00536         Lattice *lt= vgroup_edit_lattice(ob);
00537 
00538         if(lt->dvert) {
00539             if(vertnum >= lt->pntsu*lt->pntsv*lt->pntsw) {
00540                 return 0.0f;
00541             }
00542             dv = &lt->dvert[vertnum];
00543         }
00544     }
00545     
00546     if (dv) {
00547         MDeformWeight *dw= defvert_find_index(dv, def_nr);
00548         if (dw) {
00549             return dw->weight;
00550         }
00551     }
00552 
00553     return -1;
00554 }
00555 
00556 float ED_vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum)
00557 {
00558     const int def_nr= BLI_findindex(&ob->defbase, dg);
00559 
00560     if(def_nr == -1) {
00561         return -1;
00562     }
00563 
00564     return get_vert_def_nr(ob, def_nr, vertnum);
00565 }
00566 
00567 void ED_vgroup_select_by_name(Object *ob, const char *name)
00568 {   /* note: ob->actdef==0 signals on painting to create a new one, if a bone in posemode is selected */
00569     ob->actdef= defgroup_name_index(ob, name) + 1;
00570 }
00571 
00572 /********************** Operator Implementations *********************/
00573 
00574 /* only in editmode */
00575 static void vgroup_select_verts(Object *ob, int select)
00576 {
00577     const int def_nr= ob->actdef-1;
00578     MDeformVert *dv;
00579 
00580     if (!BLI_findlink(&ob->defbase, def_nr)) {
00581         return;
00582     }
00583 
00584     if(ob->type == OB_MESH) {
00585         Mesh *me= ob->data;
00586 
00587         if (me->edit_mesh) {
00588             EditMesh *em = BKE_mesh_get_editmesh(me);
00589             EditVert *eve;
00590 
00591             for (eve=em->verts.first; eve; eve=eve->next) {
00592                 if (!eve->h) {
00593                     dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
00594                     if (defvert_find_index(dv, def_nr)) {
00595                         if (select)  eve->f |=  SELECT;
00596                         else         eve->f &= ~SELECT;
00597                     }
00598                 }
00599             }
00600             /* this has to be called, because this function operates on vertices only */
00601             if(select) EM_select_flush(em); // vertices to edges/faces
00602             else EM_deselect_flush(em);
00603 
00604             BKE_mesh_end_editmesh(me, em);
00605         }
00606         else {
00607             if (me->dvert) {
00608                 MVert *mv;
00609                 MDeformVert *dv;
00610                 int i;
00611 
00612                 mv = me->mvert;
00613                 dv = me->dvert;
00614 
00615                 for (i=0; i<me->totvert; i++, mv++, dv++) {
00616                     if (!(mv->flag & ME_HIDE)) {
00617                         if (defvert_find_index(dv, def_nr)) {
00618                             if (select)  mv->flag |=  SELECT;
00619                             else         mv->flag &= ~SELECT;
00620                         }
00621                     }
00622                 }
00623 
00624                 paintvert_flush_flags(ob);
00625             }
00626         }
00627     }
00628     else if(ob->type == OB_LATTICE) {
00629         Lattice *lt= vgroup_edit_lattice(ob);
00630         
00631         if(lt->dvert) {
00632             BPoint *bp;
00633             int a, tot;
00634             
00635             dv= lt->dvert;
00636 
00637             tot= lt->pntsu*lt->pntsv*lt->pntsw;
00638             for(a=0, bp= lt->def; a<tot; a++, bp++, dv++) {
00639                 if (defvert_find_index(dv, def_nr)) {
00640                     if (select)  bp->f1 |=  SELECT;
00641                     else         bp->f1 &= ~SELECT;
00642                 }
00643             }
00644         }
00645     }
00646 }
00647 
00648 static void vgroup_duplicate(Object *ob)
00649 {
00650     bDeformGroup *dg, *cdg;
00651     char name[sizeof(dg->name)];
00652     MDeformWeight *dw_org, *dw_cpy;
00653     MDeformVert **dvert_array=NULL;
00654     int i, idg, icdg, dvert_tot=0;
00655 
00656     dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
00657     if(!dg)
00658         return;
00659     
00660     if(!strstr(dg->name, "_copy")) {
00661         BLI_snprintf(name, sizeof(name), "%s_copy", dg->name);
00662     }
00663     else {
00664         BLI_snprintf(name, sizeof(name), "%s", dg->name);
00665     }
00666 
00667     cdg = defgroup_duplicate(dg);
00668     BLI_strncpy(cdg->name, name, sizeof(cdg->name));
00669     defgroup_unique_name(cdg, ob);
00670 
00671     BLI_addtail(&ob->defbase, cdg);
00672 
00673     idg = (ob->actdef-1);
00674     ob->actdef = BLI_countlist(&ob->defbase);
00675     icdg = (ob->actdef-1);
00676 
00677     /* TODO, we might want to allow only copy selected verts here? - campbell */
00678     ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, FALSE);
00679 
00680     if (dvert_array) {
00681         for(i = 0; i < dvert_tot; i++) {
00682             MDeformVert *dv= dvert_array[i];
00683             dw_org = defvert_find_index(dv, idg);
00684             if(dw_org) {
00685                 /* defvert_verify_index re-allocs org so need to store the weight first */
00686                 dw_cpy = defvert_verify_index(dv, icdg);
00687                 dw_cpy->weight = dw_org->weight;
00688             }
00689         }
00690 
00691         MEM_freeN(dvert_array);
00692     }
00693 }
00694 
00695 static void vgroup_normalize(Object *ob)
00696 {
00697     MDeformWeight *dw;
00698     MDeformVert *dv, **dvert_array=NULL;
00699     int i, dvert_tot=0;
00700     const int def_nr= ob->actdef-1;
00701 
00702     Mesh *me = ob->data;
00703     const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
00704 
00705     if (!BLI_findlink(&ob->defbase, def_nr)) {
00706         return;
00707     }
00708 
00709     ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
00710 
00711     if (dvert_array) {
00712         float weight_max = 0.0f;
00713 
00714         for(i = 0; i < dvert_tot; i++) {
00715 
00716             /* incase its not selected */
00717             if (!(dv = dvert_array[i])) {
00718                 continue;
00719             }
00720 
00721             dw = defvert_find_index(dv, def_nr);
00722             if(dw) {
00723                 weight_max = MAX2(dw->weight, weight_max);
00724             }
00725         }
00726 
00727         if(weight_max > 0.0f) {
00728             for(i = 0; i < dvert_tot; i++) {
00729                 
00730                 /* incase its not selected */
00731                 if (!(dv = dvert_array[i])) {
00732                     continue;
00733                 }
00734 
00735                 dw = defvert_find_index(dv, def_nr);
00736                 if(dw) {
00737                     dw->weight /= weight_max;
00738                     
00739                     /* incase of division errors with very low weights */
00740                     CLAMP(dw->weight, 0.0f, 1.0f);
00741                 }
00742             }
00743         }
00744 
00745         MEM_freeN(dvert_array);
00746     }
00747 }
00748 
00749 /* This adds the indices of vertices to a list if they are not already present
00750 It returns the number that it added (0-2)
00751 It relies on verts having -1 for unassigned indices
00752 */
00753 static int tryToAddVerts(int *verts, int length, int a, int b)
00754 {
00755     char containsA = FALSE;
00756     char containsB = FALSE;
00757     int added = 0;
00758     int i;
00759     for(i = 0; i < length && (!containsA || !containsB); i++) {
00760         if(verts[i] == a) {
00761             containsA = TRUE;
00762         } else if(verts[i] == b) {
00763             containsB = TRUE;
00764         } else if(verts[i] == -1) {
00765             if(!containsA) {
00766                 verts[i] = a;
00767                 containsA = TRUE;
00768                 added++;
00769             } else if(!containsB){
00770                 verts[i] = b;
00771                 containsB = TRUE;
00772                 added++;
00773             }
00774         }
00775     }
00776     return added;
00777 }
00778 
00779 /* This finds all of the vertices connected to vert by an edge
00780 and returns an array of indices of size count
00781 
00782 count is an int passed by reference so it can be assigned the value of the length here.
00783 */
00784 static int* getSurroundingVerts(Mesh *me, int vert, int *count)
00785 {
00786     int length = 0;
00787     int *tverts;
00788     int *verts = NULL;
00789     MFace *mf = me->mface;
00790     int totface = me->totface;
00791     int found = 0;
00792     int i;
00793     for(i = 0; i < totface; i++, mf++) {
00794         if(vert == mf->v1 || vert == mf->v2 || vert == mf->v3 || (mf->v4 &&vert == mf->v4)) {
00795             length+=2;
00796         }
00797     }
00798     if(!length) {
00799         return NULL;
00800     }
00801     tverts = MEM_mallocN(sizeof(int)*length, "tempSurroundingVerts");
00802     mf = me->mface;
00803     for(i = 0; i < length; i++) {
00804         tverts[i] = -1;
00805     }
00806     for(i = 0; i < totface; i++, mf++) {
00807         int a=-1, b=-1;
00808         if(mf->v1 == vert) {
00809             a = mf->v2;
00810             if(mf->v4) {
00811                 b = mf->v4;
00812             } else {
00813                 b = mf->v3;
00814             }
00815         } else if(mf->v2 == vert) {
00816             a = mf->v1;
00817             b = mf->v3;
00818         } else if(mf->v3 == vert) {
00819             a = mf->v2;
00820             if(mf->v4) {
00821                 b = mf->v4;
00822             } else {
00823                 b = mf->v1;
00824             }
00825         } else if (mf->v4 && mf->v4 == vert){
00826             a = mf->v1;
00827             b = mf->v3;
00828         } else {
00829             continue;
00830         }
00831         found += tryToAddVerts(tverts, length, a, b);
00832     }
00833     if(found) {
00834         verts = MEM_mallocN(sizeof(int)* found, "surroundingVerts");
00835         for(i = 0; i < found; i++) {
00836             verts[i] = tverts[i];
00837         }
00838         *count = found;
00839     }
00840     MEM_freeN(tverts);
00841     return verts;
00842 }
00843 
00844 /* get a single point in space by averaging a point cloud (vectors of size 3)
00845 coord is the place the average is stored, points is the point cloud, count is the number of points in the cloud
00846 */
00847 static void getSingleCoordinate(MVert *points, int count, float coord[3])
00848 {
00849     int i;
00850     zero_v3(coord);
00851     for(i = 0; i < count; i++) {
00852         add_v3_v3(coord, points[i].co);
00853     }
00854     mul_v3_fl(coord, 1.0f/count);
00855 }
00856 
00857 /* given a plane and a start and end position,
00858 compute the amount of vertical distance relative to the plane and store it in dists,
00859 then get the horizontal and vertical change and store them in changes
00860 */
00861 static void getVerticalAndHorizontalChange(const float norm[3], float d, const float coord[3],
00862                                            const float start[3], float distToStart,
00863                                            float *end, float (*changes)[2], float *dists, int index)
00864 {
00865     // A=Q-((Q-P).N)N
00866     // D = (a*x0 + b*y0 +c*z0 +d)
00867     float projA[3], projB[3];
00868 
00869     closest_to_plane_v3(projA, coord, norm, start);
00870     closest_to_plane_v3(projB, coord, norm, end);
00871     // (vertical and horizontal refer to the plane's y and xz respectively)
00872     // vertical distance
00873     dists[index] = norm[0]*end[0] + norm[1]*end[1] + norm[2]*end[2] + d;
00874     // vertical change
00875     changes[index][0] = dists[index] - distToStart;
00876     //printf("vc %f %f\n", distance(end, projB, 3)-distance(start, projA, 3), changes[index][0]);
00877     // horizontal change
00878     changes[index][1] = len_v3v3(projA, projB);
00879 }
00880 
00881 // I need the derived mesh to be forgotten so the positions are recalculated with weight changes (see dm_deform_recalc)
00882 static void dm_deform_clear(DerivedMesh *dm, Object *ob)
00883 {
00884     if(ob->derivedDeform && (ob->derivedDeform)==dm) {
00885         ob->derivedDeform->needsFree = 1;
00886         ob->derivedDeform->release(ob->derivedDeform);
00887         ob->derivedDeform = NULL;
00888     }
00889     else if(dm) {
00890         dm->needsFree = 1;
00891         dm->release(dm);
00892     }
00893 }
00894 
00895 // recalculate the deformation
00896 static DerivedMesh* dm_deform_recalc(Scene *scene, Object *ob)
00897 {
00898     return mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
00899 }
00900 
00901 /* by changing nonzero weights, try to move a vertex in me->mverts with index 'index' to
00902 distToBe distance away from the provided plane strength can change distToBe so that it moves
00903 towards distToBe by that percentage cp changes how much the weights are adjusted
00904 to check the distance
00905 
00906 index is the index of the vertex being moved
00907 norm and d are the plane's properties for the equation: ax + by + cz + d = 0
00908 coord is a point on the plane
00909 */
00910 static void moveCloserToDistanceFromPlane(Scene *scene, Object *ob, Mesh *me, int index, float norm[3],
00911                                           float coord[3], float d, float distToBe, float strength, float cp)
00912 {
00913     DerivedMesh *dm;
00914     MDeformWeight *dw;
00915     MVert m;
00916     MDeformVert *dvert = me->dvert+index;
00917     int totweight = dvert->totweight;
00918     float oldw = 0;
00919     float oldPos[3] = {0};
00920     float vc, hc, dist = 0.0f;
00921     int i, k;
00922     float (*changes)[2] = MEM_mallocN(sizeof(float *)*totweight*2, "vertHorzChange");
00923     float *dists = MEM_mallocN(sizeof(float)*totweight, "distance");
00924 
00925     /* track if up or down moved it closer for each bone */
00926     int *upDown = MEM_callocN(sizeof(int)*totweight, "upDownTracker");
00927 
00928     int *dwIndices = MEM_callocN(sizeof(int)*totweight, "dwIndexTracker");
00929     float distToStart;
00930     int bestIndex = 0;
00931     char wasChange;
00932     char wasUp;
00933     int lastIndex = -1;
00934     float originalDistToBe = distToBe;
00935     do {
00936         wasChange = FALSE;
00937         dm = dm_deform_recalc(scene, ob);
00938         dm->getVert(dm, index, &m);
00939         copy_v3_v3(oldPos, m.co);
00940         distToStart = dot_v3v3(norm, oldPos) + d;
00941 
00942         if(distToBe == originalDistToBe) {
00943             distToBe += distToStart - distToStart*strength;
00944         }
00945         for(i = 0; i < totweight; i++) {
00946             dwIndices[i] = i;
00947             dw = (dvert->dw+i);
00948             vc = hc = 0;
00949             if(!dw->weight) {
00950                 changes[i][0] = 0;
00951                 changes[i][1] = 0;
00952                 dists[i] = distToStart;
00953                 continue;
00954             }
00955             for(k = 0; k < 2; k++) {
00956                 if(dm) {
00957                     dm_deform_clear(dm, ob); dm = NULL;
00958                 }
00959                 oldw = dw->weight;
00960                 if(k) {
00961                     dw->weight *= 1+cp;
00962                 } else {
00963                     dw->weight /= 1+cp;
00964                 }
00965                 if(dw->weight == oldw) {
00966                     changes[i][0] = 0;
00967                     changes[i][1] = 0;
00968                     dists[i] = distToStart;
00969                     break;
00970                 }
00971                 if(dw->weight > 1) {
00972                     dw->weight = 1;
00973                 }
00974                 dm = dm_deform_recalc(scene, ob);
00975                 dm->getVert(dm, index, &m);
00976                 getVerticalAndHorizontalChange(norm, d, coord, oldPos, distToStart, m.co, changes, dists, i);
00977                 dw->weight = oldw;
00978                 if(!k) {
00979                     vc = changes[i][0];
00980                     hc = changes[i][1];
00981                     dist = dists[i];
00982                 } else {
00983                     if(fabs(dist - distToBe) < fabs(dists[i] - distToBe)) {
00984                         upDown[i] = 0;
00985                         changes[i][0] = vc;
00986                         changes[i][1] = hc;
00987                         dists[i] = dist;
00988                     } else {
00989                         upDown[i] = 1;
00990                     }
00991                     if(fabs(dists[i] - distToBe) > fabs(distToStart - distToBe)) {
00992                         changes[i][0] = 0;
00993                         changes[i][1] = 0;
00994                         dists[i] = distToStart;
00995                     }
00996                 }
00997             }
00998         }
00999         // sort the changes by the vertical change
01000         for(k = 0; k < totweight; k++) {
01001             float tf;
01002             int ti;
01003             bestIndex = k;
01004             for(i = k+1; i < totweight; i++) {
01005                 dist = dists[i];
01006 
01007                 if(fabs(dist) > fabs(dists[i])) {
01008                     bestIndex = i;
01009                 }
01010             }
01011             // switch with k
01012             if(bestIndex != k) {
01013                 ti = upDown[k];
01014                 upDown[k] = upDown[bestIndex];
01015                 upDown[bestIndex] = ti;
01016 
01017                 ti = dwIndices[k];
01018                 dwIndices[k] = dwIndices[bestIndex];
01019                 dwIndices[bestIndex] = ti;
01020 
01021                 tf = changes[k][0];
01022                 changes[k][0] = changes[bestIndex][0];
01023                 changes[bestIndex][0] = tf;
01024 
01025                 tf = changes[k][1];
01026                 changes[k][1] = changes[bestIndex][1];
01027                 changes[bestIndex][1] = tf;
01028 
01029                 tf = dists[k];
01030                 dists[k] = dists[bestIndex];
01031                 dists[bestIndex] = tf;
01032             }
01033         }
01034         bestIndex = -1;
01035         // find the best change with an acceptable horizontal change
01036         for(i = 0; i < totweight; i++) {
01037             if(fabs(changes[i][0]) > fabs(changes[i][1]*2.0f)) {
01038                 bestIndex = i;
01039                 break;
01040             }
01041         }
01042         if(bestIndex != -1) {
01043             wasChange = TRUE;
01044             // it is a good place to stop if it tries to move the opposite direction
01045             // (relative to the plane) of last time
01046             if(lastIndex != -1) {
01047                 if(wasUp != upDown[bestIndex]) {
01048                     wasChange = FALSE;
01049                 }
01050             }
01051             lastIndex = bestIndex;
01052             wasUp = upDown[bestIndex];
01053             dw = (dvert->dw+dwIndices[bestIndex]);
01054             oldw = dw->weight;
01055             if(upDown[bestIndex]) {
01056                 dw->weight *= 1+cp;
01057             } else {
01058                 dw->weight /= 1+cp;
01059             }
01060             if(dw->weight > 1) {
01061                 dw->weight = 1;
01062             }
01063             if(oldw == dw->weight) {
01064                 wasChange = FALSE;
01065             }
01066             if(dm) {
01067                 dm_deform_clear(dm, ob); dm = NULL;
01068             }
01069         }
01070     } while(wasChange && (distToStart-distToBe)/fabsf(distToStart-distToBe) ==
01071                          (dists[bestIndex]-distToBe)/fabsf(dists[bestIndex]-distToBe));
01072     MEM_freeN(upDown);
01073     MEM_freeN(changes);
01074     MEM_freeN(dists);
01075     MEM_freeN(dwIndices);
01076 }
01077 
01078 /* this is used to try to smooth a surface by only adjusting the nonzero weights of a vertex 
01079 but it could be used to raise or lower an existing 'bump.' */
01080 static void vgroup_fix(Scene *scene, Object *ob, float distToBe, float strength, float cp)
01081 {
01082     int i;
01083 
01084     Mesh *me = ob->data;
01085     MVert *mvert = me->mvert;
01086     const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
01087     int *verts = NULL;
01088     for(i = 0; i < me->totvert && mvert; i++, mvert++) {
01089         
01090         if(use_vert_sel && (mvert->flag & SELECT)) {
01091             
01092             int count=0;
01093             if((verts = getSurroundingVerts(me, i, &count))) {
01094                 MVert m;
01095                 MVert *p = MEM_callocN(sizeof(MVert)*(count), "deformedPoints");
01096                 int k;
01097 
01098                 DerivedMesh *dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
01099                 for(k = 0; k < count; k++) {
01100                     dm->getVert(dm, verts[k], &m);
01101                     p[k] = m;
01102                 }
01103                 
01104                 if(count >= 3) {
01105                     float d /*, dist */ /* UNUSED */, mag;
01106                     float coord[3];
01107                     float norm[3];
01108                     getSingleCoordinate(p, count, coord);
01109                     dm->getVert(dm, i, &m);
01110                     sub_v3_v3v3(norm, m.co, coord);
01111                     mag= normalize_v3(norm);
01112                     if(mag) { /* zeros fix */
01113                         d = -dot_v3v3(norm, coord);
01114                         /* dist = (norm[0]*m.co[0] + norm[1]*m.co[1] + norm[2]*m.co[2] + d); */ /* UNUSED */
01115                         moveCloserToDistanceFromPlane(scene, ob, me, i, norm, coord, d, distToBe, strength, cp);
01116                     }
01117                 }
01118 
01119                 MEM_freeN(verts);
01120                 MEM_freeN(p);
01121             }
01122         }
01123     }
01124 }
01125 
01126 static void vgroup_levels(Object *ob, float offset, float gain)
01127 {
01128     MDeformWeight *dw;
01129     MDeformVert *dv, **dvert_array=NULL;
01130     int i, dvert_tot=0;
01131     const int def_nr= ob->actdef-1;
01132 
01133     Mesh *me = ob->data;
01134     const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
01135 
01136     if (!BLI_findlink(&ob->defbase, def_nr)) {
01137         return;
01138     }
01139 
01140     ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
01141 
01142     if (dvert_array) {
01143         for(i = 0; i < dvert_tot; i++) {
01144 
01145             /* incase its not selected */
01146             if (!(dv = dvert_array[i])) {
01147                 continue;
01148             }
01149 
01150             dw = defvert_find_index(dv, def_nr);
01151             if(dw) {
01152                 dw->weight = gain * (dw->weight + offset);
01153 
01154                 CLAMP(dw->weight, 0.0f, 1.0f);
01155             }
01156         }
01157 
01158         MEM_freeN(dvert_array);
01159     }
01160 }
01161 
01162 /* TODO - select between groups */
01163 static void vgroup_normalize_all(Object *ob, int lock_active)
01164 {
01165     MDeformVert *dv, **dvert_array=NULL;
01166     int i, dvert_tot=0;
01167     const int def_nr= ob->actdef-1;
01168 
01169     Mesh *me = ob->data;
01170     const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
01171 
01172     if (lock_active && !BLI_findlink(&ob->defbase, def_nr)) {
01173         return;
01174     }
01175 
01176     ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
01177 
01178     if (dvert_array) {
01179         if(lock_active) {
01180 
01181             for(i = 0; i < dvert_tot; i++) {
01182                 /* incase its not selected */
01183                 if (!(dv = dvert_array[i])) {
01184                     continue;
01185                 }
01186 
01187                 defvert_normalize_lock(dv, def_nr);
01188             }
01189         }
01190         else {
01191             for(i = 0; i < dvert_tot; i++) {
01192 
01193                 /* incase its not selected */
01194                 if (!(dv = dvert_array[i])) {
01195                     continue;
01196                 }
01197 
01198                 defvert_normalize(dv);
01199             }
01200         }
01201 
01202         MEM_freeN(dvert_array);
01203     }
01204 }
01205 
01206 
01207 static void vgroup_lock_all(Object *ob, int action)
01208 {
01209     bDeformGroup *dg;
01210 
01211     if(action == SEL_TOGGLE) {
01212         action= SEL_SELECT;
01213         for(dg= ob->defbase.first; dg; dg= dg->next) {
01214             if(dg->flag & DG_LOCK_WEIGHT) {
01215                 action= SEL_DESELECT;
01216                 break;
01217             }
01218         }
01219     }
01220 
01221     for(dg= ob->defbase.first; dg; dg= dg->next) {
01222         switch(action) {
01223             case SEL_SELECT:
01224                 dg->flag |= DG_LOCK_WEIGHT;
01225                 break;
01226             case SEL_DESELECT:
01227                 dg->flag &= ~DG_LOCK_WEIGHT;
01228                 break;
01229             case SEL_INVERT:
01230                 dg->flag ^= DG_LOCK_WEIGHT;
01231                 break;
01232         }
01233     }
01234 }
01235 
01236 static void vgroup_invert(Object *ob, const short auto_assign, const short auto_remove)
01237 {
01238     MDeformWeight *dw;
01239     MDeformVert *dv, **dvert_array=NULL;
01240     int i, dvert_tot=0;
01241     const int def_nr= ob->actdef-1;
01242     
01243     Mesh *me = ob->data;
01244     const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
01245 
01246     if (!BLI_findlink(&ob->defbase, def_nr)) {
01247         return;
01248     }
01249 
01250     ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
01251 
01252     if (dvert_array) {
01253         for(i = 0; i < dvert_tot; i++) {
01254 
01255             /* incase its not selected */
01256             if (!(dv = dvert_array[i])) {
01257                 continue;
01258             }
01259 
01260             if (auto_assign) {
01261                 dw= defvert_verify_index(dv, def_nr);
01262             }
01263             else {
01264                 dw= defvert_find_index(dv, def_nr);
01265             }
01266 
01267             if(dw) {
01268                 dw->weight = 1.0f - dw->weight;
01269 
01270                 if(auto_remove && dw->weight <= 0.0f) {
01271                     defvert_remove_group(dv, dw);
01272                 }
01273             }
01274         }
01275 
01276         MEM_freeN(dvert_array);
01277     }
01278 }
01279 
01280 static void vgroup_blend(Object *ob)
01281 {
01282     MDeformWeight *dw;
01283     MDeformVert *dvert_array=NULL, *dvert;
01284     int i, dvert_tot=0;
01285     const int def_nr= ob->actdef-1;
01286 
01287     EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)ob->data));
01288     // ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
01289 
01290     if (em==NULL)
01291         return;
01292 
01293     if (BLI_findlink(&ob->defbase, def_nr)) {
01294         int sel1, sel2;
01295         int i1, i2;
01296 
01297         EditEdge *eed;
01298         EditVert *eve;
01299         float *vg_weights;
01300         float *vg_users;
01301 
01302         i= 0;
01303         for(eve= em->verts.first; eve; eve= eve->next)
01304             eve->tmp.l= i++;
01305 
01306         dvert_tot= i;
01307 
01308         vg_weights= MEM_callocN(sizeof(float)*dvert_tot, "vgroup_blend_f");
01309         vg_users= MEM_callocN(sizeof(int)*dvert_tot, "vgroup_blend_i");
01310 
01311         for(eed= em->edges.first; eed; eed= eed->next) {
01312             sel1= eed->v1->f & SELECT;
01313             sel2= eed->v2->f & SELECT;
01314 
01315             if(sel1 != sel2) {
01316                 /* i1 is always the selected one */
01317                 if(sel1==TRUE && sel2==FALSE) {
01318                     i1= eed->v1->tmp.l;
01319                     i2= eed->v2->tmp.l;
01320                     eve= eed->v2;
01321                 }
01322                 else {
01323                     i2= eed->v1->tmp.l;
01324                     i1= eed->v2->tmp.l;
01325                     eve= eed->v1;
01326                 }
01327 
01328                 vg_users[i1]++;
01329 
01330                 /* TODO, we may want object mode blending */
01331                 if(em)  dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
01332                 else    dvert= dvert_array+i2;
01333 
01334                 dw= defvert_find_index(dvert, def_nr);
01335 
01336                 if(dw) {
01337                     vg_weights[i1] += dw->weight;
01338                 }
01339             }
01340         }
01341 
01342         i= 0;
01343         for(eve= em->verts.first; eve; eve= eve->next) {
01344             if(eve->f & SELECT && vg_users[i] > 0) {
01345                 /* TODO, we may want object mode blending */
01346                 if(em)  dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
01347                 else    dvert= dvert_array+i;
01348 
01349                 dw= defvert_verify_index(dvert, def_nr);
01350                 dw->weight= vg_weights[i] / (float)vg_users[i];
01351 
01352                 /* incase of division errors */
01353                 CLAMP(dw->weight, 0.0f, 1.0f);
01354             }
01355 
01356             i++;
01357         }
01358         MEM_freeN(vg_weights);
01359         MEM_freeN(vg_users);
01360     }
01361 }
01362 
01363 static void vgroup_clean(Object *ob, const float epsilon, int keep_single)
01364 {
01365     MDeformWeight *dw;
01366     MDeformVert *dv, **dvert_array=NULL;
01367     int i, dvert_tot=0;
01368     const int def_nr= ob->actdef-1;
01369     
01370     Mesh *me = ob->data;
01371     const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
01372 
01373     if (!BLI_findlink(&ob->defbase, def_nr)) {
01374         return;
01375     }
01376 
01377     ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
01378 
01379     if (dvert_array) {
01380         /* only the active group */
01381         for(i = 0; i < dvert_tot; i++) {
01382 
01383             /* incase its not selected */
01384             if (!(dv = dvert_array[i])) {
01385                 continue;
01386             }
01387 
01388             dw= defvert_find_index(dv, def_nr);
01389 
01390             if (dw) {
01391                 if (dw->weight <= epsilon) {
01392                     if(keep_single==FALSE || dv->totweight > 1) {
01393                         defvert_remove_group(dv, dw); /* dw can be NULL */
01394                     }
01395                 }
01396             }
01397         }
01398 
01399         MEM_freeN(dvert_array);
01400     }
01401 }
01402 
01403 static void vgroup_clean_all(Object *ob, const float epsilon, const int keep_single)
01404 {
01405     MDeformVert **dvert_array=NULL;
01406     int i, dvert_tot=0;
01407     
01408     Mesh *me = ob->data;
01409     const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
01410 
01411     ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
01412 
01413     if (dvert_array) {
01414         MDeformVert *dv;
01415         MDeformWeight *dw;
01416 
01417         for(i = 0; i < dvert_tot; i++) {
01418             int j;
01419 
01420             /* incase its not selected */
01421             if (!(dv = dvert_array[i])) {
01422                 continue;
01423             }
01424 
01425             j= dv->totweight;
01426 
01427             while(j--) {
01428 
01429                 if(keep_single && dv->totweight == 1)
01430                     break;
01431 
01432                 dw= dv->dw + j;
01433 
01434                 if(dw->weight <= epsilon) {
01435                     defvert_remove_group(dv, dw);
01436                 }
01437             }
01438         }
01439 
01440         MEM_freeN(dvert_array);
01441     }
01442 }
01443 
01444 
01445 static void dvert_mirror_op(MDeformVert *dvert, MDeformVert *dvert_mirr,
01446                             const char sel, const char sel_mirr,
01447                             const int *flip_map, const int flip_map_len,
01448                             const short mirror_weights, const short flip_vgroups,
01449                             const short all_vgroups, const int act_vgroup)
01450 {
01451     BLI_assert(sel || sel_mirr);
01452 
01453     if(sel_mirr && sel) {
01454         /* swap */
01455         if(mirror_weights) {
01456             if (all_vgroups) {
01457                 SWAP(MDeformVert, *dvert, *dvert_mirr);
01458             }
01459             else {
01460                 MDeformWeight *dw=      defvert_find_index(dvert, act_vgroup);
01461                 MDeformWeight *dw_mirr= defvert_find_index(dvert_mirr, act_vgroup);
01462 
01463                 if (dw || dw_mirr) {
01464                     if (dw_mirr == NULL)
01465                         dw_mirr= defvert_verify_index(dvert_mirr, act_vgroup);
01466                     if (dw == NULL)
01467                         dw= defvert_verify_index(dvert, act_vgroup);
01468 
01469                     SWAP(float, dw->weight, dw_mirr->weight);
01470                 }
01471             }
01472         }
01473 
01474         if(flip_vgroups) {
01475             defvert_flip(dvert, flip_map, flip_map_len);
01476             defvert_flip(dvert_mirr, flip_map, flip_map_len);
01477         }
01478     }
01479     else {
01480         /* dvert should always be the target, only swaps pointer */
01481         if(sel_mirr) {
01482             SWAP(MDeformVert *, dvert, dvert_mirr);
01483         }
01484 
01485         if(mirror_weights) {
01486             if (all_vgroups) {
01487                 defvert_copy(dvert, dvert_mirr);
01488             }
01489             else {
01490                 defvert_copy_index(dvert, dvert_mirr, act_vgroup);
01491             }
01492         }
01493 
01494         /* flip map already modified for 'all_vgroups' */
01495         if(flip_vgroups) {
01496             defvert_flip(dvert, flip_map, flip_map_len);
01497         }
01498     }
01499 }
01500 
01501 /* TODO, vgroup locking */
01502 /* TODO, face masking */
01503 void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_vgroups, const short all_vgroups)
01504 {
01505 
01506 #define VGROUP_MIRR_OP                                                        \
01507         dvert_mirror_op(dvert, dvert_mirr,                                    \
01508                         sel, sel_mirr,                                        \
01509                         flip_map, flip_map_len,                               \
01510                         mirror_weights, flip_vgroups,                         \
01511                         all_vgroups, def_nr                                   \
01512                         )
01513 
01514     EditVert *eve, *eve_mirr;
01515     MDeformVert *dvert, *dvert_mirr;
01516     short sel, sel_mirr;
01517     int *flip_map, flip_map_len;
01518     const int def_nr= ob->actdef-1;
01519 
01520     if ( (mirror_weights==0 && flip_vgroups==0) ||
01521          (BLI_findlink(&ob->defbase, def_nr) == NULL) )
01522     {
01523         return;
01524     }
01525 
01526     if (flip_vgroups) {
01527         flip_map= all_vgroups ?
01528                     defgroup_flip_map(ob, &flip_map_len, FALSE) :
01529                     defgroup_flip_map_single(ob, &flip_map_len, FALSE, def_nr);
01530 
01531         BLI_assert(flip_map != NULL);
01532 
01533         if (flip_map == NULL) {
01534             /* something went wrong!, possibly no groups */
01535             return;
01536         }
01537     }
01538     else {
01539         flip_map= NULL;
01540         flip_map_len= 0;
01541     }
01542 
01543     /* only the active group */
01544     if(ob->type == OB_MESH) {
01545         Mesh *me= ob->data;
01546         EditMesh *em = BKE_mesh_get_editmesh(me);
01547 
01548         if (em) {
01549             if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
01550                 goto cleanup;
01551             }
01552 
01553             EM_cache_x_mirror_vert(ob, em);
01554 
01555             /* Go through the list of editverts and assign them */
01556             for(eve=em->verts.first; eve; eve=eve->next){
01557                 if((eve_mirr=eve->tmp.v)) {
01558                     sel= eve->f & SELECT;
01559                     sel_mirr= eve_mirr->f & SELECT;
01560 
01561                     if((sel || sel_mirr) && (eve != eve_mirr)) {
01562                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
01563                         dvert_mirr= CustomData_em_get(&em->vdata, eve_mirr->data, CD_MDEFORMVERT);
01564                         if(dvert && dvert_mirr) {
01565                             VGROUP_MIRR_OP;
01566                         }
01567                     }
01568 
01569                     eve->tmp.v= eve_mirr->tmp.v= NULL;
01570                 }
01571             }
01572             BKE_mesh_end_editmesh(me, em);
01573         }
01574         else {
01575             /* object mode / weight paint */
01576             MVert *mv, *mv_mirr;
01577             int vidx, vidx_mirr;
01578             const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
01579 
01580             if (me->dvert == NULL) {
01581                 goto cleanup;
01582             }
01583 
01584             if (!use_vert_sel) {
01585                 sel= sel_mirr= TRUE;
01586             }
01587 
01588             /* tag verts we have used */
01589             for(vidx= 0, mv= me->mvert; vidx < me->totvert; vidx++, mv++) {
01590                 mv->flag &= ~ME_VERT_TMP_TAG;
01591             }
01592 
01593             for(vidx= 0, mv= me->mvert; vidx < me->totvert; vidx++, mv++) {
01594                 if (    ((mv->flag & ME_VERT_TMP_TAG) == 0) &&
01595                         ((vidx_mirr= mesh_get_x_mirror_vert(ob, vidx)) != -1) &&
01596                         (vidx != vidx_mirr) &&
01597                         ((((mv_mirr= me->mvert + vidx_mirr)->flag) & ME_VERT_TMP_TAG) == 0))
01598                 {
01599 
01600                     if (use_vert_sel) {
01601                         sel= mv->flag & SELECT;
01602                         sel_mirr= mv_mirr->flag & SELECT;
01603                     }
01604 
01605                     if (sel || sel_mirr) {
01606                         dvert= &me->dvert[vidx];
01607                         dvert_mirr= &me->dvert[vidx_mirr];
01608 
01609                         VGROUP_MIRR_OP;
01610                     }
01611 
01612                     mv->flag |= ME_VERT_TMP_TAG;
01613                     mv_mirr->flag |= ME_VERT_TMP_TAG;
01614                 }
01615             }
01616         }
01617     }
01618     else if (ob->type == OB_LATTICE) {
01619         Lattice *lt= vgroup_edit_lattice(ob);
01620         int i1, i2;
01621         int u, v, w;
01622         int pntsu_half;
01623         /* half but found up odd value */
01624 
01625         if(lt->pntsu == 1 || lt->dvert == NULL) {
01626             goto cleanup;
01627         }
01628 
01629         /* unlike editmesh we know that by only looping over the first hald of
01630          * the 'u' indicies it will cover all points except the middle which is
01631          * ok in this case */
01632         pntsu_half= lt->pntsu / 2;
01633 
01634         for(w=0; w<lt->pntsw; w++) {
01635             for(v=0; v<lt->pntsv; v++) {
01636                 for(u=0; u<pntsu_half; u++) {
01637                     int u_inv= (lt->pntsu - 1) - u;
01638                     if(u != u_inv) {
01639                         BPoint *bp, *bp_mirr;
01640 
01641                         i1= LT_INDEX(lt, u, v, w);
01642                         i2= LT_INDEX(lt, u_inv, v, w);
01643 
01644                         bp= &lt->def[i1];
01645                         bp_mirr= &lt->def[i2];
01646 
01647                         sel= bp->f1 & SELECT;
01648                         sel_mirr= bp_mirr->f1 & SELECT;
01649 
01650                         if(sel || sel_mirr) {
01651                             dvert= &lt->dvert[i1];
01652                             dvert_mirr= &lt->dvert[i2];
01653 
01654                             VGROUP_MIRR_OP;
01655                         }
01656                     }
01657                 }
01658             }
01659         }
01660     }
01661 
01662 cleanup:
01663     if (flip_map) MEM_freeN(flip_map);
01664 
01665 #undef VGROUP_MIRR_OP
01666 
01667 }
01668 
01669 static void vgroup_remap_update_users(Object *ob, int *map)
01670 {
01671     ExplodeModifierData *emd;
01672     ModifierData *md;
01673     ParticleSystem *psys;
01674     ClothModifierData *clmd;
01675     ClothSimSettings *clsim;
01676     int a;
01677 
01678     /* these cases don't use names to refer to vertex groups, so when
01679      * they get deleted the numbers get out of sync, this corrects that */
01680 
01681     if(ob->soft)
01682         ob->soft->vertgroup= map[ob->soft->vertgroup];
01683 
01684     for(md=ob->modifiers.first; md; md=md->next) {
01685         if(md->type == eModifierType_Explode) {
01686             emd= (ExplodeModifierData*)md;
01687             emd->vgroup= map[emd->vgroup];
01688         }
01689         else if(md->type == eModifierType_Cloth) {
01690             clmd= (ClothModifierData*)md;
01691             clsim= clmd->sim_parms;
01692 
01693             if(clsim) {
01694                 clsim->vgroup_mass= map[clsim->vgroup_mass];
01695                 clsim->vgroup_bend= map[clsim->vgroup_bend];
01696                 clsim->vgroup_struct= map[clsim->vgroup_struct];
01697             }
01698         }
01699     }
01700 
01701     for(psys=ob->particlesystem.first; psys; psys=psys->next) {
01702         for(a=0; a<PSYS_TOT_VG; a++)
01703             psys->vgroup[a]= map[psys->vgroup[a]];
01704     }
01705 }
01706 
01707 
01708 static void vgroup_delete_update_users(Object *ob, int id)
01709 {
01710     int i, defbase_tot= BLI_countlist(&ob->defbase) + 1;
01711     int *map= MEM_mallocN(sizeof(int) * defbase_tot, "vgroup del");
01712 
01713     map[id]= map[0]= 0;
01714     for(i=1; i<id; i++) map[i]=i;
01715     for(i=id+1; i<defbase_tot; i++) map[i]=i-1;
01716 
01717     vgroup_remap_update_users(ob, map);
01718     MEM_freeN(map);
01719 }
01720 
01721 
01722 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg)
01723 {
01724     MDeformVert *dvert_array=NULL;
01725     int dvert_tot=0;
01726     const int def_nr= BLI_findindex(&ob->defbase, dg);
01727 
01728     assert(def_nr > -1);
01729 
01730     ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
01731 
01732     if(dvert_array) {
01733         int i, j;
01734         MDeformVert *dv;
01735         for(i= 0, dv= dvert_array; i < dvert_tot; i++, dv++) {
01736             MDeformWeight *dw;
01737 
01738             dw= defvert_find_index(dv, def_nr);
01739             defvert_remove_group(dv, dw); /* dw can be NULL */
01740 
01741             /* inline, make into a function if anything else needs to do this */
01742             for(j = 0; j < dv->totweight; j++) {
01743                 if(dv->dw[j].def_nr > def_nr) {
01744                     dv->dw[j].def_nr--;
01745                 }
01746             }
01747             /* done */
01748         }
01749     }
01750 
01751     vgroup_delete_update_users(ob, def_nr + 1);
01752 
01753     /* Remove the group */
01754     BLI_freelinkN(&ob->defbase, dg);
01755 
01756     /* Update the active deform index if necessary */
01757     if(ob->actdef > def_nr)
01758         ob->actdef--;
01759     if(ob->actdef < 1 && ob->defbase.first)
01760         ob->actdef= 1;
01761 
01762 }
01763 
01764 /* only in editmode */
01765 /* removes from active defgroup, if allverts==0 only selected vertices */
01766 static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGroup *dg)
01767 {
01768     MDeformVert *dv;
01769     const int def_nr= BLI_findindex(&ob->defbase, dg);
01770 
01771     if(ob->type == OB_MESH) {
01772         Mesh *me= ob->data;
01773 
01774         if (me->edit_mesh) {
01775             EditVert *eve;
01776             EditMesh *em = BKE_mesh_get_editmesh(me);
01777 
01778             for (eve=em->verts.first; eve; eve=eve->next) {
01779                 dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
01780 
01781                 if (dv && dv->dw && (allverts || (eve->f & SELECT))) {
01782                     MDeformWeight *dw = defvert_find_index(dv, def_nr);
01783                     defvert_remove_group(dv, dw); /* dw can be NULL */
01784                 }
01785             }
01786             BKE_mesh_end_editmesh(me, em);
01787         }
01788         else {
01789             MVert *mv;
01790             MDeformVert *dv;
01791             int i;
01792 
01793             if (!me->dvert) {
01794                 ED_vgroup_data_create(&me->id);
01795             }
01796 
01797             mv = me->mvert;
01798             dv = me->dvert;
01799 
01800             for (i=0; i<me->totvert; i++, mv++, dv++) {
01801                 if (mv->flag & SELECT) {
01802                     if (dv->dw && (allverts || (mv->flag & SELECT))) {
01803                         MDeformWeight *dw = defvert_find_index(dv, def_nr);
01804                         defvert_remove_group(dv, dw); /* dw can be NULL */
01805                     }
01806                 }
01807             }
01808         }
01809     }
01810     else if(ob->type == OB_LATTICE) {
01811         Lattice *lt= vgroup_edit_lattice(ob);
01812         
01813         if(lt->dvert) {
01814             BPoint *bp;
01815             int i, tot= lt->pntsu*lt->pntsv*lt->pntsw;
01816                 
01817             for(i=0, bp= lt->def; i<tot; i++, bp++) {
01818                 if(allverts || (bp->f1 & SELECT)) {
01819                     MDeformWeight *dw;
01820 
01821                     dv= &lt->dvert[i];
01822 
01823                     dw = defvert_find_index(dv, def_nr);
01824                     defvert_remove_group(dv, dw); /* dw can be NULL */
01825                 }
01826             }
01827         }
01828     }
01829 }
01830 
01831 static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg)
01832 {
01833     int i;
01834     const int dg_index= BLI_findindex(&ob->defbase, dg);
01835 
01836     assert(dg_index > -1);
01837 
01838     /* Make sure that no verts are using this group */
01839     vgroup_active_remove_verts(ob, TRUE, dg);
01840 
01841     /* Make sure that any verts with higher indices are adjusted accordingly */
01842     if(ob->type==OB_MESH) {
01843         Mesh *me= ob->data;
01844         EditMesh *em = BKE_mesh_get_editmesh(me);
01845         EditVert *eve;
01846         MDeformVert *dvert;
01847         
01848         for(eve=em->verts.first; eve; eve=eve->next){
01849             dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
01850 
01851             if(dvert)
01852                 for(i=0; i<dvert->totweight; i++)
01853                     if(dvert->dw[i].def_nr > dg_index)
01854                         dvert->dw[i].def_nr--;
01855         }
01856         BKE_mesh_end_editmesh(me, em);
01857     }
01858     else if(ob->type==OB_LATTICE) {
01859         Lattice *lt= vgroup_edit_lattice(ob);
01860         BPoint *bp;
01861         MDeformVert *dvert= lt->dvert;
01862         int a, tot;
01863         
01864         if(dvert) {
01865             tot= lt->pntsu*lt->pntsv*lt->pntsw;
01866             for(a=0, bp= lt->def; a<tot; a++, bp++, dvert++) {
01867                 for(i=0; i<dvert->totweight; i++){
01868                     if(dvert->dw[i].def_nr > dg_index)
01869                         dvert->dw[i].def_nr--;
01870                 }
01871             }
01872         }
01873     }
01874 
01875     vgroup_delete_update_users(ob, dg_index + 1);
01876 
01877     /* Remove the group */
01878     BLI_freelinkN (&ob->defbase, dg);
01879 
01880     /* Update the active deform index if necessary */
01881     if(ob->actdef > dg_index)
01882         ob->actdef--;
01883     if(ob->actdef < 1 && ob->defbase.first)
01884         ob->actdef= 1;
01885 
01886     /* remove all dverts */
01887     if(ob->defbase.first == NULL) {
01888         if(ob->type==OB_MESH) {
01889             Mesh *me= ob->data;
01890             CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
01891             me->dvert= NULL;
01892         }
01893         else if(ob->type==OB_LATTICE) {
01894             Lattice *lt= vgroup_edit_lattice(ob);
01895             if(lt->dvert) {
01896                 MEM_freeN(lt->dvert);
01897                 lt->dvert= NULL;
01898             }
01899         }
01900     }
01901 }
01902 
01903 static int vgroup_object_in_edit_mode(Object *ob)
01904 {
01905     if(ob->type == OB_MESH)
01906         return (((Mesh*)ob->data)->edit_mesh != NULL);
01907     else if(ob->type == OB_LATTICE)
01908         return (((Lattice*)ob->data)->editlatt != NULL);
01909     
01910     return 0;
01911 }
01912 
01913 static int vgroup_object_in_wpaint_vert_select(Object *ob)
01914 {
01915     if (ob->type == OB_MESH) {
01916         Mesh *me = ob->data;
01917         return ( (ob->mode & OB_MODE_WEIGHT_PAINT) &&
01918                  (me->edit_mesh == NULL) &&
01919                  (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX) );
01920     }
01921 
01922     return 0;
01923 }
01924 
01925 static void vgroup_delete(Object *ob)
01926 {
01927     bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef-1);
01928     if(!dg)
01929         return;
01930 
01931     if(vgroup_object_in_edit_mode(ob))
01932         vgroup_delete_edit_mode(ob, dg);
01933     else
01934         vgroup_delete_object_mode(ob, dg);
01935 }
01936 
01937 static void vgroup_delete_all(Object *ob)
01938 {
01939     /* Remove all DVerts */
01940     if(ob->type==OB_MESH) {
01941         Mesh *me= ob->data;
01942         CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
01943         me->dvert= NULL;
01944     }
01945     else if(ob->type==OB_LATTICE) {
01946         Lattice *lt= vgroup_edit_lattice(ob);
01947         if(lt->dvert) {
01948             MEM_freeN(lt->dvert);
01949             lt->dvert= NULL;
01950         }
01951     }
01952     
01953     /* Remove all DefGroups */
01954     BLI_freelistN(&ob->defbase);
01955     
01956     /* Fix counters/indices */
01957     ob->actdef= 0;
01958 }
01959 
01960 /* only in editmode */
01961 static void vgroup_assign_verts(Object *ob, const float weight)
01962 {
01963     MDeformVert *dv;
01964     const int def_nr= ob->actdef-1;
01965 
01966     if(!BLI_findlink(&ob->defbase, def_nr))
01967         return;
01968 
01969     if(ob->type == OB_MESH) {
01970         Mesh *me= ob->data;
01971         if (me->edit_mesh) {
01972             EditMesh *em = BKE_mesh_get_editmesh(me);
01973             EditVert *eve;
01974 
01975             if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT))
01976                 EM_add_data_layer(em, &em->vdata, CD_MDEFORMVERT, NULL);
01977 
01978             /* Go through the list of editverts and assign them */
01979             for (eve=em->verts.first; eve; eve=eve->next) {
01980                 if (eve->f & SELECT) {
01981                     MDeformWeight *dw;
01982                     dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); /* can be NULL */
01983                     dw= defvert_verify_index(dv, def_nr);
01984                     if (dw) {
01985                         dw->weight= weight;
01986                     }
01987                 }
01988             }
01989             BKE_mesh_end_editmesh(me, em);
01990         }
01991         else {
01992             MVert *mv;
01993             MDeformVert *dv;
01994             int i;
01995 
01996             if (!me->dvert) {
01997                 ED_vgroup_data_create(&me->id);
01998             }
01999 
02000             mv = me->mvert;
02001             dv = me->dvert;
02002 
02003             for (i=0; i<me->totvert; i++, mv++, dv++) {
02004                 if (mv->flag & SELECT) {
02005                     MDeformWeight *dw;
02006                     dw= defvert_verify_index(dv, def_nr);
02007                     if (dw) {
02008                         dw->weight= weight;
02009                     }
02010                 }
02011             }
02012         }
02013     }
02014     else if(ob->type == OB_LATTICE) {
02015         Lattice *lt= vgroup_edit_lattice(ob);
02016         BPoint *bp;
02017         int a, tot;
02018 
02019         if(lt->dvert==NULL)
02020             ED_vgroup_data_create(&lt->id);
02021 
02022         dv= lt->dvert;
02023 
02024         tot= lt->pntsu*lt->pntsv*lt->pntsw;
02025         for(a=0, bp= lt->def; a<tot; a++, bp++, dv++) {
02026             if(bp->f1 & SELECT) {
02027                 MDeformWeight *dw;
02028 
02029                 dw= defvert_verify_index(dv, def_nr);
02030                 if (dw) {
02031                     dw->weight= weight;
02032                 }
02033             }
02034         }
02035     }
02036 }
02037 
02038 /* only in editmode */
02039 /* removes from all defgroup, if allverts==0 only selected vertices */
02040 static void vgroup_remove_verts(Object *ob, int allverts)
02041 {
02042     /* To prevent code redundancy, we just use vgroup_active_remove_verts, but that
02043      * only operates on the active vgroup. So we iterate through all groups, by changing
02044      * active group index
02045      */
02046     bDeformGroup *dg;
02047     for(dg= ob->defbase.first; dg; dg= dg->next) {
02048         vgroup_active_remove_verts(ob, allverts, dg);
02049     }
02050 }
02051 
02052 /********************** vertex group operators *********************/
02053 
02054 static int vertex_group_poll(bContext *C)
02055 {
02056     Object *ob= ED_object_context(C);
02057     ID *data= (ob)? ob->data: NULL;
02058     return (ob && !ob->id.lib && OB_TYPE_SUPPORT_VGROUP(ob->type) && data && !data->lib);
02059 }
02060 
02061 static int UNUSED_FUNCTION(vertex_group_poll_edit)(bContext *C)
02062 {
02063     Object *ob= ED_object_context(C);
02064     ID *data= (ob)? ob->data: NULL;
02065 
02066     if(!(ob && !ob->id.lib && data && !data->lib))
02067         return 0;
02068 
02069     return vgroup_object_in_edit_mode(ob);
02070 }
02071 
02072 /* editmode _or_ weight paint vertex sel */
02073 static int vertex_group_poll_edit_or_wpaint_vert_select(bContext *C)
02074 {
02075     Object *ob= ED_object_context(C);
02076     ID *data= (ob)? ob->data: NULL;
02077 
02078     if(!(ob && !ob->id.lib && data && !data->lib))
02079         return 0;
02080 
02081     return ( vgroup_object_in_edit_mode(ob) ||
02082              vgroup_object_in_wpaint_vert_select(ob) );
02083 }
02084 
02085 static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op))
02086 {
02087     Object *ob= ED_object_context(C);
02088 
02089     ED_vgroup_add(ob);
02090     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02091     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
02092     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
02093     
02094     return OPERATOR_FINISHED;
02095 }
02096 
02097 void OBJECT_OT_vertex_group_add(wmOperatorType *ot)
02098 {
02099     /* identifiers */
02100     ot->name= "Add Vertex Group";
02101     ot->idname= "OBJECT_OT_vertex_group_add";
02102     
02103     /* api callbacks */
02104     ot->poll= vertex_group_poll;
02105     ot->exec= vertex_group_add_exec;
02106 
02107     /* flags */
02108     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02109 }
02110 
02111 static int vertex_group_remove_exec(bContext *C, wmOperator *op)
02112 {
02113     Object *ob= ED_object_context(C);
02114 
02115     if(RNA_boolean_get(op->ptr, "all"))
02116         vgroup_delete_all(ob);
02117     else
02118         vgroup_delete(ob);
02119 
02120     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02121     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
02122     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
02123     
02124     return OPERATOR_FINISHED;
02125 }
02126 
02127 void OBJECT_OT_vertex_group_remove(wmOperatorType *ot)
02128 {
02129     /* identifiers */
02130     ot->name= "Remove Vertex Group";
02131     ot->idname= "OBJECT_OT_vertex_group_remove";
02132     
02133     /* api callbacks */
02134     ot->poll= vertex_group_poll;
02135     ot->exec= vertex_group_remove_exec;
02136 
02137     /* flags */
02138     /* redo operator will fail in this case because vertex groups aren't stored
02139        in local edit mode stack and toggling "all" property will lead to
02140        all groups deleted without way to restore them (see [#29527], sergey) */
02141     ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO;
02142 
02143     /* properties */
02144     RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups");
02145 }
02146 
02147 static int vertex_group_assign_exec(bContext *C, wmOperator *op)
02148 {
02149     ToolSettings *ts= CTX_data_tool_settings(C);
02150     Object *ob= ED_object_context(C);
02151 
02152     if(RNA_boolean_get(op->ptr, "new"))
02153         ED_vgroup_add(ob);
02154 
02155     vgroup_assign_verts(ob, ts->vgroup_weight);
02156     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02157     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
02158     
02159     return OPERATOR_FINISHED;
02160 }
02161 
02162 void OBJECT_OT_vertex_group_assign(wmOperatorType *ot)
02163 {
02164     /* identifiers */
02165     ot->name= "Assign Vertex Group";
02166     ot->idname= "OBJECT_OT_vertex_group_assign";
02167     
02168     /* api callbacks */
02169     ot->poll= vertex_group_poll_edit_or_wpaint_vert_select;
02170     ot->exec= vertex_group_assign_exec;
02171 
02172     /* flags */
02173     /* redo operator will fail in this case because vertex group assignment
02174        isn't stored in local edit mode stack and toggling "new" property will
02175        lead to creating plenty of new veretx groups (see [#29527], sergey) */
02176     ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO;
02177 
02178     /* properties */
02179     RNA_def_boolean(ot->srna, "new", 0, "New", "Assign vertex to new vertex group");
02180 }
02181 
02182 static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
02183 {
02184     Object *ob= ED_object_context(C);
02185 
02186     if(RNA_boolean_get(op->ptr, "all"))
02187         vgroup_remove_verts(ob, 0);
02188     else {
02189         bDeformGroup *dg= BLI_findlink(&ob->defbase, ob->actdef - 1);
02190 
02191         if(dg == NULL) {
02192             return OPERATOR_CANCELLED;
02193         }
02194 
02195         vgroup_active_remove_verts(ob, FALSE, dg);
02196     }
02197 
02198     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02199     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
02200 
02201     return OPERATOR_FINISHED;
02202 }
02203 
02204 void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot)
02205 {
02206     /* identifiers */
02207     ot->name= "Remove from Vertex Group";
02208     ot->idname= "OBJECT_OT_vertex_group_remove_from";
02209 
02210     /* api callbacks */
02211     ot->poll= vertex_group_poll_edit_or_wpaint_vert_select;
02212     ot->exec= vertex_group_remove_from_exec;
02213 
02214     /* flags */
02215     /* redo operator will fail in this case because vertex groups ssignment
02216        isn't stored in local edit mode stack and toggling "all" property will lead to
02217        removing vertices from all groups (see [#29527], sergey) */
02218     ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO;
02219 
02220     /* properties */
02221     RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups");
02222 }
02223 
02224 static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
02225 {
02226     Object *ob= ED_object_context(C);
02227 
02228     if(!ob || ob->id.lib)
02229         return OPERATOR_CANCELLED;
02230 
02231     vgroup_select_verts(ob, 1);
02232     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
02233 
02234     return OPERATOR_FINISHED;
02235 }
02236 
02237 void OBJECT_OT_vertex_group_select(wmOperatorType *ot)
02238 {
02239     /* identifiers */
02240     ot->name= "Select Vertex Group";
02241     ot->idname= "OBJECT_OT_vertex_group_select";
02242 
02243     /* api callbacks */
02244     ot->poll= vertex_group_poll_edit_or_wpaint_vert_select;
02245     ot->exec= vertex_group_select_exec;
02246 
02247     /* flags */
02248     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02249 }
02250 
02251 static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
02252 {
02253     Object *ob= ED_object_context(C);
02254 
02255     vgroup_select_verts(ob, 0);
02256     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
02257 
02258     return OPERATOR_FINISHED;
02259 }
02260 
02261 void OBJECT_OT_vertex_group_deselect(wmOperatorType *ot)
02262 {
02263     /* identifiers */
02264     ot->name= "Deselect Vertex Group";
02265     ot->idname= "OBJECT_OT_vertex_group_deselect";
02266 
02267     /* api callbacks */
02268     ot->poll= vertex_group_poll_edit_or_wpaint_vert_select;
02269     ot->exec= vertex_group_deselect_exec;
02270 
02271     /* flags */
02272     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02273 }
02274 
02275 static int vertex_group_copy_exec(bContext *C, wmOperator *UNUSED(op))
02276 {
02277     Object *ob= ED_object_context(C);
02278 
02279     vgroup_duplicate(ob);
02280     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02281     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
02282     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
02283 
02284     return OPERATOR_FINISHED;
02285 }
02286 
02287 void OBJECT_OT_vertex_group_copy(wmOperatorType *ot)
02288 {
02289     /* identifiers */
02290     ot->name= "Copy Vertex Group";
02291     ot->idname= "OBJECT_OT_vertex_group_copy";
02292 
02293     /* api callbacks */
02294     ot->poll= vertex_group_poll;
02295     ot->exec= vertex_group_copy_exec;
02296 
02297     /* flags */
02298     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02299 }
02300 
02301 static int vertex_group_levels_exec(bContext *C, wmOperator *op)
02302 {
02303     Object *ob= ED_object_context(C);
02304     
02305     float offset= RNA_float_get(op->ptr,"offset");
02306     float gain= RNA_float_get(op->ptr,"gain");
02307     
02308     vgroup_levels(ob, offset, gain);
02309     
02310     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02311     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
02312     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
02313     
02314     return OPERATOR_FINISHED;
02315 }
02316 
02317 void OBJECT_OT_vertex_group_levels(wmOperatorType *ot)
02318 {
02319     /* identifiers */
02320     ot->name= "Vertex Group Levels";
02321     ot->idname= "OBJECT_OT_vertex_group_levels";
02322     
02323     /* api callbacks */
02324     ot->poll= vertex_group_poll;
02325     ot->exec= vertex_group_levels_exec;
02326     
02327     /* flags */
02328     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02329     
02330     RNA_def_float(ot->srna, "offset", 0.f, -1.0, 1.0, "Offset", "Value to add to weights", -1.0f, 1.f);
02331     RNA_def_float(ot->srna, "gain", 1.f, 0.f, FLT_MAX, "Gain", "Value to multiply weights by", 0.0f, 10.f);
02332 }
02333 
02334 static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op))
02335 {
02336     Object *ob= ED_object_context(C);
02337 
02338     vgroup_normalize(ob);
02339 
02340     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02341     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
02342     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
02343 
02344     return OPERATOR_FINISHED;
02345 }
02346 
02347 void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot)
02348 {
02349     /* identifiers */
02350     ot->name= "Normalize Vertex Group";
02351     ot->idname= "OBJECT_OT_vertex_group_normalize";
02352 
02353     /* api callbacks */
02354     ot->poll= vertex_group_poll;
02355     ot->exec= vertex_group_normalize_exec;
02356 
02357     /* flags */
02358     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02359 }
02360 
02361 static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
02362 {
02363     Object *ob= ED_object_context(C);
02364     int lock_active= RNA_boolean_get(op->ptr,"lock_active");
02365 
02366     vgroup_normalize_all(ob, lock_active);
02367 
02368     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02369     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
02370     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
02371 
02372     return OPERATOR_FINISHED;
02373 }
02374 
02375 void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
02376 {
02377     /* identifiers */
02378     ot->name= "Normalize All Vertex Groups";
02379     ot->idname= "OBJECT_OT_vertex_group_normalize_all";
02380 
02381     /* api callbacks */
02382     ot->poll= vertex_group_poll;
02383     ot->exec= vertex_group_normalize_all_exec;
02384 
02385     /* flags */
02386     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02387 
02388     RNA_def_boolean(ot->srna, "lock_active", TRUE, "Lock Active",
02389                     "Keep the values of the active group while normalizing others");
02390 }
02391 
02392 static int vertex_group_fix_exec(bContext *C, wmOperator *op)
02393 {
02394     Object *ob= CTX_data_active_object(C);
02395     Scene *scene= CTX_data_scene(C);
02396     
02397     float distToBe= RNA_float_get(op->ptr, "dist");
02398     float strength= RNA_float_get(op->ptr, "strength");
02399     float cp= RNA_float_get(op->ptr, "accuracy");
02400     ModifierData *md= ob->modifiers.first;
02401 
02402     while(md) {
02403         if(md->type == eModifierType_Mirror && (md->mode&eModifierMode_Realtime)) {
02404             break;
02405         }
02406         md = md->next;
02407     }
02408     
02409     if(md && md->type == eModifierType_Mirror) {
02410         BKE_report(op->reports, RPT_ERROR_INVALID_CONTEXT, "This operator does not support an active mirror modifier");
02411         return OPERATOR_CANCELLED;
02412     }
02413     vgroup_fix(scene, ob, distToBe, strength, cp);
02414     
02415     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02416     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
02417     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
02418     
02419     return OPERATOR_FINISHED;
02420 }
02421 
02422 void OBJECT_OT_vertex_group_fix(wmOperatorType *ot)
02423 {
02424     /* identifiers */
02425     ot->name= "Fix Vertex Group Deform";
02426     ot->idname= "OBJECT_OT_vertex_group_fix";
02427     ot->description= "Modify the position of selected vertices by changing only their respective "
02428                      "groups' weights (this tool may be slow for many vertices)";
02429     
02430     /* api callbacks */
02431     ot->poll= vertex_group_poll;
02432     ot->exec= vertex_group_fix_exec;
02433     
02434     /* flags */
02435     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02436     RNA_def_float(ot->srna, "dist", 0.0f, -FLT_MAX, FLT_MAX, "Distance", "The distance to move to", -10.0f, 10.0f);
02437     RNA_def_float(ot->srna, "strength", 1.f, -2.0f, FLT_MAX, "Strength",
02438                   "The distance moved can be changed by this multiplier", -2.0f, 2.0f);
02439     RNA_def_float(ot->srna, "accuracy", 1.0f, 0.05f, FLT_MAX, "Change Sensitivity",
02440                   "Change the amount weights are altered with each iteration: lower values are slower", 0.05f, 1.f);
02441 }
02442 
02443 
02444 static int vertex_group_lock_exec(bContext *C, wmOperator *op)
02445 {
02446     Object *ob= CTX_data_active_object(C);
02447 
02448     int action = RNA_enum_get(op->ptr, "action");
02449 
02450     vgroup_lock_all(ob, action);
02451 
02452     return OPERATOR_FINISHED;
02453 }
02454 
02455 void OBJECT_OT_vertex_group_lock(wmOperatorType *ot)
02456 {
02457     /* identifiers */
02458     ot->name= "Change the Lock On Vertex Groups";
02459     ot->idname= "OBJECT_OT_vertex_group_lock";
02460 
02461     /* api callbacks */
02462     ot->poll= vertex_group_poll;
02463     ot->exec= vertex_group_lock_exec;
02464 
02465     /* flags */
02466     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02467 
02468     WM_operator_properties_select_all(ot);
02469 }
02470 
02471 static int vertex_group_invert_exec(bContext *C, wmOperator *op)
02472 {
02473     Object *ob= ED_object_context(C);
02474     int auto_assign= RNA_boolean_get(op->ptr,"auto_assign");
02475     int auto_remove= RNA_boolean_get(op->ptr,"auto_remove");
02476 
02477     vgroup_invert(ob, auto_assign, auto_remove);
02478     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02479     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
02480     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
02481 
02482     return OPERATOR_FINISHED;
02483 }
02484 
02485 void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
02486 {
02487     /* identifiers */
02488     ot->name= "Invert Vertex Group";
02489     ot->idname= "OBJECT_OT_vertex_group_invert";
02490 
02491     /* api callbacks */
02492     ot->poll= vertex_group_poll;
02493     ot->exec= vertex_group_invert_exec;
02494 
02495     /* flags */
02496     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02497 
02498     RNA_def_boolean(ot->srna, "auto_assign", TRUE, "Add Weights",
02499                     "Add verts from groups that have zero weight before inverting");
02500     RNA_def_boolean(ot->srna, "auto_remove", TRUE, "Remove Weights",
02501                     "Remove verts from groups that have zero weight after inverting");
02502 }
02503 
02504 
02505 static int vertex_group_blend_exec(bContext *C, wmOperator *UNUSED(op))
02506 {
02507     Object *ob= ED_object_context(C);
02508 
02509     vgroup_blend(ob);
02510 
02511     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02512     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
02513     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
02514 
02515     return OPERATOR_FINISHED;
02516 }
02517 
02518 void OBJECT_OT_vertex_group_blend(wmOperatorType *ot)
02519 {
02520     /* identifiers */
02521     ot->name= "Blend Vertex Group";
02522     ot->idname= "OBJECT_OT_vertex_group_blend";
02523     ot->description= "";
02524 
02525     /* api callbacks */
02526     ot->poll= vertex_group_poll;
02527     ot->exec= vertex_group_blend_exec;
02528 
02529     /* flags */
02530     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02531 }
02532 
02533 
02534 static int vertex_group_clean_exec(bContext *C, wmOperator *op)
02535 {
02536     Object *ob= ED_object_context(C);
02537 
02538     float limit= RNA_float_get(op->ptr,"limit");
02539     int all_groups= RNA_boolean_get(op->ptr,"all_groups");
02540     int keep_single= RNA_boolean_get(op->ptr,"keep_single");
02541 
02542     if(all_groups)  vgroup_clean_all(ob, limit, keep_single);
02543     else            vgroup_clean(ob, limit, keep_single);
02544 
02545     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02546     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
02547     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
02548 
02549     return OPERATOR_FINISHED;
02550 }
02551 
02552 void OBJECT_OT_vertex_group_clean(wmOperatorType *ot)
02553 {
02554     /* identifiers */
02555     ot->name= "Clean Vertex Group";
02556     ot->idname= "OBJECT_OT_vertex_group_clean";
02557     ot->description= "Remove Vertex Group assignments which aren't required";
02558 
02559     /* api callbacks */
02560     ot->poll= vertex_group_poll;
02561     ot->exec= vertex_group_clean_exec;
02562 
02563     /* flags */
02564     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02565 
02566     RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, 1.0, "Limit", "Remove weights under this limit", 0.001f, 0.99f);
02567     RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Clean all vertex groups");
02568     RNA_def_boolean(ot->srna, "keep_single", FALSE, "Keep Single",
02569                     "Keep verts assigned to at least one group when cleaning");
02570 }
02571 
02572 
02573 static int vertex_group_mirror_exec(bContext *C, wmOperator *op)
02574 {
02575     Object *ob= ED_object_context(C);
02576 
02577     ED_vgroup_mirror(ob,
02578                      RNA_boolean_get(op->ptr,"mirror_weights"),
02579                      RNA_boolean_get(op->ptr,"flip_group_names"),
02580                      RNA_boolean_get(op->ptr,"all_groups"));
02581 
02582     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02583     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
02584     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
02585 
02586     return OPERATOR_FINISHED;
02587 }
02588 
02589 void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot)
02590 {
02591     /* identifiers */
02592     ot->name= "Mirror Vertex Group";
02593     ot->idname= "OBJECT_OT_vertex_group_mirror";
02594     ot->description= "Mirror all vertex groups, flip weights and/or names, editing only selected vertices, "
02595                      "flipping when both sides are selected otherwise copy from unselected";
02596 
02597     /* api callbacks */
02598     ot->poll= vertex_group_poll;
02599     ot->exec= vertex_group_mirror_exec;
02600 
02601     /* flags */
02602     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02603 
02604     /* properties */
02605     RNA_def_boolean(ot->srna, "mirror_weights", TRUE, "Mirror Weights", "Mirror weights");
02606     RNA_def_boolean(ot->srna, "flip_group_names", TRUE, "Flip Groups", "Flip vertex group names");
02607     RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Mirror all vertex groups weights");
02608 
02609 }
02610 
02611 static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op))
02612 {
02613     Scene *scene= CTX_data_scene(C);
02614     Object *ob= ED_object_context(C);
02615     Base *base;
02616     int retval= OPERATOR_CANCELLED;
02617 
02618     for(base=scene->base.first; base; base= base->next) {
02619         if(base->object->type==ob->type) {
02620             if(base->object!=ob && base->object->data==ob->data) {
02621                 BLI_freelistN(&base->object->defbase);
02622                 BLI_duplicatelist(&base->object->defbase, &ob->defbase);
02623                 base->object->actdef= ob->actdef;
02624 
02625                 DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
02626                 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, base->object);
02627                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
02628 
02629                 retval = OPERATOR_FINISHED;
02630             }
02631         }
02632     }
02633 
02634     return retval;
02635 }
02636 
02637 void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot)
02638 {
02639     /* identifiers */
02640     ot->name= "Copy Vertex Groups to Linked";
02641     ot->idname= "OBJECT_OT_vertex_group_copy_to_linked";
02642     ot->description= "Copy Vertex Groups to all users of the same Geometry data";
02643 
02644     /* api callbacks */
02645     ot->poll= vertex_group_poll;
02646     ot->exec= vertex_group_copy_to_linked_exec;
02647 
02648     /* flags */
02649     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02650 }
02651 
02652 static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
02653 {
02654     Object *obact= ED_object_context(C);
02655     int change= 0;
02656     int fail= 0;
02657 
02658     CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects)
02659     {
02660         if(obact != ob) {
02661             if(ED_vgroup_copy_array(ob, obact)) change++;
02662             else                                fail++;
02663         }
02664     }
02665     CTX_DATA_END;
02666 
02667     if((change == 0 && fail == 0) || fail) {
02668         BKE_reportf(op->reports, RPT_ERROR,
02669                     "Copy to VGroups to Selected warning done %d, failed %d, object data must have matching indicies",
02670                     change, fail);
02671     }
02672 
02673     return OPERATOR_FINISHED;
02674 }
02675 
02676 
02677 void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot)
02678 {
02679     /* identifiers */
02680     ot->name= "Copy Vertex Group to Selected";
02681     ot->idname= "OBJECT_OT_vertex_group_copy_to_selected";
02682     ot->description= "Copy Vertex Groups to other selected objects with matching indices";
02683 
02684     /* api callbacks */
02685     ot->poll= vertex_group_poll;
02686     ot->exec= vertex_group_copy_to_selected_exec;
02687 
02688     /* flags */
02689     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02690 }
02691 
02692 static EnumPropertyItem vgroup_items[]= {
02693     {0, NULL, 0, NULL, NULL}};
02694 
02695 static int set_active_group_exec(bContext *C, wmOperator *op)
02696 {
02697     Object *ob= ED_object_context(C);
02698     int nr= RNA_enum_get(op->ptr, "group");
02699 
02700     BLI_assert(nr+1 >= 0);
02701     ob->actdef= nr+1;
02702 
02703     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02704     WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
02705 
02706     return OPERATOR_FINISHED;
02707 }
02708 
02709 static EnumPropertyItem *vgroup_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
02710 {   
02711     Object *ob= ED_object_context(C);
02712     EnumPropertyItem tmp = {0, "", 0, "", ""};
02713     EnumPropertyItem *item= NULL;
02714     bDeformGroup *def;
02715     int a, totitem= 0;
02716     
02717     if(!ob)
02718         return vgroup_items;
02719     
02720     for(a=0, def=ob->defbase.first; def; def=def->next, a++) {
02721         tmp.value= a;
02722         tmp.icon= ICON_GROUP_VERTEX;
02723         tmp.identifier= def->name;
02724         tmp.name= def->name;
02725         RNA_enum_item_add(&item, &totitem, &tmp);
02726     }
02727 
02728     RNA_enum_item_end(&item, &totitem);
02729     *free= 1;
02730 
02731     return item;
02732 }
02733 
02734 void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
02735 {
02736     PropertyRNA *prop;
02737 
02738     /* identifiers */
02739     ot->name= "Set Active Vertex Group";
02740     ot->idname= "OBJECT_OT_vertex_group_set_active";
02741     ot->description= "Set the active vertex group";
02742 
02743     /* api callbacks */
02744     ot->poll= vertex_group_poll;
02745     ot->exec= set_active_group_exec;
02746     ot->invoke= WM_menu_invoke;
02747 
02748     /* flags */
02749     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02750 
02751     /* properties */
02752     prop= RNA_def_enum(ot->srna, "group", vgroup_items, 0, "Group", "Vertex group to set as active");
02753     RNA_def_enum_funcs(prop, vgroup_itemf);
02754     ot->prop= prop;
02755 }
02756 
02757 /*creates the name_array parameter for vgroup_do_remap, call this before fiddling
02758   with the order of vgroups then call vgroup_do_remap after*/
02759 static char *vgroup_init_remap(Object *ob)
02760 {
02761     bDeformGroup *def;
02762     int defbase_tot = BLI_countlist(&ob->defbase);
02763     char *name_array= MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups");
02764     char *name;
02765 
02766     name= name_array;
02767     for(def = ob->defbase.first; def; def=def->next) {
02768         BLI_strncpy(name, def->name, MAX_VGROUP_NAME);
02769         name += MAX_VGROUP_NAME;
02770     }
02771 
02772     return name_array;
02773 }
02774 
02775 static int vgroup_do_remap(Object *ob, char *name_array, wmOperator *op)
02776 {
02777     MDeformVert *dvert= NULL;
02778     bDeformGroup *def;
02779     int defbase_tot = BLI_countlist(&ob->defbase);
02780 
02781     /* needs a dummy index at the start*/
02782     int *sort_map_update= MEM_mallocN(sizeof(int) * (defbase_tot + 1), "sort vgroups");
02783     int *sort_map= sort_map_update + 1;
02784 
02785     char *name;
02786     int i;
02787 
02788     name= name_array;
02789     for(def= ob->defbase.first, i=0; def; def=def->next, i++){
02790         sort_map[i]= BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name));
02791         name += MAX_VGROUP_NAME;
02792 
02793         BLI_assert(sort_map[i] != -1);
02794     }
02795 
02796     if(ob->mode == OB_MODE_EDIT) {
02797         if(ob->type==OB_MESH) {
02798             EditMesh *em = BKE_mesh_get_editmesh(ob->data);
02799             EditVert *eve;
02800 
02801             for(eve=em->verts.first; eve; eve=eve->next){
02802                 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
02803                 if(dvert && dvert->totweight){
02804                     defvert_remap(dvert, sort_map, defbase_tot);
02805                 }
02806             }
02807         }
02808         else {
02809             BKE_report(op->reports, RPT_ERROR, "Editmode lattice isnt supported yet");
02810             MEM_freeN(sort_map_update);
02811             return OPERATOR_CANCELLED;
02812         }
02813     }
02814     else {
02815         int dvert_tot=0;
02816 
02817         ED_vgroup_give_array(ob->data, &dvert, &dvert_tot);
02818 
02819         /*create as necassary*/
02820         while(dvert && dvert_tot--) {
02821             if(dvert->totweight)
02822                 defvert_remap(dvert, sort_map, defbase_tot);
02823             dvert++;
02824         }
02825     }
02826 
02827     /* update users */
02828     for(i=0; i<defbase_tot; i++)
02829         sort_map[i]++;
02830 
02831     sort_map_update[0]= 0;
02832     vgroup_remap_update_users(ob, sort_map_update);
02833 
02834     BLI_assert(sort_map_update[ob->actdef] >= 0);
02835     ob->actdef= sort_map_update[ob->actdef];
02836     
02837     MEM_freeN(sort_map_update);
02838 
02839     return OPERATOR_FINISHED;
02840 }
02841 
02842 static int vgroup_sort(void *def_a_ptr, void *def_b_ptr)
02843 {
02844     bDeformGroup *def_a= (bDeformGroup *)def_a_ptr;
02845     bDeformGroup *def_b= (bDeformGroup *)def_b_ptr;
02846 
02847     return BLI_natstrcmp(def_a->name, def_b->name);
02848 }
02849 
02850 static int vertex_group_sort_exec(bContext *C, wmOperator *op)
02851 {
02852     Object *ob= ED_object_context(C);
02853     char *name_array;
02854     int ret;
02855 
02856     /*init remapping*/
02857     name_array = vgroup_init_remap(ob);
02858 
02859     /*sort vgroup names*/
02860     BLI_sortlist(&ob->defbase, vgroup_sort);
02861 
02862     /*remap vgroup data to map to correct names*/
02863     ret = vgroup_do_remap(ob, name_array, op);
02864 
02865     if (ret != OPERATOR_CANCELLED) {
02866         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02867         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
02868     }
02869 
02870     if (name_array) MEM_freeN(name_array);
02871 
02872     return ret;
02873 }
02874 
02875 void OBJECT_OT_vertex_group_sort(wmOperatorType *ot)
02876 {
02877     ot->name= "Sort Vertex Groups";
02878     ot->idname= "OBJECT_OT_vertex_group_sort";
02879     ot->description= "Sorts vertex groups alphabetically";
02880 
02881     /* api callbacks */
02882     ot->poll= vertex_group_poll;
02883     ot->exec= vertex_group_sort_exec;
02884 
02885     /* flags */
02886     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02887 }
02888 
02889 static int vgroup_move_exec(bContext *C, wmOperator *op)
02890 {
02891     Object *ob= ED_object_context(C);
02892     bDeformGroup *def;
02893     char *name_array;
02894     int dir= RNA_enum_get(op->ptr, "direction"), ret;
02895 
02896     def = BLI_findlink(&ob->defbase, ob->actdef - 1);
02897     if (!def) {
02898         return OPERATOR_CANCELLED;
02899     }
02900 
02901     name_array = vgroup_init_remap(ob);
02902 
02903     if (dir == 1) { /*up*/
02904         void *prev = def->prev;
02905 
02906         BLI_remlink(&ob->defbase, def);
02907         BLI_insertlinkbefore(&ob->defbase, prev, def);
02908     } else { /*down*/
02909         void *next = def->next;
02910 
02911         BLI_remlink(&ob->defbase, def);
02912         BLI_insertlinkafter(&ob->defbase, next, def);
02913     }
02914 
02915     ret = vgroup_do_remap(ob, name_array, op);
02916 
02917     if (name_array) MEM_freeN(name_array);
02918 
02919     if (ret != OPERATOR_CANCELLED) {
02920         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02921         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
02922     }
02923 
02924     return ret;
02925 }
02926 
02927 void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
02928 {
02929     static EnumPropertyItem vgroup_slot_move[] = {
02930         {1, "UP", 0, "Up", ""},
02931         {-1, "DOWN", 0, "Down", ""},
02932         {0, NULL, 0, NULL, NULL}
02933     };
02934 
02935     /* identifiers */
02936     ot->name= "Move Vertex Group";
02937     ot->idname= "OBJECT_OT_vertex_group_move";
02938 
02939     /* api callbacks */
02940     ot->poll= vertex_group_poll;
02941     ot->exec= vgroup_move_exec;
02942 
02943     /* flags */
02944     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02945 
02946     RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
02947 }