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