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