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