svn merge ^/trunk/blender -r42466:42495
[blender-staging.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= BM_Vert_AtIndex(me->edit_btmesh->bm, 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                                                 }
636                                                 break;
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, only swaps pointer */
1581                 if(sel_mirr) {
1582                         SWAP(MDeformVert *, dvert, dvert_mirr);
1583                 }
1584
1585                 if(mirror_weights) {
1586                         if (all_vgroups) {
1587                                 defvert_copy(dvert, dvert_mirr);
1588                         }
1589                         else {
1590                                 defvert_copy_index(dvert, dvert_mirr, act_vgroup);
1591                         }
1592                 }
1593
1594                 /* flip map already modified for 'all_vgroups' */
1595                 if(flip_vgroups) {
1596                         defvert_flip(dvert, flip_map, flip_map_len);
1597                 }
1598         }
1599 }
1600
1601 /* TODO, vgroup locking */
1602 /* TODO, face masking */
1603 void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_vgroups, const short all_vgroups)
1604 {
1605
1606 #define VGROUP_MIRR_OP                                                        \
1607         dvert_mirror_op(dvert, dvert_mirr,                                    \
1608                         sel, sel_mirr,                                        \
1609                         flip_map, flip_map_len,                               \
1610                         mirror_weights, flip_vgroups,                         \
1611                         all_vgroups, def_nr                                   \
1612                         )
1613
1614         BMVert *eve, *eve_mirr;
1615
1616         MDeformVert *dvert, *dvert_mirr;
1617         short sel, sel_mirr;
1618         int     *flip_map, flip_map_len;
1619         const int def_nr= ob->actdef-1;
1620
1621         if ( (mirror_weights==0 && flip_vgroups==0) ||
1622              (BLI_findlink(&ob->defbase, def_nr) == NULL) )
1623         {
1624                 return;
1625         }
1626
1627         if (flip_vgroups) {
1628                 flip_map= all_vgroups ?
1629                                         defgroup_flip_map(ob, &flip_map_len, FALSE) :
1630                                         defgroup_flip_map_single(ob, &flip_map_len, FALSE, def_nr);
1631
1632                 BLI_assert(flip_map != NULL);
1633
1634                 if (flip_map == NULL) {
1635                         /* something went wrong!, possibly no groups */
1636                         return;
1637                 }
1638         }
1639         else {
1640                 flip_map= NULL;
1641                 flip_map_len= 0;
1642         }
1643
1644         /* only the active group */
1645         if(ob->type == OB_MESH) {
1646                 Mesh *me= ob->data;
1647                 BMEditMesh *em = me->edit_btmesh;
1648
1649                 if (em) {
1650                         BMIter iter;
1651
1652                         if(!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) {
1653                                 goto cleanup;
1654                         }
1655
1656                         EDBM_CacheMirrorVerts(em, FALSE);
1657
1658                         /* Go through the list of editverts and assign them */
1659                         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1660                                 if((eve_mirr= EDBM_GetMirrorVert(em, eve))) {
1661                                         sel= BM_TestHFlag(eve, BM_SELECT);
1662                                         sel_mirr= BM_TestHFlag(eve_mirr, BM_SELECT);
1663
1664                                         if((sel || sel_mirr) && (eve != eve_mirr)) {
1665                                                 dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
1666                                                 dvert_mirr= CustomData_bmesh_get(&em->bm->vdata, eve_mirr->head.data, CD_MDEFORMVERT);
1667                                                 if(dvert && dvert_mirr) {
1668                                                         VGROUP_MIRR_OP;
1669                                                 }
1670                                         }
1671
1672                                         /* don't use these again */
1673                                         EDBM_ClearMirrorVert(em, eve);
1674                                         EDBM_ClearMirrorVert(em, eve_mirr);
1675                                 }
1676                         }
1677                         EDBM_EndMirrorCache(em);
1678                 }
1679                 else {
1680                         /* object mode / weight paint */
1681                         MVert *mv, *mv_mirr;
1682                         int vidx, vidx_mirr;
1683                         const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1684
1685                         if (me->dvert == NULL) {
1686                                 goto cleanup;
1687                         }
1688
1689                         if (!use_vert_sel) {
1690                                 sel= sel_mirr= TRUE;
1691                         }
1692
1693                         /* tag verts we have used */
1694                         for(vidx= 0, mv= me->mvert; vidx < me->totvert; vidx++, mv++) {
1695                                 mv->flag &= ~ME_VERT_TMP_TAG;
1696                         }
1697
1698                         for(vidx= 0, mv= me->mvert; vidx < me->totvert; vidx++, mv++) {
1699                                 if (    ((mv->flag & ME_VERT_TMP_TAG) == 0) &&
1700                                         ((vidx_mirr= mesh_get_x_mirror_vert(ob, vidx)) != -1) &&
1701                                         (vidx != vidx_mirr) &&
1702                                         ((((mv_mirr= me->mvert + vidx_mirr)->flag) & ME_VERT_TMP_TAG) == 0))
1703                                 {
1704
1705                                         if (use_vert_sel) {
1706                                                 sel= mv->flag & SELECT;
1707                                                 sel_mirr= mv_mirr->flag & SELECT;
1708                                         }
1709
1710                                         if (sel || sel_mirr) {
1711                                                 dvert= &me->dvert[vidx];
1712                                                 dvert_mirr= &me->dvert[vidx_mirr];
1713
1714                                                 VGROUP_MIRR_OP;
1715                                         }
1716
1717                                         mv->flag |= ME_VERT_TMP_TAG;
1718                                         mv_mirr->flag |= ME_VERT_TMP_TAG;
1719                                 }
1720                         }
1721                 }
1722         }
1723         else if (ob->type == OB_LATTICE) {
1724                 Lattice *lt= ob->data;
1725                 int i1, i2;
1726                 int u, v, w;
1727                 int pntsu_half;
1728                 /* half but found up odd value */
1729
1730                 if(lt->editlatt) lt= lt->editlatt->latt;
1731
1732                 if(lt->pntsu == 1 || lt->dvert == NULL) {
1733                         goto cleanup;
1734                 }
1735
1736                 /* unlike editmesh we know that by only looping over the first hald of
1737                  * the 'u' indicies it will cover all points except the middle which is
1738                  * ok in this case */
1739                 pntsu_half= lt->pntsu / 2;
1740
1741                 for(w=0; w<lt->pntsw; w++) {
1742                         for(v=0; v<lt->pntsv; v++) {
1743                                 for(u=0; u<pntsu_half; u++) {
1744                                         int u_inv= (lt->pntsu - 1) - u;
1745                                         if(u != u_inv) {
1746                                                 BPoint *bp, *bp_mirr;
1747
1748                                                 i1= LT_INDEX(lt, u, v, w);
1749                                                 i2= LT_INDEX(lt, u_inv, v, w);
1750
1751                                                 bp= &lt->def[i1];
1752                                                 bp_mirr= &lt->def[i2];
1753
1754                                                 sel= bp->f1 & SELECT;
1755                                                 sel_mirr= bp_mirr->f1 & SELECT;
1756
1757                                                 if(sel || sel_mirr) {
1758                                                         dvert= &lt->dvert[i1];
1759                                                         dvert_mirr= &lt->dvert[i2];
1760
1761                                                         VGROUP_MIRR_OP;
1762                                                 }
1763                                         }
1764                                 }
1765                         }
1766                 }
1767         }
1768
1769 cleanup:
1770         if (flip_map) MEM_freeN(flip_map);
1771
1772 #undef VGROUP_MIRR_OP
1773
1774 }
1775
1776 static void vgroup_remap_update_users(Object *ob, int *map)
1777 {
1778         ExplodeModifierData *emd;
1779         ModifierData *md;
1780         ParticleSystem *psys;
1781         ClothModifierData *clmd;
1782         ClothSimSettings *clsim;
1783         int a;
1784
1785         /* these cases don't use names to refer to vertex groups, so when
1786          * they get deleted the numbers get out of sync, this corrects that */
1787
1788         if(ob->soft)
1789                 ob->soft->vertgroup= map[ob->soft->vertgroup];
1790
1791         for(md=ob->modifiers.first; md; md=md->next) {
1792                 if(md->type == eModifierType_Explode) {
1793                         emd= (ExplodeModifierData*)md;
1794                         emd->vgroup= map[emd->vgroup];
1795                 }
1796                 else if(md->type == eModifierType_Cloth) {
1797                         clmd= (ClothModifierData*)md;
1798                         clsim= clmd->sim_parms;
1799
1800                         if(clsim) {
1801                                 clsim->vgroup_mass= map[clsim->vgroup_mass];
1802                                 clsim->vgroup_bend= map[clsim->vgroup_bend];
1803                                 clsim->vgroup_struct= map[clsim->vgroup_struct];
1804                         }
1805                 }
1806         }
1807
1808         for(psys=ob->particlesystem.first; psys; psys=psys->next) {
1809                 for(a=0; a<PSYS_TOT_VG; a++)
1810                         psys->vgroup[a]= map[psys->vgroup[a]];
1811         }
1812 }
1813
1814
1815 static void vgroup_delete_update_users(Object *ob, int id)
1816 {
1817         int i, tot= BLI_countlist(&ob->defbase) + 1;
1818         int *map= MEM_mallocN(sizeof(int) * tot, "vgroup del");
1819
1820         map[id]= map[0]= 0;
1821         for(i=1; i<id; i++) map[i]=i;
1822         for(i=id+1; i<tot; i++) map[i]=i-1;
1823
1824         vgroup_remap_update_users(ob, map);
1825         MEM_freeN(map);
1826 }
1827
1828
1829 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg)
1830 {
1831         MDeformVert *dvert_array=NULL;
1832         int i, e, dvert_tot=0;
1833         const int dg_index= BLI_findindex(&ob->defbase, dg);
1834
1835         assert(dg_index > -1);
1836         
1837         ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
1838
1839         if(dvert_array) {
1840                 MDeformVert *dvert;
1841                 for(i= 0, dvert= dvert_array; i < dvert_tot; i++, dvert++) {
1842                         ED_vgroup_vert_remove(ob, dg, i); /* ok if the dg isnt in this dvert, will continue silently */
1843                 }
1844
1845                 for(i= 0, dvert= dvert_array; i < dvert_tot; i++, dvert++) {
1846                         for(e = 0; e < dvert->totweight; e++) {
1847                                 if(dvert->dw[e].def_nr > dg_index) {
1848                                         dvert->dw[e].def_nr--;
1849                                 }
1850                         }
1851                 }
1852         }
1853
1854         vgroup_delete_update_users(ob, dg_index + 1);
1855
1856         /* Remove the group */
1857         BLI_freelinkN(&ob->defbase, dg);
1858
1859         /* Update the active deform index if necessary */
1860         if(ob->actdef > dg_index)
1861                 ob->actdef--;
1862         if(ob->actdef < 1 && ob->defbase.first)
1863                 ob->actdef= 1;
1864
1865 }
1866
1867 /* only in editmode */
1868 /* removes from active defgroup, if allverts==0 only selected vertices */
1869 static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGroup *dg)
1870 {
1871         BMVert *eve;
1872         MDeformVert *dvert;
1873         MDeformWeight *newdw;
1874         bDeformGroup *eg;
1875         int     i;
1876
1877         if(ob->type == OB_MESH) {
1878                 Mesh *me= ob->data;
1879                 BMEditMesh *em = me->edit_btmesh;
1880                 BMIter iter;
1881
1882                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1883                         dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
1884                 
1885                         if(dvert && dvert->dw && (BM_TestHFlag(eve, BM_SELECT) || allverts)){
1886                                 for(i=0; i<dvert->totweight; i++){
1887                                         /* Find group */
1888                                         eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr);
1889                                         if(eg == dg){
1890                                                 dvert->totweight--;
1891                                                 if (dvert->totweight){
1892                                                         newdw = BLI_cellalloc_malloc (sizeof(MDeformWeight)*(dvert->totweight), "deformWeight");
1893                                                         
1894                                                         if(dvert->dw){
1895                                                                 memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*i);
1896                                                                 memcpy(newdw+i, dvert->dw+i+1, sizeof(MDeformWeight)*(dvert->totweight-i));
1897                                                                 BLI_cellalloc_free(dvert->dw);
1898                                                         }
1899                                                         dvert->dw=newdw;
1900                                                 }
1901                                                 else{
1902                                                         BLI_cellalloc_free (dvert->dw);
1903                                                         dvert->dw=NULL;
1904                                                         break;
1905                                                 }
1906                                         }
1907                                 }
1908                         }
1909                 }
1910         }
1911         else if(ob->type == OB_LATTICE) {
1912                 Lattice *lt= vgroup_edit_lattice(ob);
1913                 
1914                 if(lt->dvert) {
1915                         BPoint *bp;
1916                         int a, tot= lt->pntsu*lt->pntsv*lt->pntsw;
1917                                 
1918                         for(a=0, bp= lt->def; a<tot; a++, bp++) {
1919                                 if(allverts || (bp->f1 & SELECT))
1920                                         ED_vgroup_vert_remove(ob, dg, a);
1921                         }
1922                 }
1923         }
1924 }
1925
1926 static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg)
1927 {
1928         int i;
1929         const int dg_index= BLI_findindex(&ob->defbase, dg);
1930
1931         assert(dg_index > -1);
1932
1933         /* Make sure that no verts are using this group */
1934         vgroup_active_remove_verts(ob, TRUE, dg);
1935
1936         /* Make sure that any verts with higher indices are adjusted accordingly */
1937         if(ob->type==OB_MESH) {
1938                 Mesh *me= ob->data;
1939                 BMEditMesh *em = me->edit_btmesh;
1940                 BMIter iter;
1941                 BMVert *eve;
1942                 MDeformVert *dvert;
1943                 
1944                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1945                         dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
1946
1947                         if(dvert)
1948                                 for(i=0; i<dvert->totweight; i++)
1949                                         if(dvert->dw[i].def_nr > dg_index)
1950                                                 dvert->dw[i].def_nr--;
1951                 }
1952         }
1953         else if(ob->type==OB_LATTICE) {
1954                 Lattice *lt= vgroup_edit_lattice(ob);
1955                 BPoint *bp;
1956                 MDeformVert *dvert= lt->dvert;
1957                 int a, tot;
1958                 
1959                 if(dvert) {
1960                         tot= lt->pntsu*lt->pntsv*lt->pntsw;
1961                         for(a=0, bp= lt->def; a<tot; a++, bp++, dvert++) {
1962                                 for(i=0; i<dvert->totweight; i++){
1963                                         if(dvert->dw[i].def_nr > dg_index)
1964                                                 dvert->dw[i].def_nr--;
1965                                 }
1966                         }
1967                 }
1968         }
1969
1970         vgroup_delete_update_users(ob, dg_index + 1);
1971
1972         /* Remove the group */
1973         BLI_freelinkN (&ob->defbase, dg);
1974
1975         /* Update the active deform index if necessary */
1976         if(ob->actdef > dg_index)
1977                 ob->actdef--;
1978         if(ob->actdef < 1 && ob->defbase.first)
1979                 ob->actdef= 1;
1980
1981         /* remove all dverts */
1982         if(ob->defbase.first == NULL) {
1983                 if(ob->type==OB_MESH) {
1984                         Mesh *me= ob->data;
1985                         CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
1986                         me->dvert= NULL;
1987                 }
1988                 else if(ob->type==OB_LATTICE) {
1989                         Lattice *lt= vgroup_edit_lattice(ob);
1990                         if(lt->dvert) {
1991                                 BLI_cellalloc_free(lt->dvert);
1992                                 lt->dvert= NULL;
1993                         }
1994                 }
1995         }
1996 }
1997
1998 static int vgroup_object_in_edit_mode(Object *ob)
1999 {
2000         if(ob->type == OB_MESH)
2001                 return (((Mesh*)ob->data)->edit_btmesh != NULL);
2002         else if(ob->type == OB_LATTICE)
2003                 return (((Lattice*)ob->data)->editlatt != NULL);
2004         
2005         return 0;
2006 }
2007
2008 static void vgroup_delete(Object *ob)
2009 {
2010         bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef-1);
2011         if(!dg)
2012                 return;
2013
2014         if(vgroup_object_in_edit_mode(ob))
2015                 vgroup_delete_edit_mode(ob, dg);
2016         else
2017                 vgroup_delete_object_mode(ob, dg);
2018 }
2019
2020 static void vgroup_delete_all(Object *ob)
2021 {
2022         /* Remove all DVerts */
2023         if(ob->type==OB_MESH) {
2024                 Mesh *me= ob->data;
2025                 CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
2026                 me->dvert= NULL;
2027         }
2028         else if(ob->type==OB_LATTICE) {
2029                 Lattice *lt= vgroup_edit_lattice(ob);
2030                 if(lt->dvert) {
2031                         BLI_cellalloc_free(lt->dvert);
2032                         lt->dvert= NULL;
2033                 }
2034         }
2035         
2036         /* Remove all DefGroups */
2037         BLI_freelistN(&ob->defbase);
2038         
2039         /* Fix counters/indices */
2040         ob->actdef= 0;
2041 }
2042
2043 /* only in editmode */
2044 static void vgroup_assign_verts(Object *ob, float weight)
2045 {
2046         BMVert *eve;
2047         bDeformGroup *dg, *eg;
2048         MDeformWeight *newdw;
2049         MDeformVert *dvert;
2050         int     i, done;
2051
2052         dg=BLI_findlink(&ob->defbase, ob->actdef-1);
2053         if(!dg)
2054                 return;
2055
2056         if(ob->type == OB_MESH) {
2057                 Mesh *me= ob->data;
2058                 BMEditMesh *em = me->edit_btmesh;
2059                 BMIter iter;
2060
2061                 if(!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT))
2062                         BM_add_data_layer(em->bm, &em->bm->vdata, CD_MDEFORMVERT);
2063
2064                 /* Go through the list of editverts and assign them */
2065                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2066                         dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
2067
2068                         if(dvert && BM_TestHFlag(eve, BM_SELECT)) {
2069                                 /* See if this vert already has a reference to this group */
2070                                 /*              If so: Change its weight */
2071                                 done=0;
2072                                 for(i=0; i<dvert->totweight; i++){
2073                                         eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr);
2074                                         /* Find the actual group */
2075                                         if(eg==dg){
2076                                                 dvert->dw[i].weight= weight;
2077                                                 done=1;
2078                                                 break;
2079                                         }
2080                                  }
2081                                 /*              If not: Add the group and set its weight */
2082                                 if(!done){
2083                                         newdw = BLI_cellalloc_calloc(sizeof(MDeformWeight)*(dvert->totweight+1), "deformWeight");
2084                                         if(dvert->dw){
2085                                                 memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*dvert->totweight);
2086                                                 BLI_cellalloc_free(dvert->dw);
2087                                         }
2088                                         dvert->dw=newdw;
2089
2090                                         dvert->dw[dvert->totweight].weight= weight;
2091                                         dvert->dw[dvert->totweight].def_nr= ob->actdef-1;
2092
2093                                         dvert->totweight++;
2094
2095                                 }
2096                         }
2097                 }
2098         }
2099         else if(ob->type == OB_LATTICE) {
2100                 Lattice *lt= vgroup_edit_lattice(ob);
2101                 BPoint *bp;
2102                 int a, tot;
2103                 
2104                 if(lt->dvert==NULL)
2105                         ED_vgroup_data_create(&lt->id);
2106                 
2107                 tot= lt->pntsu*lt->pntsv*lt->pntsw;
2108                 for(a=0, bp= lt->def; a<tot; a++, bp++) {
2109                         if(bp->f1 & SELECT)
2110                                 ED_vgroup_nr_vert_add(ob, ob->actdef-1, a, weight, WEIGHT_REPLACE);
2111                 }
2112         }
2113 }
2114
2115 /* only in editmode */
2116 /* removes from all defgroup, if allverts==0 only selected vertices */
2117 static void vgroup_remove_verts(Object *ob, int allverts)
2118 {
2119         /* To prevent code redundancy, we just use vgroup_active_remove_verts, but that
2120          * only operates on the active vgroup. So we iterate through all groups, by changing
2121          * active group index
2122          */
2123         bDeformGroup *dg;
2124         for(dg= ob->defbase.first; dg; dg= dg->next) {
2125                 vgroup_active_remove_verts(ob, allverts, dg);
2126         }
2127 }
2128
2129 /********************** vertex group operators *********************/
2130
2131 static int vertex_group_poll(bContext *C)
2132 {
2133         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2134         ID *data= (ob)? ob->data: NULL;
2135         return (ob && !ob->id.lib && OB_TYPE_SUPPORT_VGROUP(ob->type) && data && !data->lib);
2136 }
2137
2138 static int vertex_group_poll_edit(bContext *C)
2139 {
2140         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2141         ID *data= (ob)? ob->data: NULL;
2142
2143         if(!(ob && !ob->id.lib && data && !data->lib))
2144                 return 0;
2145
2146         return vgroup_object_in_edit_mode(ob);
2147 }
2148
2149 static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op))
2150 {
2151         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2152
2153         ED_vgroup_add(ob);
2154         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2155         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2156         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2157         
2158         return OPERATOR_FINISHED;
2159 }
2160
2161 void OBJECT_OT_vertex_group_add(wmOperatorType *ot)
2162 {
2163         /* identifiers */
2164         ot->name= "Add Vertex Group";
2165         ot->idname= "OBJECT_OT_vertex_group_add";
2166         
2167         /* api callbacks */
2168         ot->poll= vertex_group_poll;
2169         ot->exec= vertex_group_add_exec;
2170
2171         /* flags */
2172         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2173 }
2174
2175 static int vertex_group_remove_exec(bContext *C, wmOperator *op)
2176 {
2177         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2178
2179         if(RNA_boolean_get(op->ptr, "all"))
2180                 vgroup_delete_all(ob);
2181         else
2182                 vgroup_delete(ob);
2183
2184         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2185         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2186         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2187         
2188         return OPERATOR_FINISHED;
2189 }
2190
2191 void OBJECT_OT_vertex_group_remove(wmOperatorType *ot)
2192 {
2193         /* identifiers */
2194         ot->name= "Remove Vertex Group";
2195         ot->idname= "OBJECT_OT_vertex_group_remove";
2196         
2197         /* api callbacks */
2198         ot->poll= vertex_group_poll;
2199         ot->exec= vertex_group_remove_exec;
2200
2201         /* flags */
2202         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2203
2204         /* properties */
2205         RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups");
2206 }
2207
2208 static int vertex_group_assign_exec(bContext *C, wmOperator *op)
2209 {
2210         ToolSettings *ts= CTX_data_tool_settings(C);
2211         Object *ob= CTX_data_edit_object(C);
2212
2213         if(RNA_boolean_get(op->ptr, "new"))
2214                 ED_vgroup_add(ob);
2215
2216         vgroup_assign_verts(ob, ts->vgroup_weight);
2217         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2218         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2219         
2220         return OPERATOR_FINISHED;
2221 }
2222
2223 void OBJECT_OT_vertex_group_assign(wmOperatorType *ot)
2224 {
2225         /* identifiers */
2226         ot->name= "Assign Vertex Group";
2227         ot->idname= "OBJECT_OT_vertex_group_assign";
2228         
2229         /* api callbacks */
2230         ot->poll= vertex_group_poll_edit;
2231         ot->exec= vertex_group_assign_exec;
2232
2233         /* flags */
2234         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2235
2236         /* properties */
2237         RNA_def_boolean(ot->srna, "new", 0, "New", "Assign vertex to new vertex group");
2238 }
2239
2240 static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
2241 {
2242         Object *ob= CTX_data_edit_object(C);
2243
2244         if(RNA_boolean_get(op->ptr, "all"))
2245                 vgroup_remove_verts(ob, 0);
2246         else {
2247                 bDeformGroup *dg= BLI_findlink(&ob->defbase, ob->actdef - 1);
2248
2249                 if(dg == NULL) {
2250                         return OPERATOR_CANCELLED;
2251                 }
2252
2253                 vgroup_active_remove_verts(ob, FALSE, dg);
2254         }
2255
2256         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2257         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2258
2259         return OPERATOR_FINISHED;
2260 }
2261
2262 void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot)
2263 {
2264         /* identifiers */
2265         ot->name= "Remove from Vertex Group";
2266         ot->idname= "OBJECT_OT_vertex_group_remove_from";
2267
2268         /* api callbacks */
2269         ot->poll= vertex_group_poll_edit;
2270         ot->exec= vertex_group_remove_from_exec;
2271
2272         /* flags */
2273         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2274
2275         /* properties */
2276         RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups");
2277 }
2278
2279 static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
2280 {
2281         Object *ob= CTX_data_edit_object(C);
2282
2283         if(!ob || ob->id.lib)
2284                 return OPERATOR_CANCELLED;
2285
2286         vgroup_select_verts(ob, 1);
2287         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
2288
2289         return OPERATOR_FINISHED;
2290 }
2291
2292 void OBJECT_OT_vertex_group_select(wmOperatorType *ot)
2293 {
2294         /* identifiers */
2295         ot->name= "Select Vertex Group";
2296         ot->idname= "OBJECT_OT_vertex_group_select";
2297
2298         /* api callbacks */
2299         ot->poll= vertex_group_poll_edit;
2300         ot->exec= vertex_group_select_exec;
2301
2302         /* flags */
2303         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2304 }
2305
2306 static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
2307 {
2308         Object *ob= CTX_data_edit_object(C);
2309
2310         vgroup_select_verts(ob, 0);
2311         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
2312
2313         return OPERATOR_FINISHED;
2314 }
2315
2316 void OBJECT_OT_vertex_group_deselect(wmOperatorType *ot)
2317 {
2318         /* identifiers */
2319         ot->name= "Deselect Vertex Group";
2320         ot->idname= "OBJECT_OT_vertex_group_deselect";
2321
2322         /* api callbacks */
2323         ot->poll= vertex_group_poll_edit;
2324         ot->exec= vertex_group_deselect_exec;
2325
2326         /* flags */
2327         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2328 }
2329
2330 static int vertex_group_copy_exec(bContext *C, wmOperator *UNUSED(op))
2331 {
2332         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2333
2334         vgroup_duplicate(ob);
2335         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2336         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2337         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2338
2339         return OPERATOR_FINISHED;
2340 }
2341
2342 void OBJECT_OT_vertex_group_copy(wmOperatorType *ot)
2343 {
2344         /* identifiers */
2345         ot->name= "Copy Vertex Group";
2346         ot->idname= "OBJECT_OT_vertex_group_copy";
2347
2348         /* api callbacks */
2349         ot->poll= vertex_group_poll;
2350         ot->exec= vertex_group_copy_exec;
2351
2352         /* flags */
2353         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2354 }
2355
2356 static int vertex_group_levels_exec(bContext *C, wmOperator *op)
2357 {
2358         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2359         
2360         float offset= RNA_float_get(op->ptr,"offset");
2361         float gain= RNA_float_get(op->ptr,"gain");
2362         
2363         vgroup_levels(ob, offset, gain);
2364         
2365         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2366         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2367         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2368         
2369         return OPERATOR_FINISHED;
2370 }
2371
2372 void OBJECT_OT_vertex_group_levels(wmOperatorType *ot)
2373 {
2374         /* identifiers */
2375         ot->name= "Vertex Group Levels";
2376         ot->idname= "OBJECT_OT_vertex_group_levels";
2377         
2378         /* api callbacks */
2379         ot->poll= vertex_group_poll;
2380         ot->exec= vertex_group_levels_exec;
2381         
2382         /* flags */
2383         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2384         
2385         RNA_def_float(ot->srna, "offset", 0.f, -1.0, 1.0, "Offset", "Value to add to weights", -1.0f, 1.f);
2386         RNA_def_float(ot->srna, "gain", 1.f, 0.f, FLT_MAX, "Gain", "Value to multiply weights by", 0.0f, 10.f);
2387 }
2388
2389 static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op))
2390 {
2391         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2392
2393         vgroup_normalize(ob);
2394
2395         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2396         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2397         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2398
2399         return OPERATOR_FINISHED;
2400 }
2401
2402 void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot)
2403 {
2404         /* identifiers */
2405         ot->name= "Normalize Vertex Group";
2406         ot->idname= "OBJECT_OT_vertex_group_normalize";
2407
2408         /* api callbacks */
2409         ot->poll= vertex_group_poll;
2410         ot->exec= vertex_group_normalize_exec;
2411
2412         /* flags */
2413         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2414 }
2415
2416 static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
2417 {
2418         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2419         int lock_active= RNA_boolean_get(op->ptr,"lock_active");
2420
2421         vgroup_normalize_all(ob, lock_active);
2422
2423         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2424         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2425         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2426
2427         return OPERATOR_FINISHED;
2428 }
2429
2430 void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
2431 {
2432         /* identifiers */
2433         ot->name= "Normalize All Vertex Groups";
2434         ot->idname= "OBJECT_OT_vertex_group_normalize_all";
2435
2436         /* api callbacks */
2437         ot->poll= vertex_group_poll;
2438         ot->exec= vertex_group_normalize_all_exec;
2439
2440         /* flags */
2441         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2442
2443         RNA_def_boolean(ot->srna, "lock_active", TRUE, "Lock Active",
2444                         "Keep the values of the active group while normalizing others");
2445 }
2446
2447 static int vertex_group_fix_exec(bContext *C, wmOperator *op)
2448 {
2449         Object *ob= CTX_data_active_object(C);
2450         Scene *scene= CTX_data_scene(C);
2451         
2452         float distToBe= RNA_float_get(op->ptr, "dist");
2453         float strength= RNA_float_get(op->ptr, "strength");
2454         float cp= RNA_float_get(op->ptr, "accuracy");
2455         ModifierData *md= ob->modifiers.first;
2456
2457         while(md) {
2458                 if(md->type == eModifierType_Mirror && (md->mode&eModifierMode_Realtime)) {
2459                         break;
2460                 }
2461                 md = md->next;
2462         }
2463         
2464         if(md && md->type == eModifierType_Mirror) {
2465                 BKE_report(op->reports, RPT_ERROR_INVALID_CONTEXT, "This operator does not support an active mirror modifier");
2466                 return OPERATOR_CANCELLED;
2467         }
2468         vgroup_fix(scene, ob, distToBe, strength, cp);
2469         
2470         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2471         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2472         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2473         
2474         return OPERATOR_FINISHED;
2475 }
2476
2477 void OBJECT_OT_vertex_group_fix(wmOperatorType *ot)
2478 {
2479         /* identifiers */
2480         ot->name= "Fix Vertex Group Deform";
2481         ot->idname= "OBJECT_OT_vertex_group_fix";
2482         ot->description= "Modify the position of selected vertices by changing only their respective "
2483                          "groups' weights (this tool may be slow for many vertices)";
2484         
2485         /* api callbacks */
2486         ot->poll= vertex_group_poll;
2487         ot->exec= vertex_group_fix_exec;
2488         
2489         /* flags */
2490         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2491         RNA_def_float(ot->srna, "dist", 0.0f, -FLT_MAX, FLT_MAX, "Distance", "The distance to move to", -10.0f, 10.0f);
2492         RNA_def_float(ot->srna, "strength", 1.f, -2.0f, FLT_MAX, "Strength",
2493                       "The distance moved can be changed by this multiplier", -2.0f, 2.0f);
2494         RNA_def_float(ot->srna, "accuracy", 1.0f, 0.05f, FLT_MAX, "Change Sensitivity",
2495                       "Change the amount weights are altered with each iteration: lower values are slower", 0.05f, 1.f);
2496 }
2497
2498
2499 static int vertex_group_lock_exec(bContext *C, wmOperator *op)
2500 {
2501         Object *ob= CTX_data_active_object(C);
2502
2503         int action = RNA_enum_get(op->ptr, "action");
2504
2505         vgroup_lock_all(ob, action);
2506
2507         return OPERATOR_FINISHED;
2508 }
2509
2510 void OBJECT_OT_vertex_group_lock(wmOperatorType *ot)
2511 {
2512         /* identifiers */
2513         ot->name= "Change the Lock On Vertex Groups";
2514         ot->idname= "OBJECT_OT_vertex_group_lock";
2515
2516         /* api callbacks */
2517         ot->poll= vertex_group_poll;
2518         ot->exec= vertex_group_lock_exec;
2519
2520         /* flags */
2521         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2522
2523         WM_operator_properties_select_all(ot);
2524 }
2525
2526 static int vertex_group_invert_exec(bContext *C, wmOperator *op)
2527 {
2528         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2529         int auto_assign= RNA_boolean_get(op->ptr,"auto_assign");
2530         int auto_remove= RNA_boolean_get(op->ptr,"auto_remove");
2531
2532         vgroup_invert(ob, auto_assign, auto_remove);
2533         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2534         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2535         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2536
2537         return OPERATOR_FINISHED;
2538 }
2539
2540 void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
2541 {
2542         /* identifiers */
2543         ot->name= "Invert Vertex Group";
2544         ot->idname= "OBJECT_OT_vertex_group_invert";
2545
2546         /* api callbacks */
2547         ot->poll= vertex_group_poll;
2548         ot->exec= vertex_group_invert_exec;
2549
2550         /* flags */
2551         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2552
2553         RNA_def_boolean(ot->srna, "auto_assign", TRUE, "Add Weights",
2554                         "Add verts from groups that have zero weight before inverting");
2555         RNA_def_boolean(ot->srna, "auto_remove", TRUE, "Remove Weights",
2556                         "Remove verts from groups that have zero weight after inverting");
2557 }
2558
2559
2560 static int vertex_group_blend_exec(bContext *C, wmOperator *UNUSED(op))
2561 {
2562         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2563
2564         vgroup_blend(ob);
2565
2566         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2567         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2568         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2569
2570         return OPERATOR_FINISHED;
2571 }
2572
2573 void OBJECT_OT_vertex_group_blend(wmOperatorType *ot)
2574 {
2575         /* identifiers */
2576         ot->name= "Blend Vertex Group";
2577         ot->idname= "OBJECT_OT_vertex_group_blend";
2578         ot->description= "";
2579
2580         /* api callbacks */
2581         ot->poll= vertex_group_poll;
2582         ot->exec= vertex_group_blend_exec;
2583
2584         /* flags */
2585         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2586 }
2587
2588
2589 static int vertex_group_clean_exec(bContext *C, wmOperator *op)
2590 {
2591         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2592
2593         float limit= RNA_float_get(op->ptr,"limit");
2594         int all_groups= RNA_boolean_get(op->ptr,"all_groups");
2595         int keep_single= RNA_boolean_get(op->ptr,"keep_single");
2596
2597         if(all_groups)  vgroup_clean_all(ob, limit, keep_single);
2598         else                    vgroup_clean(ob, limit, keep_single);
2599
2600         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2601         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2602         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2603
2604         return OPERATOR_FINISHED;
2605 }
2606
2607 void OBJECT_OT_vertex_group_clean(wmOperatorType *ot)
2608 {
2609         /* identifiers */
2610         ot->name= "Clean Vertex Group";
2611         ot->idname= "OBJECT_OT_vertex_group_clean";
2612         ot->description= "Remove Vertex Group assignments which aren't required";
2613
2614         /* api callbacks */
2615         ot->poll= vertex_group_poll;
2616         ot->exec= vertex_group_clean_exec;
2617
2618         /* flags */
2619         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2620
2621         RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, 1.0, "Limit", "Remove weights under this limit", 0.001f, 0.99f);
2622         RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Clean all vertex groups");
2623         RNA_def_boolean(ot->srna, "keep_single", FALSE, "Keep Single", "Keep verts assigned to at least one group when cleaning");
2624 }
2625
2626
2627 static int vertex_group_mirror_exec(bContext *C, wmOperator *op)
2628 {
2629         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2630
2631         ED_vgroup_mirror(ob,
2632                          RNA_boolean_get(op->ptr,"mirror_weights"),
2633                          RNA_boolean_get(op->ptr,"flip_group_names"),
2634                          RNA_boolean_get(op->ptr,"all_groups"));
2635
2636         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2637         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2638         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2639
2640         return OPERATOR_FINISHED;
2641 }
2642
2643 void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot)
2644 {
2645         /* identifiers */
2646         ot->name= "Mirror Vertex Group";
2647         ot->idname= "OBJECT_OT_vertex_group_mirror";
2648         ot->description= "Mirror all vertex groups, flip weights and/or names, editing only selected vertices, "
2649                          "flipping when both sides are selected otherwise copy from unselected";
2650
2651         /* api callbacks */
2652         ot->poll= vertex_group_poll;
2653         ot->exec= vertex_group_mirror_exec;
2654
2655         /* flags */
2656         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2657
2658         /* properties */
2659         RNA_def_boolean(ot->srna, "mirror_weights", TRUE, "Mirror Weights", "Mirror weights");
2660         RNA_def_boolean(ot->srna, "flip_group_names", TRUE, "Flip Groups", "Flip vertex group names");
2661         RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Mirror all vertex groups weights");
2662
2663 }
2664
2665 static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op))
2666 {
2667         Scene *scene= CTX_data_scene(C);
2668         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2669         Base *base;
2670         int retval= OPERATOR_CANCELLED;
2671
2672         for(base=scene->base.first; base; base= base->next) {
2673                 if(base->object->type==ob->type) {
2674                         if(base->object!=ob && base->object->data==ob->data) {
2675                                 BLI_freelistN(&base->object->defbase);
2676                                 BLI_duplicatelist(&base->object->defbase, &ob->defbase);
2677                                 base->object->actdef= ob->actdef;
2678
2679                                 DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
2680                                 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, base->object);
2681                                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
2682
2683                                 retval = OPERATOR_FINISHED;
2684                         }
2685                 }
2686         }
2687
2688         return retval;
2689 }
2690
2691 void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot)
2692 {
2693         /* identifiers */
2694         ot->name= "Copy Vertex Groups to Linked";
2695         ot->idname= "OBJECT_OT_vertex_group_copy_to_linked";
2696         ot->description= "Copy Vertex Groups to all users of the same Geometry data";
2697
2698         /* api callbacks */
2699         ot->poll= vertex_group_poll;
2700         ot->exec= vertex_group_copy_to_linked_exec;
2701
2702         /* flags */
2703         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2704 }
2705
2706 static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
2707 {
2708         Object *obact= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2709         int change= 0;
2710         int fail= 0;
2711
2712         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects)
2713         {
2714                 if(obact != ob) {
2715                         if(ED_vgroup_copy_array(ob, obact)) change++;
2716                         else                                fail++;
2717                 }
2718         }
2719         CTX_DATA_END;
2720
2721         if((change == 0 && fail == 0) || fail) {
2722                 BKE_reportf(op->reports, RPT_ERROR,
2723                             "Copy to VGroups to Selected warning done %d, failed %d, object data must have matching indicies",
2724                             change, fail);
2725         }
2726
2727         return OPERATOR_FINISHED;
2728 }
2729
2730
2731 void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot)
2732 {
2733         /* identifiers */
2734         ot->name= "Copy Vertex Group to Selected";
2735         ot->idname= "OBJECT_OT_vertex_group_copy_to_selected";
2736         ot->description= "Copy Vertex Groups to other selected objects with matching indices";
2737
2738         /* api callbacks */
2739         ot->poll= vertex_group_poll;
2740         ot->exec= vertex_group_copy_to_selected_exec;
2741
2742         /* flags */
2743         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2744 }
2745
2746 static EnumPropertyItem vgroup_items[]= {
2747         {0, NULL, 0, NULL, NULL}};
2748
2749 static int set_active_group_exec(bContext *C, wmOperator *op)
2750 {
2751         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2752         int nr= RNA_enum_get(op->ptr, "group");
2753
2754         ob->actdef= nr+1;
2755         BLI_assert(ob->actdef >= 0);
2756
2757         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2758         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2759
2760         return OPERATOR_FINISHED;
2761 }
2762
2763 static EnumPropertyItem *vgroup_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
2764 {       
2765         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2766         EnumPropertyItem tmp = {0, "", 0, "", ""};
2767         EnumPropertyItem *item= NULL;
2768         bDeformGroup *def;
2769         int a, totitem= 0;
2770         
2771         if(!ob)
2772                 return vgroup_items;
2773         
2774         for(a=0, def=ob->defbase.first; def; def=def->next, a++) {
2775                 tmp.value= a;
2776                 tmp.icon= ICON_GROUP_VERTEX;
2777                 tmp.identifier= def->name;
2778                 tmp.name= def->name;
2779                 RNA_enum_item_add(&item, &totitem, &tmp);
2780         }
2781
2782         RNA_enum_item_end(&item, &totitem);
2783         *free= 1;
2784
2785         return item;
2786 }
2787
2788 void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
2789 {
2790         PropertyRNA *prop;
2791
2792         /* identifiers */
2793         ot->name= "Set Active Vertex Group";
2794         ot->idname= "OBJECT_OT_vertex_group_set_active";
2795         ot->description= "Set the active vertex group";
2796
2797         /* api callbacks */
2798         ot->poll= vertex_group_poll;
2799         ot->exec= set_active_group_exec;
2800         ot->invoke= WM_menu_invoke;
2801
2802         /* flags */
2803         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2804
2805         /* properties */
2806         prop= RNA_def_enum(ot->srna, "group", vgroup_items, 0, "Group", "Vertex group to set as active");
2807         RNA_def_enum_funcs(prop, vgroup_itemf);
2808         ot->prop= prop;
2809 }
2810
2811 /*creates the name_array parameter for vgroup_do_remap, call this before fiddling
2812   with the order of vgroups then call vgroup_do_remap after*/
2813 static char *vgroup_init_remap(Object *ob)
2814 {
2815         bDeformGroup *def;
2816         int def_tot = BLI_countlist(&ob->defbase);
2817         char *name_array= MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * def_tot, "sort vgroups");
2818         char *name;
2819
2820         name= name_array;
2821         for(def = ob->defbase.first; def; def=def->next) {
2822                 BLI_strncpy(name, def->name, MAX_VGROUP_NAME);
2823                 name += MAX_VGROUP_NAME;
2824         }
2825
2826         return name_array;
2827 }
2828
2829 static int vgroup_do_remap(Object *ob, char *name_array, wmOperator *op)
2830 {
2831         MDeformVert *dvert= NULL;
2832         bDeformGroup *def;
2833         int def_tot = BLI_countlist(&ob->defbase);
2834         int *sort_map_update= MEM_mallocN(sizeof(int) * (def_tot + 1), "sort vgroups"); /* needs a dummy index at the start*/
2835         int *sort_map= sort_map_update + 1;
2836         char *name;
2837         int i;
2838
2839         name= name_array;
2840         for(def= ob->defbase.first, i=0; def; def=def->next, i++){
2841                 sort_map[i]= BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name));
2842                 name += MAX_VGROUP_NAME;
2843
2844                 BLI_assert(sort_map[i] != -1);
2845         }
2846
2847         if(ob->mode == OB_MODE_EDIT) {
2848                 if(ob->type==OB_MESH) {
2849                         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
2850                         BMIter iter;
2851                         BMVert *eve;
2852
2853                         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2854                                 dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
2855                                 if(dvert && dvert->totweight){
2856                                         defvert_remap(dvert, sort_map);
2857                                 }
2858                         }
2859                 }
2860                 else {
2861                         BKE_report(op->reports, RPT_ERROR, "Editmode lattice isnt supported yet");
2862                         MEM_freeN(sort_map_update);
2863                         return OPERATOR_CANCELLED;
2864                 }
2865         }
2866         else {
2867                 int dvert_tot=0;
2868
2869                 ED_vgroup_give_array(ob->data, &dvert, &dvert_tot);
2870
2871                 /*create as necassary*/
2872                 while(dvert && dvert_tot--) {
2873                         if(dvert->totweight)
2874                                 defvert_remap(dvert, sort_map);
2875                         dvert++;
2876                 }
2877         }
2878
2879         /* update users */
2880         for(i=0; i<def_tot; i++)
2881                 sort_map[i]++;
2882
2883         sort_map_update[0]= 0;
2884         vgroup_remap_update_users(ob, sort_map_update);
2885
2886         ob->actdef= sort_map_update[ob->actdef];
2887         BLI_assert(ob->actdef >= 0);
2888         
2889         MEM_freeN(sort_map_update);
2890
2891         return OPERATOR_FINISHED;
2892 }
2893
2894 static int vgroup_sort(void *def_a_ptr, void *def_b_ptr)
2895 {
2896         bDeformGroup *def_a= (bDeformGroup *)def_a_ptr;
2897         bDeformGroup *def_b= (bDeformGroup *)def_b_ptr;
2898
2899         return BLI_natstrcmp(def_a->name, def_b->name);
2900 }
2901
2902 static int vertex_group_sort_exec(bContext *C, wmOperator *op)
2903 {
2904         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2905         char *name_array;
2906         int ret;
2907
2908         /*init remapping*/
2909         name_array = vgroup_init_remap(ob);
2910
2911         /*sort vgroup names*/
2912         BLI_sortlist(&ob->defbase, vgroup_sort);
2913
2914         /*remap vgroup data to map to correct names*/
2915         ret = vgroup_do_remap(ob, name_array, op);
2916
2917         if (ret != OPERATOR_CANCELLED) {
2918                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2919                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2920         }
2921
2922         if (name_array) MEM_freeN(name_array);
2923
2924         return ret;
2925 }
2926
2927 void OBJECT_OT_vertex_group_sort(wmOperatorType *ot)
2928 {
2929         ot->name= "Sort Vertex Groups";
2930         ot->idname= "OBJECT_OT_vertex_group_sort";
2931         ot->description= "Sorts vertex groups alphabetically";
2932
2933         /* api callbacks */
2934         ot->poll= vertex_group_poll;
2935         ot->exec= vertex_group_sort_exec;
2936
2937         /* flags */
2938         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2939 }
2940
2941 static int vgroup_move_exec(bContext *C, wmOperator *op)
2942 {
2943         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2944         bDeformGroup *def;
2945         char *name_array;
2946         int dir= RNA_enum_get(op->ptr, "direction"), ret;
2947
2948         def = BLI_findlink(&ob->defbase, ob->actdef - 1);
2949         if (!def) {
2950                 return OPERATOR_CANCELLED;
2951         }
2952
2953         name_array = vgroup_init_remap(ob);
2954
2955         if (dir == 1) { /*up*/
2956                 void *prev = def->prev;
2957
2958                 BLI_remlink(&ob->defbase, def);
2959                 BLI_insertlinkbefore(&ob->defbase, prev, def);
2960         } else { /*down*/
2961                 void *next = def->next;
2962
2963                 BLI_remlink(&ob->defbase, def);
2964                 BLI_insertlinkafter(&ob->defbase, next, def);
2965         }
2966
2967         ret = vgroup_do_remap(ob, name_array, op);
2968
2969         if (name_array) MEM_freeN(name_array);
2970
2971         if (ret != OPERATOR_CANCELLED) {
2972                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2973                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2974         }
2975
2976         return ret;
2977 }
2978
2979 void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
2980 {
2981         static EnumPropertyItem vgroup_slot_move[] = {
2982                 {1, "UP", 0, "Up", ""},
2983                 {-1, "DOWN", 0, "Down", ""},
2984                 {0, NULL, 0, NULL, NULL}
2985         };
2986
2987         /* identifiers */
2988         ot->name= "Move Vertex Group";
2989         ot->idname= "OBJECT_OT_vertex_group_move";
2990
2991         /* api callbacks */
2992         ot->poll= vertex_group_poll;
2993         ot->exec= vgroup_move_exec;
2994
2995         /* flags */
2996         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2997
2998         RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
2999 }