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