svn merge ^/trunk/blender -r42521:42550
[blender.git] / source / blender / editors / object / object_vgroup.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/object/object_vgroup.c
29  *  \ingroup edobj
30  */
31
32
33 #include <string.h>
34 #include <stddef.h>
35 #include <math.h>
36 #include <assert.h>
37
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_cloth_types.h"
41 #include "DNA_curve_types.h"
42 #include "DNA_lattice_types.h"
43 #include "DNA_meshdata_types.h"
44 #include "DNA_mesh_types.h"
45 #include "DNA_modifier_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_object_force.h"
48 #include "DNA_scene_types.h"
49 #include "DNA_particle_types.h"
50
51 #include "BLI_math.h"
52 #include "BLI_blenlib.h"
53 #include "BLI_cellalloc.h"
54 #include "BLI_utildefines.h"
55
56 #include "BKE_context.h"
57 #include "BKE_customdata.h"
58 #include "BKE_deform.h"
59 #include "BKE_depsgraph.h"
60 #include "BKE_global.h"
61 #include "BKE_mesh.h"
62 #include "BKE_tessmesh.h"
63 #include "BKE_report.h"
64 #include "BKE_DerivedMesh.h"
65
66 #include "RNA_access.h"
67 #include "RNA_define.h"
68
69 #include "WM_api.h"
70 #include "WM_types.h"
71
72 #include "ED_mesh.h"
73
74 #include "UI_resources.h"
75
76 #include "object_intern.h"
77
78 /************************ Exported Functions **********************/
79 static void vgroup_remap_update_users(Object *ob, int *map);
80 static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *defgroup);
81 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg);
82 static void vgroup_delete_all(Object *ob);
83
84 static Lattice *vgroup_edit_lattice(Object *ob)
85 {
86         Lattice *lt= ob->data;
87         BLI_assert(ob->type==OB_LATTICE);
88         return (lt->editlatt)? lt->editlatt->latt: lt;
89 }
90
91 int ED_vgroup_object_is_edit_mode(Object *ob)
92 {
93         if(ob->type == OB_MESH)
94                 return (((Mesh*)ob->data)->edit_btmesh != NULL);
95         else if(ob->type == OB_LATTICE)
96                 return (((Lattice*)ob->data)->editlatt != NULL);
97
98         return 0;
99 }
100
101 bDeformGroup *ED_vgroup_add_name(Object *ob, const char *name)
102 {
103         bDeformGroup *defgroup;
104
105         if(!ob || !OB_TYPE_SUPPORT_VGROUP(ob->type))
106                 return NULL;
107         
108         defgroup = MEM_callocN(sizeof(bDeformGroup), "add deformGroup");
109
110         BLI_strncpy(defgroup->name, name, sizeof(defgroup->name));
111
112         BLI_addtail(&ob->defbase, defgroup);
113         defgroup_unique_name(defgroup, ob);
114
115         ob->actdef = BLI_countlist(&ob->defbase);
116
117         return defgroup;
118 }
119
120 bDeformGroup *ED_vgroup_add(Object *ob) 
121 {
122         return ED_vgroup_add_name(ob, "Group");
123 }
124
125 void ED_vgroup_delete(Object *ob, bDeformGroup *defgroup) 
126 {
127         bDeformGroup *dg = (bDeformGroup *)ob->defbase.first;
128
129         while (dg) {
130                 if (dg == defgroup)
131                         break;
132                 dg = dg->next;
133         }
134
135         if (dg == NULL)
136                 return;
137
138         if(ED_vgroup_object_is_edit_mode(ob))
139                 vgroup_delete_edit_mode(ob, dg);
140         else
141                 vgroup_delete_object_mode(ob, dg);
142 }
143
144 void ED_vgroup_clear(Object *ob)
145 {
146         bDeformGroup *dg= (bDeformGroup *)ob->defbase.first;
147         int edit_mode= ED_vgroup_object_is_edit_mode(ob);
148
149         while (dg) {
150                 bDeformGroup *next_dg= dg->next;
151
152                 if(edit_mode)
153                         vgroup_delete_edit_mode(ob, dg);
154                 else
155                         vgroup_delete_object_mode(ob, dg);
156
157                 dg= next_dg;
158         }
159 }
160
161 int ED_vgroup_data_create(ID *id)
162 {
163         /* create deform verts */
164
165         if(GS(id->name)==ID_ME) {
166                 Mesh *me= (Mesh *)id;
167                 me->dvert= CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert);
168                 return TRUE;
169         }
170         else if(GS(id->name)==ID_LT) {
171                 Lattice *lt= (Lattice *)id;
172                 lt->dvert= MEM_callocN(sizeof(MDeformVert)*lt->pntsu*lt->pntsv*lt->pntsw, "lattice deformVert");
173                 return TRUE;
174         }
175         else {
176                 return FALSE;
177         }
178 }
179
180 static int ED_vgroup_give_parray(ID *id, MDeformVert ***dvert_arr, int *dvert_tot)
181 {
182         *dvert_tot = 0;
183         *dvert_arr = NULL;
184
185         if(id) {
186                 switch(GS(id->name)) {
187                         case ID_ME:
188                         {
189                                 Mesh *me = (Mesh *)id;
190
191                                 if(me->edit_btmesh) {
192                                         BMEditMesh *em = me->edit_btmesh;
193                                         BMIter iter;
194                                         BMVert *eve;
195                                         int i;
196
197                                         if (!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) {
198                                                 return 0;
199                                         }
200
201                                         i = em->bm->totvert;
202
203                                         *dvert_arr= MEM_mallocN(sizeof(void*)*i, "vgroup parray from me");
204                                         *dvert_tot = i;
205
206                                         i = 0;
207                                         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
208                                                 (*dvert_arr)[i] = CustomData_em_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
209                                                 i++;
210                                         }
211
212                                         return 1;
213                                 }
214                                 else if(me->dvert) {
215                                         int i;
216
217                                         *dvert_tot= me->totvert;
218                                         *dvert_arr= MEM_mallocN(sizeof(void*)*me->totvert, "vgroup parray from me");
219
220                                         for (i=0; i<me->totvert; i++) {
221                                                 (*dvert_arr)[i] = me->dvert + i;
222                                         }
223
224                                         return 1;
225                                 }
226                                 else {
227                                         return 0;
228                                 }
229                         }
230                         case ID_LT:
231                         {
232                                 int i=0;
233
234                                 Lattice *lt= (Lattice *)id;
235                                 lt= (lt->editlatt)? lt->editlatt->latt: lt;
236
237                                 if(lt->dvert) {
238                                         *dvert_tot= lt->pntsu*lt->pntsv*lt->pntsw;
239                                         *dvert_arr= MEM_mallocN(sizeof(void*)*(*dvert_tot), "vgroup parray from me");
240
241                                         for (i=0; i<*dvert_tot; i++) {
242                                                 (*dvert_arr)[i] = lt->dvert + i;
243                                         }
244
245                                         return 1;
246                                 }
247                                 else {
248                                         return 0;
249                                 }
250                         }
251                 }
252         }
253
254         return 0;
255 }
256
257 /* returns true if the id type supports weights */
258 int ED_vgroup_give_array(ID *id, MDeformVert **dvert_arr, int *dvert_tot)
259 {
260         if(id) {
261                 switch(GS(id->name)) {
262                         case ID_ME:
263                         {
264                                 Mesh *me = (Mesh *)id;
265                                 *dvert_arr= me->dvert;
266                                 *dvert_tot= me->totvert;
267                                 return TRUE;
268                         }
269                         case ID_LT:
270                         {
271                                 Lattice *lt= (Lattice *)id;
272                                 lt= (lt->editlatt)? lt->editlatt->latt: lt;
273                                 *dvert_arr= lt->dvert;
274                                 *dvert_tot= lt->pntsu*lt->pntsv*lt->pntsw;
275                                 return TRUE;
276                         }
277                 }
278         }
279
280         *dvert_arr= NULL;
281         *dvert_tot= 0;
282         return FALSE;
283 }
284
285 /* matching index only */
286 int ED_vgroup_copy_array(Object *ob, Object *ob_from)
287 {
288         MDeformVert **dvert_array_from, **dvf;
289         MDeformVert **dvert_array, **dv;
290         int dvert_tot_from;
291         int dvert_tot;
292         int i;
293         int defbase_tot_from= BLI_countlist(&ob_from->defbase);
294         int defbase_tot= 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(defbase_tot_from < defbase_tot) {
322                 /* correct vgroup indices because the number of vgroups is being reduced. */
323                 int *remap= MEM_mallocN(sizeof(int) * (defbase_tot + 1), "ED_vgroup_copy_array");
324                 for(i=0; i<=defbase_tot_from; i++) remap[i]= i;
325                 for(; i<=defbase_tot; 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, defbase_tot= BLI_countlist(&ob->defbase) + 1;
1818         int *map= MEM_mallocN(sizeof(int) * defbase_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<defbase_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         /* redo operator will fail in this case because vertex groups aren't stored
2203            in local edit mode stack and toggling "all" property will lead to
2204            all groups deleted without way to restore them (see [#29527], sergey) */
2205         ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO;
2206
2207         /* properties */
2208         RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups");
2209 }
2210
2211 static int vertex_group_assign_exec(bContext *C, wmOperator *op)
2212 {
2213         ToolSettings *ts= CTX_data_tool_settings(C);
2214         Object *ob= CTX_data_edit_object(C);
2215
2216         if(RNA_boolean_get(op->ptr, "new"))
2217                 ED_vgroup_add(ob);
2218
2219         vgroup_assign_verts(ob, ts->vgroup_weight);
2220         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2221         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2222         
2223         return OPERATOR_FINISHED;
2224 }
2225
2226 void OBJECT_OT_vertex_group_assign(wmOperatorType *ot)
2227 {
2228         /* identifiers */
2229         ot->name= "Assign Vertex Group";
2230         ot->idname= "OBJECT_OT_vertex_group_assign";
2231         
2232         /* api callbacks */
2233         ot->poll= vertex_group_poll_edit;
2234         ot->exec= vertex_group_assign_exec;
2235
2236         /* flags */
2237         /* redo operator will fail in this case because vertex group assignment
2238            isn't stored in local edit mode stack and toggling "new" property will
2239            lead to creating plenty of new veretx groups (see [#29527], sergey) */
2240         ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO;
2241
2242         /* properties */
2243         RNA_def_boolean(ot->srna, "new", 0, "New", "Assign vertex to new vertex group");
2244 }
2245
2246 static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
2247 {
2248         Object *ob= CTX_data_edit_object(C);
2249
2250         if(RNA_boolean_get(op->ptr, "all"))
2251                 vgroup_remove_verts(ob, 0);
2252         else {
2253                 bDeformGroup *dg= BLI_findlink(&ob->defbase, ob->actdef - 1);
2254
2255                 if(dg == NULL) {
2256                         return OPERATOR_CANCELLED;
2257                 }
2258
2259                 vgroup_active_remove_verts(ob, FALSE, dg);
2260         }
2261
2262         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2263         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2264
2265         return OPERATOR_FINISHED;
2266 }
2267
2268 void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot)
2269 {
2270         /* identifiers */
2271         ot->name= "Remove from Vertex Group";
2272         ot->idname= "OBJECT_OT_vertex_group_remove_from";
2273
2274         /* api callbacks */
2275         ot->poll= vertex_group_poll_edit;
2276         ot->exec= vertex_group_remove_from_exec;
2277
2278         /* flags */
2279         /* redo operator will fail in this case because vertex groups ssignment
2280            isn't stored in local edit mode stack and toggling "all" property will lead to
2281            removing vertices from all groups (see [#29527], sergey) */
2282         ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO;
2283
2284         /* properties */
2285         RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups");
2286 }
2287
2288 static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
2289 {
2290         Object *ob= CTX_data_edit_object(C);
2291
2292         if(!ob || ob->id.lib)
2293                 return OPERATOR_CANCELLED;
2294
2295         vgroup_select_verts(ob, 1);
2296         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
2297
2298         return OPERATOR_FINISHED;
2299 }
2300
2301 void OBJECT_OT_vertex_group_select(wmOperatorType *ot)
2302 {
2303         /* identifiers */
2304         ot->name= "Select Vertex Group";
2305         ot->idname= "OBJECT_OT_vertex_group_select";
2306
2307         /* api callbacks */
2308         ot->poll= vertex_group_poll_edit;
2309         ot->exec= vertex_group_select_exec;
2310
2311         /* flags */
2312         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2313 }
2314
2315 static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
2316 {
2317         Object *ob= CTX_data_edit_object(C);
2318
2319         vgroup_select_verts(ob, 0);
2320         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
2321
2322         return OPERATOR_FINISHED;
2323 }
2324
2325 void OBJECT_OT_vertex_group_deselect(wmOperatorType *ot)
2326 {
2327         /* identifiers */
2328         ot->name= "Deselect Vertex Group";
2329         ot->idname= "OBJECT_OT_vertex_group_deselect";
2330
2331         /* api callbacks */
2332         ot->poll= vertex_group_poll_edit;
2333         ot->exec= vertex_group_deselect_exec;
2334
2335         /* flags */
2336         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2337 }
2338
2339 static int vertex_group_copy_exec(bContext *C, wmOperator *UNUSED(op))
2340 {
2341         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2342
2343         vgroup_duplicate(ob);
2344         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2345         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2346         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2347
2348         return OPERATOR_FINISHED;
2349 }
2350
2351 void OBJECT_OT_vertex_group_copy(wmOperatorType *ot)
2352 {
2353         /* identifiers */
2354         ot->name= "Copy Vertex Group";
2355         ot->idname= "OBJECT_OT_vertex_group_copy";
2356
2357         /* api callbacks */
2358         ot->poll= vertex_group_poll;
2359         ot->exec= vertex_group_copy_exec;
2360
2361         /* flags */
2362         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2363 }
2364
2365 static int vertex_group_levels_exec(bContext *C, wmOperator *op)
2366 {
2367         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2368         
2369         float offset= RNA_float_get(op->ptr,"offset");
2370         float gain= RNA_float_get(op->ptr,"gain");
2371         
2372         vgroup_levels(ob, offset, gain);
2373         
2374         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2375         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2376         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2377         
2378         return OPERATOR_FINISHED;
2379 }
2380
2381 void OBJECT_OT_vertex_group_levels(wmOperatorType *ot)
2382 {
2383         /* identifiers */
2384         ot->name= "Vertex Group Levels";
2385         ot->idname= "OBJECT_OT_vertex_group_levels";
2386         
2387         /* api callbacks */
2388         ot->poll= vertex_group_poll;
2389         ot->exec= vertex_group_levels_exec;
2390         
2391         /* flags */
2392         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2393         
2394         RNA_def_float(ot->srna, "offset", 0.f, -1.0, 1.0, "Offset", "Value to add to weights", -1.0f, 1.f);
2395         RNA_def_float(ot->srna, "gain", 1.f, 0.f, FLT_MAX, "Gain", "Value to multiply weights by", 0.0f, 10.f);
2396 }
2397
2398 static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op))
2399 {
2400         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2401
2402         vgroup_normalize(ob);
2403
2404         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2405         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2406         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2407
2408         return OPERATOR_FINISHED;
2409 }
2410
2411 void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot)
2412 {
2413         /* identifiers */
2414         ot->name= "Normalize Vertex Group";
2415         ot->idname= "OBJECT_OT_vertex_group_normalize";
2416
2417         /* api callbacks */
2418         ot->poll= vertex_group_poll;
2419         ot->exec= vertex_group_normalize_exec;
2420
2421         /* flags */
2422         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2423 }
2424
2425 static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
2426 {
2427         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2428         int lock_active= RNA_boolean_get(op->ptr,"lock_active");
2429
2430         vgroup_normalize_all(ob, lock_active);
2431
2432         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2433         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2434         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2435
2436         return OPERATOR_FINISHED;
2437 }
2438
2439 void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
2440 {
2441         /* identifiers */
2442         ot->name= "Normalize All Vertex Groups";
2443         ot->idname= "OBJECT_OT_vertex_group_normalize_all";
2444
2445         /* api callbacks */
2446         ot->poll= vertex_group_poll;
2447         ot->exec= vertex_group_normalize_all_exec;
2448
2449         /* flags */
2450         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2451
2452         RNA_def_boolean(ot->srna, "lock_active", TRUE, "Lock Active",
2453                         "Keep the values of the active group while normalizing others");
2454 }
2455
2456 static int vertex_group_fix_exec(bContext *C, wmOperator *op)
2457 {
2458         Object *ob= CTX_data_active_object(C);
2459         Scene *scene= CTX_data_scene(C);
2460         
2461         float distToBe= RNA_float_get(op->ptr, "dist");
2462         float strength= RNA_float_get(op->ptr, "strength");
2463         float cp= RNA_float_get(op->ptr, "accuracy");
2464         ModifierData *md= ob->modifiers.first;
2465
2466         while(md) {
2467                 if(md->type == eModifierType_Mirror && (md->mode&eModifierMode_Realtime)) {
2468                         break;
2469                 }
2470                 md = md->next;
2471         }
2472         
2473         if(md && md->type == eModifierType_Mirror) {
2474                 BKE_report(op->reports, RPT_ERROR_INVALID_CONTEXT, "This operator does not support an active mirror modifier");
2475                 return OPERATOR_CANCELLED;
2476         }
2477         vgroup_fix(scene, ob, distToBe, strength, cp);
2478         
2479         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2480         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2481         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2482         
2483         return OPERATOR_FINISHED;
2484 }
2485
2486 void OBJECT_OT_vertex_group_fix(wmOperatorType *ot)
2487 {
2488         /* identifiers */
2489         ot->name= "Fix Vertex Group Deform";
2490         ot->idname= "OBJECT_OT_vertex_group_fix";
2491         ot->description= "Modify the position of selected vertices by changing only their respective "
2492                          "groups' weights (this tool may be slow for many vertices)";
2493         
2494         /* api callbacks */
2495         ot->poll= vertex_group_poll;
2496         ot->exec= vertex_group_fix_exec;
2497         
2498         /* flags */
2499         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2500         RNA_def_float(ot->srna, "dist", 0.0f, -FLT_MAX, FLT_MAX, "Distance", "The distance to move to", -10.0f, 10.0f);
2501         RNA_def_float(ot->srna, "strength", 1.f, -2.0f, FLT_MAX, "Strength",
2502                       "The distance moved can be changed by this multiplier", -2.0f, 2.0f);
2503         RNA_def_float(ot->srna, "accuracy", 1.0f, 0.05f, FLT_MAX, "Change Sensitivity",
2504                       "Change the amount weights are altered with each iteration: lower values are slower", 0.05f, 1.f);
2505 }
2506
2507
2508 static int vertex_group_lock_exec(bContext *C, wmOperator *op)
2509 {
2510         Object *ob= CTX_data_active_object(C);
2511
2512         int action = RNA_enum_get(op->ptr, "action");
2513
2514         vgroup_lock_all(ob, action);
2515
2516         return OPERATOR_FINISHED;
2517 }
2518
2519 void OBJECT_OT_vertex_group_lock(wmOperatorType *ot)
2520 {
2521         /* identifiers */
2522         ot->name= "Change the Lock On Vertex Groups";
2523         ot->idname= "OBJECT_OT_vertex_group_lock";
2524
2525         /* api callbacks */
2526         ot->poll= vertex_group_poll;
2527         ot->exec= vertex_group_lock_exec;
2528
2529         /* flags */
2530         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2531
2532         WM_operator_properties_select_all(ot);
2533 }
2534
2535 static int vertex_group_invert_exec(bContext *C, wmOperator *op)
2536 {
2537         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2538         int auto_assign= RNA_boolean_get(op->ptr,"auto_assign");
2539         int auto_remove= RNA_boolean_get(op->ptr,"auto_remove");
2540
2541         vgroup_invert(ob, auto_assign, auto_remove);
2542         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2543         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2544         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2545
2546         return OPERATOR_FINISHED;
2547 }
2548
2549 void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
2550 {
2551         /* identifiers */
2552         ot->name= "Invert Vertex Group";
2553         ot->idname= "OBJECT_OT_vertex_group_invert";
2554
2555         /* api callbacks */
2556         ot->poll= vertex_group_poll;
2557         ot->exec= vertex_group_invert_exec;
2558
2559         /* flags */
2560         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2561
2562         RNA_def_boolean(ot->srna, "auto_assign", TRUE, "Add Weights",
2563                         "Add verts from groups that have zero weight before inverting");
2564         RNA_def_boolean(ot->srna, "auto_remove", TRUE, "Remove Weights",
2565                         "Remove verts from groups that have zero weight after inverting");
2566 }
2567
2568
2569 static int vertex_group_blend_exec(bContext *C, wmOperator *UNUSED(op))
2570 {
2571         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2572
2573         vgroup_blend(ob);
2574
2575         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2576         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2577         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2578
2579         return OPERATOR_FINISHED;
2580 }
2581
2582 void OBJECT_OT_vertex_group_blend(wmOperatorType *ot)
2583 {
2584         /* identifiers */
2585         ot->name= "Blend Vertex Group";
2586         ot->idname= "OBJECT_OT_vertex_group_blend";
2587         ot->description= "";
2588
2589         /* api callbacks */
2590         ot->poll= vertex_group_poll;
2591         ot->exec= vertex_group_blend_exec;
2592
2593         /* flags */
2594         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2595 }
2596
2597
2598 static int vertex_group_clean_exec(bContext *C, wmOperator *op)
2599 {
2600         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2601
2602         float limit= RNA_float_get(op->ptr,"limit");
2603         int all_groups= RNA_boolean_get(op->ptr,"all_groups");
2604         int keep_single= RNA_boolean_get(op->ptr,"keep_single");
2605
2606         if(all_groups)  vgroup_clean_all(ob, limit, keep_single);
2607         else                    vgroup_clean(ob, limit, keep_single);
2608
2609         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2610         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2611         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2612
2613         return OPERATOR_FINISHED;
2614 }
2615
2616 void OBJECT_OT_vertex_group_clean(wmOperatorType *ot)
2617 {
2618         /* identifiers */
2619         ot->name= "Clean Vertex Group";
2620         ot->idname= "OBJECT_OT_vertex_group_clean";
2621         ot->description= "Remove Vertex Group assignments which aren't required";
2622
2623         /* api callbacks */
2624         ot->poll= vertex_group_poll;
2625         ot->exec= vertex_group_clean_exec;
2626
2627         /* flags */
2628         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2629
2630         RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, 1.0, "Limit", "Remove weights under this limit", 0.001f, 0.99f);
2631         RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Clean all vertex groups");
2632         RNA_def_boolean(ot->srna, "keep_single", FALSE, "Keep Single", "Keep verts assigned to at least one group when cleaning");
2633 }
2634
2635
2636 static int vertex_group_mirror_exec(bContext *C, wmOperator *op)
2637 {
2638         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2639
2640         ED_vgroup_mirror(ob,
2641                          RNA_boolean_get(op->ptr,"mirror_weights"),
2642                          RNA_boolean_get(op->ptr,"flip_group_names"),
2643                          RNA_boolean_get(op->ptr,"all_groups"));
2644
2645         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2646         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2647         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2648
2649         return OPERATOR_FINISHED;
2650 }
2651
2652 void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot)
2653 {
2654         /* identifiers */
2655         ot->name= "Mirror Vertex Group";
2656         ot->idname= "OBJECT_OT_vertex_group_mirror";
2657         ot->description= "Mirror all vertex groups, flip weights and/or names, editing only selected vertices, "
2658                          "flipping when both sides are selected otherwise copy from unselected";
2659
2660         /* api callbacks */
2661         ot->poll= vertex_group_poll;
2662         ot->exec= vertex_group_mirror_exec;
2663
2664         /* flags */
2665         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2666
2667         /* properties */
2668         RNA_def_boolean(ot->srna, "mirror_weights", TRUE, "Mirror Weights", "Mirror weights");
2669         RNA_def_boolean(ot->srna, "flip_group_names", TRUE, "Flip Groups", "Flip vertex group names");
2670         RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Mirror all vertex groups weights");
2671
2672 }
2673
2674 static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op))
2675 {
2676         Scene *scene= CTX_data_scene(C);
2677         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2678         Base *base;
2679         int retval= OPERATOR_CANCELLED;
2680
2681         for(base=scene->base.first; base; base= base->next) {
2682                 if(base->object->type==ob->type) {
2683                         if(base->object!=ob && base->object->data==ob->data) {
2684                                 BLI_freelistN(&base->object->defbase);
2685                                 BLI_duplicatelist(&base->object->defbase, &ob->defbase);
2686                                 base->object->actdef= ob->actdef;
2687
2688                                 DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
2689                                 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, base->object);
2690                                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
2691
2692                                 retval = OPERATOR_FINISHED;
2693                         }
2694                 }
2695         }
2696
2697         return retval;
2698 }
2699
2700 void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot)
2701 {
2702         /* identifiers */
2703         ot->name= "Copy Vertex Groups to Linked";
2704         ot->idname= "OBJECT_OT_vertex_group_copy_to_linked";
2705         ot->description= "Copy Vertex Groups to all users of the same Geometry data";
2706
2707         /* api callbacks */
2708         ot->poll= vertex_group_poll;
2709         ot->exec= vertex_group_copy_to_linked_exec;
2710
2711         /* flags */
2712         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2713 }
2714
2715 static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
2716 {
2717         Object *obact= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2718         int change= 0;
2719         int fail= 0;
2720
2721         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects)
2722         {
2723                 if(obact != ob) {
2724                         if(ED_vgroup_copy_array(ob, obact)) change++;
2725                         else                                fail++;
2726                 }
2727         }
2728         CTX_DATA_END;
2729
2730         if((change == 0 && fail == 0) || fail) {
2731                 BKE_reportf(op->reports, RPT_ERROR,
2732                             "Copy to VGroups to Selected warning done %d, failed %d, object data must have matching indicies",
2733                             change, fail);
2734         }
2735
2736         return OPERATOR_FINISHED;
2737 }
2738
2739
2740 void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot)
2741 {
2742         /* identifiers */
2743         ot->name= "Copy Vertex Group to Selected";
2744         ot->idname= "OBJECT_OT_vertex_group_copy_to_selected";
2745         ot->description= "Copy Vertex Groups to other selected objects with matching indices";
2746
2747         /* api callbacks */
2748         ot->poll= vertex_group_poll;
2749         ot->exec= vertex_group_copy_to_selected_exec;
2750
2751         /* flags */
2752         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2753 }
2754
2755 static EnumPropertyItem vgroup_items[]= {
2756         {0, NULL, 0, NULL, NULL}};
2757
2758 static int set_active_group_exec(bContext *C, wmOperator *op)
2759 {
2760         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2761         int nr= RNA_enum_get(op->ptr, "group");
2762
2763         ob->actdef= nr+1;
2764         BLI_assert(ob->actdef >= 0);
2765
2766         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2767         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2768
2769         return OPERATOR_FINISHED;
2770 }
2771
2772 static EnumPropertyItem *vgroup_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
2773 {       
2774         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2775         EnumPropertyItem tmp = {0, "", 0, "", ""};
2776         EnumPropertyItem *item= NULL;
2777         bDeformGroup *def;
2778         int a, totitem= 0;
2779         
2780         if(!ob)
2781                 return vgroup_items;
2782         
2783         for(a=0, def=ob->defbase.first; def; def=def->next, a++) {
2784                 tmp.value= a;
2785                 tmp.icon= ICON_GROUP_VERTEX;
2786                 tmp.identifier= def->name;
2787                 tmp.name= def->name;
2788                 RNA_enum_item_add(&item, &totitem, &tmp);
2789         }
2790
2791         RNA_enum_item_end(&item, &totitem);
2792         *free= 1;
2793
2794         return item;
2795 }
2796
2797 void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
2798 {
2799         PropertyRNA *prop;
2800
2801         /* identifiers */
2802         ot->name= "Set Active Vertex Group";
2803         ot->idname= "OBJECT_OT_vertex_group_set_active";
2804         ot->description= "Set the active vertex group";
2805
2806         /* api callbacks */
2807         ot->poll= vertex_group_poll;
2808         ot->exec= set_active_group_exec;
2809         ot->invoke= WM_menu_invoke;
2810
2811         /* flags */
2812         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2813
2814         /* properties */
2815         prop= RNA_def_enum(ot->srna, "group", vgroup_items, 0, "Group", "Vertex group to set as active");
2816         RNA_def_enum_funcs(prop, vgroup_itemf);
2817         ot->prop= prop;
2818 }
2819
2820 /*creates the name_array parameter for vgroup_do_remap, call this before fiddling
2821   with the order of vgroups then call vgroup_do_remap after*/
2822 static char *vgroup_init_remap(Object *ob)
2823 {
2824         bDeformGroup *def;
2825         int defbase_tot = BLI_countlist(&ob->defbase);
2826         char *name_array= MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups");
2827         char *name;
2828
2829         name= name_array;
2830         for(def = ob->defbase.first; def; def=def->next) {
2831                 BLI_strncpy(name, def->name, MAX_VGROUP_NAME);
2832                 name += MAX_VGROUP_NAME;
2833         }
2834
2835         return name_array;
2836 }
2837
2838 static int vgroup_do_remap(Object *ob, char *name_array, wmOperator *op)
2839 {
2840         MDeformVert *dvert= NULL;
2841         bDeformGroup *def;
2842         int defbase_tot = BLI_countlist(&ob->defbase);
2843         int *sort_map_update= MEM_mallocN(sizeof(int) * (defbase_tot + 1), "sort vgroups"); /* needs a dummy index at the start*/
2844         int *sort_map= sort_map_update + 1;
2845         char *name;
2846         int i;
2847
2848         name= name_array;
2849         for(def= ob->defbase.first, i=0; def; def=def->next, i++){
2850                 sort_map[i]= BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name));
2851                 name += MAX_VGROUP_NAME;
2852
2853                 BLI_assert(sort_map[i] != -1);
2854         }
2855
2856         if(ob->mode == OB_MODE_EDIT) {
2857                 if(ob->type==OB_MESH) {
2858                         BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
2859                         BMIter iter;
2860                         BMVert *eve;
2861
2862                         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2863                                 dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
2864                                 if(dvert && dvert->totweight){
2865                                         defvert_remap(dvert, sort_map, defbase_tot);
2866                                 }
2867                         }
2868                 }
2869                 else {
2870                         BKE_report(op->reports, RPT_ERROR, "Editmode lattice isnt supported yet");
2871                         MEM_freeN(sort_map_update);
2872                         return OPERATOR_CANCELLED;
2873                 }
2874         }
2875         else {
2876                 int dvert_tot=0;
2877
2878                 ED_vgroup_give_array(ob->data, &dvert, &dvert_tot);
2879
2880                 /*create as necassary*/
2881                 while(dvert && dvert_tot--) {
2882                         if(dvert->totweight)
2883                                 defvert_remap(dvert, sort_map, defbase_tot);
2884                         dvert++;
2885                 }
2886         }
2887
2888         /* update users */
2889         for(i=0; i<defbase_tot; i++)
2890                 sort_map[i]++;
2891
2892         sort_map_update[0]= 0;
2893         vgroup_remap_update_users(ob, sort_map_update);
2894
2895         ob->actdef= sort_map_update[ob->actdef];
2896         BLI_assert(ob->actdef >= 0);
2897         
2898         MEM_freeN(sort_map_update);
2899
2900         return OPERATOR_FINISHED;
2901 }
2902
2903 static int vgroup_sort(void *def_a_ptr, void *def_b_ptr)
2904 {
2905         bDeformGroup *def_a= (bDeformGroup *)def_a_ptr;
2906         bDeformGroup *def_b= (bDeformGroup *)def_b_ptr;
2907
2908         return BLI_natstrcmp(def_a->name, def_b->name);
2909 }
2910
2911 static int vertex_group_sort_exec(bContext *C, wmOperator *op)
2912 {
2913         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2914         char *name_array;
2915         int ret;
2916
2917         /*init remapping*/
2918         name_array = vgroup_init_remap(ob);
2919
2920         /*sort vgroup names*/
2921         BLI_sortlist(&ob->defbase, vgroup_sort);
2922
2923         /*remap vgroup data to map to correct names*/
2924         ret = vgroup_do_remap(ob, name_array, op);
2925
2926         if (ret != OPERATOR_CANCELLED) {
2927                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2928                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2929         }
2930
2931         if (name_array) MEM_freeN(name_array);
2932
2933         return ret;
2934 }
2935
2936 void OBJECT_OT_vertex_group_sort(wmOperatorType *ot)
2937 {
2938         ot->name= "Sort Vertex Groups";
2939         ot->idname= "OBJECT_OT_vertex_group_sort";
2940         ot->description= "Sorts vertex groups alphabetically";
2941
2942         /* api callbacks */
2943         ot->poll= vertex_group_poll;
2944         ot->exec= vertex_group_sort_exec;
2945
2946         /* flags */
2947         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2948 }
2949
2950 static int vgroup_move_exec(bContext *C, wmOperator *op)
2951 {
2952         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2953         bDeformGroup *def;
2954         char *name_array;
2955         int dir= RNA_enum_get(op->ptr, "direction"), ret;
2956
2957         def = BLI_findlink(&ob->defbase, ob->actdef - 1);
2958         if (!def) {
2959                 return OPERATOR_CANCELLED;
2960         }
2961
2962         name_array = vgroup_init_remap(ob);
2963
2964         if (dir == 1) { /*up*/
2965                 void *prev = def->prev;
2966
2967                 BLI_remlink(&ob->defbase, def);
2968                 BLI_insertlinkbefore(&ob->defbase, prev, def);
2969         } else { /*down*/
2970                 void *next = def->next;
2971
2972                 BLI_remlink(&ob->defbase, def);
2973                 BLI_insertlinkafter(&ob->defbase, next, def);
2974         }
2975
2976         ret = vgroup_do_remap(ob, name_array, op);
2977
2978         if (name_array) MEM_freeN(name_array);
2979
2980         if (ret != OPERATOR_CANCELLED) {
2981                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2982                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2983         }
2984
2985         return ret;
2986 }
2987
2988 void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
2989 {
2990         static EnumPropertyItem vgroup_slot_move[] = {
2991                 {1, "UP", 0, "Up", ""},
2992                 {-1, "DOWN", 0, "Down", ""},
2993                 {0, NULL, 0, NULL, NULL}
2994         };
2995
2996         /* identifiers */
2997         ot->name= "Move Vertex Group";
2998         ot->idname= "OBJECT_OT_vertex_group_move";
2999
3000         /* api callbacks */
3001         ot->poll= vertex_group_poll;
3002         ot->exec= vgroup_move_exec;
3003
3004         /* flags */
3005         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3006
3007         RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
3008 }