Commented and tagged some unused vars (gcc warnings...). Also fixed some uninitialize...
[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         char containsA = FALSE;
761         char containsB = FALSE;
762         int added = 0;
763         int i;
764         for(i = 0; i < length && (!containsA || !containsB); i++) {
765                 if(verts[i] == a) {
766                         containsA = TRUE;
767                 } else if(verts[i] == b) {
768                         containsB = TRUE;
769                 } else if(verts[i] == -1) {
770                         if(!containsA) {
771                                 verts[i] = a;
772                                 containsA = TRUE;
773                                 added++;
774                         } else if(!containsB){
775                                 verts[i] = b;
776                                 containsB = TRUE;
777                                 added++;
778                         }
779                 }
780         }
781         return added;
782 }
783
784 /* This finds all of the vertices connected to vert by an edge
785 and returns an array of indices of size count
786
787 count is an int passed by reference so it can be assigned the value of the length here.
788 */
789 static int* getSurroundingVerts(Mesh *me, int vert, int *count) {
790         int length = 0;
791         int *tverts;
792         int *verts = NULL;
793         MFace *mf = me->mface;
794         int totface = me->totface;
795         int found = 0;
796         int i;
797         for(i = 0; i < totface; i++, mf++) {
798                 if(vert == mf->v1 || vert == mf->v2 || vert == mf->v3 || (mf->v4 &&vert == mf->v4)) {
799                         length+=2;
800                 }
801         }
802         if(!length) {
803                 return 0;
804         }
805         tverts = MEM_mallocN(sizeof(int)*length, "tempSurroundingVerts");
806         mf = me->mface;
807         for(i = 0; i < length; i++) {
808                 tverts[i] = -1;
809         }
810         for(i = 0; i < totface; i++, mf++) {
811                 int a=-1, b=-1;
812                 if(mf->v1 == vert) {
813                         a = mf->v2;
814                         if(mf->v4) {
815                                 b = mf->v4;
816                         } else {
817                                 b = mf->v3;
818                         }
819                 } else if(mf->v2 == vert) {
820                         a = mf->v1;
821                         b = mf->v3;
822                 } else if(mf->v3 == vert) {
823                         a = mf->v2;
824                         if(mf->v4) {
825                                 b = mf->v4;
826                         } else {
827                                 b = mf->v1;
828                         }
829                 } else if (mf->v4 && mf->v4 == vert){
830                         a = mf->v1;
831                         b = mf->v3;
832                 } else {
833                         continue;
834                 }
835                 found += tryToAddVerts(tverts, length, a, b);
836         }
837         if(found) {
838                 verts = MEM_mallocN(sizeof(int)* found, "surroundingVerts");
839                 for(i = 0; i < found; i++) {
840                         verts[i] = tverts[i];
841                 }
842                 *count = found;
843         }
844         MEM_freeN(tverts);
845         return verts;
846 }
847
848 /* get a single point in space by averaging a point cloud (vectors of size 3)
849 coord is the place the average is stored, points is the point cloud, count is the number of points in the cloud
850 */
851 static void getSingleCoordinate(MVert *points, int count, float coord[3]) {
852         int i;
853         zero_v3(coord);
854         for(i = 0; i < count; i++) {
855                 add_v3_v3(coord, points[i].co);
856         }
857         mul_v3_fl(coord, 1.0f/count);
858 }
859
860 /* find the closest point on a plane to another point and store it in dst */
861 /* coord is a point on the plane */
862 /* point is the point that you want the nearest of */
863 /* norm is the plane's normal, and d is the last number in the plane equation 0 = ax + by + cz + d */
864 static void getNearestPointOnPlane(const float norm[3], const float coord[3], const float point[3], float dst_r[3])
865 {
866         float temp[3];
867         float dotprod;
868
869         sub_v3_v3v3(temp, point, coord);
870         dotprod= dot_v3v3(temp, norm);
871
872         dst_r[0] = point[0] - (norm[0] * dotprod);
873         dst_r[1] = point[1] - (norm[1] * dotprod);
874         dst_r[2] = point[2] - (norm[2] * dotprod);
875 }
876
877 /* distance of two vectors a and b of size length */
878 static float distance(float* a, float *b, int length) {
879         int i;
880         float sum = 0;
881         for(i = 0; i < length; i++) {
882                 sum += (b[i]-a[i])*(b[i]-a[i]);
883         }
884         return sqrt(sum);
885 }
886
887 /* given a plane and a start and end position,
888 compute the amount of vertical distance relative to the plane and store it in dists,
889 then get the horizontal and vertical change and store them in changes
890 */
891 static void getVerticalAndHorizontalChange(float *norm, float d, float *coord, float *start, float distToStart, float *end, float (*changes)[2], float *dists, int index) {
892         // A=Q-((Q-P).N)N
893         // D = (a*x0 + b*y0 +c*z0 +d)
894         float projA[3] = {0}, projB[3] = {0};
895
896         getNearestPointOnPlane(norm, coord, start, projA);
897         getNearestPointOnPlane(norm, coord, end, projB);
898         // (vertical and horizontal refer to the plane's y and xz respectively)
899         // vertical distance
900         dists[index] = norm[0]*end[0] + norm[1]*end[1] + norm[2]*end[2] + d;
901         // vertical change
902         changes[index][0] = dists[index] - distToStart;
903         //printf("vc %f %f\n", distance(end, projB, 3)-distance(start, projA, 3), changes[index][0]);
904         // horizontal change
905         changes[index][1] = distance(projA, projB, 3);
906 }
907
908 // I need the derived mesh to be forgotten so the positions are recalculated with weight changes (see dm_deform_recalc)
909 static void dm_deform_clear(DerivedMesh *dm, Object *ob) {
910         if(ob->derivedDeform && (ob->derivedDeform)==dm) {
911                 ob->derivedDeform->needsFree = 1;
912                 ob->derivedDeform->release(ob->derivedDeform);
913                 ob->derivedDeform = NULL;
914         }
915         else if(dm) {
916                 dm->needsFree = 1;
917                 dm->release(dm);
918         }
919 }
920
921 // recalculate the deformation
922 static DerivedMesh* dm_deform_recalc(Scene *scene, Object *ob) {
923         return mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
924 }
925
926 /* by changing nonzero weights, try to move a vertex in me->mverts with index 'index' to distToBe distance away from the provided plane
927 strength can change distToBe so that it moves towards distToBe by that percentage
928 cp changes how much the weights are adjusted to check the distance
929
930 index is the index of the vertex being moved
931 norm and d are the plane's properties for the equation: ax + by + cz + d = 0
932 coord is a point on the plane
933 */
934 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) {
935         DerivedMesh *dm;
936         MDeformWeight *dw;
937         MVert m;
938         MDeformVert *dvert = me->dvert+index;
939         int totweight = dvert->totweight;
940         float oldw = 0;
941         float oldPos[3] = {0};
942         float vc, hc, dist = 0.0f /* Not necessary, but quites down gcc warnings! */;
943         int i, k;
944         float (*changes)[2] = MEM_mallocN(sizeof(float *)*totweight*2, "vertHorzChange");
945         float *dists = MEM_mallocN(sizeof(float)*totweight, "distance");
946         int *upDown = MEM_callocN(sizeof(int)*totweight, "upDownTracker");// track if up or down moved it closer for each bone
947         int *dwIndices = MEM_callocN(sizeof(int)*totweight, "dwIndexTracker");
948         float distToStart;
949         int bestIndex = 0;
950         char wasChange;
951         char wasUp;
952         int lastIndex = -1;
953         float originalDistToBe = distToBe;
954         do {
955                 wasChange = FALSE;
956                 dm = dm_deform_recalc(scene, ob);
957                 dm->getVert(dm, index, &m);
958                 copy_v3_v3(oldPos, m.co);
959                 distToStart = dot_v3v3(norm, oldPos) + d;
960
961                 if(distToBe == originalDistToBe) {
962                         distToBe += distToStart - distToStart*strength;
963                 }
964                 for(i = 0; i < totweight; i++) {
965                         dwIndices[i] = i;
966                         dw = (dvert->dw+i);
967                         vc = hc = 0;
968                         if(!dw->weight) {
969                                 changes[i][0] = 0;
970                                 changes[i][1] = 0;
971                                 dists[i] = distToStart;
972                                 continue;
973                         }
974                         for(k = 0; k < 2; k++) {
975                                 if(dm) {
976                                         dm_deform_clear(dm, ob); dm = NULL;
977                                 }
978                                 oldw = dw->weight;
979                                 if(k) {
980                                         dw->weight *= 1+cp;
981                                 } else {
982                                         dw->weight /= 1+cp;
983                                 }
984                                 if(dw->weight == oldw) {
985                                         changes[i][0] = 0;
986                                         changes[i][1] = 0;
987                                         dists[i] = distToStart;
988                                         break;
989                                 }
990                                 if(dw->weight > 1) {
991                                         dw->weight = 1;
992                                 }
993                                 dm = dm_deform_recalc(scene, ob);
994                                 dm->getVert(dm, index, &m);
995                                 getVerticalAndHorizontalChange(norm, d, coord, oldPos, distToStart, m.co, changes, dists, i);
996                                 dw->weight = oldw;
997                                 if(!k) {
998                                         vc = changes[i][0];
999                                         hc = changes[i][1];
1000                                         dist = dists[i];
1001                                 } else {
1002                                         if(fabs(dist - distToBe) < fabs(dists[i] - distToBe)) {
1003                                                 upDown[i] = 0;
1004                                                 changes[i][0] = vc;
1005                                                 changes[i][1] = hc;
1006                                                 dists[i] = dist;
1007                                         } else {
1008                                                 upDown[i] = 1;
1009                                         }
1010                                         if(fabs(dists[i] - distToBe) > fabs(distToStart - distToBe)) {
1011                                                 changes[i][0] = 0;
1012                                                 changes[i][1] = 0;
1013                                                 dists[i] = distToStart;
1014                                         }
1015                                 }
1016                         }
1017                 }
1018                 // sort the changes by the vertical change
1019                 for(k = 0; k < totweight; k++) {
1020                         float tf;
1021                         int ti;
1022                         bestIndex = k;
1023                         for(i = k+1; i < totweight; i++) {
1024                                 dist = dists[i];
1025
1026                                 if(fabs(dist) > fabs(dists[i])) {
1027                                         bestIndex = i;
1028                                 }
1029                         }
1030                         // switch with k
1031                         if(bestIndex != k) {
1032                                 ti = upDown[k];
1033                                 upDown[k] = upDown[bestIndex];
1034                                 upDown[bestIndex] = ti;
1035
1036                                 ti = dwIndices[k];
1037                                 dwIndices[k] = dwIndices[bestIndex];
1038                                 dwIndices[bestIndex] = ti;
1039
1040                                 tf = changes[k][0];
1041                                 changes[k][0] = changes[bestIndex][0];
1042                                 changes[bestIndex][0] = tf;
1043
1044                                 tf = changes[k][1];
1045                                 changes[k][1] = changes[bestIndex][1];
1046                                 changes[bestIndex][1] = tf;
1047
1048                                 tf = dists[k];
1049                                 dists[k] = dists[bestIndex];
1050                                 dists[bestIndex] = tf;
1051                         }
1052                 }
1053                 bestIndex = -1;
1054                 // find the best change with an acceptable horizontal change
1055                 for(i = 0; i < totweight; i++) {
1056                         if(fabs(changes[i][0]) > fabs(changes[i][1]*2.0f)) {
1057                                 bestIndex = i;
1058                                 break;
1059                         }
1060                 }
1061                 if(bestIndex != -1) {
1062                         wasChange = TRUE;
1063                         // it is a good place to stop if it tries to move the opposite direction
1064                         // (relative to the plane) of last time
1065                         if(lastIndex != -1) {
1066                                 if(wasUp != upDown[bestIndex]) {
1067                                         wasChange = FALSE;
1068                                 }
1069                         }
1070                         lastIndex = bestIndex;
1071                         wasUp = upDown[bestIndex];
1072                         dw = (dvert->dw+dwIndices[bestIndex]);
1073                         oldw = dw->weight;
1074                         if(upDown[bestIndex]) {
1075                                 dw->weight *= 1+cp;
1076                         } else {
1077                                 dw->weight /= 1+cp;
1078                         }
1079                         if(dw->weight > 1) {
1080                                 dw->weight = 1;
1081                         }
1082                         if(oldw == dw->weight) {
1083                                 wasChange = FALSE;
1084                         }
1085                         if(dm) {
1086                                 dm_deform_clear(dm, ob); dm = NULL;
1087                         }
1088                 }
1089         }while(wasChange && (distToStart-distToBe)/fabs(distToStart-distToBe) == (dists[bestIndex]-distToBe)/fabs(dists[bestIndex]-distToBe));
1090         MEM_freeN(upDown);
1091         MEM_freeN(changes);
1092         MEM_freeN(dists);
1093         MEM_freeN(dwIndices);
1094 }
1095
1096 /* this is used to try to smooth a surface by only adjusting the nonzero weights of a vertex 
1097 but it could be used to raise or lower an existing 'bump.' */
1098 static void vgroup_fix(Scene *scene, Object *ob, float distToBe, float strength, float cp)
1099 {
1100         int i;
1101
1102         Mesh *me = ob->data;
1103         MVert *mvert = me->mvert;
1104         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1105         int *verts = NULL;
1106         for(i = 0; i < me->totvert && mvert; i++, mvert++) {
1107                 
1108                 if(use_vert_sel && (mvert->flag & SELECT)) {
1109                         
1110                         int count=0;
1111                         if((verts = getSurroundingVerts(me, i, &count))) {
1112                                 MVert m;
1113                                 MVert *p = MEM_callocN(sizeof(MVert)*(count), "deformedPoints");
1114                                 int k;
1115
1116                                 DerivedMesh *dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
1117                                 for(k = 0; k < count; k++) {
1118                                         dm->getVert(dm, verts[k], &m);
1119                                         p[k] = m;
1120                                 }
1121                                 
1122                                 if(count >= 3) {
1123                                         float d /*, dist */ /* UNUSED */, mag;
1124                                         float coord[3];
1125                                         float norm[3];
1126                                         getSingleCoordinate(p, count, coord);
1127                                         dm->getVert(dm, i, &m);
1128                                         sub_v3_v3v3(norm, m.co, coord);
1129                                         mag= normalize_v3(norm);
1130                                         if(mag) { /* zeros fix */
1131                                                 d = -dot_v3v3(norm, coord);
1132                                                 /* dist = (norm[0]*m.co[0] + norm[1]*m.co[1] + norm[2]*m.co[2] + d); */ /* UNUSED */
1133                                                 moveCloserToDistanceFromPlane(scene, ob, me, i, norm, coord, d, distToBe, strength, cp);
1134                                         }
1135                                 }
1136
1137                                 MEM_freeN(verts);
1138                                 MEM_freeN(p);
1139                         }
1140                 }
1141         }
1142 }
1143
1144 static void vgroup_levels(Object *ob, float offset, float gain)
1145 {
1146         bDeformGroup *dg;
1147         MDeformWeight *dw;
1148         MDeformVert *dvert, **dvert_array=NULL;
1149         int i, def_nr, dvert_tot=0;
1150         
1151         Mesh *me = ob->data;
1152         MVert *mvert = me->mvert;
1153         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1154
1155         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1156         
1157         dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
1158         
1159         if(dg) {
1160                 def_nr= ob->actdef-1;
1161                 
1162                 for(i = 0; i < dvert_tot; i++) {
1163                         
1164                         if(use_vert_sel && !(mvert[i].flag & SELECT)) {
1165                                 continue;
1166                         }
1167
1168                         dvert = dvert_array[i];
1169                         dw = defvert_find_index(dvert, def_nr);
1170                         if(dw) {
1171                                 dw->weight = gain * (dw->weight + offset);
1172                                 
1173                                 CLAMP(dw->weight, 0.0f, 1.0f);
1174                         }
1175                 }
1176         }
1177
1178         if (dvert_array) MEM_freeN(dvert_array);
1179 }
1180
1181 /* TODO - select between groups */
1182 static void vgroup_normalize_all(Object *ob, int lock_active)
1183 {
1184         MDeformWeight *dw, *dw_act;
1185         MDeformVert *dvert, **dvert_array=NULL;
1186         int i, dvert_tot=0;
1187         float tot_weight;
1188
1189         
1190         Mesh *me = ob->data;
1191         MVert *mvert = me->mvert;
1192         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1193
1194         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1195
1196         if(dvert_array) {
1197                 if(lock_active) {
1198                         int def_nr= ob->actdef-1;
1199
1200                         for(i = 0; i < dvert_tot; i++) {
1201                                 float lock_iweight= 1.0f;
1202                                 int j;
1203                                 
1204                                 if(use_vert_sel && !(mvert[i].flag & SELECT)) {
1205                                         continue;
1206                                 }
1207
1208                                 tot_weight= 0.0f;
1209                                 dw_act= NULL;
1210                                 dvert = dvert_array[i];
1211
1212                                 j= dvert->totweight;
1213                                 while(j--) {
1214                                         dw= dvert->dw + j;
1215
1216                                         if(dw->def_nr==def_nr) {
1217                                                 dw_act= dw;
1218                                                 lock_iweight = (1.0f - dw_act->weight);
1219                                         }
1220                                         else {
1221                                                 tot_weight += dw->weight;
1222                                         }
1223                                 }
1224
1225                                 if(tot_weight) {
1226                                         j= dvert->totweight;
1227                                         while(j--) {
1228                                                 dw= dvert->dw + j;
1229                                                 if(dw == dw_act) {
1230                                                         if (dvert->totweight==1) {
1231                                                                 dw_act->weight= 1.0f; /* no other weights, set to 1.0 */
1232                                                         }
1233                                                 } else {
1234                                                         if(dw->weight > 0.0f)
1235                                                                 dw->weight = (dw->weight / tot_weight) * lock_iweight;
1236                                                 }
1237
1238                                                 /* incase of division errors with very low weights */
1239                                                 CLAMP(dw->weight, 0.0f, 1.0f);
1240                                         }
1241                                 }
1242                         }
1243                 }
1244                 else {
1245                         for(i = 0; i < dvert_tot; i++) {
1246                                 int j;
1247                                 
1248                                 if(use_vert_sel && !(mvert[i].flag & SELECT)) {
1249                                         continue;
1250                                 }
1251
1252                                 tot_weight= 0.0f;
1253                                 dvert = dvert_array[i];
1254
1255                                 j= dvert->totweight;
1256                                 while(j--) {
1257                                         dw= dvert->dw + j;
1258                                         tot_weight += dw->weight;
1259                                 }
1260
1261                                 if(tot_weight) {
1262                                         j= dvert->totweight;
1263                                         while(j--) {
1264                                                 dw= dvert->dw + j;
1265                                                 dw->weight /= tot_weight;
1266
1267                                                 /* incase of division errors with very low weights */
1268                                                 CLAMP(dw->weight, 0.0f, 1.0f);
1269                                         }
1270                                 }
1271                         }
1272                 }
1273         }
1274
1275         if (dvert_array) MEM_freeN(dvert_array);
1276 }
1277
1278
1279 static void vgroup_lock_all(Object *ob, int action)
1280 {
1281         bDeformGroup *dg;
1282
1283         if(action == SEL_TOGGLE) {
1284                 action= SEL_SELECT;
1285                 for(dg= ob->defbase.first; dg; dg= dg->next) {
1286                         if(dg->flag & DG_LOCK_WEIGHT) {
1287                                 action= SEL_DESELECT;
1288                                 break;
1289                         }
1290                 }
1291         }
1292
1293         for(dg= ob->defbase.first; dg; dg= dg->next) {
1294                 switch(action) {
1295                         case SEL_SELECT:
1296                                 dg->flag |= DG_LOCK_WEIGHT;
1297                                 break;
1298                         case SEL_DESELECT:
1299                                 dg->flag &= ~DG_LOCK_WEIGHT;
1300                                 break;
1301                         case SEL_INVERT:
1302                                 dg->flag ^= DG_LOCK_WEIGHT;
1303                                 break;
1304                 }
1305         }
1306 }
1307
1308 static void vgroup_invert(Object *ob, int auto_assign, int auto_remove)
1309 {
1310         bDeformGroup *dg;
1311         MDeformWeight *dw;
1312         MDeformVert *dvert, **dvert_array=NULL;
1313         int i, def_nr, dvert_tot=0;
1314         
1315         Mesh *me = ob->data;
1316         MVert *mvert = me->mvert;
1317         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1318
1319         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1320
1321         dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
1322
1323         if(dg) {
1324                 def_nr= ob->actdef-1;
1325
1326
1327                 for(i = 0; i < dvert_tot; i++) {
1328                         
1329                         if(use_vert_sel && !(mvert[i].flag & SELECT)) {
1330                                 continue;
1331                         }
1332                         dvert = dvert_array[i];
1333
1334                         if(auto_assign) {
1335                                 dw= defvert_verify_index(dvert, def_nr);
1336                         } else {
1337                                 dw= defvert_find_index(dvert, def_nr);
1338                         }
1339
1340                         if(dw) {
1341                                 dw->weight = 1.0f-dw->weight;
1342
1343                                 if(auto_remove && dw->weight <= 0.0f) {
1344                                         /* could have a faster function for this */
1345                                         ED_vgroup_nr_vert_remove(ob, def_nr, i);
1346                                 }
1347                         }
1348                 }
1349         }
1350
1351         if (dvert_array) MEM_freeN(dvert_array);
1352 }
1353
1354 static void vgroup_blend(Object *ob)
1355 {
1356         bDeformGroup *dg;
1357         MDeformWeight *dw;
1358         MDeformVert *dvert_array=NULL, *dvert;
1359         int i, def_nr, dvert_tot=0;
1360
1361         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)ob->data));
1362         // ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
1363
1364         if(em==NULL)
1365                 return;
1366
1367         dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
1368
1369         if(dg) {
1370                 int sel1, sel2;
1371                 int i1, i2;
1372
1373                 EditEdge *eed;
1374                 EditVert *eve;
1375                 float *vg_weights;
1376                 float *vg_users;
1377
1378                 def_nr= ob->actdef-1;
1379
1380                 i= 0;
1381                 for(eve= em->verts.first; eve; eve= eve->next)
1382                         eve->tmp.l= i++;
1383
1384                 dvert_tot= i;
1385
1386                 vg_weights= MEM_callocN(sizeof(float)*dvert_tot, "vgroup_blend_f");
1387                 vg_users= MEM_callocN(sizeof(int)*dvert_tot, "vgroup_blend_i");
1388
1389                 for(eed= em->edges.first; eed; eed= eed->next) {
1390                         sel1= eed->v1->f & SELECT;
1391                         sel2= eed->v2->f & SELECT;
1392
1393                         if(sel1 != sel2) {
1394                                 /* i1 is always the selected one */
1395                                 if(sel1==TRUE && sel2==FALSE) {
1396                                         i1= eed->v1->tmp.l;
1397                                         i2= eed->v2->tmp.l;
1398                                         eve= eed->v2;
1399                                 }
1400                                 else {
1401                                         i2= eed->v1->tmp.l;
1402                                         i1= eed->v2->tmp.l;
1403                                         eve= eed->v1;
1404                                 }
1405
1406                                 vg_users[i1]++;
1407
1408                                 /* TODO, we may want object mode blending */
1409                                 if(em)  dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1410                                 else    dvert= dvert_array+i2;
1411
1412                                 dw= defvert_find_index(dvert, def_nr);
1413
1414                                 if(dw) {
1415                                         vg_weights[i1] += dw->weight;
1416                                 }
1417                         }
1418                 }
1419
1420                 i= 0;
1421                 for(eve= em->verts.first; eve; eve= eve->next) {
1422                         if(eve->f & SELECT && vg_users[i] > 0) {
1423                                 /* TODO, we may want object mode blending */
1424                                 if(em)  dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1425                                 else    dvert= dvert_array+i;
1426
1427                                 dw= defvert_verify_index(dvert, def_nr);
1428                                 dw->weight= vg_weights[i] / (float)vg_users[i];
1429                         }
1430
1431                         i++;
1432                 }
1433                 MEM_freeN(vg_weights);
1434                 MEM_freeN(vg_users);
1435         }
1436 }
1437
1438 static void vgroup_clean(Object *ob, float eul, int keep_single)
1439 {
1440         bDeformGroup *dg;
1441         MDeformWeight *dw;
1442         MDeformVert *dvert, **dvert_array=NULL;
1443         int i, def_nr, dvert_tot=0;
1444         
1445         Mesh *me = ob->data;
1446         MVert *mvert = me->mvert;
1447         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1448
1449         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1450
1451         /* only the active group */
1452         dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
1453         if(dg) {
1454                 def_nr= ob->actdef-1;
1455
1456                 for(i = 0; i < dvert_tot; i++) {
1457                         
1458                         if(use_vert_sel && !(mvert[i].flag & SELECT)) {
1459                                 continue;
1460                         }
1461                         dvert = dvert_array[i];
1462
1463                         dw= defvert_find_index(dvert, def_nr);
1464
1465                         if(dw) {
1466                                 if(dw->weight <= eul)
1467                                         if(keep_single==FALSE || dvert->totweight > 1)
1468                                                 ED_vgroup_nr_vert_remove(ob, def_nr, i);
1469                         }
1470                 }
1471         }
1472
1473         if (dvert_array) MEM_freeN(dvert_array);
1474 }
1475
1476 static void vgroup_clean_all(Object *ob, float eul, int keep_single)
1477 {
1478
1479         MDeformWeight *dw;
1480         MDeformVert *dvert, **dvert_array=NULL;
1481         int i, dvert_tot=0;
1482         
1483         Mesh *me = ob->data;
1484         MVert *mvert = me->mvert;
1485         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1486
1487         ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1488
1489         if(dvert_array) {
1490                 for(i = 0; i < dvert_tot; i++) {
1491                         int j;
1492                         
1493                         if(use_vert_sel && !(mvert[i].flag & SELECT)) {
1494                                 continue;
1495                         }
1496
1497                         dvert = dvert_array[i];
1498                         j= dvert->totweight;
1499
1500                         while(j--) {
1501
1502                                 if(keep_single && dvert->totweight == 1)
1503                                         break;
1504
1505                                 dw= dvert->dw + j;
1506
1507                                 if(dw->weight <= eul)
1508                                         ED_vgroup_nr_vert_remove(ob, dw->def_nr, i);
1509
1510                         }
1511                 }
1512         }
1513
1514         if (dvert_array) MEM_freeN(dvert_array);
1515 }
1516
1517
1518 static void dvert_mirror_op(MDeformVert *dvert, MDeformVert *dvert_mirr,
1519                             const char sel, const char sel_mirr,
1520                             const int *flip_map,
1521                             const short mirror_weights, const short flip_vgroups)
1522 {
1523         BLI_assert(sel || sel_mirr);
1524
1525         if(sel_mirr && sel) {
1526                 /* swap */
1527                 if(mirror_weights)
1528                         SWAP(MDeformVert, *dvert, *dvert_mirr);
1529                 if(flip_vgroups) {
1530                         defvert_flip(dvert, flip_map);
1531                         defvert_flip(dvert_mirr, flip_map);
1532                 }
1533         }
1534         else {
1535                 /* dvert should always be the target */
1536                 if(sel_mirr) {
1537                         SWAP(MDeformVert *, dvert, dvert_mirr);
1538                 }
1539
1540                 if(mirror_weights)
1541                         defvert_copy(dvert, dvert_mirr);
1542                 if(flip_vgroups) {
1543                         defvert_flip(dvert, flip_map);
1544                 }
1545         }
1546 }
1547
1548 void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_vgroups)
1549 {
1550 #define VGROUP_MIRR_OP dvert_mirror_op(dvert, dvert_mirr, sel, sel_mirr, flip_map, mirror_weights, flip_vgroups)
1551
1552         EditVert *eve, *eve_mirr;
1553         MDeformVert *dvert, *dvert_mirr;
1554         short sel, sel_mirr;
1555         int     *flip_map;
1556
1557         if(mirror_weights==0 && flip_vgroups==0)
1558                 return;
1559
1560         flip_map= defgroup_flip_map(ob, 0);
1561
1562         /* only the active group */
1563         if(ob->type == OB_MESH) {
1564                 Mesh *me= ob->data;
1565                 EditMesh *em = BKE_mesh_get_editmesh(me);
1566
1567
1568                 if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
1569                         MEM_freeN(flip_map);
1570                         return;
1571                 }
1572
1573                 EM_cache_x_mirror_vert(ob, em);
1574
1575                 /* Go through the list of editverts and assign them */
1576                 for(eve=em->verts.first; eve; eve=eve->next){
1577                         if((eve_mirr=eve->tmp.v)) {
1578                                 sel= eve->f & SELECT;
1579                                 sel_mirr= eve_mirr->f & SELECT;
1580
1581                                 if((sel || sel_mirr) && (eve != eve_mirr)) {
1582                                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1583                                         dvert_mirr= CustomData_em_get(&em->vdata, eve_mirr->data, CD_MDEFORMVERT);
1584                                         if(dvert && dvert_mirr) {
1585                                                 VGROUP_MIRR_OP;
1586                                         }
1587                                 }
1588
1589                                 eve->tmp.v= eve_mirr->tmp.v= NULL;
1590                         }
1591                 }
1592
1593                 BKE_mesh_end_editmesh(me, em);
1594         }
1595         else if (ob->type == OB_LATTICE) {
1596                 Lattice *lt= ob->data;
1597                 int i1, i2;
1598                 int u, v, w;
1599                 int pntsu_half;
1600                 /* half but found up odd value */
1601
1602                 if(lt->editlatt) lt= lt->editlatt->latt;
1603
1604                 if(lt->pntsu == 1 || lt->dvert == NULL) {
1605                         MEM_freeN(flip_map);
1606                         return;
1607                 }
1608
1609                 /* unlike editmesh we know that by only looping over the first hald of
1610                  * the 'u' indicies it will cover all points except the middle which is
1611                  * ok in this case */
1612                 pntsu_half= lt->pntsu / 2;
1613
1614                 for(w=0; w<lt->pntsw; w++) {
1615                         for(v=0; v<lt->pntsv; v++) {
1616                                 for(u=0; u<pntsu_half; u++) {
1617                                         int u_inv= (lt->pntsu - 1) - u;
1618                                         if(u != u_inv) {
1619                                                 BPoint *bp, *bp_mirr;
1620
1621                                                 i1= LT_INDEX(lt, u, v, w);
1622                                                 i2= LT_INDEX(lt, u_inv, v, w);
1623
1624                                                 bp= &lt->def[i1];
1625                                                 bp_mirr= &lt->def[i2];
1626
1627                                                 sel= bp->f1 & SELECT;
1628                                                 sel_mirr= bp_mirr->f1 & SELECT;
1629
1630                                                 if(sel || sel_mirr) {
1631                                                         dvert= &lt->dvert[i1];
1632                                                         dvert_mirr= &lt->dvert[i2];
1633
1634                                                         VGROUP_MIRR_OP;
1635                                                 }
1636                                         }
1637                                 }
1638                         }
1639                 }
1640         }
1641
1642         MEM_freeN(flip_map);
1643
1644 #undef VGROUP_MIRR_OP
1645 }
1646
1647 static void vgroup_remap_update_users(Object *ob, int *map)
1648 {
1649         ExplodeModifierData *emd;
1650         ModifierData *md;
1651         ParticleSystem *psys;
1652         ClothModifierData *clmd;
1653         ClothSimSettings *clsim;
1654         int a;
1655
1656         /* these cases don't use names to refer to vertex groups, so when
1657          * they get deleted the numbers get out of sync, this corrects that */
1658
1659         if(ob->soft)
1660                 ob->soft->vertgroup= map[ob->soft->vertgroup];
1661
1662         for(md=ob->modifiers.first; md; md=md->next) {
1663                 if(md->type == eModifierType_Explode) {
1664                         emd= (ExplodeModifierData*)md;
1665                         emd->vgroup= map[emd->vgroup];
1666                 }
1667                 else if(md->type == eModifierType_Cloth) {
1668                         clmd= (ClothModifierData*)md;
1669                         clsim= clmd->sim_parms;
1670
1671                         if(clsim) {
1672                                 clsim->vgroup_mass= map[clsim->vgroup_mass];
1673                                 clsim->vgroup_bend= map[clsim->vgroup_bend];
1674                                 clsim->vgroup_struct= map[clsim->vgroup_struct];
1675                         }
1676                 }
1677         }
1678
1679         for(psys=ob->particlesystem.first; psys; psys=psys->next) {
1680                 for(a=0; a<PSYS_TOT_VG; a++)
1681                         psys->vgroup[a]= map[psys->vgroup[a]];
1682         }
1683 }
1684
1685
1686 static void vgroup_delete_update_users(Object *ob, int id)
1687 {
1688         int i, tot= BLI_countlist(&ob->defbase) + 1;
1689         int *map= MEM_mallocN(sizeof(int) * tot, "vgroup del");
1690
1691         map[id]= map[0]= 0;
1692         for(i=1; i<id; i++) map[i]=i;
1693         for(i=id+1; i<tot; i++) map[i]=i-1;
1694
1695         vgroup_remap_update_users(ob, map);
1696         MEM_freeN(map);
1697 }
1698
1699
1700 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg)
1701 {
1702         MDeformVert *dvert_array=NULL;
1703         int i, e, dvert_tot=0;
1704         const int dg_index= BLI_findindex(&ob->defbase, dg);
1705
1706         assert(dg_index > -1);
1707         
1708         ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
1709
1710         if(dvert_array) {
1711                 MDeformVert *dvert;
1712                 for(i= 0, dvert= dvert_array; i < dvert_tot; i++, dvert++) {
1713                         ED_vgroup_vert_remove(ob, dg, i); /* ok if the dg isnt in this dvert, will continue silently */
1714                 }
1715
1716                 for(i= 0, dvert= dvert_array; i < dvert_tot; i++, dvert++) {
1717                         for(e = 0; e < dvert->totweight; e++) {
1718                                 if(dvert->dw[e].def_nr > dg_index) {
1719                                         dvert->dw[e].def_nr--;
1720                                 }
1721                         }
1722                 }
1723         }
1724
1725         vgroup_delete_update_users(ob, dg_index + 1);
1726
1727         /* Remove the group */
1728         BLI_freelinkN(&ob->defbase, dg);
1729
1730         /* Update the active deform index if necessary */
1731         if(ob->actdef > dg_index)
1732                 ob->actdef--;
1733         if(ob->actdef < 1 && ob->defbase.first)
1734                 ob->actdef= 1;
1735
1736 }
1737
1738 /* only in editmode */
1739 /* removes from active defgroup, if allverts==0 only selected vertices */
1740 static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGroup *dg)
1741 {
1742         EditVert *eve;
1743         MDeformVert *dvert;
1744         MDeformWeight *newdw;
1745         bDeformGroup *eg;
1746         int     i;
1747
1748         if(ob->type == OB_MESH) {
1749                 Mesh *me= ob->data;
1750                 EditMesh *em = BKE_mesh_get_editmesh(me);
1751
1752                 for(eve=em->verts.first; eve; eve=eve->next){
1753                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1754                 
1755                         if(dvert && dvert->dw && ((eve->f & SELECT) || allverts)){
1756                                 for(i=0; i<dvert->totweight; i++){
1757                                         /* Find group */
1758                                         eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr);
1759                                         if(eg == dg){
1760                                                 dvert->totweight--;
1761                                                 if(dvert->totweight){
1762                                                         newdw = MEM_mallocN(sizeof(MDeformWeight)*(dvert->totweight), "deformWeight");
1763                                                         
1764                                                         if(dvert->dw){
1765                                                                 memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*i);
1766                                                                 memcpy(newdw+i, dvert->dw+i+1, sizeof(MDeformWeight)*(dvert->totweight-i));
1767                                                                 MEM_freeN(dvert->dw);
1768                                                         }
1769                                                         dvert->dw=newdw;
1770                                                 }
1771                                                 else{
1772                                                         MEM_freeN(dvert->dw);
1773                                                         dvert->dw=NULL;
1774                                                         break;
1775                                                 }
1776                                         }
1777                                 }
1778                         }
1779                 }
1780                 BKE_mesh_end_editmesh(me, em);
1781         }
1782         else if(ob->type == OB_LATTICE) {
1783                 Lattice *lt= vgroup_edit_lattice(ob);
1784                 
1785                 if(lt->dvert) {
1786                         BPoint *bp;
1787                         int a, tot= lt->pntsu*lt->pntsv*lt->pntsw;
1788                                 
1789                         for(a=0, bp= lt->def; a<tot; a++, bp++) {
1790                                 if(allverts || (bp->f1 & SELECT))
1791                                         ED_vgroup_vert_remove(ob, dg, a);
1792                         }
1793                 }
1794         }
1795 }
1796
1797 static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg)
1798 {
1799         int i;
1800         const int dg_index= BLI_findindex(&ob->defbase, dg);
1801
1802         assert(dg_index > -1);
1803
1804         /* Make sure that no verts are using this group */
1805         vgroup_active_remove_verts(ob, TRUE, dg);
1806
1807         /* Make sure that any verts with higher indices are adjusted accordingly */
1808         if(ob->type==OB_MESH) {
1809                 Mesh *me= ob->data;
1810                 EditMesh *em = BKE_mesh_get_editmesh(me);
1811                 EditVert *eve;
1812                 MDeformVert *dvert;
1813                 
1814                 for(eve=em->verts.first; eve; eve=eve->next){
1815                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1816
1817                         if(dvert)
1818                                 for(i=0; i<dvert->totweight; i++)
1819                                         if(dvert->dw[i].def_nr > dg_index)
1820                                                 dvert->dw[i].def_nr--;
1821                 }
1822                 BKE_mesh_end_editmesh(me, em);
1823         }
1824         else if(ob->type==OB_LATTICE) {
1825                 Lattice *lt= vgroup_edit_lattice(ob);
1826                 BPoint *bp;
1827                 MDeformVert *dvert= lt->dvert;
1828                 int a, tot;
1829                 
1830                 if(dvert) {
1831                         tot= lt->pntsu*lt->pntsv*lt->pntsw;
1832                         for(a=0, bp= lt->def; a<tot; a++, bp++, dvert++) {
1833                                 for(i=0; i<dvert->totweight; i++){
1834                                         if(dvert->dw[i].def_nr > dg_index)
1835                                                 dvert->dw[i].def_nr--;
1836                                 }
1837                         }
1838                 }
1839         }
1840
1841         vgroup_delete_update_users(ob, dg_index + 1);
1842
1843         /* Remove the group */
1844         BLI_freelinkN (&ob->defbase, dg);
1845
1846         /* Update the active deform index if necessary */
1847         if(ob->actdef > dg_index)
1848                 ob->actdef--;
1849         if(ob->actdef < 1 && ob->defbase.first)
1850                 ob->actdef= 1;
1851
1852         /* remove all dverts */
1853         if(ob->defbase.first == NULL) {
1854                 if(ob->type==OB_MESH) {
1855                         Mesh *me= ob->data;
1856                         CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
1857                         me->dvert= NULL;
1858                 }
1859                 else if(ob->type==OB_LATTICE) {
1860                         Lattice *lt= vgroup_edit_lattice(ob);
1861                         if(lt->dvert) {
1862                                 MEM_freeN(lt->dvert);
1863                                 lt->dvert= NULL;
1864                         }
1865                 }
1866         }
1867 }
1868
1869 static int vgroup_object_in_edit_mode(Object *ob)
1870 {
1871         if(ob->type == OB_MESH)
1872                 return (((Mesh*)ob->data)->edit_mesh != NULL);
1873         else if(ob->type == OB_LATTICE)
1874                 return (((Lattice*)ob->data)->editlatt != NULL);
1875         
1876         return 0;
1877 }
1878
1879 static void vgroup_delete(Object *ob)
1880 {
1881         bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef-1);
1882         if(!dg)
1883                 return;
1884
1885         if(vgroup_object_in_edit_mode(ob))
1886                 vgroup_delete_edit_mode(ob, dg);
1887         else
1888                 vgroup_delete_object_mode(ob, dg);
1889 }
1890
1891 static void vgroup_delete_all(Object *ob)
1892 {
1893         /* Remove all DVerts */
1894         if(ob->type==OB_MESH) {
1895                 Mesh *me= ob->data;
1896                 CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
1897                 me->dvert= NULL;
1898         }
1899         else if(ob->type==OB_LATTICE) {
1900                 Lattice *lt= vgroup_edit_lattice(ob);
1901                 if(lt->dvert) {
1902                         MEM_freeN(lt->dvert);
1903                         lt->dvert= NULL;
1904                 }
1905         }
1906         
1907         /* Remove all DefGroups */
1908         BLI_freelistN(&ob->defbase);
1909         
1910         /* Fix counters/indices */
1911         ob->actdef= 0;
1912 }
1913
1914 /* only in editmode */
1915 static void vgroup_assign_verts(Object *ob, float weight)
1916 {
1917         EditVert *eve;
1918         bDeformGroup *dg, *eg;
1919         MDeformWeight *newdw;
1920         MDeformVert *dvert;
1921         int     i, done;
1922
1923         dg=BLI_findlink(&ob->defbase, ob->actdef-1);
1924         if(!dg)
1925                 return;
1926
1927         if(ob->type == OB_MESH) {
1928                 Mesh *me= ob->data;
1929                 EditMesh *em = BKE_mesh_get_editmesh(me);
1930
1931                 if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT))
1932                         EM_add_data_layer(em, &em->vdata, CD_MDEFORMVERT, NULL);
1933
1934                 /* Go through the list of editverts and assign them */
1935                 for(eve=em->verts.first; eve; eve=eve->next){
1936                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1937
1938                         if(dvert && (eve->f & SELECT)){
1939                                 /* See if this vert already has a reference to this group */
1940                                 /*              If so: Change its weight */
1941                                 done=0;
1942                                 for(i=0; i<dvert->totweight; i++){
1943                                         eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr);
1944                                         /* Find the actual group */
1945                                         if(eg==dg){
1946                                                 dvert->dw[i].weight= weight;
1947                                                 done=1;
1948                                                 break;
1949                                         }
1950                                  }
1951                                 /*              If not: Add the group and set its weight */
1952                                 if(!done){
1953                                         newdw = MEM_callocN(sizeof(MDeformWeight)*(dvert->totweight+1), "deformWeight");
1954                                         if(dvert->dw){
1955                                                 memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*dvert->totweight);
1956                                                 MEM_freeN(dvert->dw);
1957                                         }
1958                                         dvert->dw=newdw;
1959
1960                                         dvert->dw[dvert->totweight].weight= weight;
1961                                         dvert->dw[dvert->totweight].def_nr= ob->actdef-1;
1962
1963                                         dvert->totweight++;
1964
1965                                 }
1966                         }
1967                 }
1968                 BKE_mesh_end_editmesh(me, em);
1969         }
1970         else if(ob->type == OB_LATTICE) {
1971                 Lattice *lt= vgroup_edit_lattice(ob);
1972                 BPoint *bp;
1973                 int a, tot;
1974                 
1975                 if(lt->dvert==NULL)
1976                         ED_vgroup_data_create(&lt->id);
1977                 
1978                 tot= lt->pntsu*lt->pntsv*lt->pntsw;
1979                 for(a=0, bp= lt->def; a<tot; a++, bp++) {
1980                         if(bp->f1 & SELECT)
1981                                 ED_vgroup_nr_vert_add(ob, ob->actdef-1, a, weight, WEIGHT_REPLACE);
1982                 }
1983         }
1984 }
1985
1986 /* only in editmode */
1987 /* removes from all defgroup, if allverts==0 only selected vertices */
1988 static void vgroup_remove_verts(Object *ob, int allverts)
1989 {
1990         /* To prevent code redundancy, we just use vgroup_active_remove_verts, but that
1991          * only operates on the active vgroup. So we iterate through all groups, by changing
1992          * active group index
1993          */
1994         bDeformGroup *dg;
1995         for(dg= ob->defbase.first; dg; dg= dg->next) {
1996                 vgroup_active_remove_verts(ob, allverts, dg);
1997         }
1998 }
1999
2000 /********************** vertex group operators *********************/
2001
2002 static int vertex_group_poll(bContext *C)
2003 {
2004         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2005         ID *data= (ob)? ob->data: NULL;
2006         return (ob && !ob->id.lib && ELEM(ob->type, OB_MESH, OB_LATTICE) && data && !data->lib);
2007 }
2008
2009 static int vertex_group_poll_edit(bContext *C)
2010 {
2011         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2012         ID *data= (ob)? ob->data: NULL;
2013
2014         if(!(ob && !ob->id.lib && data && !data->lib))
2015                 return 0;
2016
2017         return vgroup_object_in_edit_mode(ob);
2018 }
2019
2020 static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op))
2021 {
2022         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2023
2024         ED_vgroup_add(ob);
2025         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2026         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2027         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2028         
2029         return OPERATOR_FINISHED;
2030 }
2031
2032 void OBJECT_OT_vertex_group_add(wmOperatorType *ot)
2033 {
2034         /* identifiers */
2035         ot->name= "Add Vertex Group";
2036         ot->idname= "OBJECT_OT_vertex_group_add";
2037         
2038         /* api callbacks */
2039         ot->poll= vertex_group_poll;
2040         ot->exec= vertex_group_add_exec;
2041
2042         /* flags */
2043         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2044 }
2045
2046 static int vertex_group_remove_exec(bContext *C, wmOperator *op)
2047 {
2048         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2049
2050         if(RNA_boolean_get(op->ptr, "all"))
2051                 vgroup_delete_all(ob);
2052         else
2053                 vgroup_delete(ob);
2054
2055         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2056         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2057         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2058         
2059         return OPERATOR_FINISHED;
2060 }
2061
2062 void OBJECT_OT_vertex_group_remove(wmOperatorType *ot)
2063 {
2064         /* identifiers */
2065         ot->name= "Remove Vertex Group";
2066         ot->idname= "OBJECT_OT_vertex_group_remove";
2067         
2068         /* api callbacks */
2069         ot->poll= vertex_group_poll;
2070         ot->exec= vertex_group_remove_exec;
2071
2072         /* flags */
2073         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2074
2075         /* properties */
2076         RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups");
2077 }
2078
2079 static int vertex_group_assign_exec(bContext *C, wmOperator *op)
2080 {
2081         ToolSettings *ts= CTX_data_tool_settings(C);
2082         Object *ob= CTX_data_edit_object(C);
2083
2084         if(RNA_boolean_get(op->ptr, "new"))
2085                 ED_vgroup_add(ob);
2086
2087         vgroup_assign_verts(ob, ts->vgroup_weight);
2088         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2089         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2090         
2091         return OPERATOR_FINISHED;
2092 }
2093
2094 void OBJECT_OT_vertex_group_assign(wmOperatorType *ot)
2095 {
2096         /* identifiers */
2097         ot->name= "Assign Vertex Group";
2098         ot->idname= "OBJECT_OT_vertex_group_assign";
2099         
2100         /* api callbacks */
2101         ot->poll= vertex_group_poll_edit;
2102         ot->exec= vertex_group_assign_exec;
2103
2104         /* flags */
2105         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2106
2107         /* properties */
2108         RNA_def_boolean(ot->srna, "new", 0, "New", "Assign vertex to new vertex group");
2109 }
2110
2111 static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
2112 {
2113         Object *ob= CTX_data_edit_object(C);
2114
2115         if(RNA_boolean_get(op->ptr, "all"))
2116                 vgroup_remove_verts(ob, 0);
2117         else {
2118                 bDeformGroup *dg= BLI_findlink(&ob->defbase, ob->actdef - 1);
2119
2120                 if(dg == NULL) {
2121                         return OPERATOR_CANCELLED;
2122                 }
2123
2124                 vgroup_active_remove_verts(ob, FALSE, dg);
2125         }
2126
2127         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2128         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2129
2130         return OPERATOR_FINISHED;
2131 }
2132
2133 void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot)
2134 {
2135         /* identifiers */
2136         ot->name= "Remove from Vertex Group";
2137         ot->idname= "OBJECT_OT_vertex_group_remove_from";
2138
2139         /* api callbacks */
2140         ot->poll= vertex_group_poll_edit;
2141         ot->exec= vertex_group_remove_from_exec;
2142
2143         /* flags */
2144         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2145
2146         /* properties */
2147         RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups");
2148 }
2149
2150 static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
2151 {
2152         Object *ob= CTX_data_edit_object(C);
2153
2154         if(!ob || ob->id.lib)
2155                 return OPERATOR_CANCELLED;
2156
2157         vgroup_select_verts(ob, 1);
2158         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
2159
2160         return OPERATOR_FINISHED;
2161 }
2162
2163 void OBJECT_OT_vertex_group_select(wmOperatorType *ot)
2164 {
2165         /* identifiers */
2166         ot->name= "Select Vertex Group";
2167         ot->idname= "OBJECT_OT_vertex_group_select";
2168
2169         /* api callbacks */
2170         ot->poll= vertex_group_poll_edit;
2171         ot->exec= vertex_group_select_exec;
2172
2173         /* flags */
2174         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2175 }
2176
2177 static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
2178 {
2179         Object *ob= CTX_data_edit_object(C);
2180
2181         vgroup_select_verts(ob, 0);
2182         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
2183
2184         return OPERATOR_FINISHED;
2185 }
2186
2187 void OBJECT_OT_vertex_group_deselect(wmOperatorType *ot)
2188 {
2189         /* identifiers */
2190         ot->name= "Deselect Vertex Group";
2191         ot->idname= "OBJECT_OT_vertex_group_deselect";
2192
2193         /* api callbacks */
2194         ot->poll= vertex_group_poll_edit;
2195         ot->exec= vertex_group_deselect_exec;
2196
2197         /* flags */
2198         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2199 }
2200
2201 static int vertex_group_copy_exec(bContext *C, wmOperator *UNUSED(op))
2202 {
2203         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2204
2205         vgroup_duplicate(ob);
2206         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2207         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2208         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2209
2210         return OPERATOR_FINISHED;
2211 }
2212
2213 void OBJECT_OT_vertex_group_copy(wmOperatorType *ot)
2214 {
2215         /* identifiers */
2216         ot->name= "Copy Vertex Group";
2217         ot->idname= "OBJECT_OT_vertex_group_copy";
2218
2219         /* api callbacks */
2220         ot->poll= vertex_group_poll;
2221         ot->exec= vertex_group_copy_exec;
2222
2223         /* flags */
2224         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2225 }
2226
2227 static int vertex_group_levels_exec(bContext *C, wmOperator *op)
2228 {
2229         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2230         
2231         float offset= RNA_float_get(op->ptr,"offset");
2232         float gain= RNA_float_get(op->ptr,"gain");
2233         
2234         vgroup_levels(ob, offset, gain);
2235         
2236         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2237         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2238         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2239         
2240         return OPERATOR_FINISHED;
2241 }
2242
2243 void OBJECT_OT_vertex_group_levels(wmOperatorType *ot)
2244 {
2245         /* identifiers */
2246         ot->name= "Vertex Group Levels";
2247         ot->idname= "OBJECT_OT_vertex_group_levels";
2248         
2249         /* api callbacks */
2250         ot->poll= vertex_group_poll;
2251         ot->exec= vertex_group_levels_exec;
2252         
2253         /* flags */
2254         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2255         
2256         RNA_def_float(ot->srna, "offset", 0.f, -1.0, 1.0, "Offset", "Value to add to weights", -1.0f, 1.f);
2257         RNA_def_float(ot->srna, "gain", 1.f, 0.f, FLT_MAX, "Gain", "Value to multiply weights by", 0.0f, 10.f);
2258 }
2259
2260 static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op))
2261 {
2262         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2263
2264         vgroup_normalize(ob);
2265
2266         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2267         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2268         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2269
2270         return OPERATOR_FINISHED;
2271 }
2272
2273 void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot)
2274 {
2275         /* identifiers */
2276         ot->name= "Normalize Vertex Group";
2277         ot->idname= "OBJECT_OT_vertex_group_normalize";
2278
2279         /* api callbacks */
2280         ot->poll= vertex_group_poll;
2281         ot->exec= vertex_group_normalize_exec;
2282
2283         /* flags */
2284         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2285 }
2286
2287 static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
2288 {
2289         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2290         int lock_active= RNA_boolean_get(op->ptr,"lock_active");
2291
2292         vgroup_normalize_all(ob, lock_active);
2293
2294         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2295         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2296         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2297
2298         return OPERATOR_FINISHED;
2299 }
2300
2301 void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
2302 {
2303         /* identifiers */
2304         ot->name= "Normalize All Vertex Groups";
2305         ot->idname= "OBJECT_OT_vertex_group_normalize_all";
2306
2307         /* api callbacks */
2308         ot->poll= vertex_group_poll;
2309         ot->exec= vertex_group_normalize_all_exec;
2310
2311         /* flags */
2312         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2313
2314         RNA_def_boolean(ot->srna, "lock_active", TRUE, "Lock Active", "Keep the values of the active group while normalizing others");
2315 }
2316
2317 static int vertex_group_fix_exec(bContext *C, wmOperator *op)
2318 {
2319         Object *ob= CTX_data_active_object(C);
2320         Scene *scene= CTX_data_scene(C);
2321         
2322         float distToBe= RNA_float_get(op->ptr, "dist");
2323         float strength= RNA_float_get(op->ptr, "strength");
2324         float cp= RNA_float_get(op->ptr, "accuracy");
2325         ModifierData *md= ob->modifiers.first;
2326
2327         while(md) {
2328                 if(md->type == eModifierType_Mirror && (md->mode&eModifierMode_Realtime)) {
2329                         break;
2330                 }
2331                 md = md->next;
2332         }
2333         
2334         if(md && md->type == eModifierType_Mirror) {
2335                 BKE_report(op->reports, RPT_ERROR_INVALID_CONTEXT, "This operator does not support an active mirror modifier");
2336                 return OPERATOR_CANCELLED;
2337         }
2338         vgroup_fix(scene, ob, distToBe, strength, cp);
2339         
2340         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2341         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2342         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2343         
2344         return OPERATOR_FINISHED;
2345 }
2346
2347 void OBJECT_OT_vertex_group_fix(wmOperatorType *ot)
2348 {
2349         /* identifiers */
2350         ot->name= "Fix Vertex Group Deform";
2351         ot->idname= "OBJECT_OT_vertex_group_fix";
2352         ot->description= "Modify the position of selected vertices by changing only their respective groups' weights (this tool may be slow for many vertices)";
2353         
2354         /* api callbacks */
2355         ot->poll= vertex_group_poll;
2356         ot->exec= vertex_group_fix_exec;
2357         
2358         /* flags */
2359         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2360         RNA_def_float(ot->srna, "dist", 0.0f, -FLT_MAX, FLT_MAX, "Distance", "The distance to move to", -10.0f, 10.0f);
2361         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);
2362         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);
2363 }
2364
2365
2366 static int vertex_group_lock_exec(bContext *C, wmOperator *op)
2367 {
2368         Object *ob= CTX_data_active_object(C);
2369
2370         int action = RNA_enum_get(op->ptr, "action");
2371
2372         vgroup_lock_all(ob, action);
2373
2374         return OPERATOR_FINISHED;
2375 }
2376
2377 void OBJECT_OT_vertex_group_lock(wmOperatorType *ot)
2378 {
2379         /* identifiers */
2380         ot->name= "Change the Lock On Vertex Groups";
2381         ot->idname= "OBJECT_OT_vertex_group_lock";
2382
2383         /* api callbacks */
2384         ot->poll= vertex_group_poll;
2385         ot->exec= vertex_group_lock_exec;
2386
2387         /* flags */
2388         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2389
2390         WM_operator_properties_select_all(ot);
2391 }
2392
2393 static int vertex_group_invert_exec(bContext *C, wmOperator *op)
2394 {
2395         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2396         int auto_assign= RNA_boolean_get(op->ptr,"auto_assign");
2397         int auto_remove= RNA_boolean_get(op->ptr,"auto_remove");
2398
2399         vgroup_invert(ob, auto_assign, auto_remove);
2400         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2401         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2402         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2403
2404         return OPERATOR_FINISHED;
2405 }
2406
2407 void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
2408 {
2409         /* identifiers */
2410         ot->name= "Invert Vertex Group";
2411         ot->idname= "OBJECT_OT_vertex_group_invert";
2412
2413         /* api callbacks */
2414         ot->poll= vertex_group_poll;
2415         ot->exec= vertex_group_invert_exec;
2416
2417         /* flags */
2418         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2419
2420         RNA_def_boolean(ot->srna, "auto_assign", TRUE, "Add Weights", "Add verts from groups that have zero weight before inverting");
2421         RNA_def_boolean(ot->srna, "auto_remove", TRUE, "Remove Weights", "Remove verts from groups that have zero weight after inverting");
2422 }
2423
2424
2425 static int vertex_group_blend_exec(bContext *C, wmOperator *UNUSED(op))
2426 {
2427         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2428
2429         vgroup_blend(ob);
2430
2431         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2432         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2433         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2434
2435         return OPERATOR_FINISHED;
2436 }
2437
2438 void OBJECT_OT_vertex_group_blend(wmOperatorType *ot)
2439 {
2440         /* identifiers */
2441         ot->name= "Blend Vertex Group";
2442         ot->idname= "OBJECT_OT_vertex_group_blend";
2443         ot->description= "";
2444
2445         /* api callbacks */
2446         ot->poll= vertex_group_poll;
2447         ot->exec= vertex_group_blend_exec;
2448
2449         /* flags */
2450         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2451 }
2452
2453
2454 static int vertex_group_clean_exec(bContext *C, wmOperator *op)
2455 {
2456         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2457
2458         float limit= RNA_float_get(op->ptr,"limit");
2459         int all_groups= RNA_boolean_get(op->ptr,"all_groups");
2460         int keep_single= RNA_boolean_get(op->ptr,"keep_single");
2461
2462         if(all_groups)  vgroup_clean_all(ob, limit, keep_single);
2463         else                    vgroup_clean(ob, limit, keep_single);
2464
2465         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2466         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2467         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2468
2469         return OPERATOR_FINISHED;
2470 }
2471
2472 void OBJECT_OT_vertex_group_clean(wmOperatorType *ot)
2473 {
2474         /* identifiers */
2475         ot->name= "Clean Vertex Group";
2476         ot->idname= "OBJECT_OT_vertex_group_clean";
2477         ot->description= "Remove Vertex Group assignments which aren't required";
2478
2479         /* api callbacks */
2480         ot->poll= vertex_group_poll;
2481         ot->exec= vertex_group_clean_exec;
2482
2483         /* flags */
2484         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2485
2486         RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, 1.0, "Limit", "Remove weights under this limit", 0.001f, 0.99f);
2487         RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Clean all vertex groups");
2488         RNA_def_boolean(ot->srna, "keep_single", FALSE, "Keep Single", "Keep verts assigned to at least one group when cleaning");
2489 }
2490
2491
2492 static int vertex_group_mirror_exec(bContext *C, wmOperator *op)
2493 {
2494         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2495
2496         ED_vgroup_mirror(ob, RNA_boolean_get(op->ptr,"mirror_weights"), RNA_boolean_get(op->ptr,"flip_group_names"));
2497
2498         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2499         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2500         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2501
2502         return OPERATOR_FINISHED;
2503 }
2504
2505 void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot)
2506 {
2507         /* identifiers */
2508         ot->name= "Mirror Vertex Group";
2509         ot->idname= "OBJECT_OT_vertex_group_mirror";
2510         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";
2511
2512         /* api callbacks */
2513         ot->poll= vertex_group_poll_edit;
2514         ot->exec= vertex_group_mirror_exec;
2515
2516         /* flags */
2517         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2518
2519         /* properties */
2520         RNA_def_boolean(ot->srna, "mirror_weights", TRUE, "Mirror Weights", "Mirror weights");
2521         RNA_def_boolean(ot->srna, "flip_group_names", TRUE, "Flip Groups", "Flip vertex group names");
2522
2523 }
2524
2525 static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op))
2526 {
2527         Scene *scene= CTX_data_scene(C);
2528         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2529         Base *base;
2530         int retval= OPERATOR_CANCELLED;
2531
2532         for(base=scene->base.first; base; base= base->next) {
2533                 if(base->object->type==ob->type) {
2534                         if(base->object!=ob && base->object->data==ob->data) {
2535                                 BLI_freelistN(&base->object->defbase);
2536                                 BLI_duplicatelist(&base->object->defbase, &ob->defbase);
2537                                 base->object->actdef= ob->actdef;
2538
2539                                 DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
2540                                 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, base->object);
2541                                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
2542
2543                                 retval = OPERATOR_FINISHED;
2544                         }
2545                 }
2546         }
2547
2548         return retval;
2549 }
2550
2551 void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot)
2552 {
2553         /* identifiers */
2554         ot->name= "Copy Vertex Groups to Linked";
2555         ot->idname= "OBJECT_OT_vertex_group_copy_to_linked";
2556         ot->description= "Copy Vertex Groups to all users of the same Geometry data";
2557
2558         /* api callbacks */
2559         ot->poll= vertex_group_poll;
2560         ot->exec= vertex_group_copy_to_linked_exec;
2561
2562         /* flags */
2563         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2564 }
2565
2566 static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
2567 {
2568         Object *obact= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2569         int change= 0;
2570         int fail= 0;
2571
2572         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects)
2573         {
2574                 if(obact != ob) {
2575                         if(ED_vgroup_copy_array(ob, obact)) change++;
2576                         else                                fail++;
2577                 }
2578         }
2579         CTX_DATA_END;
2580
2581         if((change == 0 && fail == 0) || fail) {
2582                 BKE_reportf(op->reports, RPT_ERROR, "Copy to VGroups to Selected warning done %d, failed %d, object data must have matching indicies", change, fail);
2583         }
2584
2585         return OPERATOR_FINISHED;
2586 }
2587
2588
2589 void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot)
2590 {
2591         /* identifiers */
2592         ot->name= "Copy Vertex Group to Selected";
2593         ot->idname= "OBJECT_OT_vertex_group_copy_to_selected";
2594         ot->description= "Copy Vertex Groups to other selected objects with matching indices";
2595
2596         /* api callbacks */
2597         ot->poll= vertex_group_poll;
2598         ot->exec= vertex_group_copy_to_selected_exec;
2599
2600         /* flags */
2601         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2602 }
2603
2604 static EnumPropertyItem vgroup_items[]= {
2605         {0, NULL, 0, NULL, NULL}};
2606
2607 static int set_active_group_exec(bContext *C, wmOperator *op)
2608 {
2609         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2610         int nr= RNA_enum_get(op->ptr, "group");
2611
2612         ob->actdef= nr+1;
2613
2614         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2615         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2616
2617         return OPERATOR_FINISHED;
2618 }
2619
2620 static EnumPropertyItem *vgroup_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
2621 {       
2622         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2623         EnumPropertyItem tmp = {0, "", 0, "", ""};
2624         EnumPropertyItem *item= NULL;
2625         bDeformGroup *def;
2626         int a, totitem= 0;
2627         
2628         if(!ob)
2629                 return vgroup_items;
2630         
2631         for(a=0, def=ob->defbase.first; def; def=def->next, a++) {
2632                 tmp.value= a;
2633                 tmp.icon= ICON_GROUP_VERTEX;
2634                 tmp.identifier= def->name;
2635                 tmp.name= def->name;
2636                 RNA_enum_item_add(&item, &totitem, &tmp);
2637         }
2638
2639         RNA_enum_item_end(&item, &totitem);
2640         *free= 1;
2641
2642         return item;
2643 }
2644
2645 void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
2646 {
2647         PropertyRNA *prop;
2648
2649         /* identifiers */
2650         ot->name= "Set Active Vertex Group";
2651         ot->idname= "OBJECT_OT_vertex_group_set_active";
2652         ot->description= "Set the active vertex group";
2653
2654         /* api callbacks */
2655         ot->poll= vertex_group_poll;
2656         ot->exec= set_active_group_exec;
2657         ot->invoke= WM_menu_invoke;
2658
2659         /* flags */
2660         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2661
2662         /* properties */
2663         prop= RNA_def_enum(ot->srna, "group", vgroup_items, 0, "Group", "Vertex group to set as active");
2664         RNA_def_enum_funcs(prop, vgroup_itemf);
2665         ot->prop= prop;
2666 }
2667
2668 /*creates the name_array parameter for vgroup_do_remap, call this before fiddling
2669   with the order of vgroups then call vgroup_do_remap after*/
2670 static char *vgroup_init_remap(Object *ob)
2671 {
2672         bDeformGroup *def;
2673         int def_tot = BLI_countlist(&ob->defbase);
2674         char *name_array= MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * def_tot, "sort vgroups");
2675         char *name;
2676
2677         name= name_array;
2678         for(def = ob->defbase.first; def; def=def->next) {
2679                 BLI_strncpy(name, def->name, MAX_VGROUP_NAME);
2680                 name += MAX_VGROUP_NAME;
2681         }
2682
2683         return name_array;
2684 }
2685
2686 static int vgroup_do_remap(Object *ob, char *name_array, wmOperator *op)
2687 {
2688         MDeformVert *dvert= NULL;
2689         bDeformGroup *def;
2690         int def_tot = BLI_countlist(&ob->defbase);
2691         int *sort_map_update= MEM_mallocN(MAX_VGROUP_NAME * sizeof(int) * def_tot + 1, "sort vgroups"); /* needs a dummy index at the start*/
2692         int *sort_map= sort_map_update + 1;
2693         char *name;
2694         int i;
2695
2696         name= name_array;
2697         for(def= ob->defbase.first, i=0; def; def=def->next, i++){
2698                 sort_map[i]= BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name));
2699                 name += MAX_VGROUP_NAME;
2700         }
2701
2702         if(ob->mode == OB_MODE_EDIT) {
2703                 if(ob->type==OB_MESH) {
2704                         EditMesh *em = BKE_mesh_get_editmesh(ob->data);
2705                         EditVert *eve;
2706
2707                         for(eve=em->verts.first; eve; eve=eve->next){
2708                                 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
2709                                 if(dvert && dvert->totweight){
2710                                         defvert_remap(dvert, sort_map);
2711                                 }
2712                         }
2713                 }
2714                 else {
2715                         BKE_report(op->reports, RPT_ERROR, "Editmode lattice isnt supported yet");
2716                         MEM_freeN(sort_map_update);
2717                         return OPERATOR_CANCELLED;
2718                 }
2719         }
2720         else {
2721                 int dvert_tot=0;
2722
2723                 ED_vgroup_give_array(ob->data, &dvert, &dvert_tot);
2724
2725                 /*create as necassary*/
2726                 while(dvert && dvert_tot--) {
2727                         if(dvert->totweight)
2728                                 defvert_remap(dvert, sort_map);
2729                         dvert++;
2730                 }
2731         }
2732
2733         /* update users */
2734         for(i=0; i<def_tot; i++)
2735                 sort_map[i]++;
2736
2737         sort_map_update[0]= 0;
2738         vgroup_remap_update_users(ob, sort_map_update);
2739
2740         ob->actdef= sort_map_update[ob->actdef];
2741         
2742         MEM_freeN(sort_map_update);
2743
2744         return OPERATOR_FINISHED;
2745 }
2746
2747 static int vgroup_sort(void *def_a_ptr, void *def_b_ptr)
2748 {
2749         bDeformGroup *def_a= (bDeformGroup *)def_a_ptr;
2750         bDeformGroup *def_b= (bDeformGroup *)def_b_ptr;
2751
2752         return BLI_natstrcmp(def_a->name, def_b->name);
2753 }
2754
2755 static int vertex_group_sort_exec(bContext *C, wmOperator *op)
2756 {
2757         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2758         char *name_array;
2759         int ret;
2760
2761         /*init remapping*/
2762         name_array = vgroup_init_remap(ob);
2763
2764         /*sort vgroup names*/
2765         BLI_sortlist(&ob->defbase, vgroup_sort);
2766
2767         /*remap vgroup data to map to correct names*/
2768         ret = vgroup_do_remap(ob, name_array, op);
2769
2770         if (ret != OPERATOR_CANCELLED) {
2771                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2772                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2773         }
2774
2775         if (name_array) MEM_freeN(name_array);
2776
2777         return ret;
2778 }
2779
2780 void OBJECT_OT_vertex_group_sort(wmOperatorType *ot)
2781 {
2782         ot->name= "Sort Vertex Groups";
2783         ot->idname= "OBJECT_OT_vertex_group_sort";
2784         ot->description= "Sorts vertex groups alphabetically";
2785
2786         /* api callbacks */
2787         ot->poll= vertex_group_poll;
2788         ot->exec= vertex_group_sort_exec;
2789
2790         /* flags */
2791         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2792 }
2793
2794 static int vgroup_move_exec(bContext *C, wmOperator *op)
2795 {
2796         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2797         bDeformGroup *def;
2798         char *name_array;
2799         int dir= RNA_enum_get(op->ptr, "direction"), ret;
2800
2801         def = BLI_findlink(&ob->defbase, ob->actdef - 1);
2802         if (!def) {
2803                 return OPERATOR_CANCELLED;
2804         }
2805
2806         name_array = vgroup_init_remap(ob);
2807
2808         if (dir == 1) { /*up*/
2809                 void *prev = def->prev;
2810
2811                 BLI_remlink(&ob->defbase, def);
2812                 BLI_insertlinkbefore(&ob->defbase, prev, def);
2813         } else { /*down*/
2814                 void *next = def->next;
2815
2816                 BLI_remlink(&ob->defbase, def);
2817                 BLI_insertlinkafter(&ob->defbase, next, def);
2818         }
2819
2820         ret = vgroup_do_remap(ob, name_array, op);
2821
2822         if (name_array) MEM_freeN(name_array);
2823
2824         if (ret != OPERATOR_CANCELLED) {
2825                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2826                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2827         }
2828
2829         return ret;
2830 }
2831
2832 void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
2833 {
2834         static EnumPropertyItem vgroup_slot_move[] = {
2835                 {1, "UP", 0, "Up", ""},
2836                 {-1, "DOWN", 0, "Down", ""},
2837                 {0, NULL, 0, NULL, NULL}
2838         };
2839
2840         /* identifiers */
2841         ot->name= "Move Vertex Group";
2842         ot->idname= "OBJECT_OT_vertex_group_move";
2843
2844         /* api callbacks */
2845         ot->poll= vertex_group_poll;
2846         ot->exec= vgroup_move_exec;
2847
2848         /* flags */
2849         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2850
2851         RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
2852 }