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