Merging r42602 through r42620 from trunk into soc-2011-tomato
[blender.git] / source / blender / editors / object / object_vgroup.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/object/object_vgroup.c
29  *  \ingroup edobj
30  */
31
32
33 #include <string.h>
34 #include <stddef.h>
35 #include <math.h>
36 #include <assert.h>
37
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_cloth_types.h"
41 #include "DNA_curve_types.h"
42 #include "DNA_lattice_types.h"
43 #include "DNA_meshdata_types.h"
44 #include "DNA_modifier_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_object_force.h"
47 #include "DNA_scene_types.h"
48 #include "DNA_particle_types.h"
49
50 #include "BLI_math.h"
51 #include "BLI_blenlib.h"
52 #include "BLI_editVert.h"
53 #include "BLI_utildefines.h"
54
55 #include "BKE_context.h"
56 #include "BKE_customdata.h"
57 #include "BKE_deform.h"
58 #include "BKE_depsgraph.h"
59 #include "BKE_global.h"
60 #include "BKE_mesh.h"
61 #include "BKE_report.h"
62 #include "BKE_DerivedMesh.h"
63
64 #include "RNA_access.h"
65 #include "RNA_define.h"
66
67 #include "WM_api.h"
68 #include "WM_types.h"
69
70 #include "ED_mesh.h"
71
72 #include "UI_resources.h"
73
74 #include "object_intern.h"
75
76 /************************ Exported Functions **********************/
77 static void vgroup_remap_update_users(Object *ob, int *map);
78 static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *defgroup);
79 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg);
80 static void vgroup_delete_all(Object *ob);
81
82 static Lattice *vgroup_edit_lattice(Object *ob)
83 {
84         Lattice *lt= ob->data;
85         BLI_assert(ob->type==OB_LATTICE);
86         return (lt->editlatt)? lt->editlatt->latt: lt;
87 }
88
89 int ED_vgroup_object_is_edit_mode(Object *ob)
90 {
91         if(ob->type == OB_MESH)
92                 return (((Mesh*)ob->data)->edit_mesh != NULL);
93         else if(ob->type == OB_LATTICE)
94                 return (((Lattice*)ob->data)->editlatt != NULL);
95
96         return 0;
97 }
98
99 bDeformGroup *ED_vgroup_add_name(Object *ob, const char *name)
100 {
101         bDeformGroup *defgroup;
102
103         if(!ob || !OB_TYPE_SUPPORT_VGROUP(ob->type))
104                 return NULL;
105         
106         defgroup = MEM_callocN(sizeof(bDeformGroup), "add deformGroup");
107
108         BLI_strncpy(defgroup->name, name, sizeof(defgroup->name));
109
110         BLI_addtail(&ob->defbase, defgroup);
111         defgroup_unique_name(defgroup, ob);
112
113         ob->actdef = BLI_countlist(&ob->defbase);
114
115         return defgroup;
116 }
117
118 bDeformGroup *ED_vgroup_add(Object *ob) 
119 {
120         return ED_vgroup_add_name(ob, "Group");
121 }
122
123 void ED_vgroup_delete(Object *ob, bDeformGroup *defgroup) 
124 {
125         bDeformGroup *dg = (bDeformGroup *)ob->defbase.first;
126
127         while (dg) {
128                 if (dg == defgroup)
129                         break;
130                 dg = dg->next;
131         }
132
133         if (dg == NULL)
134                 return;
135
136         if(ED_vgroup_object_is_edit_mode(ob))
137                 vgroup_delete_edit_mode(ob, dg);
138         else
139                 vgroup_delete_object_mode(ob, dg);
140 }
141
142 void ED_vgroup_clear(Object *ob)
143 {
144         bDeformGroup *dg= (bDeformGroup *)ob->defbase.first;
145         int edit_mode= ED_vgroup_object_is_edit_mode(ob);
146
147         while (dg) {
148                 bDeformGroup *next_dg= dg->next;
149
150                 if(edit_mode)
151                         vgroup_delete_edit_mode(ob, dg);
152                 else
153                         vgroup_delete_object_mode(ob, dg);
154
155                 dg= next_dg;
156         }
157 }
158
159 int ED_vgroup_data_create(ID *id)
160 {
161         /* create deform verts */
162
163         if(GS(id->name)==ID_ME) {
164                 Mesh *me= (Mesh *)id;
165                 me->dvert= CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert);
166                 return TRUE;
167         }
168         else if(GS(id->name)==ID_LT) {
169                 Lattice *lt= (Lattice *)id;
170                 lt->dvert= MEM_callocN(sizeof(MDeformVert)*lt->pntsu*lt->pntsv*lt->pntsw, "lattice deformVert");
171                 return TRUE;
172         }
173         else {
174                 return FALSE;
175         }
176 }
177
178 static int ED_vgroup_give_parray(ID *id, MDeformVert ***dvert_arr, int *dvert_tot)
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 defbase_tot_from= BLI_countlist(&ob_from->defbase);
290         int defbase_tot= 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(defbase_tot_from < defbase_tot) {
318                 /* correct vgroup indices because the number of vgroups is being reduced. */
319                 int *remap= MEM_mallocN(sizeof(int) * (defbase_tot + 1), "ED_vgroup_copy_array");
320                 for(i=0; i<=defbase_tot_from; i++) remap[i]= i;
321                 for(; i<=defbase_tot; 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, def_nr                                   \
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 def_nr= ob->actdef-1;
1619
1620         if ( (mirror_weights==0 && flip_vgroups==0) ||
1621              (BLI_findlink(&ob->defbase, def_nr) == NULL) )
1622         {
1623                 return;
1624         }
1625
1626         if (flip_vgroups) {
1627                 flip_map= all_vgroups ?
1628                                         defgroup_flip_map(ob, &flip_map_len, FALSE) :
1629                                         defgroup_flip_map_single(ob, &flip_map_len, FALSE, def_nr);
1630
1631                 BLI_assert(flip_map != NULL);
1632
1633                 if (flip_map == NULL) {
1634                         /* something went wrong!, possibly no groups */
1635                         return;
1636                 }
1637         }
1638         else {
1639                 flip_map= NULL;
1640                 flip_map_len= 0;
1641         }
1642
1643         /* only the active group */
1644         if(ob->type == OB_MESH) {
1645                 Mesh *me= ob->data;
1646                 EditMesh *em = BKE_mesh_get_editmesh(me);
1647
1648                 if (em) {
1649                         if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
1650                                 goto cleanup;
1651                         }
1652
1653                         EM_cache_x_mirror_vert(ob, em);
1654
1655                         /* Go through the list of editverts and assign them */
1656                         for(eve=em->verts.first; eve; eve=eve->next){
1657                                 if((eve_mirr=eve->tmp.v)) {
1658                                         sel= eve->f & SELECT;
1659                                         sel_mirr= eve_mirr->f & SELECT;
1660
1661                                         if((sel || sel_mirr) && (eve != eve_mirr)) {
1662                                                 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1663                                                 dvert_mirr= CustomData_em_get(&em->vdata, eve_mirr->data, CD_MDEFORMVERT);
1664                                                 if(dvert && dvert_mirr) {
1665                                                         VGROUP_MIRR_OP;
1666                                                 }
1667                                         }
1668
1669                                         eve->tmp.v= eve_mirr->tmp.v= NULL;
1670                                 }
1671                         }
1672                         BKE_mesh_end_editmesh(me, em);
1673                 }
1674                 else {
1675                         /* object mode / weight paint */
1676                         MVert *mv, *mv_mirr;
1677                         int vidx, vidx_mirr;
1678                         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1679
1680                         if (me->dvert == NULL) {
1681                                 goto cleanup;
1682                         }
1683
1684                         if (!use_vert_sel) {
1685                                 sel= sel_mirr= TRUE;
1686                         }
1687
1688                         /* tag verts we have used */
1689                         for(vidx= 0, mv= me->mvert; vidx < me->totvert; vidx++, mv++) {
1690                                 mv->flag &= ~ME_VERT_TMP_TAG;
1691                         }
1692
1693                         for(vidx= 0, mv= me->mvert; vidx < me->totvert; vidx++, mv++) {
1694                                 if (    ((mv->flag & ME_VERT_TMP_TAG) == 0) &&
1695                                         ((vidx_mirr= mesh_get_x_mirror_vert(ob, vidx)) != -1) &&
1696                                         (vidx != vidx_mirr) &&
1697                                         ((((mv_mirr= me->mvert + vidx_mirr)->flag) & ME_VERT_TMP_TAG) == 0))
1698                                 {
1699
1700                                         if (use_vert_sel) {
1701                                                 sel= mv->flag & SELECT;
1702                                                 sel_mirr= mv_mirr->flag & SELECT;
1703                                         }
1704
1705                                         if (sel || sel_mirr) {
1706                                                 dvert= &me->dvert[vidx];
1707                                                 dvert_mirr= &me->dvert[vidx_mirr];
1708
1709                                                 VGROUP_MIRR_OP;
1710                                         }
1711
1712                                         mv->flag |= ME_VERT_TMP_TAG;
1713                                         mv_mirr->flag |= ME_VERT_TMP_TAG;
1714                                 }
1715                         }
1716                 }
1717         }
1718         else if (ob->type == OB_LATTICE) {
1719                 Lattice *lt= ob->data;
1720                 int i1, i2;
1721                 int u, v, w;
1722                 int pntsu_half;
1723                 /* half but found up odd value */
1724
1725                 if(lt->editlatt) lt= lt->editlatt->latt;
1726
1727                 if(lt->pntsu == 1 || lt->dvert == NULL) {
1728                         goto cleanup;
1729                 }
1730
1731                 /* unlike editmesh we know that by only looping over the first hald of
1732                  * the 'u' indicies it will cover all points except the middle which is
1733                  * ok in this case */
1734                 pntsu_half= lt->pntsu / 2;
1735
1736                 for(w=0; w<lt->pntsw; w++) {
1737                         for(v=0; v<lt->pntsv; v++) {
1738                                 for(u=0; u<pntsu_half; u++) {
1739                                         int u_inv= (lt->pntsu - 1) - u;
1740                                         if(u != u_inv) {
1741                                                 BPoint *bp, *bp_mirr;
1742
1743                                                 i1= LT_INDEX(lt, u, v, w);
1744                                                 i2= LT_INDEX(lt, u_inv, v, w);
1745
1746                                                 bp= &lt->def[i1];
1747                                                 bp_mirr= &lt->def[i2];
1748
1749                                                 sel= bp->f1 & SELECT;
1750                                                 sel_mirr= bp_mirr->f1 & SELECT;
1751
1752                                                 if(sel || sel_mirr) {
1753                                                         dvert= &lt->dvert[i1];
1754                                                         dvert_mirr= &lt->dvert[i2];
1755
1756                                                         VGROUP_MIRR_OP;
1757                                                 }
1758                                         }
1759                                 }
1760                         }
1761                 }
1762         }
1763
1764 cleanup:
1765         if (flip_map) MEM_freeN(flip_map);
1766
1767 #undef VGROUP_MIRR_OP
1768
1769 }
1770
1771 static void vgroup_remap_update_users(Object *ob, int *map)
1772 {
1773         ExplodeModifierData *emd;
1774         ModifierData *md;
1775         ParticleSystem *psys;
1776         ClothModifierData *clmd;
1777         ClothSimSettings *clsim;
1778         int a;
1779
1780         /* these cases don't use names to refer to vertex groups, so when
1781          * they get deleted the numbers get out of sync, this corrects that */
1782
1783         if(ob->soft)
1784                 ob->soft->vertgroup= map[ob->soft->vertgroup];
1785
1786         for(md=ob->modifiers.first; md; md=md->next) {
1787                 if(md->type == eModifierType_Explode) {
1788                         emd= (ExplodeModifierData*)md;
1789                         emd->vgroup= map[emd->vgroup];
1790                 }
1791                 else if(md->type == eModifierType_Cloth) {
1792                         clmd= (ClothModifierData*)md;
1793                         clsim= clmd->sim_parms;
1794
1795                         if(clsim) {
1796                                 clsim->vgroup_mass= map[clsim->vgroup_mass];
1797                                 clsim->vgroup_bend= map[clsim->vgroup_bend];
1798                                 clsim->vgroup_struct= map[clsim->vgroup_struct];
1799                         }
1800                 }
1801         }
1802
1803         for(psys=ob->particlesystem.first; psys; psys=psys->next) {
1804                 for(a=0; a<PSYS_TOT_VG; a++)
1805                         psys->vgroup[a]= map[psys->vgroup[a]];
1806         }
1807 }
1808
1809
1810 static void vgroup_delete_update_users(Object *ob, int id)
1811 {
1812         int i, defbase_tot= BLI_countlist(&ob->defbase) + 1;
1813         int *map= MEM_mallocN(sizeof(int) * defbase_tot, "vgroup del");
1814
1815         map[id]= map[0]= 0;
1816         for(i=1; i<id; i++) map[i]=i;
1817         for(i=id+1; i<defbase_tot; i++) map[i]=i-1;
1818
1819         vgroup_remap_update_users(ob, map);
1820         MEM_freeN(map);
1821 }
1822
1823
1824 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg)
1825 {
1826         MDeformVert *dvert_array=NULL;
1827         int i, e, dvert_tot=0;
1828         const int dg_index= BLI_findindex(&ob->defbase, dg);
1829
1830         assert(dg_index > -1);
1831         
1832         ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
1833
1834         if(dvert_array) {
1835                 MDeformVert *dvert;
1836                 for(i= 0, dvert= dvert_array; i < dvert_tot; i++, dvert++) {
1837                         ED_vgroup_vert_remove(ob, dg, i); /* ok if the dg isnt in this dvert, will continue silently */
1838                 }
1839
1840                 for(i= 0, dvert= dvert_array; i < dvert_tot; i++, dvert++) {
1841                         for(e = 0; e < dvert->totweight; e++) {
1842                                 if(dvert->dw[e].def_nr > dg_index) {
1843                                         dvert->dw[e].def_nr--;
1844                                 }
1845                         }
1846                 }
1847         }
1848
1849         vgroup_delete_update_users(ob, dg_index + 1);
1850
1851         /* Remove the group */
1852         BLI_freelinkN(&ob->defbase, dg);
1853
1854         /* Update the active deform index if necessary */
1855         if(ob->actdef > dg_index)
1856                 ob->actdef--;
1857         if(ob->actdef < 1 && ob->defbase.first)
1858                 ob->actdef= 1;
1859
1860 }
1861
1862 /* only in editmode */
1863 /* removes from active defgroup, if allverts==0 only selected vertices */
1864 static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGroup *dg)
1865 {
1866         EditVert *eve;
1867         MDeformVert *dvert;
1868         MDeformWeight *newdw;
1869         bDeformGroup *eg;
1870         int     i;
1871
1872         if(ob->type == OB_MESH) {
1873                 Mesh *me= ob->data;
1874                 EditMesh *em = BKE_mesh_get_editmesh(me);
1875
1876                 for(eve=em->verts.first; eve; eve=eve->next){
1877                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1878                 
1879                         if(dvert && dvert->dw && ((eve->f & SELECT) || allverts)){
1880                                 for(i=0; i<dvert->totweight; i++){
1881                                         /* Find group */
1882                                         eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr);
1883                                         if(eg == dg){
1884                                                 dvert->totweight--;
1885                                                 if(dvert->totweight){
1886                                                         newdw = MEM_mallocN(sizeof(MDeformWeight)*(dvert->totweight), "deformWeight");
1887                                                         
1888                                                         if(dvert->dw){
1889                                                                 memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*i);
1890                                                                 memcpy(newdw+i, dvert->dw+i+1, sizeof(MDeformWeight)*(dvert->totweight-i));
1891                                                                 MEM_freeN(dvert->dw);
1892                                                         }
1893                                                         dvert->dw=newdw;
1894                                                 }
1895                                                 else{
1896                                                         MEM_freeN(dvert->dw);
1897                                                         dvert->dw=NULL;
1898                                                         break;
1899                                                 }
1900                                         }
1901                                 }
1902                         }
1903                 }
1904                 BKE_mesh_end_editmesh(me, em);
1905         }
1906         else if(ob->type == OB_LATTICE) {
1907                 Lattice *lt= vgroup_edit_lattice(ob);
1908                 
1909                 if(lt->dvert) {
1910                         BPoint *bp;
1911                         int a, tot= lt->pntsu*lt->pntsv*lt->pntsw;
1912                                 
1913                         for(a=0, bp= lt->def; a<tot; a++, bp++) {
1914                                 if(allverts || (bp->f1 & SELECT))
1915                                         ED_vgroup_vert_remove(ob, dg, a);
1916                         }
1917                 }
1918         }
1919 }
1920
1921 static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg)
1922 {
1923         int i;
1924         const int dg_index= BLI_findindex(&ob->defbase, dg);
1925
1926         assert(dg_index > -1);
1927
1928         /* Make sure that no verts are using this group */
1929         vgroup_active_remove_verts(ob, TRUE, dg);
1930
1931         /* Make sure that any verts with higher indices are adjusted accordingly */
1932         if(ob->type==OB_MESH) {
1933                 Mesh *me= ob->data;
1934                 EditMesh *em = BKE_mesh_get_editmesh(me);
1935                 EditVert *eve;
1936                 MDeformVert *dvert;
1937                 
1938                 for(eve=em->verts.first; eve; eve=eve->next){
1939                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1940
1941                         if(dvert)
1942                                 for(i=0; i<dvert->totweight; i++)
1943                                         if(dvert->dw[i].def_nr > dg_index)
1944                                                 dvert->dw[i].def_nr--;
1945                 }
1946                 BKE_mesh_end_editmesh(me, em);
1947         }
1948         else if(ob->type==OB_LATTICE) {
1949                 Lattice *lt= vgroup_edit_lattice(ob);
1950                 BPoint *bp;
1951                 MDeformVert *dvert= lt->dvert;
1952                 int a, tot;
1953                 
1954                 if(dvert) {
1955                         tot= lt->pntsu*lt->pntsv*lt->pntsw;
1956                         for(a=0, bp= lt->def; a<tot; a++, bp++, dvert++) {
1957                                 for(i=0; i<dvert->totweight; i++){
1958                                         if(dvert->dw[i].def_nr > dg_index)
1959                                                 dvert->dw[i].def_nr--;
1960                                 }
1961                         }
1962                 }
1963         }
1964
1965         vgroup_delete_update_users(ob, dg_index + 1);
1966
1967         /* Remove the group */
1968         BLI_freelinkN (&ob->defbase, dg);
1969
1970         /* Update the active deform index if necessary */
1971         if(ob->actdef > dg_index)
1972                 ob->actdef--;
1973         if(ob->actdef < 1 && ob->defbase.first)
1974                 ob->actdef= 1;
1975
1976         /* remove all dverts */
1977         if(ob->defbase.first == NULL) {
1978                 if(ob->type==OB_MESH) {
1979                         Mesh *me= ob->data;
1980                         CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
1981                         me->dvert= NULL;
1982                 }
1983                 else if(ob->type==OB_LATTICE) {
1984                         Lattice *lt= vgroup_edit_lattice(ob);
1985                         if(lt->dvert) {
1986                                 MEM_freeN(lt->dvert);
1987                                 lt->dvert= NULL;
1988                         }
1989                 }
1990         }
1991 }
1992
1993 static int vgroup_object_in_edit_mode(Object *ob)
1994 {
1995         if(ob->type == OB_MESH)
1996                 return (((Mesh*)ob->data)->edit_mesh != NULL);
1997         else if(ob->type == OB_LATTICE)
1998                 return (((Lattice*)ob->data)->editlatt != NULL);
1999         
2000         return 0;
2001 }
2002
2003 static void vgroup_delete(Object *ob)
2004 {
2005         bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef-1);
2006         if(!dg)
2007                 return;
2008
2009         if(vgroup_object_in_edit_mode(ob))
2010                 vgroup_delete_edit_mode(ob, dg);
2011         else
2012                 vgroup_delete_object_mode(ob, dg);
2013 }
2014
2015 static void vgroup_delete_all(Object *ob)
2016 {
2017         /* Remove all DVerts */
2018         if(ob->type==OB_MESH) {
2019                 Mesh *me= ob->data;
2020                 CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
2021                 me->dvert= NULL;
2022         }
2023         else if(ob->type==OB_LATTICE) {
2024                 Lattice *lt= vgroup_edit_lattice(ob);
2025                 if(lt->dvert) {
2026                         MEM_freeN(lt->dvert);
2027                         lt->dvert= NULL;
2028                 }
2029         }
2030         
2031         /* Remove all DefGroups */
2032         BLI_freelistN(&ob->defbase);
2033         
2034         /* Fix counters/indices */
2035         ob->actdef= 0;
2036 }
2037
2038 /* only in editmode */
2039 static void vgroup_assign_verts(Object *ob, float weight)
2040 {
2041         EditVert *eve;
2042         bDeformGroup *dg, *eg;
2043         MDeformWeight *newdw;
2044         MDeformVert *dvert;
2045         int     i, done;
2046
2047         dg=BLI_findlink(&ob->defbase, ob->actdef-1);
2048         if(!dg)
2049                 return;
2050
2051         if(ob->type == OB_MESH) {
2052                 Mesh *me= ob->data;
2053                 EditMesh *em = BKE_mesh_get_editmesh(me);
2054
2055                 if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT))
2056                         EM_add_data_layer(em, &em->vdata, CD_MDEFORMVERT, NULL);
2057
2058                 /* Go through the list of editverts and assign them */
2059                 for(eve=em->verts.first; eve; eve=eve->next){
2060                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
2061
2062                         if(dvert && (eve->f & SELECT)){
2063                                 /* See if this vert already has a reference to this group */
2064                                 /*              If so: Change its weight */
2065                                 done=0;
2066                                 for(i=0; i<dvert->totweight; i++){
2067                                         eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr);
2068                                         /* Find the actual group */
2069                                         if(eg==dg){
2070                                                 dvert->dw[i].weight= weight;
2071                                                 done=1;
2072                                                 break;
2073                                         }
2074                                  }
2075                                 /*              If not: Add the group and set its weight */
2076                                 if(!done){
2077                                         newdw = MEM_callocN(sizeof(MDeformWeight)*(dvert->totweight+1), "deformWeight");
2078                                         if(dvert->dw){
2079                                                 memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*dvert->totweight);
2080                                                 MEM_freeN(dvert->dw);
2081                                         }
2082                                         dvert->dw=newdw;
2083
2084                                         dvert->dw[dvert->totweight].weight= weight;
2085                                         dvert->dw[dvert->totweight].def_nr= ob->actdef-1;
2086
2087                                         dvert->totweight++;
2088
2089                                 }
2090                         }
2091                 }
2092                 BKE_mesh_end_editmesh(me, em);
2093         }
2094         else if(ob->type == OB_LATTICE) {
2095                 Lattice *lt= vgroup_edit_lattice(ob);
2096                 BPoint *bp;
2097                 int a, tot;
2098                 
2099                 if(lt->dvert==NULL)
2100                         ED_vgroup_data_create(&lt->id);
2101                 
2102                 tot= lt->pntsu*lt->pntsv*lt->pntsw;
2103                 for(a=0, bp= lt->def; a<tot; a++, bp++) {
2104                         if(bp->f1 & SELECT)
2105                                 ED_vgroup_nr_vert_add(ob, ob->actdef-1, a, weight, WEIGHT_REPLACE);
2106                 }
2107         }
2108 }
2109
2110 /* only in editmode */
2111 /* removes from all defgroup, if allverts==0 only selected vertices */
2112 static void vgroup_remove_verts(Object *ob, int allverts)
2113 {
2114         /* To prevent code redundancy, we just use vgroup_active_remove_verts, but that
2115          * only operates on the active vgroup. So we iterate through all groups, by changing
2116          * active group index
2117          */
2118         bDeformGroup *dg;
2119         for(dg= ob->defbase.first; dg; dg= dg->next) {
2120                 vgroup_active_remove_verts(ob, allverts, dg);
2121         }
2122 }
2123
2124 /********************** vertex group operators *********************/
2125
2126 static int vertex_group_poll(bContext *C)
2127 {
2128         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2129         ID *data= (ob)? ob->data: NULL;
2130         return (ob && !ob->id.lib && OB_TYPE_SUPPORT_VGROUP(ob->type) && data && !data->lib);
2131 }
2132
2133 static int vertex_group_poll_edit(bContext *C)
2134 {
2135         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2136         ID *data= (ob)? ob->data: NULL;
2137
2138         if(!(ob && !ob->id.lib && data && !data->lib))
2139                 return 0;
2140
2141         return vgroup_object_in_edit_mode(ob);
2142 }
2143
2144 static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op))
2145 {
2146         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2147
2148         ED_vgroup_add(ob);
2149         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2150         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2151         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2152         
2153         return OPERATOR_FINISHED;
2154 }
2155
2156 void OBJECT_OT_vertex_group_add(wmOperatorType *ot)
2157 {
2158         /* identifiers */
2159         ot->name= "Add Vertex Group";
2160         ot->idname= "OBJECT_OT_vertex_group_add";
2161         
2162         /* api callbacks */
2163         ot->poll= vertex_group_poll;
2164         ot->exec= vertex_group_add_exec;
2165
2166         /* flags */
2167         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2168 }
2169
2170 static int vertex_group_remove_exec(bContext *C, wmOperator *op)
2171 {
2172         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2173
2174         if(RNA_boolean_get(op->ptr, "all"))
2175                 vgroup_delete_all(ob);
2176         else
2177                 vgroup_delete(ob);
2178
2179         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2180         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2181         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2182         
2183         return OPERATOR_FINISHED;
2184 }
2185
2186 void OBJECT_OT_vertex_group_remove(wmOperatorType *ot)
2187 {
2188         /* identifiers */
2189         ot->name= "Remove Vertex Group";
2190         ot->idname= "OBJECT_OT_vertex_group_remove";
2191         
2192         /* api callbacks */
2193         ot->poll= vertex_group_poll;
2194         ot->exec= vertex_group_remove_exec;
2195
2196         /* flags */
2197         /* redo operator will fail in this case because vertex groups aren't stored
2198            in local edit mode stack and toggling "all" property will lead to
2199            all groups deleted without way to restore them (see [#29527], sergey) */
2200         ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO;
2201
2202         /* properties */
2203         RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups");
2204 }
2205
2206 static int vertex_group_assign_exec(bContext *C, wmOperator *op)
2207 {
2208         ToolSettings *ts= CTX_data_tool_settings(C);
2209         Object *ob= CTX_data_edit_object(C);
2210
2211         if(RNA_boolean_get(op->ptr, "new"))
2212                 ED_vgroup_add(ob);
2213
2214         vgroup_assign_verts(ob, ts->vgroup_weight);
2215         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2216         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2217         
2218         return OPERATOR_FINISHED;
2219 }
2220
2221 void OBJECT_OT_vertex_group_assign(wmOperatorType *ot)
2222 {
2223         /* identifiers */
2224         ot->name= "Assign Vertex Group";
2225         ot->idname= "OBJECT_OT_vertex_group_assign";
2226         
2227         /* api callbacks */
2228         ot->poll= vertex_group_poll_edit;
2229         ot->exec= vertex_group_assign_exec;
2230
2231         /* flags */
2232         /* redo operator will fail in this case because vertex group assignment
2233            isn't stored in local edit mode stack and toggling "new" property will
2234            lead to creating plenty of new veretx groups (see [#29527], sergey) */
2235         ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO;
2236
2237         /* properties */
2238         RNA_def_boolean(ot->srna, "new", 0, "New", "Assign vertex to new vertex group");
2239 }
2240
2241 static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
2242 {
2243         Object *ob= CTX_data_edit_object(C);
2244
2245         if(RNA_boolean_get(op->ptr, "all"))
2246                 vgroup_remove_verts(ob, 0);
2247         else {
2248                 bDeformGroup *dg= BLI_findlink(&ob->defbase, ob->actdef - 1);
2249
2250                 if(dg == NULL) {
2251                         return OPERATOR_CANCELLED;
2252                 }
2253
2254                 vgroup_active_remove_verts(ob, FALSE, dg);
2255         }
2256
2257         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2258         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2259
2260         return OPERATOR_FINISHED;
2261 }
2262
2263 void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot)
2264 {
2265         /* identifiers */
2266         ot->name= "Remove from Vertex Group";
2267         ot->idname= "OBJECT_OT_vertex_group_remove_from";
2268
2269         /* api callbacks */
2270         ot->poll= vertex_group_poll_edit;
2271         ot->exec= vertex_group_remove_from_exec;
2272
2273         /* flags */
2274         /* redo operator will fail in this case because vertex groups ssignment
2275            isn't stored in local edit mode stack and toggling "all" property will lead to
2276            removing vertices from all groups (see [#29527], sergey) */
2277         ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO;
2278
2279         /* properties */
2280         RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups");
2281 }
2282
2283 static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
2284 {
2285         Object *ob= CTX_data_edit_object(C);
2286
2287         if(!ob || ob->id.lib)
2288                 return OPERATOR_CANCELLED;
2289
2290         vgroup_select_verts(ob, 1);
2291         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
2292
2293         return OPERATOR_FINISHED;
2294 }
2295
2296 void OBJECT_OT_vertex_group_select(wmOperatorType *ot)
2297 {
2298         /* identifiers */
2299         ot->name= "Select Vertex Group";
2300         ot->idname= "OBJECT_OT_vertex_group_select";
2301
2302         /* api callbacks */
2303         ot->poll= vertex_group_poll_edit;
2304         ot->exec= vertex_group_select_exec;
2305
2306         /* flags */
2307         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2308 }
2309
2310 static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
2311 {
2312         Object *ob= CTX_data_edit_object(C);
2313
2314         vgroup_select_verts(ob, 0);
2315         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
2316
2317         return OPERATOR_FINISHED;
2318 }
2319
2320 void OBJECT_OT_vertex_group_deselect(wmOperatorType *ot)
2321 {
2322         /* identifiers */
2323         ot->name= "Deselect Vertex Group";
2324         ot->idname= "OBJECT_OT_vertex_group_deselect";
2325
2326         /* api callbacks */
2327         ot->poll= vertex_group_poll_edit;
2328         ot->exec= vertex_group_deselect_exec;
2329
2330         /* flags */
2331         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2332 }
2333
2334 static int vertex_group_copy_exec(bContext *C, wmOperator *UNUSED(op))
2335 {
2336         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2337
2338         vgroup_duplicate(ob);
2339         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2340         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2341         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2342
2343         return OPERATOR_FINISHED;
2344 }
2345
2346 void OBJECT_OT_vertex_group_copy(wmOperatorType *ot)
2347 {
2348         /* identifiers */
2349         ot->name= "Copy Vertex Group";
2350         ot->idname= "OBJECT_OT_vertex_group_copy";
2351
2352         /* api callbacks */
2353         ot->poll= vertex_group_poll;
2354         ot->exec= vertex_group_copy_exec;
2355
2356         /* flags */
2357         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2358 }
2359
2360 static int vertex_group_levels_exec(bContext *C, wmOperator *op)
2361 {
2362         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2363         
2364         float offset= RNA_float_get(op->ptr,"offset");
2365         float gain= RNA_float_get(op->ptr,"gain");
2366         
2367         vgroup_levels(ob, offset, gain);
2368         
2369         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2370         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2371         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2372         
2373         return OPERATOR_FINISHED;
2374 }
2375
2376 void OBJECT_OT_vertex_group_levels(wmOperatorType *ot)
2377 {
2378         /* identifiers */
2379         ot->name= "Vertex Group Levels";
2380         ot->idname= "OBJECT_OT_vertex_group_levels";
2381         
2382         /* api callbacks */
2383         ot->poll= vertex_group_poll;
2384         ot->exec= vertex_group_levels_exec;
2385         
2386         /* flags */
2387         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2388         
2389         RNA_def_float(ot->srna, "offset", 0.f, -1.0, 1.0, "Offset", "Value to add to weights", -1.0f, 1.f);
2390         RNA_def_float(ot->srna, "gain", 1.f, 0.f, FLT_MAX, "Gain", "Value to multiply weights by", 0.0f, 10.f);
2391 }
2392
2393 static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op))
2394 {
2395         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2396
2397         vgroup_normalize(ob);
2398
2399         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2400         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2401         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2402
2403         return OPERATOR_FINISHED;
2404 }
2405
2406 void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot)
2407 {
2408         /* identifiers */
2409         ot->name= "Normalize Vertex Group";
2410         ot->idname= "OBJECT_OT_vertex_group_normalize";
2411
2412         /* api callbacks */
2413         ot->poll= vertex_group_poll;
2414         ot->exec= vertex_group_normalize_exec;
2415
2416         /* flags */
2417         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2418 }
2419
2420 static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
2421 {
2422         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2423         int lock_active= RNA_boolean_get(op->ptr,"lock_active");
2424
2425         vgroup_normalize_all(ob, lock_active);
2426
2427         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2428         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2429         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2430
2431         return OPERATOR_FINISHED;
2432 }
2433
2434 void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
2435 {
2436         /* identifiers */
2437         ot->name= "Normalize All Vertex Groups";
2438         ot->idname= "OBJECT_OT_vertex_group_normalize_all";
2439
2440         /* api callbacks */
2441         ot->poll= vertex_group_poll;
2442         ot->exec= vertex_group_normalize_all_exec;
2443
2444         /* flags */
2445         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2446
2447         RNA_def_boolean(ot->srna, "lock_active", TRUE, "Lock Active",
2448                         "Keep the values of the active group while normalizing others");
2449 }
2450
2451 static int vertex_group_fix_exec(bContext *C, wmOperator *op)
2452 {
2453         Object *ob= CTX_data_active_object(C);
2454         Scene *scene= CTX_data_scene(C);
2455         
2456         float distToBe= RNA_float_get(op->ptr, "dist");
2457         float strength= RNA_float_get(op->ptr, "strength");
2458         float cp= RNA_float_get(op->ptr, "accuracy");
2459         ModifierData *md= ob->modifiers.first;
2460
2461         while(md) {
2462                 if(md->type == eModifierType_Mirror && (md->mode&eModifierMode_Realtime)) {
2463                         break;
2464                 }
2465                 md = md->next;
2466         }
2467         
2468         if(md && md->type == eModifierType_Mirror) {
2469                 BKE_report(op->reports, RPT_ERROR_INVALID_CONTEXT, "This operator does not support an active mirror modifier");
2470                 return OPERATOR_CANCELLED;
2471         }
2472         vgroup_fix(scene, ob, distToBe, strength, cp);
2473         
2474         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2475         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2476         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2477         
2478         return OPERATOR_FINISHED;
2479 }
2480
2481 void OBJECT_OT_vertex_group_fix(wmOperatorType *ot)
2482 {
2483         /* identifiers */
2484         ot->name= "Fix Vertex Group Deform";
2485         ot->idname= "OBJECT_OT_vertex_group_fix";
2486         ot->description= "Modify the position of selected vertices by changing only their respective "
2487                          "groups' weights (this tool may be slow for many vertices)";
2488         
2489         /* api callbacks */
2490         ot->poll= vertex_group_poll;
2491         ot->exec= vertex_group_fix_exec;
2492         
2493         /* flags */
2494         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2495         RNA_def_float(ot->srna, "dist", 0.0f, -FLT_MAX, FLT_MAX, "Distance", "The distance to move to", -10.0f, 10.0f);
2496         RNA_def_float(ot->srna, "strength", 1.f, -2.0f, FLT_MAX, "Strength",
2497                       "The distance moved can be changed by this multiplier", -2.0f, 2.0f);
2498         RNA_def_float(ot->srna, "accuracy", 1.0f, 0.05f, FLT_MAX, "Change Sensitivity",
2499                       "Change the amount weights are altered with each iteration: lower values are slower", 0.05f, 1.f);
2500 }
2501
2502
2503 static int vertex_group_lock_exec(bContext *C, wmOperator *op)
2504 {
2505         Object *ob= CTX_data_active_object(C);
2506
2507         int action = RNA_enum_get(op->ptr, "action");
2508
2509         vgroup_lock_all(ob, action);
2510
2511         return OPERATOR_FINISHED;
2512 }
2513
2514 void OBJECT_OT_vertex_group_lock(wmOperatorType *ot)
2515 {
2516         /* identifiers */
2517         ot->name= "Change the Lock On Vertex Groups";
2518         ot->idname= "OBJECT_OT_vertex_group_lock";
2519
2520         /* api callbacks */
2521         ot->poll= vertex_group_poll;
2522         ot->exec= vertex_group_lock_exec;
2523
2524         /* flags */
2525         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2526
2527         WM_operator_properties_select_all(ot);
2528 }
2529
2530 static int vertex_group_invert_exec(bContext *C, wmOperator *op)
2531 {
2532         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2533         int auto_assign= RNA_boolean_get(op->ptr,"auto_assign");
2534         int auto_remove= RNA_boolean_get(op->ptr,"auto_remove");
2535
2536         vgroup_invert(ob, auto_assign, auto_remove);
2537         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2538         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2539         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2540
2541         return OPERATOR_FINISHED;
2542 }
2543
2544 void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
2545 {
2546         /* identifiers */
2547         ot->name= "Invert Vertex Group";
2548         ot->idname= "OBJECT_OT_vertex_group_invert";
2549
2550         /* api callbacks */
2551         ot->poll= vertex_group_poll;
2552         ot->exec= vertex_group_invert_exec;
2553
2554         /* flags */
2555         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2556
2557         RNA_def_boolean(ot->srna, "auto_assign", TRUE, "Add Weights",
2558                         "Add verts from groups that have zero weight before inverting");
2559         RNA_def_boolean(ot->srna, "auto_remove", TRUE, "Remove Weights",
2560                         "Remove verts from groups that have zero weight after inverting");
2561 }
2562
2563
2564 static int vertex_group_blend_exec(bContext *C, wmOperator *UNUSED(op))
2565 {
2566         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2567
2568         vgroup_blend(ob);
2569
2570         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2571         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2572         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2573
2574         return OPERATOR_FINISHED;
2575 }
2576
2577 void OBJECT_OT_vertex_group_blend(wmOperatorType *ot)
2578 {
2579         /* identifiers */
2580         ot->name= "Blend Vertex Group";
2581         ot->idname= "OBJECT_OT_vertex_group_blend";
2582         ot->description= "";
2583
2584         /* api callbacks */
2585         ot->poll= vertex_group_poll;
2586         ot->exec= vertex_group_blend_exec;
2587
2588         /* flags */
2589         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2590 }
2591
2592
2593 static int vertex_group_clean_exec(bContext *C, wmOperator *op)
2594 {
2595         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2596
2597         float limit= RNA_float_get(op->ptr,"limit");
2598         int all_groups= RNA_boolean_get(op->ptr,"all_groups");
2599         int keep_single= RNA_boolean_get(op->ptr,"keep_single");
2600
2601         if(all_groups)  vgroup_clean_all(ob, limit, keep_single);
2602         else                    vgroup_clean(ob, limit, keep_single);
2603
2604         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2605         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2606         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2607
2608         return OPERATOR_FINISHED;
2609 }
2610
2611 void OBJECT_OT_vertex_group_clean(wmOperatorType *ot)
2612 {
2613         /* identifiers */
2614         ot->name= "Clean Vertex Group";
2615         ot->idname= "OBJECT_OT_vertex_group_clean";
2616         ot->description= "Remove Vertex Group assignments which aren't required";
2617
2618         /* api callbacks */
2619         ot->poll= vertex_group_poll;
2620         ot->exec= vertex_group_clean_exec;
2621
2622         /* flags */
2623         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2624
2625         RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, 1.0, "Limit", "Remove weights under this limit", 0.001f, 0.99f);
2626         RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Clean all vertex groups");
2627         RNA_def_boolean(ot->srna, "keep_single", FALSE, "Keep Single", "Keep verts assigned to at least one group when cleaning");
2628 }
2629
2630
2631 static int vertex_group_mirror_exec(bContext *C, wmOperator *op)
2632 {
2633         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2634
2635         ED_vgroup_mirror(ob,
2636                          RNA_boolean_get(op->ptr,"mirror_weights"),
2637                          RNA_boolean_get(op->ptr,"flip_group_names"),
2638                          RNA_boolean_get(op->ptr,"all_groups"));
2639
2640         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2641         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2642         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2643
2644         return OPERATOR_FINISHED;
2645 }
2646
2647 void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot)
2648 {
2649         /* identifiers */
2650         ot->name= "Mirror Vertex Group";
2651         ot->idname= "OBJECT_OT_vertex_group_mirror";
2652         ot->description= "Mirror all vertex groups, flip weights and/or names, editing only selected vertices, "
2653                          "flipping when both sides are selected otherwise copy from unselected";
2654
2655         /* api callbacks */
2656         ot->poll= vertex_group_poll;
2657         ot->exec= vertex_group_mirror_exec;
2658
2659         /* flags */
2660         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2661
2662         /* properties */
2663         RNA_def_boolean(ot->srna, "mirror_weights", TRUE, "Mirror Weights", "Mirror weights");
2664         RNA_def_boolean(ot->srna, "flip_group_names", TRUE, "Flip Groups", "Flip vertex group names");
2665         RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Mirror all vertex groups weights");
2666
2667 }
2668
2669 static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op))
2670 {
2671         Scene *scene= CTX_data_scene(C);
2672         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2673         Base *base;
2674         int retval= OPERATOR_CANCELLED;
2675
2676         for(base=scene->base.first; base; base= base->next) {
2677                 if(base->object->type==ob->type) {
2678                         if(base->object!=ob && base->object->data==ob->data) {
2679                                 BLI_freelistN(&base->object->defbase);
2680                                 BLI_duplicatelist(&base->object->defbase, &ob->defbase);
2681                                 base->object->actdef= ob->actdef;
2682
2683                                 DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
2684                                 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, base->object);
2685                                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
2686
2687                                 retval = OPERATOR_FINISHED;
2688                         }
2689                 }
2690         }
2691
2692         return retval;
2693 }
2694
2695 void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot)
2696 {
2697         /* identifiers */
2698         ot->name= "Copy Vertex Groups to Linked";
2699         ot->idname= "OBJECT_OT_vertex_group_copy_to_linked";
2700         ot->description= "Copy Vertex Groups to all users of the same Geometry data";
2701
2702         /* api callbacks */
2703         ot->poll= vertex_group_poll;
2704         ot->exec= vertex_group_copy_to_linked_exec;
2705
2706         /* flags */
2707         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2708 }
2709
2710 static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
2711 {
2712         Object *obact= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2713         int change= 0;
2714         int fail= 0;
2715
2716         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects)
2717         {
2718                 if(obact != ob) {
2719                         if(ED_vgroup_copy_array(ob, obact)) change++;
2720                         else                                fail++;
2721                 }
2722         }
2723         CTX_DATA_END;
2724
2725         if((change == 0 && fail == 0) || fail) {
2726                 BKE_reportf(op->reports, RPT_ERROR,
2727                             "Copy to VGroups to Selected warning done %d, failed %d, object data must have matching indicies",
2728                             change, fail);
2729         }
2730
2731         return OPERATOR_FINISHED;
2732 }
2733
2734
2735 void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot)
2736 {
2737         /* identifiers */
2738         ot->name= "Copy Vertex Group to Selected";
2739         ot->idname= "OBJECT_OT_vertex_group_copy_to_selected";
2740         ot->description= "Copy Vertex Groups to other selected objects with matching indices";
2741
2742         /* api callbacks */
2743         ot->poll= vertex_group_poll;
2744         ot->exec= vertex_group_copy_to_selected_exec;
2745
2746         /* flags */
2747         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2748 }
2749
2750 static EnumPropertyItem vgroup_items[]= {
2751         {0, NULL, 0, NULL, NULL}};
2752
2753 static int set_active_group_exec(bContext *C, wmOperator *op)
2754 {
2755         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2756         int nr= RNA_enum_get(op->ptr, "group");
2757
2758         ob->actdef= nr+1;
2759         BLI_assert(ob->actdef >= 0);
2760
2761         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2762         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2763
2764         return OPERATOR_FINISHED;
2765 }
2766
2767 static EnumPropertyItem *vgroup_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
2768 {       
2769         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2770         EnumPropertyItem tmp = {0, "", 0, "", ""};
2771         EnumPropertyItem *item= NULL;
2772         bDeformGroup *def;
2773         int a, totitem= 0;
2774         
2775         if(!ob)
2776                 return vgroup_items;
2777         
2778         for(a=0, def=ob->defbase.first; def; def=def->next, a++) {
2779                 tmp.value= a;
2780                 tmp.icon= ICON_GROUP_VERTEX;
2781                 tmp.identifier= def->name;
2782                 tmp.name= def->name;
2783                 RNA_enum_item_add(&item, &totitem, &tmp);
2784         }
2785
2786         RNA_enum_item_end(&item, &totitem);
2787         *free= 1;
2788
2789         return item;
2790 }
2791
2792 void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
2793 {
2794         PropertyRNA *prop;
2795
2796         /* identifiers */
2797         ot->name= "Set Active Vertex Group";
2798         ot->idname= "OBJECT_OT_vertex_group_set_active";
2799         ot->description= "Set the active vertex group";
2800
2801         /* api callbacks */
2802         ot->poll= vertex_group_poll;
2803         ot->exec= set_active_group_exec;
2804         ot->invoke= WM_menu_invoke;
2805
2806         /* flags */
2807         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2808
2809         /* properties */
2810         prop= RNA_def_enum(ot->srna, "group", vgroup_items, 0, "Group", "Vertex group to set as active");
2811         RNA_def_enum_funcs(prop, vgroup_itemf);
2812         ot->prop= prop;
2813 }
2814
2815 /*creates the name_array parameter for vgroup_do_remap, call this before fiddling
2816   with the order of vgroups then call vgroup_do_remap after*/
2817 static char *vgroup_init_remap(Object *ob)
2818 {
2819         bDeformGroup *def;
2820         int defbase_tot = BLI_countlist(&ob->defbase);
2821         char *name_array= MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups");
2822         char *name;
2823
2824         name= name_array;
2825         for(def = ob->defbase.first; def; def=def->next) {
2826                 BLI_strncpy(name, def->name, MAX_VGROUP_NAME);
2827                 name += MAX_VGROUP_NAME;
2828         }
2829
2830         return name_array;
2831 }
2832
2833 static int vgroup_do_remap(Object *ob, char *name_array, wmOperator *op)
2834 {
2835         MDeformVert *dvert= NULL;
2836         bDeformGroup *def;
2837         int defbase_tot = BLI_countlist(&ob->defbase);
2838         int *sort_map_update= MEM_mallocN(sizeof(int) * (defbase_tot + 1), "sort vgroups"); /* needs a dummy index at the start*/
2839         int *sort_map= sort_map_update + 1;
2840         char *name;
2841         int i;
2842
2843         name= name_array;
2844         for(def= ob->defbase.first, i=0; def; def=def->next, i++){
2845                 sort_map[i]= BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name));
2846                 name += MAX_VGROUP_NAME;
2847
2848                 BLI_assert(sort_map[i] != -1);
2849         }
2850
2851         if(ob->mode == OB_MODE_EDIT) {
2852                 if(ob->type==OB_MESH) {
2853                         EditMesh *em = BKE_mesh_get_editmesh(ob->data);
2854                         EditVert *eve;
2855
2856                         for(eve=em->verts.first; eve; eve=eve->next){
2857                                 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
2858                                 if(dvert && dvert->totweight){
2859                                         defvert_remap(dvert, sort_map, defbase_tot);
2860                                 }
2861                         }
2862                 }
2863                 else {
2864                         BKE_report(op->reports, RPT_ERROR, "Editmode lattice isnt supported yet");
2865                         MEM_freeN(sort_map_update);
2866                         return OPERATOR_CANCELLED;
2867                 }
2868         }
2869         else {
2870                 int dvert_tot=0;
2871
2872                 ED_vgroup_give_array(ob->data, &dvert, &dvert_tot);
2873
2874                 /*create as necassary*/
2875                 while(dvert && dvert_tot--) {
2876                         if(dvert->totweight)
2877                                 defvert_remap(dvert, sort_map, defbase_tot);
2878                         dvert++;
2879                 }
2880         }
2881
2882         /* update users */
2883         for(i=0; i<defbase_tot; i++)
2884                 sort_map[i]++;
2885
2886         sort_map_update[0]= 0;
2887         vgroup_remap_update_users(ob, sort_map_update);
2888
2889         ob->actdef= sort_map_update[ob->actdef];
2890         BLI_assert(ob->actdef >= 0);
2891         
2892         MEM_freeN(sort_map_update);
2893
2894         return OPERATOR_FINISHED;
2895 }
2896
2897 static int vgroup_sort(void *def_a_ptr, void *def_b_ptr)
2898 {
2899         bDeformGroup *def_a= (bDeformGroup *)def_a_ptr;
2900         bDeformGroup *def_b= (bDeformGroup *)def_b_ptr;
2901
2902         return BLI_natstrcmp(def_a->name, def_b->name);
2903 }
2904
2905 static int vertex_group_sort_exec(bContext *C, wmOperator *op)
2906 {
2907         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2908         char *name_array;
2909         int ret;
2910
2911         /*init remapping*/
2912         name_array = vgroup_init_remap(ob);
2913
2914         /*sort vgroup names*/
2915         BLI_sortlist(&ob->defbase, vgroup_sort);
2916
2917         /*remap vgroup data to map to correct names*/
2918         ret = vgroup_do_remap(ob, name_array, op);
2919
2920         if (ret != OPERATOR_CANCELLED) {
2921                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2922                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2923         }
2924
2925         if (name_array) MEM_freeN(name_array);
2926
2927         return ret;
2928 }
2929
2930 void OBJECT_OT_vertex_group_sort(wmOperatorType *ot)
2931 {
2932         ot->name= "Sort Vertex Groups";
2933         ot->idname= "OBJECT_OT_vertex_group_sort";
2934         ot->description= "Sorts vertex groups alphabetically";
2935
2936         /* api callbacks */
2937         ot->poll= vertex_group_poll;
2938         ot->exec= vertex_group_sort_exec;
2939
2940         /* flags */
2941         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2942 }
2943
2944 static int vgroup_move_exec(bContext *C, wmOperator *op)
2945 {
2946         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2947         bDeformGroup *def;
2948         char *name_array;
2949         int dir= RNA_enum_get(op->ptr, "direction"), ret;
2950
2951         def = BLI_findlink(&ob->defbase, ob->actdef - 1);
2952         if (!def) {
2953                 return OPERATOR_CANCELLED;
2954         }
2955
2956         name_array = vgroup_init_remap(ob);
2957
2958         if (dir == 1) { /*up*/
2959                 void *prev = def->prev;
2960
2961                 BLI_remlink(&ob->defbase, def);
2962                 BLI_insertlinkbefore(&ob->defbase, prev, def);
2963         } else { /*down*/
2964                 void *next = def->next;
2965
2966                 BLI_remlink(&ob->defbase, def);
2967                 BLI_insertlinkafter(&ob->defbase, next, def);
2968         }
2969
2970         ret = vgroup_do_remap(ob, name_array, op);
2971
2972         if (name_array) MEM_freeN(name_array);
2973
2974         if (ret != OPERATOR_CANCELLED) {
2975                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2976                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2977         }
2978
2979         return ret;
2980 }
2981
2982 void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
2983 {
2984         static EnumPropertyItem vgroup_slot_move[] = {
2985                 {1, "UP", 0, "Up", ""},
2986                 {-1, "DOWN", 0, "Down", ""},
2987                 {0, NULL, 0, NULL, NULL}
2988         };
2989
2990         /* identifiers */
2991         ot->name= "Move Vertex Group";
2992         ot->idname= "OBJECT_OT_vertex_group_move";
2993
2994         /* api callbacks */
2995         ot->poll= vertex_group_poll;
2996         ot->exec= vgroup_move_exec;
2997
2998         /* flags */
2999         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3000
3001         RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
3002 }