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