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