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