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