d96a667857225ad1dfa0d395ed20e6c512b206d6
[blender.git] / source / blender / editors / object / object_vgroup.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /** \file blender/editors/object/object_vgroup.c
31  *  \ingroup edobj
32  */
33
34
35 #include <string.h>
36 #include <stddef.h>
37 #include <math.h>
38 #include <assert.h>
39
40 #include "MEM_guardedalloc.h"
41
42 #include "DNA_cloth_types.h"
43 #include "DNA_curve_types.h"
44 #include "DNA_lattice_types.h"
45 #include "DNA_meshdata_types.h"
46 #include "DNA_modifier_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_object_force.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_particle_types.h"
51
52 #include "BLI_math.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_editVert.h"
55 #include "BLI_utildefines.h"
56
57 #include "BKE_context.h"
58 #include "BKE_customdata.h"
59 #include "BKE_deform.h"
60 #include "BKE_depsgraph.h"
61 #include "BKE_global.h"
62 #include "BKE_mesh.h"
63 #include "BKE_report.h"
64 #include "BKE_DerivedMesh.h"//Radish
65
66 #include "RNA_access.h"
67 #include "RNA_define.h"
68
69 #include "WM_api.h"
70 #include "WM_types.h"
71
72 #include "ED_mesh.h"
73
74 #include "UI_resources.h"
75
76 #include "object_intern.h"
77
78 /************************ Exported Functions **********************/
79 static void vgroup_remap_update_users(Object *ob, int *map);
80 static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *defgroup);
81 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg);
82 static void vgroup_delete_all(Object *ob);
83
84 static Lattice *vgroup_edit_lattice(Object *ob)
85 {
86         Lattice *lt= ob->data;
87         BLI_assert(ob->type==OB_LATTICE);
88         return (lt->editlatt)? lt->editlatt->latt: lt;
89 }
90
91 int ED_vgroup_object_is_edit_mode(Object *ob)
92 {
93         if(ob->type == OB_MESH)
94                 return (((Mesh*)ob->data)->edit_mesh != NULL);
95         else if(ob->type == OB_LATTICE)
96                 return (((Lattice*)ob->data)->editlatt != NULL);
97
98         return 0;
99 }
100
101 bDeformGroup *ED_vgroup_add_name(Object *ob, const char *name)
102 {
103         bDeformGroup *defgroup;
104         
105         if(!ob || !ELEM(ob->type, OB_MESH, OB_LATTICE))
106                 return NULL;
107         
108         defgroup = MEM_callocN(sizeof(bDeformGroup), "add deformGroup");
109
110         BLI_strncpy(defgroup->name, name, sizeof(defgroup->name));
111
112         BLI_addtail(&ob->defbase, defgroup);
113         defgroup_unique_name(defgroup, ob);
114
115         ob->actdef = BLI_countlist(&ob->defbase);
116
117         return defgroup;
118 }
119
120 bDeformGroup *ED_vgroup_add(Object *ob) 
121 {
122         return ED_vgroup_add_name(ob, "Group");
123 }
124
125 void ED_vgroup_delete(Object *ob, bDeformGroup *defgroup) 
126 {
127         bDeformGroup *dg = (bDeformGroup *)ob->defbase.first;
128
129         while (dg) {
130                 if (dg == defgroup)
131                         break;
132                 dg = dg->next;
133         }
134
135         if (dg == NULL)
136                 return;
137
138         if(ED_vgroup_object_is_edit_mode(ob))
139                 vgroup_delete_edit_mode(ob, dg);
140         else
141                 vgroup_delete_object_mode(ob, dg);
142 }
143
144 int ED_vgroup_data_create(ID *id)
145 {
146         /* create deform verts */
147
148         if(GS(id->name)==ID_ME) {
149                 Mesh *me= (Mesh *)id;
150                 me->dvert= CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert);
151                 return TRUE;
152         }
153         else if(GS(id->name)==ID_LT) {
154                 Lattice *lt= (Lattice *)id;
155                 lt->dvert= MEM_callocN(sizeof(MDeformVert)*lt->pntsu*lt->pntsv*lt->pntsw, "lattice deformVert");
156                 return TRUE;
157         }
158         else {
159                 return FALSE;
160         }
161 }
162
163 static int ED_vgroup_give_parray(ID *id, MDeformVert ***dvert_arr, int *dvert_tot)
164 {
165         *dvert_tot = 0;
166         *dvert_arr = NULL;
167
168         if(id) {
169                 switch(GS(id->name)) {
170                         case ID_ME:
171                         {
172                                 Mesh *me = (Mesh *)id;
173
174                                 if(me->edit_mesh) {
175                                         EditMesh *em = me->edit_mesh;
176                                         EditVert *eve;
177                                         int i;
178
179                                         if (!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
180                                                 return 0;
181                                         }
182
183                                         i= BLI_countlist(&em->verts);
184
185                                         *dvert_arr= MEM_mallocN(sizeof(void*)*i, "vgroup parray from me");
186                                         *dvert_tot = i;
187
188                                         i = 0;
189                                         for (eve=em->verts.first; eve; eve=eve->next, i++) {
190                                                 (*dvert_arr)[i] = CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
191                                         }
192
193                                         return 1;
194                                 }
195                                 else if(me->dvert) {
196                                         int i;
197
198                                         *dvert_tot= me->totvert;
199                                         *dvert_arr= MEM_mallocN(sizeof(void*)*me->totvert, "vgroup parray from me");
200
201                                         for (i=0; i<me->totvert; i++) {
202                                                 (*dvert_arr)[i] = me->dvert + i;
203                                         }
204
205                                         return 1;
206                                 }
207                                 else {
208                                         return 0;
209                                 }
210                         }
211                         case ID_LT:
212                         {
213                                 int i=0;
214
215                                 Lattice *lt= (Lattice *)id;
216                                 lt= (lt->editlatt)? lt->editlatt->latt: lt;
217
218                                 if(lt->dvert) {
219                                         *dvert_tot= lt->pntsu*lt->pntsv*lt->pntsw;
220                                         *dvert_arr= MEM_mallocN(sizeof(void*)*(*dvert_tot), "vgroup parray from me");
221
222                                         for (i=0; i<*dvert_tot; i++) {
223                                                 (*dvert_arr)[i] = lt->dvert + i;
224                                         }
225
226                                         return 1;
227                                 }
228                                 else {
229                                         return 0;
230                                 }
231                         }
232                 }
233         }
234
235         return 0;
236 }
237
238 /* returns true if the id type supports weights */
239 int ED_vgroup_give_array(ID *id, MDeformVert **dvert_arr, int *dvert_tot)
240 {
241         if(id) {
242                 switch(GS(id->name)) {
243                         case ID_ME:
244                         {
245                                 Mesh *me = (Mesh *)id;
246                                 *dvert_arr= me->dvert;
247                                 *dvert_tot= me->totvert;
248                                 return TRUE;
249                         }
250                         case ID_LT:
251                         {
252                                 Lattice *lt= (Lattice *)id;
253                                 lt= (lt->editlatt)? lt->editlatt->latt: lt;
254                                 *dvert_arr= lt->dvert;
255                                 *dvert_tot= lt->pntsu*lt->pntsv*lt->pntsw;
256                                 return TRUE;
257                         }
258                 }
259         }
260
261         *dvert_arr= NULL;
262         *dvert_tot= 0;
263         return FALSE;
264 }
265
266 /* matching index only */
267 int ED_vgroup_copy_array(Object *ob, Object *ob_from)
268 {
269         MDeformVert **dvert_array_from, **dvf;
270         MDeformVert **dvert_array, **dv;
271         int dvert_tot_from;
272         int dvert_tot;
273         int i;
274         int totdef_from= BLI_countlist(&ob_from->defbase);
275         int totdef= BLI_countlist(&ob->defbase);
276         short new_vgroup= FALSE;
277
278         ED_vgroup_give_parray(ob_from->data, &dvert_array_from, &dvert_tot_from);
279         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
280
281         if((dvert_array == NULL) && (dvert_array_from != NULL) && ED_vgroup_data_create(ob->data)) {
282                 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
283                 new_vgroup= TRUE;
284         }
285
286         if(ob==ob_from || dvert_tot==0 || (dvert_tot != dvert_tot_from) || dvert_array_from==NULL || dvert_array==NULL) {
287                 if (dvert_array) MEM_freeN(dvert_array);
288                 if (dvert_array_from) MEM_freeN(dvert_array_from);
289
290                 if(new_vgroup == TRUE) {
291                         /* free the newly added vgroup since it wasn't compatible */
292                         vgroup_delete_all(ob);
293                 }
294                 return 0;
295         }
296
297         /* do the copy */
298         BLI_freelistN(&ob->defbase);
299         BLI_duplicatelist(&ob->defbase, &ob_from->defbase);
300         ob->actdef= ob_from->actdef;
301
302         if(totdef_from < totdef) {
303                 /* correct vgroup indices because the number of vgroups is being reduced. */
304                 int *remap= MEM_mallocN(sizeof(int) * (totdef + 1), "ED_vgroup_copy_array");
305                 for(i=0; i<=totdef_from; i++) remap[i]= i;
306                 for(; i<=totdef; i++) remap[i]= 0; /* can't use these, so disable */
307
308                 vgroup_remap_update_users(ob, remap);
309                 MEM_freeN(remap);
310         }
311
312         dvf= dvert_array_from;
313         dv= dvert_array;
314
315         for(i=0; i<dvert_tot; i++, dvf++, dv++) {
316                 if((*dv)->dw)
317                         MEM_freeN((*dv)->dw);
318
319                 *(*dv)= *(*dvf);
320
321                 if((*dv)->dw)
322                         (*dv)->dw= MEM_dupallocN((*dv)->dw);
323         }
324
325         MEM_freeN(dvert_array);
326         MEM_freeN(dvert_array_from);
327
328         return 1;
329 }
330
331 /* for mesh in object mode
332    lattice can be in editmode */
333 static void ED_vgroup_nr_vert_remove(Object *ob, int def_nr, int vertnum)
334 {
335         /* This routine removes the vertex from the deform
336          * group with number def_nr.
337          *
338          * This routine is meant to be fast, so it is the
339          * responsibility of the calling routine to:
340          *   a) test whether ob is non-NULL
341          *   b) test whether ob is a mesh
342          *   c) calculate def_nr
343          */
344
345         MDeformWeight *newdw;
346         MDeformVert *dvert= NULL;
347         int i, tot;
348
349         /* get the deform vertices corresponding to the
350          * vertnum
351          */
352         ED_vgroup_give_array(ob->data, &dvert, &tot);
353
354         if(dvert==NULL)
355                 return;
356         
357         dvert+= vertnum;
358
359         /* for all of the deform weights in the
360          * deform vert
361          */
362         for(i=dvert->totweight - 1 ; i>=0 ; i--){
363
364                 /* if the def_nr is the same as the one
365                  * for our weight group then remove it
366                  * from this deform vert.
367                  */
368                 if(dvert->dw[i].def_nr == def_nr) {
369                         dvert->totweight--;
370
371                         /* if there are still other deform weights
372                          * attached to this vert then remove this
373                          * deform weight, and reshuffle the others
374                          */
375                         if(dvert->totweight) {
376                                 newdw = MEM_mallocN(sizeof(MDeformWeight)*(dvert->totweight), 
377                                                                          "deformWeight");
378                                 if(dvert->dw){
379                                         memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*i);
380                                         memcpy(newdw+i, dvert->dw+i+1, 
381                                                         sizeof(MDeformWeight)*(dvert->totweight-i));
382                                         MEM_freeN(dvert->dw);
383                                 }
384                                 dvert->dw=newdw;
385                         }
386                         /* if there are no other deform weights
387                          * left then just remove the deform weight
388                          */
389                         else {
390                                 MEM_freeN(dvert->dw);
391                                 dvert->dw = NULL;
392                                 break;
393                         }
394                 }
395         }
396
397 }
398
399 /* for Mesh in Object mode */
400 /* allows editmode for Lattice */
401 static void ED_vgroup_nr_vert_add(Object *ob, int def_nr, int vertnum, float weight, int assignmode)
402 {
403         /* add the vert to the deform group with the
404          * specified number
405          */
406         MDeformVert *dv= NULL;
407         MDeformWeight *newdw;
408         int     i, tot;
409
410         /* get the vert */
411         ED_vgroup_give_array(ob->data, &dv, &tot);
412         
413         if(dv==NULL)
414                 return;
415         
416         /* check that vertnum is valid before trying to get the relevant dvert */
417         if ((vertnum < 0) || (vertnum >= tot))
418                 return;
419         else
420                 dv += vertnum;
421
422         /* Lets first check to see if this vert is
423          * already in the weight group -- if so
424          * lets update it
425          */
426         for(i=0; i<dv->totweight; i++){
427                 
428                 /* if this weight cooresponds to the
429                  * deform group, then add it using
430                  * the assign mode provided
431                  */
432                 if(dv->dw[i].def_nr == def_nr){
433                         
434                         switch(assignmode) {
435                         case WEIGHT_REPLACE:
436                                 dv->dw[i].weight=weight;
437                                 break;
438                         case WEIGHT_ADD:
439                                 dv->dw[i].weight+=weight;
440                                 if(dv->dw[i].weight >= 1.0f)
441                                         dv->dw[i].weight = 1.0f;
442                                 break;
443                         case WEIGHT_SUBTRACT:
444                                 dv->dw[i].weight-=weight;
445                                 /* if the weight is zero or less then
446                                  * remove the vert from the deform group
447                                  */
448                                 if(dv->dw[i].weight <= 0.0f)
449                                         ED_vgroup_nr_vert_remove(ob, def_nr, vertnum);
450                                 break;
451                         }
452                         return;
453                 }
454         }
455
456         /* if the vert wasn't in the deform group then
457          * we must take a different form of action ...
458          */
459
460         switch(assignmode) {
461         case WEIGHT_SUBTRACT:
462                 /* if we are subtracting then we don't
463                  * need to do anything
464                  */
465                 return;
466
467         case WEIGHT_REPLACE:
468         case WEIGHT_ADD:
469                 /* if we are doing an additive assignment, then
470                  * we need to create the deform weight
471                  */
472                 newdw = MEM_callocN(sizeof(MDeformWeight)*(dv->totweight+1), 
473                                                          "deformWeight");
474                 if(dv->dw){
475                         memcpy(newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
476                         MEM_freeN(dv->dw);
477                 }
478                 dv->dw=newdw;
479
480                 dv->dw[dv->totweight].weight=weight;
481                 dv->dw[dv->totweight].def_nr=def_nr;
482
483                 dv->totweight++;
484                 break;
485         }
486 }
487
488 /* called while not in editmode */
489 void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
490 {
491         /* add the vert to the deform group with the
492          * specified assign mode
493          */
494         int     def_nr;
495
496         MDeformVert *dv= NULL;
497         int tot;
498
499         /* get the deform group number, exit if
500          * it can't be found
501          */
502         def_nr = defgroup_find_index(ob, dg);
503         if(def_nr < 0) return;
504
505         /* if there's no deform verts then create some,
506          */
507         if(ED_vgroup_give_array(ob->data, &dv, &tot) && dv==NULL)
508                 ED_vgroup_data_create(ob->data);
509
510         /* call another function to do the work
511          */
512         ED_vgroup_nr_vert_add(ob, def_nr, vertnum, weight, assignmode);
513 }
514
515 /* mesh object mode, lattice can be in editmode */
516 void ED_vgroup_vert_remove(Object *ob, bDeformGroup     *dg, int vertnum)
517 {
518         /* This routine removes the vertex from the specified
519          * deform group.
520          */
521         const int def_nr= defgroup_find_index(ob, dg);
522         if(def_nr < 0)
523                 return;
524
525         ED_vgroup_nr_vert_remove(ob, def_nr, vertnum);
526 }
527
528 static float get_vert_def_nr(Object *ob, int def_nr, int vertnum)
529 {
530         MDeformVert *dvert= NULL;
531         EditVert *eve;
532         Mesh *me;
533         int i;
534
535         /* get the deform vertices corresponding to the vertnum */
536         if(ob->type==OB_MESH) {
537                 me= ob->data;
538
539                 if(me->edit_mesh) {
540                         eve= BLI_findlink(&me->edit_mesh->verts, vertnum);
541                         if(!eve) {
542                                 return 0.0f;
543                         }
544                         dvert= CustomData_em_get(&me->edit_mesh->vdata, eve->data, CD_MDEFORMVERT);
545                         vertnum= 0;
546                 }
547                 else {
548                         if(vertnum >= me->totvert) {
549                                 return 0.0f;
550                         }
551                         dvert = me->dvert;
552                 }
553         }
554         else if(ob->type==OB_LATTICE) {
555                 Lattice *lt= vgroup_edit_lattice(ob);
556
557                 if(lt->dvert) {
558                         if(vertnum >= lt->pntsu*lt->pntsv*lt->pntsw) {
559                                 return 0.0f;
560                         }
561                         dvert = lt->dvert;
562                 }
563         }
564         
565         if(dvert==NULL)
566                 return -1;
567         
568         dvert += vertnum;
569         
570         for(i=dvert->totweight-1 ; i>=0 ; i--)
571                 if(dvert->dw[i].def_nr == def_nr)
572                         return dvert->dw[i].weight;
573
574         return -1;
575 }
576
577 float ED_vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum)
578 {
579         int def_nr;
580
581         if(!ob) return -1;
582
583         def_nr = defgroup_find_index(ob, dg);
584         if(def_nr < 0) return -1;
585
586         return get_vert_def_nr(ob, def_nr, vertnum);
587 }
588
589 void ED_vgroup_select_by_name(Object *ob, const char *name)
590 {       /* note: ob->actdef==0 signals on painting to create a new one, if a bone in posemode is selected */
591         ob->actdef= defgroup_name_index(ob, name) + 1;
592 }
593
594 /********************** Operator Implementations *********************/
595
596 /* only in editmode */
597 static void vgroup_select_verts(Object *ob, int select)
598 {
599         EditVert *eve;
600         MDeformVert *dvert;
601         int i;
602
603         if(ob->type == OB_MESH) {
604                 Mesh *me= ob->data;
605                 EditMesh *em = BKE_mesh_get_editmesh(me);
606
607                 for(eve=em->verts.first; eve; eve=eve->next){
608                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
609
610                         if(dvert && dvert->totweight){
611                                 for(i=0; i<dvert->totweight; i++){
612                                         if(dvert->dw[i].def_nr == (ob->actdef-1)){
613                                                 if(!eve->h) {
614                                                         if(select) eve->f |= SELECT;
615                                                         else eve->f &= ~SELECT;
616                                                 }
617                                                 break;
618                                         }
619                                 }
620                         }
621                 }
622                 /* this has to be called, because this function operates on vertices only */
623                 if(select) EM_select_flush(em); // vertices to edges/faces
624                 else EM_deselect_flush(em);
625
626                 BKE_mesh_end_editmesh(me, em);
627         }
628         else if(ob->type == OB_LATTICE) {
629                 Lattice *lt= vgroup_edit_lattice(ob);
630                 
631                 if(lt->dvert) {
632                         BPoint *bp;
633                         int a, tot;
634                         
635                         dvert= lt->dvert;
636
637                         tot= lt->pntsu*lt->pntsv*lt->pntsw;
638                         for(a=0, bp= lt->def; a<tot; a++, bp++, dvert++) {
639                                 for(i=0; i<dvert->totweight; i++){
640                                         if(dvert->dw[i].def_nr == (ob->actdef-1)) {
641                                                 if(select) bp->f1 |= SELECT;
642                                                 else bp->f1 &= ~SELECT;
643                                                 
644                                                 break;
645                                         }
646                                 }
647                         }
648                 }
649         }
650 }
651
652 static void vgroup_duplicate(Object *ob)
653 {
654         bDeformGroup *dg, *cdg;
655         char name[sizeof(dg->name)];
656         MDeformWeight *org, *cpy;
657         MDeformVert *dvert, **dvert_array=NULL;
658         int i, idg, icdg, dvert_tot=0;
659
660         dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
661         if(!dg)
662                 return;
663         
664         if(!strstr(dg->name, "_copy")) {
665                 BLI_snprintf(name, sizeof(name), "%s_copy", dg->name);
666         }
667         else {
668                 BLI_snprintf(name, sizeof(name), "%s", dg->name);
669         }
670
671         cdg = defgroup_duplicate(dg);
672         strcpy(cdg->name, name);
673         defgroup_unique_name(cdg, ob);
674
675         BLI_addtail(&ob->defbase, cdg);
676
677         idg = (ob->actdef-1);
678         ob->actdef = BLI_countlist(&ob->defbase);
679         icdg = (ob->actdef-1);
680
681         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
682         
683         if(!dvert_array)
684                 return;
685
686         for(i = 0; i < dvert_tot; i++) {
687                 dvert = dvert_array[i];
688                 org = defvert_find_index(dvert, idg);
689                 if(org) {
690                         float weight = org->weight;
691                         /* defvert_verify_index re-allocs org so need to store the weight first */
692                         cpy = defvert_verify_index(dvert, icdg);
693                         cpy->weight = weight;
694                 }
695         }
696
697         MEM_freeN(dvert_array);
698 }
699
700 static void vgroup_normalize(Object *ob)
701 {
702         bDeformGroup *dg;
703         MDeformWeight *dw;
704         MDeformVert *dvert, **dvert_array=NULL;
705         int i, def_nr, dvert_tot=0;
706         /* Radish */
707         Mesh *me = ob->data;
708         MVert *mvert = me->mvert;
709         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
710
711         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
712
713         dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
714
715         if(dg) {
716                 float weight_max = 0.0f;
717
718                 def_nr= ob->actdef-1;
719
720                 for(i = 0; i < dvert_tot; i++) {
721                         /* Radish */
722                         if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
723                                 continue;
724                         }
725
726                         dvert = dvert_array[i];
727                         dw = defvert_find_index(dvert, def_nr);
728                         if(dw) {
729                                 weight_max = MAX2(dw->weight, weight_max);
730                         }
731                 }
732
733                 if(weight_max > 0.0f) {
734                         for(i = 0; i < dvert_tot; i++) {
735                                 /* Radish */
736                                 if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
737                                         continue;
738                                 }
739
740                                 dvert = dvert_array[i];
741                                 dw = defvert_find_index(dvert, def_nr);
742                                 if(dw) {
743                                         dw->weight /= weight_max;
744                                         
745                                         /* incase of division errors with very low weights */
746                                         CLAMP(dw->weight, 0.0f, 1.0f);
747                                 }
748                         }
749                 }
750         }
751
752         if (dvert_array) MEM_freeN(dvert_array);
753 }
754 /* Radish */
755 /* This adds the indices of vertices to a list if they are not already present
756 It returns the number that it added (0-2)
757 It relies on verts having -1 for unassigned indices
758 */
759 static int tryToAddVerts(int *verts, int length, int a, int b) {
760         char containsA = FALSE;
761         char containsB = FALSE;
762         int added = 0;
763         int i;
764         for(i = 0; i < length && (!containsA || !containsB); i++) {
765                 if(verts[i] == a) {
766                         containsA = TRUE;
767                 } else if(verts[i] == b) {
768                         containsB = TRUE;
769                 } else if(verts[i] == -1) {
770                         if(!containsA) {
771                                 verts[i] = a;
772                                 containsA = TRUE;
773                                 added++;
774                         } else if(!containsB){
775                                 verts[i] = b;
776                                 containsB = TRUE;
777                                 added++;
778                         }
779                 }
780         }
781         return added;
782 }
783 //Radish
784 /* This finds all of the vertices connected to vert by an edge
785 and returns an array of indices of size count
786
787 count is an int passed by reference so it can be assigned the value of the length here.
788 */
789 static int* getSurroundingVerts(Mesh *me, int vert, int *count) {
790         int length = 0;
791         int *tverts;
792         int *verts = NULL;
793         MFace *mf = me->mface;
794         int totface = me->totface;
795         int found = 0;
796         int i;
797         for(i = 0; i < totface; i++, mf++) {
798                 if(vert == mf->v1 || vert == mf->v2 || vert == mf->v3 || (mf->v4 &&vert == mf->v4)) {
799                         length+=2;
800                 }
801         }
802         if(!length) {
803                 return 0;
804         }
805         tverts = MEM_mallocN(sizeof(int)*length, "tempSurroundingVerts");
806         mf = me->mface;
807         for(i = 0; i < length; i++) {
808                 tverts[i] = -1;
809         }
810         for(i = 0; i < totface; i++, mf++) {
811                 int a=-1, b=-1;
812                 if(mf->v1 == vert) {
813                         a = mf->v2;
814                         if(mf->v4) {
815                                 b = mf->v4;
816                         } else {
817                                 b = mf->v3;
818                         }
819                 } else if(mf->v2 == vert) {
820                         a = mf->v1;
821                         b = mf->v3;
822                 } else if(mf->v3 == vert) {
823                         a = mf->v2;
824                         if(mf->v4) {
825                                 b = mf->v4;
826                         } else {
827                                 b = mf->v1;
828                         }
829                 } else if (mf->v4 && mf->v4 == vert){
830                         a = mf->v1;
831                         b = mf->v3;
832                 } else {
833                         continue;
834                 }
835                 found += tryToAddVerts(tverts, length, a, b);
836         }
837         if(found) {
838                 verts = MEM_mallocN(sizeof(int)* found, "surroundingVerts");
839                 for(i = 0; i < found; i++) {
840                         verts[i] = tverts[i];
841                 }
842                 *count = found;
843         }
844         MEM_freeN(tverts);
845         return verts;
846 }
847 /* Radish */
848 /* get a single point in space by averaging a point cloud (vectors of size 3)
849 coord is the place the average is stored, points is the point cloud, count is the number of points in the cloud
850 */
851 static void getSingleCoordinate(MVert *points, int count, float coord[3]) {
852         int i;
853         zero_v3(coord);
854         for(i = 0; i < count; i++) {
855                 add_v3_v3(coord, points[i].co);
856         }
857         mul_v3_fl(coord, 1.0f/count);
858 }
859 /* Radish */
860 /* find the closest point on a plane to another point and store it in dst */
861 /* coord is a point on the plane */
862 /* point is the point that you want the nearest of */
863 /* norm is the plane's normal, and d is the last number in the plane equation 0 = ax + by + cz + d */
864 static void getNearestPointOnPlane(const float norm[3], const float coord[3], const float point[3], float dst_r[3])
865 {
866         float temp[3];
867         float dotprod;
868
869         sub_v3_v3v3(temp, point, coord);
870         dotprod= dot_v3v3(temp, norm);
871
872         dst_r[0] = point[0] - (norm[0] * dotprod);
873         dst_r[1] = point[1] - (norm[1] * dotprod);
874         dst_r[2] = point[2] - (norm[2] * dotprod);
875 }
876 /* Radish */
877 /* distance of two vectors a and b of size length */
878 static float distance(float* a, float *b, int length) {
879         int i;
880         float sum = 0;
881         for(i = 0; i < length; i++) {
882                 sum += (b[i]-a[i])*(b[i]-a[i]);
883         }
884         return sqrt(sum);
885 }
886 /* Radish */
887 /* given a plane and a start and end position,
888 compute the amount of vertical distance relative to the plane and store it in dists,
889 then get the horizontal and vertical change and store them in changes
890 */
891 static void getVerticalAndHorizontalChange(float *norm, float d, float *coord, float *start, float distToStart, float *end, float (*changes)[2], float *dists, int index) {
892         // A=Q-((Q-P).N)N
893         // D = (a*x0 + b*y0 +c*z0 +d)
894         float projA[3] = {0}, projB[3] = {0};
895
896         getNearestPointOnPlane(norm, coord, start, projA);
897         getNearestPointOnPlane(norm, coord, end, projB);
898         // (vertical and horizontal refer to the plane's y and xz respectively)
899         // vertical distance
900         dists[index] = norm[0]*end[0] + norm[1]*end[1] + norm[2]*end[2] + d;
901         // vertical change
902         changes[index][0] = dists[index] - distToStart;
903         //printf("vc %f %f\n", distance(end, projB, 3)-distance(start, projA, 3), changes[index][0]);
904         // horizontal change
905         changes[index][1] = distance(projA, projB, 3);
906 }
907 /* Radish */
908 // I need the derived mesh to be forgotten so the positions are recalculated with weight changes (see dm_deform_recalc)
909 static void dm_deform_clear(DerivedMesh *dm, Object *ob) {
910         if(ob->derivedDeform && (ob->derivedDeform)==dm) {
911                 ob->derivedDeform->needsFree = 1;
912                 ob->derivedDeform->release(ob->derivedDeform);
913                 ob->derivedDeform = NULL;
914         }
915         else if(dm) {
916                 dm->needsFree = 1;
917                 dm->release(dm);
918         }
919 }
920 /* Radish */
921 // recalculate the deformation
922 static DerivedMesh* dm_deform_recalc(Scene *scene, Object *ob) {
923         return mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
924 }
925 /* Radish */
926 /* by changing nonzero weights, try to move a vertex in me->mverts with index 'index' to distToBe distance away from the provided plane
927 strength can change distToBe so that it moves towards distToBe by that percentage
928 cp changes how much the weights are adjusted to check the distance
929
930 index is the index of the vertex being moved
931 norm and d are the plane's properties for the equation: ax + by + cz + d = 0
932 coord is a point on the plane
933 */
934 static void moveCloserToDistanceFromPlane(Scene *scene, Object *ob, Mesh *me, int index, float norm[3], float coord[3], float d, float distToBe, float strength, float cp) {
935         DerivedMesh *dm;
936         MDeformWeight *dw;
937         MVert m;
938         MDeformVert *dvert = me->dvert+index;
939         int totweight = dvert->totweight;
940         float oldw = 0;
941         float oldPos[3] = {0};
942         float vc, hc, dist;
943         int i, k;
944         float (*changes)[2] = MEM_mallocN(sizeof(float *)*totweight*2, "vertHorzChange");
945         float *dists = MEM_mallocN(sizeof(float)*totweight, "distance");
946         int *upDown = MEM_callocN(sizeof(int)*totweight, "upDownTracker");// track if up or down moved it closer for each bone
947         int *dwIndices = MEM_callocN(sizeof(int)*totweight, "dwIndexTracker");
948         float distToStart;
949         int bestIndex = 0;
950         char wasChange;
951         char wasUp;
952         int lastIndex = -1;
953         float originalDistToBe = distToBe;
954         do {
955                 wasChange = FALSE;
956                 dm = dm_deform_recalc(scene, ob);
957                 dm->getVert(dm, index, &m);
958                 oldPos[0] = m.co[0];
959                 oldPos[1] = m.co[1];
960                 oldPos[2] = m.co[2];
961                 distToStart = norm[0]*oldPos[0] + norm[1]*oldPos[1] + norm[2]*oldPos[2] + d;
962
963                 if(distToBe == originalDistToBe) {
964                         distToBe += distToStart - distToStart*strength;
965                 }
966                 for(i = 0; i < totweight; i++) {
967                         dwIndices[i] = i;
968                         dw = (dvert->dw+i);
969                         vc = hc = 0;
970                         if(!dw->weight) {
971                                 changes[i][0] = 0;
972                                 changes[i][1] = 0;
973                                 dists[i] = distToStart;
974                                 continue;
975                         }
976                         for(k = 0; k < 2; k++) {
977                                 if(dm) {
978                                         dm_deform_clear(dm, ob); dm = NULL;
979                                 }
980                                 oldw = dw->weight;
981                                 if(k) {
982                                         dw->weight *= 1+cp;
983                                 } else {
984                                         dw->weight /= 1+cp;
985                                 }
986                                 if(dw->weight == oldw) {
987                                         changes[i][0] = 0;
988                                         changes[i][1] = 0;
989                                         dists[i] = distToStart;
990                                         break;
991                                 }
992                                 if(dw->weight > 1) {
993                                         dw->weight = 1;
994                                 }
995                                 dm = dm_deform_recalc(scene, ob);
996                                 dm->getVert(dm, index, &m);
997                                 getVerticalAndHorizontalChange(norm, d, coord, oldPos, distToStart, m.co, changes, dists, i);
998                                 dw->weight = oldw;
999                                 if(!k) {
1000                                         vc = changes[i][0];
1001                                         hc = changes[i][1];
1002                                         dist = dists[i];
1003                                 } else {
1004                                         if(fabs(dist - distToBe) < fabs(dists[i] - distToBe)) {
1005                                                 upDown[i] = 0;
1006                                                 changes[i][0] = vc;
1007                                                 changes[i][1] = hc;
1008                                                 dists[i] = dist;
1009                                         } else {
1010                                                 upDown[i] = 1;
1011                                         }
1012                                         if(fabs(dists[i] - distToBe) > fabs(distToStart - distToBe)) {
1013                                                 changes[i][0] = 0;
1014                                                 changes[i][1] = 0;
1015                                                 dists[i] = distToStart;
1016                                         }
1017                                 }
1018                         }
1019                 }
1020                 // sort the changes by the vertical change
1021                 for(k = 0; k < totweight; k++) {
1022                         float tf;
1023                         int ti;
1024                         bestIndex = k;
1025                         for(i = k+1; i < totweight; i++) {
1026                                 dist = dists[i];
1027
1028                                 if(fabs(dist) > fabs(dists[i])) {
1029                                         bestIndex = i;
1030                                 }
1031                         }
1032                         // switch with k
1033                         if(bestIndex != k) {
1034                                 ti = upDown[k];
1035                                 upDown[k] = upDown[bestIndex];
1036                                 upDown[bestIndex] = ti;
1037
1038                                 ti = dwIndices[k];
1039                                 dwIndices[k] = dwIndices[bestIndex];
1040                                 dwIndices[bestIndex] = ti;
1041
1042                                 tf = changes[k][0];
1043                                 changes[k][0] = changes[bestIndex][0];
1044                                 changes[bestIndex][0] = tf;
1045
1046                                 tf = changes[k][1];
1047                                 changes[k][1] = changes[bestIndex][1];
1048                                 changes[bestIndex][1] = tf;
1049
1050                                 tf = dists[k];
1051                                 dists[k] = dists[bestIndex];
1052                                 dists[bestIndex] = tf;
1053                         }
1054                 }
1055                 bestIndex = -1;
1056                 // find the best change with an acceptable horizontal change
1057                 for(i = 0; i < totweight; i++) {
1058                         if(fabs(changes[i][0]) > fabs(changes[i][1]*2.0f)) {
1059                                 bestIndex = i;
1060                                 break;
1061                         }
1062                 }
1063                 if(bestIndex != -1) {
1064                         wasChange = TRUE;
1065                         // it is a good place to stop if it tries to move the opposite direction
1066                         // (relative to the plane) of last time
1067                         if(lastIndex != -1) {
1068                                 if(wasUp != upDown[bestIndex]) {
1069                                         wasChange = FALSE;
1070                                 }
1071                         }
1072                         lastIndex = bestIndex;
1073                         wasUp = upDown[bestIndex];
1074                         dw = (dvert->dw+dwIndices[bestIndex]);
1075                         oldw = dw->weight;
1076                         if(upDown[bestIndex]) {
1077                                 dw->weight *= 1+cp;
1078                         } else {
1079                                 dw->weight /= 1+cp;
1080                         }
1081                         if(dw->weight > 1) {
1082                                 dw->weight = 1;
1083                         }
1084                         if(oldw == dw->weight) {
1085                                 wasChange = FALSE;
1086                         }
1087                         if(dm) {
1088                                 dm_deform_clear(dm, ob); dm = NULL;
1089                         }
1090                 }
1091         }while(wasChange && (distToStart-distToBe)/fabs(distToStart-distToBe) == (dists[bestIndex]-distToBe)/fabs(dists[bestIndex]-distToBe));
1092         MEM_freeN(upDown);
1093         MEM_freeN(changes);
1094         MEM_freeN(dists);
1095         MEM_freeN(dwIndices);
1096 }
1097 /* Radish */
1098 /* this is used to try to smooth a surface by only adjusting the nonzero weights of a vertex 
1099 but it could be used to raise or lower an existing 'bump.' */
1100 static void vgroup_fix(Scene *scene, Object *ob, float distToBe, float strength, float cp)
1101 {
1102         int i;
1103
1104         Mesh *me = ob->data;
1105         MVert *mvert = me->mvert;
1106         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1107         int *verts = NULL;
1108         for(i = 0; i < me->totvert && mvert; i++, mvert++) {
1109                 /* Radish */
1110                 if(use_vert_sel && (mvert->flag & SELECT)) {
1111                         
1112                         int count=0;
1113                         if((verts = getSurroundingVerts(me, i, &count))) {
1114                                 MVert m;
1115                                 MVert *p = MEM_callocN(sizeof(MVert)*(count), "deformedPoints");
1116                                 int k;
1117
1118                                 DerivedMesh *dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
1119                                 for(k = 0; k < count; k++) {
1120                                         dm->getVert(dm, verts[k], &m);
1121                                         p[k] = m;
1122                                 }
1123                                 
1124                                 if(count >= 3) {
1125                                         float d /*, dist */ /* UNUSED */, mag;
1126                                         float coord[3] = {0};
1127                                         float norm[3] = {0};
1128                                         getSingleCoordinate(p, count, coord);
1129                                         dm->getVert(dm, i, &m);
1130                                         norm[0] = m.co[0]-coord[0];
1131                                         norm[1] = m.co[1]-coord[1];
1132                                         norm[2] = m.co[2]-coord[2];
1133                                         mag = sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]);
1134                                         if(mag) {// zeros fix
1135                                                 mul_v3_fl(norm, 1.0f/mag);
1136                                                 
1137                                                 d = -norm[0]*coord[0] -norm[1]*coord[1] -norm[2]*coord[2];
1138                                                 /* dist = (norm[0]*m.co[0] + norm[1]*m.co[1] + norm[2]*m.co[2] + d); */ /* UNUSED */
1139                                                 moveCloserToDistanceFromPlane(scene, ob, me, i, norm, coord, d, distToBe, strength, cp);
1140                                         }
1141                                 }
1142
1143                                 MEM_freeN(verts);
1144                                 MEM_freeN(p);
1145                         }
1146                 }
1147         }
1148 }
1149
1150 static void vgroup_levels(Object *ob, float offset, float gain)
1151 {
1152         bDeformGroup *dg;
1153         MDeformWeight *dw;
1154         MDeformVert *dvert, **dvert_array=NULL;
1155         int i, def_nr, dvert_tot=0;
1156         /* Radish */
1157         Mesh *me = ob->data;
1158         MVert *mvert = me->mvert;
1159         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1160
1161         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1162         
1163         dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
1164         
1165         if(dg) {
1166                 def_nr= ob->actdef-1;
1167                 
1168                 for(i = 0; i < dvert_tot; i++) {
1169                         /* Radish */
1170                         if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
1171                                 continue;
1172                         }
1173
1174                         dvert = dvert_array[i];
1175                         dw = defvert_find_index(dvert, def_nr);
1176                         if(dw) {
1177                                 dw->weight = gain * (dw->weight + offset);
1178                                 
1179                                 CLAMP(dw->weight, 0.0f, 1.0f);
1180                         }
1181                 }
1182         }
1183
1184         if (dvert_array) MEM_freeN(dvert_array);
1185 }
1186
1187 /* TODO - select between groups */
1188 static void vgroup_normalize_all(Object *ob, int lock_active)
1189 {
1190         MDeformWeight *dw, *dw_act;
1191         MDeformVert *dvert, **dvert_array=NULL;
1192         int i, dvert_tot=0;
1193         float tot_weight;
1194
1195         /* Radish */
1196         Mesh *me = ob->data;
1197         MVert *mvert = me->mvert;
1198         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1199
1200         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1201
1202         if(dvert_array) {
1203                 if(lock_active) {
1204                         int def_nr= ob->actdef-1;
1205
1206                         for(i = 0; i < dvert_tot; i++) {
1207                                 float lock_iweight= 1.0f;
1208                                 int j;
1209                                 /* Radish */
1210                                 if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
1211                                         continue;
1212                                 }
1213
1214                                 tot_weight= 0.0f;
1215                                 dw_act= NULL;
1216                                 dvert = dvert_array[i];
1217
1218                                 j= dvert->totweight;
1219                                 while(j--) {
1220                                         dw= dvert->dw + j;
1221
1222                                         if(dw->def_nr==def_nr) {
1223                                                 dw_act= dw;
1224                                                 lock_iweight = (1.0f - dw_act->weight);
1225                                         }
1226                                         else {
1227                                                 tot_weight += dw->weight;
1228                                         }
1229                                 }
1230
1231                                 if(tot_weight) {
1232                                         j= dvert->totweight;
1233                                         while(j--) {
1234                                                 dw= dvert->dw + j;
1235                                                 if(dw == dw_act) {
1236                                                         if (dvert->totweight==1) {
1237                                                                 dw_act->weight= 1.0f; /* no other weights, set to 1.0 */
1238                                                         }
1239                                                 } else {
1240                                                         if(dw->weight > 0.0f)
1241                                                                 dw->weight = (dw->weight / tot_weight) * lock_iweight;
1242                                                 }
1243
1244                                                 /* incase of division errors with very low weights */
1245                                                 CLAMP(dw->weight, 0.0f, 1.0f);
1246                                         }
1247                                 }
1248                         }
1249                 }
1250                 else {
1251                         for(i = 0; i < dvert_tot; i++) {
1252                                 int j;
1253                                 /* Radish */
1254                                 if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
1255                                         continue;
1256                                 }
1257
1258                                 tot_weight= 0.0f;
1259                                 dvert = dvert_array[i];
1260
1261                                 j= dvert->totweight;
1262                                 while(j--) {
1263                                         dw= dvert->dw + j;
1264                                         tot_weight += dw->weight;
1265                                 }
1266
1267                                 if(tot_weight) {
1268                                         j= dvert->totweight;
1269                                         while(j--) {
1270                                                 dw= dvert->dw + j;
1271                                                 dw->weight /= tot_weight;
1272
1273                                                 /* incase of division errors with very low weights */
1274                                                 CLAMP(dw->weight, 0.0f, 1.0f);
1275                                         }
1276                                 }
1277                         }
1278                 }
1279         }
1280
1281         if (dvert_array) MEM_freeN(dvert_array);
1282 }
1283
1284 /* Radish */
1285 static void vgroup_lock_all(Object *ob, int action)
1286 {
1287         bDeformGroup *dg;
1288
1289         if(action == SEL_TOGGLE) {
1290                 action= SEL_SELECT;
1291                 for(dg= ob->defbase.first; dg; dg= dg->next) {
1292                         if(dg->flag & DG_LOCK_WEIGHT) {
1293                                 action= SEL_DESELECT;
1294                                 break;
1295                         }
1296                 }
1297         }
1298
1299         for(dg= ob->defbase.first; dg; dg= dg->next) {
1300                 switch(action) {
1301                         case SEL_SELECT:
1302                                 dg->flag |= DG_LOCK_WEIGHT;
1303                                 break;
1304                         case SEL_DESELECT:
1305                                 dg->flag &= ~DG_LOCK_WEIGHT;
1306                                 break;
1307                         case SEL_INVERT:
1308                                 dg->flag ^= DG_LOCK_WEIGHT;
1309                                 break;
1310                 }
1311         }
1312 }
1313
1314 static void vgroup_invert(Object *ob, int auto_assign, int auto_remove)
1315 {
1316         bDeformGroup *dg;
1317         MDeformWeight *dw;
1318         MDeformVert *dvert, **dvert_array=NULL;
1319         int i, def_nr, dvert_tot=0;
1320         /* Radish */
1321         Mesh *me = ob->data;
1322         MVert *mvert = me->mvert;
1323         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1324
1325         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1326
1327         dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
1328
1329         if(dg) {
1330                 def_nr= ob->actdef-1;
1331
1332
1333                 for(i = 0; i < dvert_tot; i++) {
1334                         /* Radish */
1335                         if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
1336                                 continue;
1337                         }
1338                         dvert = dvert_array[i];
1339
1340                         if(auto_assign) {
1341                                 dw= defvert_verify_index(dvert, def_nr);
1342                         } else {
1343                                 dw= defvert_find_index(dvert, def_nr);
1344                         }
1345
1346                         if(dw) {
1347                                 dw->weight = 1.0f-dw->weight;
1348
1349                                 if(auto_remove && dw->weight <= 0.0f) {
1350                                         /* could have a faster function for this */
1351                                         ED_vgroup_nr_vert_remove(ob, def_nr, i);
1352                                 }
1353                         }
1354                 }
1355         }
1356
1357         if (dvert_array) MEM_freeN(dvert_array);
1358 }
1359
1360 static void vgroup_blend(Object *ob)
1361 {
1362         bDeformGroup *dg;
1363         MDeformWeight *dw;
1364         MDeformVert *dvert_array=NULL, *dvert;
1365         int i, def_nr, dvert_tot=0;
1366
1367         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)ob->data));
1368         // ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
1369
1370         if(em==NULL)
1371                 return;
1372
1373         dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
1374
1375         if(dg) {
1376                 int sel1, sel2;
1377                 int i1, i2;
1378
1379                 EditEdge *eed;
1380                 EditVert *eve;
1381                 float *vg_weights;
1382                 float *vg_users;
1383
1384                 def_nr= ob->actdef-1;
1385
1386                 i= 0;
1387                 for(eve= em->verts.first; eve; eve= eve->next)
1388                         eve->tmp.l= i++;
1389
1390                 dvert_tot= i;
1391
1392                 vg_weights= MEM_callocN(sizeof(float)*dvert_tot, "vgroup_blend_f");
1393                 vg_users= MEM_callocN(sizeof(int)*dvert_tot, "vgroup_blend_i");
1394
1395                 for(eed= em->edges.first; eed; eed= eed->next) {
1396                         sel1= eed->v1->f & SELECT;
1397                         sel2= eed->v2->f & SELECT;
1398
1399                         if(sel1 != sel2) {
1400                                 /* i1 is always the selected one */
1401                                 if(sel1==TRUE && sel2==FALSE) {
1402                                         i1= eed->v1->tmp.l;
1403                                         i2= eed->v2->tmp.l;
1404                                         eve= eed->v2;
1405                                 }
1406                                 else {
1407                                         i2= eed->v1->tmp.l;
1408                                         i1= eed->v2->tmp.l;
1409                                         eve= eed->v1;
1410                                 }
1411
1412                                 vg_users[i1]++;
1413
1414                                 /* TODO, we may want object mode blending */
1415                                 if(em)  dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1416                                 else    dvert= dvert_array+i2;
1417
1418                                 dw= defvert_find_index(dvert, def_nr);
1419
1420                                 if(dw) {
1421                                         vg_weights[i1] += dw->weight;
1422                                 }
1423                         }
1424                 }
1425
1426                 i= 0;
1427                 for(eve= em->verts.first; eve; eve= eve->next) {
1428                         if(eve->f & SELECT && vg_users[i] > 0) {
1429                                 /* TODO, we may want object mode blending */
1430                                 if(em)  dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1431                                 else    dvert= dvert_array+i;
1432
1433                                 dw= defvert_verify_index(dvert, def_nr);
1434                                 dw->weight= vg_weights[i] / (float)vg_users[i];
1435                         }
1436
1437                         i++;
1438                 }
1439                 MEM_freeN(vg_weights);
1440                 MEM_freeN(vg_users);
1441         }
1442 }
1443
1444 static void vgroup_clean(Object *ob, float eul, int keep_single)
1445 {
1446         bDeformGroup *dg;
1447         MDeformWeight *dw;
1448         MDeformVert *dvert, **dvert_array=NULL;
1449         int i, def_nr, dvert_tot=0;
1450         /* Radish */
1451         Mesh *me = ob->data;
1452         MVert *mvert = me->mvert;
1453         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1454
1455         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1456
1457         /* only the active group */
1458         dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
1459         if(dg) {
1460                 def_nr= ob->actdef-1;
1461
1462                 for(i = 0; i < dvert_tot; i++) {
1463                         /* Radish */
1464                         if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
1465                                 continue;
1466                         }
1467                         dvert = dvert_array[i];
1468
1469                         dw= defvert_find_index(dvert, def_nr);
1470
1471                         if(dw) {
1472                                 if(dw->weight <= eul)
1473                                         if(keep_single==FALSE || dvert->totweight > 1)
1474                                                 ED_vgroup_nr_vert_remove(ob, def_nr, i);
1475                         }
1476                 }
1477         }
1478
1479         if (dvert_array) MEM_freeN(dvert_array);
1480 }
1481
1482 static void vgroup_clean_all(Object *ob, float eul, int keep_single)
1483 {
1484
1485         MDeformWeight *dw;
1486         MDeformVert *dvert, **dvert_array=NULL;
1487         int i, dvert_tot=0;
1488         /* Radish */
1489         Mesh *me = ob->data;
1490         MVert *mvert = me->mvert;
1491         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1492
1493         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1494
1495         if(dvert_array) {
1496                 for(i = 0; i < dvert_tot; i++) {
1497                         int j;
1498                         /* Radish */
1499                         if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
1500                                 continue;
1501                         }
1502
1503                         dvert = dvert_array[i];
1504                         j= dvert->totweight;
1505
1506                         while(j--) {
1507
1508                                 if(keep_single && dvert->totweight == 1)
1509                                         break;
1510
1511                                 dw= dvert->dw + j;
1512
1513                                 if(dw->weight <= eul)
1514                                         ED_vgroup_nr_vert_remove(ob, dw->def_nr, i);
1515
1516                         }
1517                 }
1518         }
1519
1520         if (dvert_array) MEM_freeN(dvert_array);
1521 }
1522
1523
1524 static void dvert_mirror_op(MDeformVert *dvert, MDeformVert *dvert_mirr,
1525                             const char sel, const char sel_mirr,
1526                             const int *flip_map,
1527                             const short mirror_weights, const short flip_vgroups)
1528 {
1529         BLI_assert(sel || sel_mirr);
1530
1531         if(sel_mirr && sel) {
1532                 /* swap */
1533                 if(mirror_weights)
1534                         SWAP(MDeformVert, *dvert, *dvert_mirr);
1535                 if(flip_vgroups) {
1536                         defvert_flip(dvert, flip_map);
1537                         defvert_flip(dvert_mirr, flip_map);
1538                 }
1539         }
1540         else {
1541                 /* dvert should always be the target */
1542                 if(sel_mirr) {
1543                         SWAP(MDeformVert *, dvert, dvert_mirr);
1544                 }
1545
1546                 if(mirror_weights)
1547                         defvert_copy(dvert, dvert_mirr);
1548                 if(flip_vgroups) {
1549                         defvert_flip(dvert, flip_map);
1550                 }
1551         }
1552 }
1553
1554 void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_vgroups)
1555 {
1556 #define VGROUP_MIRR_OP dvert_mirror_op(dvert, dvert_mirr, sel, sel_mirr, flip_map, mirror_weights, flip_vgroups)
1557
1558         EditVert *eve, *eve_mirr;
1559         MDeformVert *dvert, *dvert_mirr;
1560         short sel, sel_mirr;
1561         int     *flip_map;
1562
1563         if(mirror_weights==0 && flip_vgroups==0)
1564                 return;
1565
1566         flip_map= defgroup_flip_map(ob, 0);
1567
1568         /* only the active group */
1569         if(ob->type == OB_MESH) {
1570                 Mesh *me= ob->data;
1571                 EditMesh *em = BKE_mesh_get_editmesh(me);
1572
1573
1574                 if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
1575                         MEM_freeN(flip_map);
1576                         return;
1577                 }
1578
1579                 EM_cache_x_mirror_vert(ob, em);
1580
1581                 /* Go through the list of editverts and assign them */
1582                 for(eve=em->verts.first; eve; eve=eve->next){
1583                         if((eve_mirr=eve->tmp.v)) {
1584                                 sel= eve->f & SELECT;
1585                                 sel_mirr= eve_mirr->f & SELECT;
1586
1587                                 if((sel || sel_mirr) && (eve != eve_mirr)) {
1588                                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1589                                         dvert_mirr= CustomData_em_get(&em->vdata, eve_mirr->data, CD_MDEFORMVERT);
1590                                         if(dvert && dvert_mirr) {
1591                                                 VGROUP_MIRR_OP;
1592                                         }
1593                                 }
1594
1595                                 eve->tmp.v= eve_mirr->tmp.v= NULL;
1596                         }
1597                 }
1598
1599                 BKE_mesh_end_editmesh(me, em);
1600         }
1601         else if (ob->type == OB_LATTICE) {
1602                 Lattice *lt= ob->data;
1603                 int i1, i2;
1604                 int u, v, w;
1605                 int pntsu_half;
1606                 /* half but found up odd value */
1607
1608                 if(lt->editlatt) lt= lt->editlatt->latt;
1609
1610                 if(lt->pntsu == 1 || lt->dvert == NULL) {
1611                         MEM_freeN(flip_map);
1612                         return;
1613                 }
1614
1615                 /* unlike editmesh we know that by only looping over the first hald of
1616                  * the 'u' indicies it will cover all points except the middle which is
1617                  * ok in this case */
1618                 pntsu_half= lt->pntsu / 2;
1619
1620                 for(w=0; w<lt->pntsw; w++) {
1621                         for(v=0; v<lt->pntsv; v++) {
1622                                 for(u=0; u<pntsu_half; u++) {
1623                                         int u_inv= (lt->pntsu - 1) - u;
1624                                         if(u != u_inv) {
1625                                                 BPoint *bp, *bp_mirr;
1626
1627                                                 i1= LT_INDEX(lt, u, v, w);
1628                                                 i2= LT_INDEX(lt, u_inv, v, w);
1629
1630                                                 bp= &lt->def[i1];
1631                                                 bp_mirr= &lt->def[i2];
1632
1633                                                 sel= bp->f1 & SELECT;
1634                                                 sel_mirr= bp_mirr->f1 & SELECT;
1635
1636                                                 if(sel || sel_mirr) {
1637                                                         dvert= &lt->dvert[i1];
1638                                                         dvert_mirr= &lt->dvert[i2];
1639
1640                                                         VGROUP_MIRR_OP;
1641                                                 }
1642                                         }
1643                                 }
1644                         }
1645                 }
1646         }
1647
1648         MEM_freeN(flip_map);
1649
1650 #undef VGROUP_MIRR_OP
1651 }
1652
1653 static void vgroup_remap_update_users(Object *ob, int *map)
1654 {
1655         ExplodeModifierData *emd;
1656         ModifierData *md;
1657         ParticleSystem *psys;
1658         ClothModifierData *clmd;
1659         ClothSimSettings *clsim;
1660         int a;
1661
1662         /* these cases don't use names to refer to vertex groups, so when
1663          * they get deleted the numbers get out of sync, this corrects that */
1664
1665         if(ob->soft)
1666                 ob->soft->vertgroup= map[ob->soft->vertgroup];
1667
1668         for(md=ob->modifiers.first; md; md=md->next) {
1669                 if(md->type == eModifierType_Explode) {
1670                         emd= (ExplodeModifierData*)md;
1671                         emd->vgroup= map[emd->vgroup];
1672                 }
1673                 else if(md->type == eModifierType_Cloth) {
1674                         clmd= (ClothModifierData*)md;
1675                         clsim= clmd->sim_parms;
1676
1677                         if(clsim) {
1678                                 clsim->vgroup_mass= map[clsim->vgroup_mass];
1679                                 clsim->vgroup_bend= map[clsim->vgroup_bend];
1680                                 clsim->vgroup_struct= map[clsim->vgroup_struct];
1681                         }
1682                 }
1683         }
1684
1685         for(psys=ob->particlesystem.first; psys; psys=psys->next) {
1686                 for(a=0; a<PSYS_TOT_VG; a++)
1687                         psys->vgroup[a]= map[psys->vgroup[a]];
1688         }
1689 }
1690
1691
1692 static void vgroup_delete_update_users(Object *ob, int id)
1693 {
1694         int i, tot= BLI_countlist(&ob->defbase) + 1;
1695         int *map= MEM_mallocN(sizeof(int) * tot, "vgroup del");
1696
1697         map[id]= map[0]= 0;
1698         for(i=1; i<id; i++) map[i]=i;
1699         for(i=id+1; i<tot; i++) map[i]=i-1;
1700
1701         vgroup_remap_update_users(ob, map);
1702         MEM_freeN(map);
1703 }
1704
1705
1706 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg)
1707 {
1708         MDeformVert *dvert_array=NULL;
1709         int i, e, dvert_tot=0;
1710         const int dg_index= BLI_findindex(&ob->defbase, dg);
1711
1712         assert(dg_index > -1);
1713         
1714         ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
1715
1716         if(dvert_array) {
1717                 MDeformVert *dvert;
1718                 for(i= 0, dvert= dvert_array; i < dvert_tot; i++, dvert++) {
1719                         ED_vgroup_vert_remove(ob, dg, i); /* ok if the dg isnt in this dvert, will continue silently */
1720                 }
1721
1722                 for(i= 0, dvert= dvert_array; i < dvert_tot; i++, dvert++) {
1723                         for(e = 0; e < dvert->totweight; e++) {
1724                                 if(dvert->dw[e].def_nr > dg_index) {
1725                                         dvert->dw[e].def_nr--;
1726                                 }
1727                         }
1728                 }
1729         }
1730
1731         vgroup_delete_update_users(ob, dg_index + 1);
1732
1733         /* Remove the group */
1734         BLI_freelinkN(&ob->defbase, dg);
1735
1736         /* Update the active deform index if necessary */
1737         if(ob->actdef > dg_index)
1738                 ob->actdef--;
1739         if(ob->actdef < 1 && ob->defbase.first)
1740                 ob->actdef= 1;
1741
1742 }
1743
1744 /* only in editmode */
1745 /* removes from active defgroup, if allverts==0 only selected vertices */
1746 static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGroup *dg)
1747 {
1748         EditVert *eve;
1749         MDeformVert *dvert;
1750         MDeformWeight *newdw;
1751         bDeformGroup *eg;
1752         int     i;
1753
1754         if(ob->type == OB_MESH) {
1755                 Mesh *me= ob->data;
1756                 EditMesh *em = BKE_mesh_get_editmesh(me);
1757
1758                 for(eve=em->verts.first; eve; eve=eve->next){
1759                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1760                 
1761                         if(dvert && dvert->dw && ((eve->f & SELECT) || allverts)){
1762                                 for(i=0; i<dvert->totweight; i++){
1763                                         /* Find group */
1764                                         eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr);
1765                                         if(eg == dg){
1766                                                 dvert->totweight--;
1767                                                 if(dvert->totweight){
1768                                                         newdw = MEM_mallocN(sizeof(MDeformWeight)*(dvert->totweight), "deformWeight");
1769                                                         
1770                                                         if(dvert->dw){
1771                                                                 memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*i);
1772                                                                 memcpy(newdw+i, dvert->dw+i+1, sizeof(MDeformWeight)*(dvert->totweight-i));
1773                                                                 MEM_freeN(dvert->dw);
1774                                                         }
1775                                                         dvert->dw=newdw;
1776                                                 }
1777                                                 else{
1778                                                         MEM_freeN(dvert->dw);
1779                                                         dvert->dw=NULL;
1780                                                         break;
1781                                                 }
1782                                         }
1783                                 }
1784                         }
1785                 }
1786                 BKE_mesh_end_editmesh(me, em);
1787         }
1788         else if(ob->type == OB_LATTICE) {
1789                 Lattice *lt= vgroup_edit_lattice(ob);
1790                 
1791                 if(lt->dvert) {
1792                         BPoint *bp;
1793                         int a, tot= lt->pntsu*lt->pntsv*lt->pntsw;
1794                                 
1795                         for(a=0, bp= lt->def; a<tot; a++, bp++) {
1796                                 if(allverts || (bp->f1 & SELECT))
1797                                         ED_vgroup_vert_remove(ob, dg, a);
1798                         }
1799                 }
1800         }
1801 }
1802
1803 static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg)
1804 {
1805         int i;
1806         const int dg_index= BLI_findindex(&ob->defbase, dg);
1807
1808         assert(dg_index > -1);
1809
1810         /* Make sure that no verts are using this group */
1811         vgroup_active_remove_verts(ob, TRUE, dg);
1812
1813         /* Make sure that any verts with higher indices are adjusted accordingly */
1814         if(ob->type==OB_MESH) {
1815                 Mesh *me= ob->data;
1816                 EditMesh *em = BKE_mesh_get_editmesh(me);
1817                 EditVert *eve;
1818                 MDeformVert *dvert;
1819                 
1820                 for(eve=em->verts.first; eve; eve=eve->next){
1821                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1822
1823                         if(dvert)
1824                                 for(i=0; i<dvert->totweight; i++)
1825                                         if(dvert->dw[i].def_nr > dg_index)
1826                                                 dvert->dw[i].def_nr--;
1827                 }
1828                 BKE_mesh_end_editmesh(me, em);
1829         }
1830         else if(ob->type==OB_LATTICE) {
1831                 Lattice *lt= vgroup_edit_lattice(ob);
1832                 BPoint *bp;
1833                 MDeformVert *dvert= lt->dvert;
1834                 int a, tot;
1835                 
1836                 if(dvert) {
1837                         tot= lt->pntsu*lt->pntsv*lt->pntsw;
1838                         for(a=0, bp= lt->def; a<tot; a++, bp++, dvert++) {
1839                                 for(i=0; i<dvert->totweight; i++){
1840                                         if(dvert->dw[i].def_nr > dg_index)
1841                                                 dvert->dw[i].def_nr--;
1842                                 }
1843                         }
1844                 }
1845         }
1846
1847         vgroup_delete_update_users(ob, dg_index + 1);
1848
1849         /* Remove the group */
1850         BLI_freelinkN (&ob->defbase, dg);
1851
1852         /* Update the active deform index if necessary */
1853         if(ob->actdef > dg_index)
1854                 ob->actdef--;
1855         if(ob->actdef < 1 && ob->defbase.first)
1856                 ob->actdef= 1;
1857
1858         /* remove all dverts */
1859         if(ob->defbase.first == NULL) {
1860                 if(ob->type==OB_MESH) {
1861                         Mesh *me= ob->data;
1862                         CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
1863                         me->dvert= NULL;
1864                 }
1865                 else if(ob->type==OB_LATTICE) {
1866                         Lattice *lt= vgroup_edit_lattice(ob);
1867                         if(lt->dvert) {
1868                                 MEM_freeN(lt->dvert);
1869                                 lt->dvert= NULL;
1870                         }
1871                 }
1872         }
1873 }
1874
1875 static int vgroup_object_in_edit_mode(Object *ob)
1876 {
1877         if(ob->type == OB_MESH)
1878                 return (((Mesh*)ob->data)->edit_mesh != NULL);
1879         else if(ob->type == OB_LATTICE)
1880                 return (((Lattice*)ob->data)->editlatt != NULL);
1881         
1882         return 0;
1883 }
1884
1885 static void vgroup_delete(Object *ob)
1886 {
1887         bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef-1);
1888         if(!dg)
1889                 return;
1890
1891         if(vgroup_object_in_edit_mode(ob))
1892                 vgroup_delete_edit_mode(ob, dg);
1893         else
1894                 vgroup_delete_object_mode(ob, dg);
1895 }
1896
1897 static void vgroup_delete_all(Object *ob)
1898 {
1899         /* Remove all DVerts */
1900         if(ob->type==OB_MESH) {
1901                 Mesh *me= ob->data;
1902                 CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
1903                 me->dvert= NULL;
1904         }
1905         else if(ob->type==OB_LATTICE) {
1906                 Lattice *lt= vgroup_edit_lattice(ob);
1907                 if(lt->dvert) {
1908                         MEM_freeN(lt->dvert);
1909                         lt->dvert= NULL;
1910                 }
1911         }
1912         
1913         /* Remove all DefGroups */
1914         BLI_freelistN(&ob->defbase);
1915         
1916         /* Fix counters/indices */
1917         ob->actdef= 0;
1918 }
1919
1920 /* only in editmode */
1921 static void vgroup_assign_verts(Object *ob, float weight)
1922 {
1923         EditVert *eve;
1924         bDeformGroup *dg, *eg;
1925         MDeformWeight *newdw;
1926         MDeformVert *dvert;
1927         int     i, done;
1928
1929         dg=BLI_findlink(&ob->defbase, ob->actdef-1);
1930         if(!dg)
1931                 return;
1932
1933         if(ob->type == OB_MESH) {
1934                 Mesh *me= ob->data;
1935                 EditMesh *em = BKE_mesh_get_editmesh(me);
1936
1937                 if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT))
1938                         EM_add_data_layer(em, &em->vdata, CD_MDEFORMVERT, NULL);
1939
1940                 /* Go through the list of editverts and assign them */
1941                 for(eve=em->verts.first; eve; eve=eve->next){
1942                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1943
1944                         if(dvert && (eve->f & SELECT)){
1945                                 /* See if this vert already has a reference to this group */
1946                                 /*              If so: Change its weight */
1947                                 done=0;
1948                                 for(i=0; i<dvert->totweight; i++){
1949                                         eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr);
1950                                         /* Find the actual group */
1951                                         if(eg==dg){
1952                                                 dvert->dw[i].weight= weight;
1953                                                 done=1;
1954                                                 break;
1955                                         }
1956                                  }
1957                                 /*              If not: Add the group and set its weight */
1958                                 if(!done){
1959                                         newdw = MEM_callocN(sizeof(MDeformWeight)*(dvert->totweight+1), "deformWeight");
1960                                         if(dvert->dw){
1961                                                 memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*dvert->totweight);
1962                                                 MEM_freeN(dvert->dw);
1963                                         }
1964                                         dvert->dw=newdw;
1965
1966                                         dvert->dw[dvert->totweight].weight= weight;
1967                                         dvert->dw[dvert->totweight].def_nr= ob->actdef-1;
1968
1969                                         dvert->totweight++;
1970
1971                                 }
1972                         }
1973                 }
1974                 BKE_mesh_end_editmesh(me, em);
1975         }
1976         else if(ob->type == OB_LATTICE) {
1977                 Lattice *lt= vgroup_edit_lattice(ob);
1978                 BPoint *bp;
1979                 int a, tot;
1980                 
1981                 if(lt->dvert==NULL)
1982                         ED_vgroup_data_create(&lt->id);
1983                 
1984                 tot= lt->pntsu*lt->pntsv*lt->pntsw;
1985                 for(a=0, bp= lt->def; a<tot; a++, bp++) {
1986                         if(bp->f1 & SELECT)
1987                                 ED_vgroup_nr_vert_add(ob, ob->actdef-1, a, weight, WEIGHT_REPLACE);
1988                 }
1989         }
1990 }
1991
1992 /* only in editmode */
1993 /* removes from all defgroup, if allverts==0 only selected vertices */
1994 static void vgroup_remove_verts(Object *ob, int allverts)
1995 {
1996         /* To prevent code redundancy, we just use vgroup_active_remove_verts, but that
1997          * only operates on the active vgroup. So we iterate through all groups, by changing
1998          * active group index
1999          */
2000         bDeformGroup *dg;
2001         for(dg= ob->defbase.first; dg; dg= dg->next) {
2002                 vgroup_active_remove_verts(ob, allverts, dg);
2003         }
2004 }
2005
2006 /********************** vertex group operators *********************/
2007
2008 static int vertex_group_poll(bContext *C)
2009 {
2010         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2011         ID *data= (ob)? ob->data: NULL;
2012         return (ob && !ob->id.lib && ELEM(ob->type, OB_MESH, OB_LATTICE) && data && !data->lib);
2013 }
2014
2015 static int vertex_group_poll_edit(bContext *C)
2016 {
2017         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2018         ID *data= (ob)? ob->data: NULL;
2019
2020         if(!(ob && !ob->id.lib && data && !data->lib))
2021                 return 0;
2022
2023         return vgroup_object_in_edit_mode(ob);
2024 }
2025
2026 static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op))
2027 {
2028         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2029
2030         ED_vgroup_add(ob);
2031         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2032         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2033         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2034         
2035         return OPERATOR_FINISHED;
2036 }
2037
2038 void OBJECT_OT_vertex_group_add(wmOperatorType *ot)
2039 {
2040         /* identifiers */
2041         ot->name= "Add Vertex Group";
2042         ot->idname= "OBJECT_OT_vertex_group_add";
2043         
2044         /* api callbacks */
2045         ot->poll= vertex_group_poll;
2046         ot->exec= vertex_group_add_exec;
2047
2048         /* flags */
2049         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2050 }
2051
2052 static int vertex_group_remove_exec(bContext *C, wmOperator *op)
2053 {
2054         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2055
2056         if(RNA_boolean_get(op->ptr, "all"))
2057                 vgroup_delete_all(ob);
2058         else
2059                 vgroup_delete(ob);
2060
2061         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2062         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2063         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2064         
2065         return OPERATOR_FINISHED;
2066 }
2067
2068 void OBJECT_OT_vertex_group_remove(wmOperatorType *ot)
2069 {
2070         /* identifiers */
2071         ot->name= "Remove Vertex Group";
2072         ot->idname= "OBJECT_OT_vertex_group_remove";
2073         
2074         /* api callbacks */
2075         ot->poll= vertex_group_poll;
2076         ot->exec= vertex_group_remove_exec;
2077
2078         /* flags */
2079         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2080
2081         /* properties */
2082         RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups.");
2083 }
2084
2085 static int vertex_group_assign_exec(bContext *C, wmOperator *op)
2086 {
2087         ToolSettings *ts= CTX_data_tool_settings(C);
2088         Object *ob= CTX_data_edit_object(C);
2089
2090         if(RNA_boolean_get(op->ptr, "new"))
2091                 ED_vgroup_add(ob);
2092
2093         vgroup_assign_verts(ob, ts->vgroup_weight);
2094         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2095         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2096         
2097         return OPERATOR_FINISHED;
2098 }
2099
2100 void OBJECT_OT_vertex_group_assign(wmOperatorType *ot)
2101 {
2102         /* identifiers */
2103         ot->name= "Assign Vertex Group";
2104         ot->idname= "OBJECT_OT_vertex_group_assign";
2105         
2106         /* api callbacks */
2107         ot->poll= vertex_group_poll_edit;
2108         ot->exec= vertex_group_assign_exec;
2109
2110         /* flags */
2111         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2112
2113         /* properties */
2114         RNA_def_boolean(ot->srna, "new", 0, "New", "Assign vertex to new vertex group.");
2115 }
2116
2117 static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
2118 {
2119         Object *ob= CTX_data_edit_object(C);
2120
2121         if(RNA_boolean_get(op->ptr, "all"))
2122                 vgroup_remove_verts(ob, 0);
2123         else {
2124                 bDeformGroup *dg= BLI_findlink(&ob->defbase, ob->actdef - 1);
2125
2126                 if(dg == NULL) {
2127                         return OPERATOR_CANCELLED;
2128                 }
2129
2130                 vgroup_active_remove_verts(ob, FALSE, dg);
2131         }
2132
2133         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2134         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2135
2136         return OPERATOR_FINISHED;
2137 }
2138
2139 void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot)
2140 {
2141         /* identifiers */
2142         ot->name= "Remove from Vertex Group";
2143         ot->idname= "OBJECT_OT_vertex_group_remove_from";
2144
2145         /* api callbacks */
2146         ot->poll= vertex_group_poll_edit;
2147         ot->exec= vertex_group_remove_from_exec;
2148
2149         /* flags */
2150         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2151
2152         /* properties */
2153         RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups.");
2154 }
2155
2156 static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
2157 {
2158         Object *ob= CTX_data_edit_object(C);
2159
2160         if(!ob || ob->id.lib)
2161                 return OPERATOR_CANCELLED;
2162
2163         vgroup_select_verts(ob, 1);
2164         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
2165
2166         return OPERATOR_FINISHED;
2167 }
2168
2169 void OBJECT_OT_vertex_group_select(wmOperatorType *ot)
2170 {
2171         /* identifiers */
2172         ot->name= "Select Vertex Group";
2173         ot->idname= "OBJECT_OT_vertex_group_select";
2174
2175         /* api callbacks */
2176         ot->poll= vertex_group_poll_edit;
2177         ot->exec= vertex_group_select_exec;
2178
2179         /* flags */
2180         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2181 }
2182
2183 static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
2184 {
2185         Object *ob= CTX_data_edit_object(C);
2186
2187         vgroup_select_verts(ob, 0);
2188         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
2189
2190         return OPERATOR_FINISHED;
2191 }
2192
2193 void OBJECT_OT_vertex_group_deselect(wmOperatorType *ot)
2194 {
2195         /* identifiers */
2196         ot->name= "Deselect Vertex Group";
2197         ot->idname= "OBJECT_OT_vertex_group_deselect";
2198
2199         /* api callbacks */
2200         ot->poll= vertex_group_poll_edit;
2201         ot->exec= vertex_group_deselect_exec;
2202
2203         /* flags */
2204         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2205 }
2206
2207 static int vertex_group_copy_exec(bContext *C, wmOperator *UNUSED(op))
2208 {
2209         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2210
2211         vgroup_duplicate(ob);
2212         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2213         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2214         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2215
2216         return OPERATOR_FINISHED;
2217 }
2218
2219 void OBJECT_OT_vertex_group_copy(wmOperatorType *ot)
2220 {
2221         /* identifiers */
2222         ot->name= "Copy Vertex Group";
2223         ot->idname= "OBJECT_OT_vertex_group_copy";
2224
2225         /* api callbacks */
2226         ot->poll= vertex_group_poll;
2227         ot->exec= vertex_group_copy_exec;
2228
2229         /* flags */
2230         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2231 }
2232
2233 static int vertex_group_levels_exec(bContext *C, wmOperator *op)
2234 {
2235         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2236         
2237         float offset= RNA_float_get(op->ptr,"offset");
2238         float gain= RNA_float_get(op->ptr,"gain");
2239         
2240         vgroup_levels(ob, offset, gain);
2241         
2242         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2243         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2244         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2245         
2246         return OPERATOR_FINISHED;
2247 }
2248
2249 void OBJECT_OT_vertex_group_levels(wmOperatorType *ot)
2250 {
2251         /* identifiers */
2252         ot->name= "Vertex Group Levels";
2253         ot->idname= "OBJECT_OT_vertex_group_levels";
2254         
2255         /* api callbacks */
2256         ot->poll= vertex_group_poll;
2257         ot->exec= vertex_group_levels_exec;
2258         
2259         /* flags */
2260         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2261         
2262         RNA_def_float(ot->srna, "offset", 0.f, -1.0, 1.0, "Offset", "Value to add to weights.", -1.0f, 1.f);
2263         RNA_def_float(ot->srna, "gain", 1.f, 0.f, FLT_MAX, "Gain", "Value to multiply weights by.", 0.0f, 10.f);
2264 }
2265
2266 static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op))
2267 {
2268         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2269
2270         vgroup_normalize(ob);
2271
2272         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2273         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2274         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2275
2276         return OPERATOR_FINISHED;
2277 }
2278
2279 void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot)
2280 {
2281         /* identifiers */
2282         ot->name= "Normalize Vertex Group";
2283         ot->idname= "OBJECT_OT_vertex_group_normalize";
2284
2285         /* api callbacks */
2286         ot->poll= vertex_group_poll;
2287         ot->exec= vertex_group_normalize_exec;
2288
2289         /* flags */
2290         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2291 }
2292
2293 static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
2294 {
2295         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2296         int lock_active= RNA_boolean_get(op->ptr,"lock_active");
2297
2298         vgroup_normalize_all(ob, lock_active);
2299
2300         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2301         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2302         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2303
2304         return OPERATOR_FINISHED;
2305 }
2306
2307 void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
2308 {
2309         /* identifiers */
2310         ot->name= "Normalize All Vertex Groups";
2311         ot->idname= "OBJECT_OT_vertex_group_normalize_all";
2312
2313         /* api callbacks */
2314         ot->poll= vertex_group_poll;
2315         ot->exec= vertex_group_normalize_all_exec;
2316
2317         /* flags */
2318         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2319
2320         RNA_def_boolean(ot->srna, "lock_active", TRUE, "Lock Active", "Keep the values of the active group while normalizing others.");
2321 }
2322 /* Radish */
2323 static int vertex_group_fix_exec(bContext *C, wmOperator *op)
2324 {
2325         Object *ob= CTX_data_active_object(C);
2326         Scene *scene= CTX_data_scene(C);
2327         
2328         float distToBe= RNA_float_get(op->ptr,"dist");
2329         float strength= RNA_float_get(op->ptr,"strength");
2330         float cp= RNA_float_get(op->ptr,"cp");
2331         ModifierData *md = ob->modifiers.first;
2332
2333         while(md) {
2334                 if(md->type == eModifierType_Mirror && (md->mode&eModifierMode_Realtime)) {
2335                         break;
2336                 }
2337                 md = md->next;
2338         }
2339         
2340         if(md && md->type == eModifierType_Mirror) {
2341                 BKE_report(op->reports, RPT_ERROR_INVALID_CONTEXT, "This operator does not support an active mirror modifier");
2342                 return OPERATOR_CANCELLED;
2343         }
2344         vgroup_fix(scene, ob, distToBe, strength, cp);
2345         
2346         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2347         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2348         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2349         
2350         return OPERATOR_FINISHED;
2351 }
2352
2353 void OBJECT_OT_vertex_group_fix(wmOperatorType *ot)
2354 {
2355         /* identifiers */
2356         ot->name= "Fix Vertex Group Deform";
2357         ot->idname= "OBJECT_OT_vertex_group_fix";
2358         
2359         /* api callbacks */
2360         ot->poll= vertex_group_poll;
2361         ot->exec= vertex_group_fix_exec;
2362         
2363         /* flags */
2364         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2365         RNA_def_float(ot->srna, "dist", 0.0f, -FLT_MAX, FLT_MAX, "Distance", "The distance to move to.", -10.0f, 10.0f);        
2366         RNA_def_float(ot->srna, "strength", 1.f, -2.0f, FLT_MAX, "Strength", "The distance moved can be changed by this multiplier.", -2.0f, 2.0f);
2367         RNA_def_float(ot->srna, "cp", 1.0f, 0.05f, FLT_MAX, "Change Sensitivity", "Changes the amount weights are altered with each iteration: lower values are slower.", 0.05f, 1.f);
2368 }
2369
2370 /* Radish */
2371 static int vertex_group_lock_exec(bContext *C, wmOperator *op)
2372 {
2373         Object *ob= CTX_data_active_object(C);
2374
2375         int action = RNA_enum_get(op->ptr, "action");
2376
2377         vgroup_lock_all(ob, action);
2378
2379         return OPERATOR_FINISHED;
2380 }
2381 /* Radish */
2382 void OBJECT_OT_vertex_group_lock(wmOperatorType *ot)
2383 {
2384         /* identifiers */
2385         ot->name= "Change the Lock On Vertex Groups";
2386         ot->idname= "OBJECT_OT_vertex_group_lock";
2387
2388         /* api callbacks */
2389         ot->poll= vertex_group_poll;
2390         ot->exec= vertex_group_lock_exec;
2391
2392         /* flags */
2393         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2394
2395         WM_operator_properties_select_all(ot);
2396 }
2397
2398 static int vertex_group_invert_exec(bContext *C, wmOperator *op)
2399 {
2400         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2401         int auto_assign= RNA_boolean_get(op->ptr,"auto_assign");
2402         int auto_remove= RNA_boolean_get(op->ptr,"auto_remove");
2403
2404         vgroup_invert(ob, auto_assign, auto_remove);
2405         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2406         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2407         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2408
2409         return OPERATOR_FINISHED;
2410 }
2411
2412 void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
2413 {
2414         /* identifiers */
2415         ot->name= "Invert Vertex Group";
2416         ot->idname= "OBJECT_OT_vertex_group_invert";
2417
2418         /* api callbacks */
2419         ot->poll= vertex_group_poll;
2420         ot->exec= vertex_group_invert_exec;
2421
2422         /* flags */
2423         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2424
2425         RNA_def_boolean(ot->srna, "auto_assign", TRUE, "Add Weights", "Add verts from groups that have zero weight before inverting.");
2426         RNA_def_boolean(ot->srna, "auto_remove", TRUE, "Remove Weights", "Remove verts from groups that have zero weight after inverting.");
2427 }
2428
2429
2430 static int vertex_group_blend_exec(bContext *C, wmOperator *UNUSED(op))
2431 {
2432         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2433
2434         vgroup_blend(ob);
2435
2436         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2437         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2438         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2439
2440         return OPERATOR_FINISHED;
2441 }
2442
2443 void OBJECT_OT_vertex_group_blend(wmOperatorType *ot)
2444 {
2445         /* identifiers */
2446         ot->name= "Blend Vertex Group";
2447         ot->idname= "OBJECT_OT_vertex_group_blend";
2448         ot->description= "";
2449
2450         /* api callbacks */
2451         ot->poll= vertex_group_poll;
2452         ot->exec= vertex_group_blend_exec;
2453
2454         /* flags */
2455         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2456 }
2457
2458
2459 static int vertex_group_clean_exec(bContext *C, wmOperator *op)
2460 {
2461         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2462
2463         float limit= RNA_float_get(op->ptr,"limit");
2464         int all_groups= RNA_boolean_get(op->ptr,"all_groups");
2465         int keep_single= RNA_boolean_get(op->ptr,"keep_single");
2466
2467         if(all_groups)  vgroup_clean_all(ob, limit, keep_single);
2468         else                    vgroup_clean(ob, limit, keep_single);
2469
2470         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2471         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2472         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2473
2474         return OPERATOR_FINISHED;
2475 }
2476
2477 void OBJECT_OT_vertex_group_clean(wmOperatorType *ot)
2478 {
2479         /* identifiers */
2480         ot->name= "Clean Vertex Group";
2481         ot->idname= "OBJECT_OT_vertex_group_clean";
2482         ot->description= "Remove Vertex Group assignments which aren't required";
2483
2484         /* api callbacks */
2485         ot->poll= vertex_group_poll;
2486         ot->exec= vertex_group_clean_exec;
2487
2488         /* flags */
2489         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2490
2491         RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, 1.0, "Limit", "Remove weights under this limit.", 0.001f, 0.99f);
2492         RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Clean all vertex groups.");
2493         RNA_def_boolean(ot->srna, "keep_single", FALSE, "Keep Single", "Keep verts assigned to at least one group when cleaning.");
2494 }
2495
2496
2497 static int vertex_group_mirror_exec(bContext *C, wmOperator *op)
2498 {
2499         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2500
2501         ED_vgroup_mirror(ob, RNA_boolean_get(op->ptr,"mirror_weights"), RNA_boolean_get(op->ptr,"flip_group_names"));
2502
2503         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2504         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2505         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2506
2507         return OPERATOR_FINISHED;
2508 }
2509
2510 void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot)
2511 {
2512         /* identifiers */
2513         ot->name= "Mirror Vertex Group";
2514         ot->idname= "OBJECT_OT_vertex_group_mirror";
2515         ot->description= "Mirror all vertex groups, flip weights and/or names, editing only selected vertices, flipping when both sides are selected otherwise copy from unselected";
2516
2517         /* api callbacks */
2518         ot->poll= vertex_group_poll_edit;
2519         ot->exec= vertex_group_mirror_exec;
2520
2521         /* flags */
2522         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2523
2524         /* properties */
2525         RNA_def_boolean(ot->srna, "mirror_weights", TRUE, "Mirror Weights", "Mirror weights.");
2526         RNA_def_boolean(ot->srna, "flip_group_names", TRUE, "Flip Groups", "Flip vertex group names.");
2527
2528 }
2529
2530 static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op))
2531 {
2532         Scene *scene= CTX_data_scene(C);
2533         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2534         Base *base;
2535         int retval= OPERATOR_CANCELLED;
2536
2537         for(base=scene->base.first; base; base= base->next) {
2538                 if(base->object->type==ob->type) {
2539                         if(base->object!=ob && base->object->data==ob->data) {
2540                                 BLI_freelistN(&base->object->defbase);
2541                                 BLI_duplicatelist(&base->object->defbase, &ob->defbase);
2542                                 base->object->actdef= ob->actdef;
2543
2544                                 DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
2545                                 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, base->object);
2546                                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
2547
2548                                 retval = OPERATOR_FINISHED;
2549                         }
2550                 }
2551         }
2552
2553         return retval;
2554 }
2555
2556 void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot)
2557 {
2558         /* identifiers */
2559         ot->name= "Copy Vertex Groups to Linked";
2560         ot->idname= "OBJECT_OT_vertex_group_copy_to_linked";
2561         ot->description= "Copy Vertex Groups to all users of the same Geometry data";
2562
2563         /* api callbacks */
2564         ot->poll= vertex_group_poll;
2565         ot->exec= vertex_group_copy_to_linked_exec;
2566
2567         /* flags */
2568         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2569 }
2570
2571 static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
2572 {
2573         Object *obact= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2574         int change= 0;
2575         int fail= 0;
2576
2577         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects)
2578         {
2579                 if(obact != ob) {
2580                         if(ED_vgroup_copy_array(ob, obact)) change++;
2581                         else                                fail++;
2582                 }
2583         }
2584         CTX_DATA_END;
2585
2586         if((change == 0 && fail == 0) || fail) {
2587                 BKE_reportf(op->reports, RPT_ERROR, "Copy to VGroups to Selected warning done %d, failed %d, object data must have matching indicies", change, fail);
2588         }
2589
2590         return OPERATOR_FINISHED;
2591 }
2592
2593
2594 void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot)
2595 {
2596         /* identifiers */
2597         ot->name= "Copy Vertex Group to Selected";
2598         ot->idname= "OBJECT_OT_vertex_group_copy_to_selected";
2599         ot->description= "Copy Vertex Groups to other selected objects with matching indices";
2600
2601         /* api callbacks */
2602         ot->poll= vertex_group_poll;
2603         ot->exec= vertex_group_copy_to_selected_exec;
2604
2605         /* flags */
2606         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2607 }
2608
2609 static EnumPropertyItem vgroup_items[]= {
2610         {0, NULL, 0, NULL, NULL}};
2611
2612 static int set_active_group_exec(bContext *C, wmOperator *op)
2613 {
2614         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2615         int nr= RNA_enum_get(op->ptr, "group");
2616
2617         ob->actdef= nr+1;
2618
2619         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2620         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2621
2622         return OPERATOR_FINISHED;
2623 }
2624
2625 static EnumPropertyItem *vgroup_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
2626 {       
2627         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2628         EnumPropertyItem tmp = {0, "", 0, "", ""};
2629         EnumPropertyItem *item= NULL;
2630         bDeformGroup *def;
2631         int a, totitem= 0;
2632         
2633         if(!ob)
2634                 return vgroup_items;
2635         
2636         for(a=0, def=ob->defbase.first; def; def=def->next, a++) {
2637                 tmp.value= a;
2638                 tmp.icon= ICON_GROUP_VERTEX;
2639                 tmp.identifier= def->name;
2640                 tmp.name= def->name;
2641                 RNA_enum_item_add(&item, &totitem, &tmp);
2642         }
2643
2644         RNA_enum_item_end(&item, &totitem);
2645         *free= 1;
2646
2647         return item;
2648 }
2649
2650 void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
2651 {
2652         PropertyRNA *prop;
2653
2654         /* identifiers */
2655         ot->name= "Set Active Vertex Group";
2656         ot->idname= "OBJECT_OT_vertex_group_set_active";
2657         ot->description= "Set the active vertex group";
2658
2659         /* api callbacks */
2660         ot->poll= vertex_group_poll;
2661         ot->exec= set_active_group_exec;
2662         ot->invoke= WM_menu_invoke;
2663
2664         /* flags */
2665         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2666
2667         /* properties */
2668         prop= RNA_def_enum(ot->srna, "group", vgroup_items, 0, "Group", "Vertex group to set as active.");
2669         RNA_def_enum_funcs(prop, vgroup_itemf);
2670         ot->prop= prop;
2671 }
2672
2673 /*creates the name_array parameter for vgroup_do_remap, call this before fiddling
2674   with the order of vgroups then call vgroup_do_remap after*/
2675 static char *vgroup_init_remap(Object *ob)
2676 {
2677         bDeformGroup *def;
2678         int def_tot = BLI_countlist(&ob->defbase);
2679         char *name_array= MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * def_tot, "sort vgroups");
2680         char *name;
2681
2682         name= name_array;
2683         for(def = ob->defbase.first; def; def=def->next) {
2684                 BLI_strncpy(name, def->name, MAX_VGROUP_NAME);
2685                 name += MAX_VGROUP_NAME;
2686         }
2687
2688         return name_array;
2689 }
2690
2691 static int vgroup_do_remap(Object *ob, char *name_array, wmOperator *op)
2692 {
2693         MDeformVert *dvert= NULL;
2694         bDeformGroup *def;
2695         int def_tot = BLI_countlist(&ob->defbase);
2696         int *sort_map_update= MEM_mallocN(MAX_VGROUP_NAME * sizeof(int) * def_tot + 1, "sort vgroups"); /* needs a dummy index at the start*/
2697         int *sort_map= sort_map_update + 1;
2698         char *name;
2699         int i;
2700
2701         name= name_array;
2702         for(def= ob->defbase.first, i=0; def; def=def->next, i++){
2703                 sort_map[i]= BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name));
2704                 name += MAX_VGROUP_NAME;
2705         }
2706
2707         if(ob->mode == OB_MODE_EDIT) {
2708                 if(ob->type==OB_MESH) {
2709                         EditMesh *em = BKE_mesh_get_editmesh(ob->data);
2710                         EditVert *eve;
2711
2712                         for(eve=em->verts.first; eve; eve=eve->next){
2713                                 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
2714                                 if(dvert && dvert->totweight){
2715                                         defvert_remap(dvert, sort_map);
2716                                 }
2717                         }
2718                 }
2719                 else {
2720                         BKE_report(op->reports, RPT_ERROR, "Editmode lattice isnt supported yet.");
2721                         MEM_freeN(sort_map_update);
2722                         return OPERATOR_CANCELLED;
2723                 }
2724         }
2725         else {
2726                 int dvert_tot=0;
2727
2728                 ED_vgroup_give_array(ob->data, &dvert, &dvert_tot);
2729
2730                 /*create as necassary*/
2731                 while(dvert && dvert_tot--) {
2732                         if(dvert->totweight)
2733                                 defvert_remap(dvert, sort_map);
2734                         dvert++;
2735                 }
2736         }
2737
2738         /* update users */
2739         for(i=0; i<def_tot; i++)
2740                 sort_map[i]++;
2741
2742         sort_map_update[0]= 0;
2743         vgroup_remap_update_users(ob, sort_map_update);
2744
2745         ob->actdef= sort_map_update[ob->actdef];
2746         
2747         MEM_freeN(sort_map_update);
2748
2749         return OPERATOR_FINISHED;
2750 }
2751
2752 static int vgroup_sort(void *def_a_ptr, void *def_b_ptr)
2753 {
2754         bDeformGroup *def_a= (bDeformGroup *)def_a_ptr;
2755         bDeformGroup *def_b= (bDeformGroup *)def_b_ptr;
2756
2757         return BLI_natstrcmp(def_a->name, def_b->name);
2758 }
2759
2760 static int vertex_group_sort_exec(bContext *C, wmOperator *op)
2761 {
2762         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2763         char *name_array;
2764         int ret;
2765
2766         /*init remapping*/
2767         name_array = vgroup_init_remap(ob);
2768
2769         /*sort vgroup names*/
2770         BLI_sortlist(&ob->defbase, vgroup_sort);
2771
2772         /*remap vgroup data to map to correct names*/
2773         ret = vgroup_do_remap(ob, name_array, op);
2774
2775         if (ret != OPERATOR_CANCELLED) {
2776                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2777                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2778         }
2779
2780         if (name_array) MEM_freeN(name_array);
2781
2782         return ret;
2783 }
2784
2785 void OBJECT_OT_vertex_group_sort(wmOperatorType *ot)
2786 {
2787         ot->name= "Sort Vertex Groups";
2788         ot->idname= "OBJECT_OT_vertex_group_sort";
2789         ot->description= "Sorts vertex groups alphabetically";
2790
2791         /* api callbacks */
2792         ot->poll= vertex_group_poll;
2793         ot->exec= vertex_group_sort_exec;
2794
2795         /* flags */
2796         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2797 }
2798
2799 static int vgroup_move_exec(bContext *C, wmOperator *op)
2800 {
2801         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2802         bDeformGroup *def;
2803         char *name_array;
2804         int dir= RNA_enum_get(op->ptr, "direction"), ret;
2805
2806         def = BLI_findlink(&ob->defbase, ob->actdef - 1);
2807         if (!def) {
2808                 return OPERATOR_CANCELLED;
2809         }
2810
2811         name_array = vgroup_init_remap(ob);
2812
2813         if (dir == 1) { /*up*/
2814                 void *prev = def->prev;
2815
2816                 BLI_remlink(&ob->defbase, def);
2817                 BLI_insertlinkbefore(&ob->defbase, prev, def);
2818         } else { /*down*/
2819                 void *next = def->next;
2820
2821                 BLI_remlink(&ob->defbase, def);
2822                 BLI_insertlinkafter(&ob->defbase, next, def);
2823         }
2824
2825         ret = vgroup_do_remap(ob, name_array, op);
2826
2827         if (name_array) MEM_freeN(name_array);
2828
2829         if (ret != OPERATOR_CANCELLED) {
2830                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2831                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2832         }
2833
2834         return ret;
2835 }
2836
2837 void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
2838 {
2839         static EnumPropertyItem vgroup_slot_move[] = {
2840                 {1, "UP", 0, "Up", ""},
2841                 {-1, "DOWN", 0, "Down", ""},
2842                 {0, NULL, 0, NULL, NULL}
2843         };
2844
2845         /* identifiers */
2846         ot->name= "Move Vertex Group";
2847         ot->idname= "OBJECT_OT_vertex_group_move";
2848
2849         /* api callbacks */
2850         ot->poll= vertex_group_poll;
2851         ot->exec= vgroup_move_exec;
2852
2853         /* flags */
2854         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2855
2856         RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
2857 }