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