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