4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
30 /** \file blender/editors/object/object_vgroup.c
40 #include "MEM_guardedalloc.h"
42 #include "DNA_cloth_types.h"
43 #include "DNA_curve_types.h"
44 #include "DNA_lattice_types.h"
45 #include "DNA_meshdata_types.h"
46 #include "DNA_modifier_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_object_force.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_particle_types.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_editVert.h"
55 #include "BLI_utildefines.h"
57 #include "BKE_context.h"
58 #include "BKE_customdata.h"
59 #include "BKE_deform.h"
60 #include "BKE_depsgraph.h"
61 #include "BKE_global.h"
63 #include "BKE_report.h"
64 #include "BKE_DerivedMesh.h"//Jason
66 #include "RNA_access.h"
67 #include "RNA_define.h"
74 #include "UI_resources.h"
76 #include "object_intern.h"
78 /************************ Exported Functions **********************/
79 static void vgroup_remap_update_users(Object *ob, int *map);
80 static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *defgroup);
81 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg);
82 static void vgroup_delete_all(Object *ob);
84 static Lattice *vgroup_edit_lattice(Object *ob)
86 Lattice *lt= ob->data;
87 BLI_assert(ob->type==OB_LATTICE);
88 return (lt->editlatt)? lt->editlatt->latt: lt;
91 int ED_vgroup_object_is_edit_mode(Object *ob)
93 if(ob->type == OB_MESH)
94 return (((Mesh*)ob->data)->edit_mesh != NULL);
95 else if(ob->type == OB_LATTICE)
96 return (((Lattice*)ob->data)->editlatt != NULL);
101 bDeformGroup *ED_vgroup_add_name(Object *ob, const char *name)
103 bDeformGroup *defgroup;
105 if(!ob || !ELEM(ob->type, OB_MESH, OB_LATTICE))
108 defgroup = MEM_callocN(sizeof(bDeformGroup), "add deformGroup");
110 BLI_strncpy(defgroup->name, name, sizeof(defgroup->name));
112 BLI_addtail(&ob->defbase, defgroup);
113 defgroup_unique_name(defgroup, ob);
115 ob->actdef = BLI_countlist(&ob->defbase);
120 bDeformGroup *ED_vgroup_add(Object *ob)
122 return ED_vgroup_add_name(ob, "Group");
125 void ED_vgroup_delete(Object *ob, bDeformGroup *defgroup)
127 bDeformGroup *dg = (bDeformGroup *)ob->defbase.first;
138 if(ED_vgroup_object_is_edit_mode(ob))
139 vgroup_delete_edit_mode(ob, dg);
141 vgroup_delete_object_mode(ob, dg);
144 int ED_vgroup_data_create(ID *id)
146 /* create deform verts */
148 if(GS(id->name)==ID_ME) {
149 Mesh *me= (Mesh *)id;
150 me->dvert= CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert);
153 else if(GS(id->name)==ID_LT) {
154 Lattice *lt= (Lattice *)id;
155 lt->dvert= MEM_callocN(sizeof(MDeformVert)*lt->pntsu*lt->pntsv*lt->pntsw, "lattice deformVert");
163 static int ED_vgroup_give_parray(ID *id, MDeformVert ***dvert_arr, int *dvert_tot)
169 switch(GS(id->name)) {
172 Mesh *me = (Mesh *)id;
175 EditMesh *em = me->edit_mesh;
179 if (!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
183 i= BLI_countlist(&em->verts);
185 *dvert_arr= MEM_mallocN(sizeof(void*)*i, "vgroup parray from me");
189 for (eve=em->verts.first; eve; eve=eve->next, i++) {
190 (*dvert_arr)[i] = CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
198 *dvert_tot= me->totvert;
199 *dvert_arr= MEM_mallocN(sizeof(void*)*me->totvert, "vgroup parray from me");
201 for (i=0; i<me->totvert; i++) {
202 (*dvert_arr)[i] = me->dvert + i;
215 Lattice *lt= (Lattice *)id;
216 lt= (lt->editlatt)? lt->editlatt->latt: lt;
219 *dvert_tot= lt->pntsu*lt->pntsv*lt->pntsw;
220 *dvert_arr= MEM_mallocN(sizeof(void*)*(*dvert_tot), "vgroup parray from me");
222 for (i=0; i<*dvert_tot; i++) {
223 (*dvert_arr)[i] = lt->dvert + i;
238 /* returns true if the id type supports weights */
239 int ED_vgroup_give_array(ID *id, MDeformVert **dvert_arr, int *dvert_tot)
242 switch(GS(id->name)) {
245 Mesh *me = (Mesh *)id;
246 *dvert_arr= me->dvert;
247 *dvert_tot= me->totvert;
252 Lattice *lt= (Lattice *)id;
253 lt= (lt->editlatt)? lt->editlatt->latt: lt;
254 *dvert_arr= lt->dvert;
255 *dvert_tot= lt->pntsu*lt->pntsv*lt->pntsw;
266 /* matching index only */
267 int ED_vgroup_copy_array(Object *ob, Object *ob_from)
269 MDeformVert **dvert_array_from, **dvf;
270 MDeformVert **dvert_array, **dv;
274 int totdef_from= BLI_countlist(&ob_from->defbase);
275 int totdef= BLI_countlist(&ob->defbase);
276 short new_vgroup= FALSE;
278 ED_vgroup_give_parray(ob_from->data, &dvert_array_from, &dvert_tot_from);
279 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
281 if((dvert_array == NULL) && (dvert_array_from != NULL) && ED_vgroup_data_create(ob->data)) {
282 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
286 if(ob==ob_from || dvert_tot==0 || (dvert_tot != dvert_tot_from) || dvert_array_from==NULL || dvert_array==NULL) {
287 if (dvert_array) MEM_freeN(dvert_array);
288 if (dvert_array_from) MEM_freeN(dvert_array_from);
290 if(new_vgroup == TRUE) {
291 /* free the newly added vgroup since it wasn't compatible */
292 vgroup_delete_all(ob);
298 BLI_freelistN(&ob->defbase);
299 BLI_duplicatelist(&ob->defbase, &ob_from->defbase);
300 ob->actdef= ob_from->actdef;
302 if(totdef_from < totdef) {
303 /* correct vgroup indices because the number of vgroups is being reduced. */
304 int *remap= MEM_mallocN(sizeof(int) * (totdef + 1), "ED_vgroup_copy_array");
305 for(i=0; i<=totdef_from; i++) remap[i]= i;
306 for(; i<=totdef; i++) remap[i]= 0; /* can't use these, so disable */
308 vgroup_remap_update_users(ob, remap);
312 dvf= dvert_array_from;
315 for(i=0; i<dvert_tot; i++, dvf++, dv++) {
317 MEM_freeN((*dv)->dw);
322 (*dv)->dw= MEM_dupallocN((*dv)->dw);
325 MEM_freeN(dvert_array);
326 MEM_freeN(dvert_array_from);
331 /* for mesh in object mode
332 lattice can be in editmode */
333 static void ED_vgroup_nr_vert_remove(Object *ob, int def_nr, int vertnum)
335 /* This routine removes the vertex from the deform
336 * group with number def_nr.
338 * This routine is meant to be fast, so it is the
339 * responsibility of the calling routine to:
340 * a) test whether ob is non-NULL
341 * b) test whether ob is a mesh
342 * c) calculate def_nr
345 MDeformWeight *newdw;
346 MDeformVert *dvert= NULL;
349 /* get the deform vertices corresponding to the
352 ED_vgroup_give_array(ob->data, &dvert, &tot);
359 /* for all of the deform weights in the
362 for(i=dvert->totweight - 1 ; i>=0 ; i--){
364 /* if the def_nr is the same as the one
365 * for our weight group then remove it
366 * from this deform vert.
368 if(dvert->dw[i].def_nr == def_nr) {
371 /* if there are still other deform weights
372 * attached to this vert then remove this
373 * deform weight, and reshuffle the others
375 if(dvert->totweight) {
376 newdw = MEM_mallocN(sizeof(MDeformWeight)*(dvert->totweight),
379 memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*i);
380 memcpy(newdw+i, dvert->dw+i+1,
381 sizeof(MDeformWeight)*(dvert->totweight-i));
382 MEM_freeN(dvert->dw);
386 /* if there are no other deform weights
387 * left then just remove the deform weight
390 MEM_freeN(dvert->dw);
399 /* for Mesh in Object mode */
400 /* allows editmode for Lattice */
401 static void ED_vgroup_nr_vert_add(Object *ob, int def_nr, int vertnum, float weight, int assignmode)
403 /* add the vert to the deform group with the
406 MDeformVert *dv= NULL;
407 MDeformWeight *newdw;
411 ED_vgroup_give_array(ob->data, &dv, &tot);
416 /* check that vertnum is valid before trying to get the relevant dvert */
417 if ((vertnum < 0) || (vertnum >= tot))
422 /* Lets first check to see if this vert is
423 * already in the weight group -- if so
426 for(i=0; i<dv->totweight; i++){
428 /* if this weight cooresponds to the
429 * deform group, then add it using
430 * the assign mode provided
432 if(dv->dw[i].def_nr == def_nr){
436 dv->dw[i].weight=weight;
439 dv->dw[i].weight+=weight;
440 if(dv->dw[i].weight >= 1.0f)
441 dv->dw[i].weight = 1.0f;
443 case WEIGHT_SUBTRACT:
444 dv->dw[i].weight-=weight;
445 /* if the weight is zero or less then
446 * remove the vert from the deform group
448 if(dv->dw[i].weight <= 0.0f)
449 ED_vgroup_nr_vert_remove(ob, def_nr, vertnum);
456 /* if the vert wasn't in the deform group then
457 * we must take a different form of action ...
461 case WEIGHT_SUBTRACT:
462 /* if we are subtracting then we don't
463 * need to do anything
469 /* if we are doing an additive assignment, then
470 * we need to create the deform weight
472 newdw = MEM_callocN(sizeof(MDeformWeight)*(dv->totweight+1),
475 memcpy(newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
480 dv->dw[dv->totweight].weight=weight;
481 dv->dw[dv->totweight].def_nr=def_nr;
488 /* called while not in editmode */
489 void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
491 /* add the vert to the deform group with the
492 * specified assign mode
496 MDeformVert *dv= NULL;
499 /* get the deform group number, exit if
502 def_nr = defgroup_find_index(ob, dg);
503 if(def_nr < 0) return;
505 /* if there's no deform verts then create some,
507 if(ED_vgroup_give_array(ob->data, &dv, &tot) && dv==NULL)
508 ED_vgroup_data_create(ob->data);
510 /* call another function to do the work
512 ED_vgroup_nr_vert_add(ob, def_nr, vertnum, weight, assignmode);
515 /* mesh object mode, lattice can be in editmode */
516 void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
518 /* This routine removes the vertex from the specified
521 const int def_nr= defgroup_find_index(ob, dg);
525 ED_vgroup_nr_vert_remove(ob, def_nr, vertnum);
528 static float get_vert_def_nr(Object *ob, int def_nr, int vertnum)
530 MDeformVert *dvert= NULL;
535 /* get the deform vertices corresponding to the vertnum */
536 if(ob->type==OB_MESH) {
540 eve= BLI_findlink(&me->edit_mesh->verts, vertnum);
544 dvert= CustomData_em_get(&me->edit_mesh->vdata, eve->data, CD_MDEFORMVERT);
548 if(vertnum >= me->totvert) {
554 else if(ob->type==OB_LATTICE) {
555 Lattice *lt= vgroup_edit_lattice(ob);
558 if(vertnum >= lt->pntsu*lt->pntsv*lt->pntsw) {
570 for(i=dvert->totweight-1 ; i>=0 ; i--)
571 if(dvert->dw[i].def_nr == def_nr)
572 return dvert->dw[i].weight;
577 float ED_vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum)
583 def_nr = defgroup_find_index(ob, dg);
584 if(def_nr < 0) return -1;
586 return get_vert_def_nr(ob, def_nr, vertnum);
589 void ED_vgroup_select_by_name(Object *ob, const char *name)
590 { /* note: ob->actdef==0 signals on painting to create a new one, if a bone in posemode is selected */
591 ob->actdef= defgroup_name_index(ob, name) + 1;
594 /********************** Operator Implementations *********************/
596 /* only in editmode */
597 static void vgroup_select_verts(Object *ob, int select)
603 if(ob->type == OB_MESH) {
605 EditMesh *em = BKE_mesh_get_editmesh(me);
607 for(eve=em->verts.first; eve; eve=eve->next){
608 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
610 if(dvert && dvert->totweight){
611 for(i=0; i<dvert->totweight; i++){
612 if(dvert->dw[i].def_nr == (ob->actdef-1)){
614 if(select) eve->f |= SELECT;
615 else eve->f &= ~SELECT;
622 /* this has to be called, because this function operates on vertices only */
623 if(select) EM_select_flush(em); // vertices to edges/faces
624 else EM_deselect_flush(em);
626 BKE_mesh_end_editmesh(me, em);
628 else if(ob->type == OB_LATTICE) {
629 Lattice *lt= vgroup_edit_lattice(ob);
637 tot= lt->pntsu*lt->pntsv*lt->pntsw;
638 for(a=0, bp= lt->def; a<tot; a++, bp++, dvert++) {
639 for(i=0; i<dvert->totweight; i++){
640 if(dvert->dw[i].def_nr == (ob->actdef-1)) {
641 if(select) bp->f1 |= SELECT;
642 else bp->f1 &= ~SELECT;
652 static void vgroup_duplicate(Object *ob)
654 bDeformGroup *dg, *cdg;
655 char name[sizeof(dg->name)];
656 MDeformWeight *org, *cpy;
657 MDeformVert *dvert, **dvert_array=NULL;
658 int i, idg, icdg, dvert_tot=0;
660 dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
664 if(!strstr(dg->name, "_copy")) {
665 BLI_snprintf(name, sizeof(name), "%s_copy", dg->name);
668 BLI_snprintf(name, sizeof(name), "%s", dg->name);
671 cdg = defgroup_duplicate(dg);
672 strcpy(cdg->name, name);
673 defgroup_unique_name(cdg, ob);
675 BLI_addtail(&ob->defbase, cdg);
677 idg = (ob->actdef-1);
678 ob->actdef = BLI_countlist(&ob->defbase);
679 icdg = (ob->actdef-1);
681 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
686 for(i = 0; i < dvert_tot; i++) {
687 dvert = dvert_array[i];
688 org = defvert_find_index(dvert, idg);
690 float weight = org->weight;
691 /* defvert_verify_index re-allocs org so need to store the weight first */
692 cpy = defvert_verify_index(dvert, icdg);
693 cpy->weight = weight;
697 MEM_freeN(dvert_array);
700 static void vgroup_normalize(Object *ob)
704 MDeformVert *dvert, **dvert_array=NULL;
705 int i, def_nr, dvert_tot=0;
708 MVert *mvert = me->mvert;
709 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
711 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
713 dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
716 float weight_max = 0.0f;
718 def_nr= ob->actdef-1;
720 for(i = 0; i < dvert_tot; i++) {
722 if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
726 dvert = dvert_array[i];
727 dw = defvert_find_index(dvert, def_nr);
729 weight_max = MAX2(dw->weight, weight_max);
733 if(weight_max > 0.0f) {
734 for(i = 0; i < dvert_tot; i++) {
736 if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
740 dvert = dvert_array[i];
741 dw = defvert_find_index(dvert, def_nr);
743 dw->weight /= weight_max;
745 /* incase of division errors with very low weights */
746 CLAMP(dw->weight, 0.0f, 1.0f);
752 if (dvert_array) MEM_freeN(dvert_array);
755 /* This adds the indices of vertices to a list if they are not already present
756 It returns the number that it added (0-2)
757 It relies on verts having -1 for unassigned indices
759 static int tryToAddVerts(int *verts, int length, int a, int b) {
760 char containsA = FALSE;
761 char containsB = FALSE;
764 for(i = 0; i < length && (!containsA || !containsB); i++) {
767 } else if(verts[i] == b) {
769 } else if(verts[i] == -1) {
774 } else if(!containsB){
784 /* This finds all of the vertices connected to vert by an edge
785 and returns an array of indices of size count
787 count is an int passed by reference so it can be assigned the value of the length here.
789 static int* getSurroundingVerts(Mesh *me, int vert, int *count) {
793 MFace *mf = me->mface;
794 int totface = me->totface;
797 for(i = 0; i < totface; i++, mf++) {
798 if(vert == mf->v1 || vert == mf->v2 || vert == mf->v3 || (mf->v4 &&vert == mf->v4)) {
805 tverts = MEM_mallocN(sizeof(int)*length, "tempSurroundingVerts");
807 for(i = 0; i < length; i++) {
810 for(i = 0; i < totface; i++, mf++) {
819 } else if(mf->v2 == vert) {
822 } else if(mf->v3 == vert) {
829 } else if (mf->v4 && mf->v4 == vert){
835 found += tryToAddVerts(tverts, length, a, b);
838 verts = MEM_mallocN(sizeof(int)* found, "surroundingVerts");
839 for(i = 0; i < found; i++) {
840 verts[i] = tverts[i];
848 /* get a single point in space by averaging a point cloud (vectors of size 3)
849 coord is the place the average is stored, points is the point cloud, count is the number of points in the cloud
851 static void getSingleCoordinate(MVert *points, int count, float coord[3]) {
854 for(i = 0; i < count; i++) {
855 add_v3_v3(coord, points[i].co);
857 mul_v3_fl(coord, 1.0f/count);
860 /* find the closest point on a plane to another point and store it in dst */
861 /* coord is a point on the plane */
862 /* point is the point that you want the nearest of */
863 /* norm is the plane's normal, and d is the last number in the plane equation 0 = ax + by + cz + d */
864 static void getNearestPointOnPlane(const float norm[3], const float coord[3], const float point[3], float dst_r[3])
869 sub_v3_v3v3(temp, point, coord);
870 dotprod= dot_v3v3(temp, norm);
872 dst_r[0] = point[0] - (norm[0] * dotprod);
873 dst_r[1] = point[1] - (norm[1] * dotprod);
874 dst_r[2] = point[2] - (norm[2] * dotprod);
877 /* distance of two vectors a and b of size length */
878 static float distance(float* a, float *b, int length) {
881 for(i = 0; i < length; i++) {
882 sum += (b[i]-a[i])*(b[i]-a[i]);
887 /* given a plane and a start and end position,
888 compute the amount of vertical distance relative to the plane and store it in dists,
889 then get the horizontal and vertical change and store them in changes
891 static void getVerticalAndHorizontalChange(float *norm, float d, float *coord, float *start, float distToStart, float *end, float (*changes)[2], float *dists, int index) {
893 // D = (a*x0 + b*y0 +c*z0 +d)
894 float projA[3] = {0}, projB[3] = {0};
896 getNearestPointOnPlane(norm, coord, start, projA);
897 getNearestPointOnPlane(norm, coord, end, projB);
898 // (vertical and horizontal refer to the plane's y and xz respectively)
900 dists[index] = norm[0]*end[0] + norm[1]*end[1] + norm[2]*end[2] + d;
902 changes[index][0] = dists[index] - distToStart;
903 //printf("vc %f %f\n", distance(end, projB, 3)-distance(start, projA, 3), changes[index][0]);
905 changes[index][1] = distance(projA, projB, 3);
908 // I need the derived mesh to be forgotten so the positions are recalculated with weight changes (see dm_deform_recalc)
909 static void dm_deform_clear(DerivedMesh *dm, Object *ob) {
910 if(ob->derivedDeform && (ob->derivedDeform)==dm) {
911 ob->derivedDeform->needsFree = 1;
912 ob->derivedDeform->release(ob->derivedDeform);
913 ob->derivedDeform = NULL;
921 // recalculate the deformation
922 static DerivedMesh* dm_deform_recalc(Scene *scene, Object *ob) {
923 return mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
926 /* by changing nonzero weights, try to move a vertex in me->mverts with index 'index' to distToBe distance away from the provided plane
927 strength can change distToBe so that it moves towards distToBe by that percentage
928 cp changes how much the weights are adjusted to check the distance
930 index is the index of the vertex being moved
931 norm and d are the plane's properties for the equation: ax + by + cz + d = 0
932 coord is a point on the plane
934 static void moveCloserToDistanceFromPlane(Scene *scene, Object *ob, Mesh *me, int index, float norm[3], float coord[3], float d, float distToBe, float strength, float cp) {
938 MDeformVert *dvert = me->dvert+index;
939 int totweight = dvert->totweight;
941 float oldPos[3] = {0};
944 float (*changes)[2] = MEM_mallocN(sizeof(float *)*totweight*2, "vertHorzChange");
945 float *dists = MEM_mallocN(sizeof(float)*totweight, "distance");
946 int *upDown = MEM_callocN(sizeof(int)*totweight, "upDownTracker");// track if up or down moved it closer for each bone
947 int *dwIndices = MEM_callocN(sizeof(int)*totweight, "dwIndexTracker");
953 float originalDistToBe = distToBe;
956 dm = dm_deform_recalc(scene, ob);
957 dm->getVert(dm, index, &m);
961 distToStart = norm[0]*oldPos[0] + norm[1]*oldPos[1] + norm[2]*oldPos[2] + d;
963 if(distToBe == originalDistToBe) {
964 distToBe += distToStart - distToStart*strength;
966 for(i = 0; i < totweight; i++) {
973 dists[i] = distToStart;
976 for(k = 0; k < 2; k++) {
978 dm_deform_clear(dm, ob); dm = NULL;
986 if(dw->weight == oldw) {
989 dists[i] = distToStart;
995 dm = dm_deform_recalc(scene, ob);
996 dm->getVert(dm, index, &m);
997 getVerticalAndHorizontalChange(norm, d, coord, oldPos, distToStart, m.co, changes, dists, i);
1004 if(fabs(dist - distToBe) < fabs(dists[i] - distToBe)) {
1012 if(fabs(dists[i] - distToBe) > fabs(distToStart - distToBe)) {
1015 dists[i] = distToStart;
1020 // sort the changes by the vertical change
1021 for(k = 0; k < totweight; k++) {
1025 for(i = k+1; i < totweight; i++) {
1028 if(fabs(dist) > fabs(dists[i])) {
1033 if(bestIndex != k) {
1035 upDown[k] = upDown[bestIndex];
1036 upDown[bestIndex] = ti;
1039 dwIndices[k] = dwIndices[bestIndex];
1040 dwIndices[bestIndex] = ti;
1043 changes[k][0] = changes[bestIndex][0];
1044 changes[bestIndex][0] = tf;
1047 changes[k][1] = changes[bestIndex][1];
1048 changes[bestIndex][1] = tf;
1051 dists[k] = dists[bestIndex];
1052 dists[bestIndex] = tf;
1056 // find the best change with an acceptable horizontal change
1057 for(i = 0; i < totweight; i++) {
1058 if(fabs(changes[i][0]) > fabs(changes[i][1]*2.0f)) {
1063 if(bestIndex != -1) {
1065 // it is a good place to stop if it tries to move the opposite direction
1066 // (relative to the plane) of last time
1067 if(lastIndex != -1) {
1068 if(wasUp != upDown[bestIndex]) {
1072 lastIndex = bestIndex;
1073 wasUp = upDown[bestIndex];
1074 dw = (dvert->dw+dwIndices[bestIndex]);
1076 if(upDown[bestIndex]) {
1081 if(dw->weight > 1) {
1084 if(oldw == dw->weight) {
1088 dm_deform_clear(dm, ob); dm = NULL;
1091 }while(wasChange && (distToStart-distToBe)/fabs(distToStart-distToBe) == (dists[bestIndex]-distToBe)/fabs(dists[bestIndex]-distToBe));
1095 MEM_freeN(dwIndices);
1098 /* this is used to try to smooth a surface by only adjusting the nonzero weights of a vertex
1099 but it could be used to raise or lower an existing 'bump.' */
1100 static void vgroup_fix(Scene *scene, Object *ob, float distToBe, float strength, float cp)
1104 Mesh *me = ob->data;
1105 MVert *mvert = me->mvert;
1106 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1108 for(i = 0; i < me->totvert && mvert; i++, mvert++) {
1110 if(use_vert_sel && (mvert->flag & SELECT)) {
1113 if((verts = getSurroundingVerts(me, i, &count))) {
1115 MVert *p = MEM_callocN(sizeof(MVert)*(count), "deformedPoints");
1118 DerivedMesh *dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
1119 for(k = 0; k < count; k++) {
1120 dm->getVert(dm, verts[k], &m);
1125 float d /*, dist */ /* UNUSED */, mag;
1126 float coord[3] = {0};
1127 float norm[3] = {0};
1128 getSingleCoordinate(p, count, coord);
1129 dm->getVert(dm, i, &m);
1130 norm[0] = m.co[0]-coord[0];
1131 norm[1] = m.co[1]-coord[1];
1132 norm[2] = m.co[2]-coord[2];
1133 mag = sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]);
1134 if(mag) {// zeros fix
1135 mul_v3_fl(norm, 1.0f/mag);
1137 d = -norm[0]*coord[0] -norm[1]*coord[1] -norm[2]*coord[2];
1138 /* dist = (norm[0]*m.co[0] + norm[1]*m.co[1] + norm[2]*m.co[2] + d); */ /* UNUSED */
1139 moveCloserToDistanceFromPlane(scene, ob, me, i, norm, coord, d, distToBe, strength, cp);
1150 static void vgroup_levels(Object *ob, float offset, float gain)
1154 MDeformVert *dvert, **dvert_array=NULL;
1155 int i, def_nr, dvert_tot=0;
1157 Mesh *me = ob->data;
1158 MVert *mvert = me->mvert;
1159 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1161 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1163 dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
1166 def_nr= ob->actdef-1;
1168 for(i = 0; i < dvert_tot; i++) {
1170 if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
1174 dvert = dvert_array[i];
1175 dw = defvert_find_index(dvert, def_nr);
1177 dw->weight = gain * (dw->weight + offset);
1179 CLAMP(dw->weight, 0.0f, 1.0f);
1184 if (dvert_array) MEM_freeN(dvert_array);
1187 /* TODO - select between groups */
1188 static void vgroup_normalize_all(Object *ob, int lock_active)
1190 MDeformWeight *dw, *dw_act;
1191 MDeformVert *dvert, **dvert_array=NULL;
1196 Mesh *me = ob->data;
1197 MVert *mvert = me->mvert;
1198 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1200 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1204 int def_nr= ob->actdef-1;
1206 for(i = 0; i < dvert_tot; i++) {
1207 float lock_iweight= 1.0f;
1210 if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
1216 dvert = dvert_array[i];
1218 j= dvert->totweight;
1222 if(dw->def_nr==def_nr) {
1224 lock_iweight = (1.0f - dw_act->weight);
1227 tot_weight += dw->weight;
1232 j= dvert->totweight;
1236 if (dvert->totweight==1) {
1237 dw_act->weight= 1.0f; /* no other weights, set to 1.0 */
1240 if(dw->weight > 0.0f)
1241 dw->weight = (dw->weight / tot_weight) * lock_iweight;
1244 /* incase of division errors with very low weights */
1245 CLAMP(dw->weight, 0.0f, 1.0f);
1251 for(i = 0; i < dvert_tot; i++) {
1254 if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
1259 dvert = dvert_array[i];
1261 j= dvert->totweight;
1264 tot_weight += dw->weight;
1268 j= dvert->totweight;
1271 dw->weight /= tot_weight;
1273 /* incase of division errors with very low weights */
1274 CLAMP(dw->weight, 0.0f, 1.0f);
1281 if (dvert_array) MEM_freeN(dvert_array);
1284 /* Jason was here */
1285 static void vgroup_lock_all(Object *ob, int action)
1289 if(action == SEL_TOGGLE) {
1291 for(dg= ob->defbase.first; dg; dg= dg->next) {
1292 if(dg->flag & DG_LOCK_WEIGHT) {
1293 action= SEL_DESELECT;
1299 for(dg= ob->defbase.first; dg; dg= dg->next) {
1302 dg->flag |= DG_LOCK_WEIGHT;
1305 dg->flag &= ~DG_LOCK_WEIGHT;
1308 dg->flag ^= DG_LOCK_WEIGHT;
1314 static void vgroup_invert(Object *ob, int auto_assign, int auto_remove)
1318 MDeformVert *dvert, **dvert_array=NULL;
1319 int i, def_nr, dvert_tot=0;
1321 Mesh *me = ob->data;
1322 MVert *mvert = me->mvert;
1323 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1325 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1327 dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
1330 def_nr= ob->actdef-1;
1333 for(i = 0; i < dvert_tot; i++) {
1335 if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
1338 dvert = dvert_array[i];
1341 dw= defvert_verify_index(dvert, def_nr);
1343 dw= defvert_find_index(dvert, def_nr);
1347 dw->weight = 1.0f-dw->weight;
1349 if(auto_remove && dw->weight <= 0.0f) {
1350 /* could have a faster function for this */
1351 ED_vgroup_nr_vert_remove(ob, def_nr, i);
1357 if (dvert_array) MEM_freeN(dvert_array);
1360 static void vgroup_blend(Object *ob)
1364 MDeformVert *dvert_array=NULL, *dvert;
1365 int i, def_nr, dvert_tot=0;
1367 EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)ob->data));
1368 // ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
1373 dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
1384 def_nr= ob->actdef-1;
1387 for(eve= em->verts.first; eve; eve= eve->next)
1392 vg_weights= MEM_callocN(sizeof(float)*dvert_tot, "vgroup_blend_f");
1393 vg_users= MEM_callocN(sizeof(int)*dvert_tot, "vgroup_blend_i");
1395 for(eed= em->edges.first; eed; eed= eed->next) {
1396 sel1= eed->v1->f & SELECT;
1397 sel2= eed->v2->f & SELECT;
1400 /* i1 is always the selected one */
1401 if(sel1==TRUE && sel2==FALSE) {
1414 /* TODO, we may want object mode blending */
1415 if(em) dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1416 else dvert= dvert_array+i2;
1418 dw= defvert_find_index(dvert, def_nr);
1421 vg_weights[i1] += dw->weight;
1427 for(eve= em->verts.first; eve; eve= eve->next) {
1428 if(eve->f & SELECT && vg_users[i] > 0) {
1429 /* TODO, we may want object mode blending */
1430 if(em) dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1431 else dvert= dvert_array+i;
1433 dw= defvert_verify_index(dvert, def_nr);
1434 dw->weight= vg_weights[i] / (float)vg_users[i];
1439 MEM_freeN(vg_weights);
1440 MEM_freeN(vg_users);
1444 static void vgroup_clean(Object *ob, float eul, int keep_single)
1448 MDeformVert *dvert, **dvert_array=NULL;
1449 int i, def_nr, dvert_tot=0;
1451 Mesh *me = ob->data;
1452 MVert *mvert = me->mvert;
1453 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1455 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1457 /* only the active group */
1458 dg = BLI_findlink(&ob->defbase, (ob->actdef-1));
1460 def_nr= ob->actdef-1;
1462 for(i = 0; i < dvert_tot; i++) {
1464 if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
1467 dvert = dvert_array[i];
1469 dw= defvert_find_index(dvert, def_nr);
1472 if(dw->weight <= eul)
1473 if(keep_single==FALSE || dvert->totweight > 1)
1474 ED_vgroup_nr_vert_remove(ob, def_nr, i);
1479 if (dvert_array) MEM_freeN(dvert_array);
1482 static void vgroup_clean_all(Object *ob, float eul, int keep_single)
1486 MDeformVert *dvert, **dvert_array=NULL;
1489 Mesh *me = ob->data;
1490 MVert *mvert = me->mvert;
1491 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0;
1493 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot);
1496 for(i = 0; i < dvert_tot; i++) {
1499 if(use_vert_sel && !((mvert+i)->flag & SELECT)) {
1503 dvert = dvert_array[i];
1504 j= dvert->totweight;
1508 if(keep_single && dvert->totweight == 1)
1513 if(dw->weight <= eul)
1514 ED_vgroup_nr_vert_remove(ob, dw->def_nr, i);
1520 if (dvert_array) MEM_freeN(dvert_array);
1524 static void dvert_mirror_op(MDeformVert *dvert, MDeformVert *dvert_mirr,
1525 const char sel, const char sel_mirr,
1526 const int *flip_map,
1527 const short mirror_weights, const short flip_vgroups)
1529 BLI_assert(sel || sel_mirr);
1531 if(sel_mirr && sel) {
1534 SWAP(MDeformVert, *dvert, *dvert_mirr);
1536 defvert_flip(dvert, flip_map);
1537 defvert_flip(dvert_mirr, flip_map);
1541 /* dvert should always be the target */
1543 SWAP(MDeformVert *, dvert, dvert_mirr);
1547 defvert_copy(dvert, dvert_mirr);
1549 defvert_flip(dvert, flip_map);
1554 void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_vgroups)
1556 #define VGROUP_MIRR_OP dvert_mirror_op(dvert, dvert_mirr, sel, sel_mirr, flip_map, mirror_weights, flip_vgroups)
1558 EditVert *eve, *eve_mirr;
1559 MDeformVert *dvert, *dvert_mirr;
1560 short sel, sel_mirr;
1563 if(mirror_weights==0 && flip_vgroups==0)
1566 flip_map= defgroup_flip_map(ob, 0);
1568 /* only the active group */
1569 if(ob->type == OB_MESH) {
1571 EditMesh *em = BKE_mesh_get_editmesh(me);
1574 if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
1575 MEM_freeN(flip_map);
1579 EM_cache_x_mirror_vert(ob, em);
1581 /* Go through the list of editverts and assign them */
1582 for(eve=em->verts.first; eve; eve=eve->next){
1583 if((eve_mirr=eve->tmp.v)) {
1584 sel= eve->f & SELECT;
1585 sel_mirr= eve_mirr->f & SELECT;
1587 if((sel || sel_mirr) && (eve != eve_mirr)) {
1588 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1589 dvert_mirr= CustomData_em_get(&em->vdata, eve_mirr->data, CD_MDEFORMVERT);
1590 if(dvert && dvert_mirr) {
1595 eve->tmp.v= eve_mirr->tmp.v= NULL;
1599 BKE_mesh_end_editmesh(me, em);
1601 else if (ob->type == OB_LATTICE) {
1602 Lattice *lt= ob->data;
1606 /* half but found up odd value */
1608 if(lt->editlatt) lt= lt->editlatt->latt;
1610 if(lt->pntsu == 1 || lt->dvert == NULL) {
1611 MEM_freeN(flip_map);
1615 /* unlike editmesh we know that by only looping over the first hald of
1616 * the 'u' indicies it will cover all points except the middle which is
1617 * ok in this case */
1618 pntsu_half= lt->pntsu / 2;
1620 for(w=0; w<lt->pntsw; w++) {
1621 for(v=0; v<lt->pntsv; v++) {
1622 for(u=0; u<pntsu_half; u++) {
1623 int u_inv= (lt->pntsu - 1) - u;
1625 BPoint *bp, *bp_mirr;
1627 i1= LT_INDEX(lt, u, v, w);
1628 i2= LT_INDEX(lt, u_inv, v, w);
1631 bp_mirr= <->def[i2];
1633 sel= bp->f1 & SELECT;
1634 sel_mirr= bp_mirr->f1 & SELECT;
1636 if(sel || sel_mirr) {
1637 dvert= <->dvert[i1];
1638 dvert_mirr= <->dvert[i2];
1648 MEM_freeN(flip_map);
1650 #undef VGROUP_MIRR_OP
1653 static void vgroup_remap_update_users(Object *ob, int *map)
1655 ExplodeModifierData *emd;
1657 ParticleSystem *psys;
1658 ClothModifierData *clmd;
1659 ClothSimSettings *clsim;
1662 /* these cases don't use names to refer to vertex groups, so when
1663 * they get deleted the numbers get out of sync, this corrects that */
1666 ob->soft->vertgroup= map[ob->soft->vertgroup];
1668 for(md=ob->modifiers.first; md; md=md->next) {
1669 if(md->type == eModifierType_Explode) {
1670 emd= (ExplodeModifierData*)md;
1671 emd->vgroup= map[emd->vgroup];
1673 else if(md->type == eModifierType_Cloth) {
1674 clmd= (ClothModifierData*)md;
1675 clsim= clmd->sim_parms;
1678 clsim->vgroup_mass= map[clsim->vgroup_mass];
1679 clsim->vgroup_bend= map[clsim->vgroup_bend];
1680 clsim->vgroup_struct= map[clsim->vgroup_struct];
1685 for(psys=ob->particlesystem.first; psys; psys=psys->next) {
1686 for(a=0; a<PSYS_TOT_VG; a++)
1687 psys->vgroup[a]= map[psys->vgroup[a]];
1692 static void vgroup_delete_update_users(Object *ob, int id)
1694 int i, tot= BLI_countlist(&ob->defbase) + 1;
1695 int *map= MEM_mallocN(sizeof(int) * tot, "vgroup del");
1698 for(i=1; i<id; i++) map[i]=i;
1699 for(i=id+1; i<tot; i++) map[i]=i-1;
1701 vgroup_remap_update_users(ob, map);
1706 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg)
1708 MDeformVert *dvert_array=NULL;
1709 int i, e, dvert_tot=0;
1710 const int dg_index= BLI_findindex(&ob->defbase, dg);
1712 assert(dg_index > -1);
1714 ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot);
1718 for(i= 0, dvert= dvert_array; i < dvert_tot; i++, dvert++) {
1719 ED_vgroup_vert_remove(ob, dg, i); /* ok if the dg isnt in this dvert, will continue silently */
1722 for(i= 0, dvert= dvert_array; i < dvert_tot; i++, dvert++) {
1723 for(e = 0; e < dvert->totweight; e++) {
1724 if(dvert->dw[e].def_nr > dg_index) {
1725 dvert->dw[e].def_nr--;
1731 vgroup_delete_update_users(ob, dg_index + 1);
1733 /* Remove the group */
1734 BLI_freelinkN(&ob->defbase, dg);
1736 /* Update the active deform index if necessary */
1737 if(ob->actdef > dg_index)
1739 if(ob->actdef < 1 && ob->defbase.first)
1744 /* only in editmode */
1745 /* removes from active defgroup, if allverts==0 only selected vertices */
1746 static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGroup *dg)
1750 MDeformWeight *newdw;
1754 if(ob->type == OB_MESH) {
1756 EditMesh *em = BKE_mesh_get_editmesh(me);
1758 for(eve=em->verts.first; eve; eve=eve->next){
1759 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1761 if(dvert && dvert->dw && ((eve->f & SELECT) || allverts)){
1762 for(i=0; i<dvert->totweight; i++){
1764 eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr);
1767 if(dvert->totweight){
1768 newdw = MEM_mallocN(sizeof(MDeformWeight)*(dvert->totweight), "deformWeight");
1771 memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*i);
1772 memcpy(newdw+i, dvert->dw+i+1, sizeof(MDeformWeight)*(dvert->totweight-i));
1773 MEM_freeN(dvert->dw);
1778 MEM_freeN(dvert->dw);
1786 BKE_mesh_end_editmesh(me, em);
1788 else if(ob->type == OB_LATTICE) {
1789 Lattice *lt= vgroup_edit_lattice(ob);
1793 int a, tot= lt->pntsu*lt->pntsv*lt->pntsw;
1795 for(a=0, bp= lt->def; a<tot; a++, bp++) {
1796 if(allverts || (bp->f1 & SELECT))
1797 ED_vgroup_vert_remove(ob, dg, a);
1803 static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg)
1806 const int dg_index= BLI_findindex(&ob->defbase, dg);
1808 assert(dg_index > -1);
1810 /* Make sure that no verts are using this group */
1811 vgroup_active_remove_verts(ob, TRUE, dg);
1813 /* Make sure that any verts with higher indices are adjusted accordingly */
1814 if(ob->type==OB_MESH) {
1816 EditMesh *em = BKE_mesh_get_editmesh(me);
1820 for(eve=em->verts.first; eve; eve=eve->next){
1821 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1824 for(i=0; i<dvert->totweight; i++)
1825 if(dvert->dw[i].def_nr > dg_index)
1826 dvert->dw[i].def_nr--;
1828 BKE_mesh_end_editmesh(me, em);
1830 else if(ob->type==OB_LATTICE) {
1831 Lattice *lt= vgroup_edit_lattice(ob);
1833 MDeformVert *dvert= lt->dvert;
1837 tot= lt->pntsu*lt->pntsv*lt->pntsw;
1838 for(a=0, bp= lt->def; a<tot; a++, bp++, dvert++) {
1839 for(i=0; i<dvert->totweight; i++){
1840 if(dvert->dw[i].def_nr > dg_index)
1841 dvert->dw[i].def_nr--;
1847 vgroup_delete_update_users(ob, dg_index + 1);
1849 /* Remove the group */
1850 BLI_freelinkN (&ob->defbase, dg);
1852 /* Update the active deform index if necessary */
1853 if(ob->actdef > dg_index)
1855 if(ob->actdef < 1 && ob->defbase.first)
1858 /* remove all dverts */
1859 if(ob->defbase.first == NULL) {
1860 if(ob->type==OB_MESH) {
1862 CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
1865 else if(ob->type==OB_LATTICE) {
1866 Lattice *lt= vgroup_edit_lattice(ob);
1868 MEM_freeN(lt->dvert);
1875 static int vgroup_object_in_edit_mode(Object *ob)
1877 if(ob->type == OB_MESH)
1878 return (((Mesh*)ob->data)->edit_mesh != NULL);
1879 else if(ob->type == OB_LATTICE)
1880 return (((Lattice*)ob->data)->editlatt != NULL);
1885 static void vgroup_delete(Object *ob)
1887 bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef-1);
1891 if(vgroup_object_in_edit_mode(ob))
1892 vgroup_delete_edit_mode(ob, dg);
1894 vgroup_delete_object_mode(ob, dg);
1897 static void vgroup_delete_all(Object *ob)
1899 /* Remove all DVerts */
1900 if(ob->type==OB_MESH) {
1902 CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
1905 else if(ob->type==OB_LATTICE) {
1906 Lattice *lt= vgroup_edit_lattice(ob);
1908 MEM_freeN(lt->dvert);
1913 /* Remove all DefGroups */
1914 BLI_freelistN(&ob->defbase);
1916 /* Fix counters/indices */
1920 /* only in editmode */
1921 static void vgroup_assign_verts(Object *ob, float weight)
1924 bDeformGroup *dg, *eg;
1925 MDeformWeight *newdw;
1929 dg=BLI_findlink(&ob->defbase, ob->actdef-1);
1933 if(ob->type == OB_MESH) {
1935 EditMesh *em = BKE_mesh_get_editmesh(me);
1937 if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT))
1938 EM_add_data_layer(em, &em->vdata, CD_MDEFORMVERT, NULL);
1940 /* Go through the list of editverts and assign them */
1941 for(eve=em->verts.first; eve; eve=eve->next){
1942 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
1944 if(dvert && (eve->f & SELECT)){
1945 /* See if this vert already has a reference to this group */
1946 /* If so: Change its weight */
1948 for(i=0; i<dvert->totweight; i++){
1949 eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr);
1950 /* Find the actual group */
1952 dvert->dw[i].weight= weight;
1957 /* If not: Add the group and set its weight */
1959 newdw = MEM_callocN(sizeof(MDeformWeight)*(dvert->totweight+1), "deformWeight");
1961 memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*dvert->totweight);
1962 MEM_freeN(dvert->dw);
1966 dvert->dw[dvert->totweight].weight= weight;
1967 dvert->dw[dvert->totweight].def_nr= ob->actdef-1;
1974 BKE_mesh_end_editmesh(me, em);
1976 else if(ob->type == OB_LATTICE) {
1977 Lattice *lt= vgroup_edit_lattice(ob);
1982 ED_vgroup_data_create(<->id);
1984 tot= lt->pntsu*lt->pntsv*lt->pntsw;
1985 for(a=0, bp= lt->def; a<tot; a++, bp++) {
1987 ED_vgroup_nr_vert_add(ob, ob->actdef-1, a, weight, WEIGHT_REPLACE);
1992 /* only in editmode */
1993 /* removes from all defgroup, if allverts==0 only selected vertices */
1994 static void vgroup_remove_verts(Object *ob, int allverts)
1996 /* To prevent code redundancy, we just use vgroup_active_remove_verts, but that
1997 * only operates on the active vgroup. So we iterate through all groups, by changing
1998 * active group index
2001 for(dg= ob->defbase.first; dg; dg= dg->next) {
2002 vgroup_active_remove_verts(ob, allverts, dg);
2006 /********************** vertex group operators *********************/
2008 static int vertex_group_poll(bContext *C)
2010 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2011 ID *data= (ob)? ob->data: NULL;
2012 return (ob && !ob->id.lib && ELEM(ob->type, OB_MESH, OB_LATTICE) && data && !data->lib);
2015 static int vertex_group_poll_edit(bContext *C)
2017 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2018 ID *data= (ob)? ob->data: NULL;
2020 if(!(ob && !ob->id.lib && data && !data->lib))
2023 return vgroup_object_in_edit_mode(ob);
2026 static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op))
2028 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2031 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2032 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2033 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2035 return OPERATOR_FINISHED;
2038 void OBJECT_OT_vertex_group_add(wmOperatorType *ot)
2041 ot->name= "Add Vertex Group";
2042 ot->idname= "OBJECT_OT_vertex_group_add";
2045 ot->poll= vertex_group_poll;
2046 ot->exec= vertex_group_add_exec;
2049 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2052 static int vertex_group_remove_exec(bContext *C, wmOperator *op)
2054 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2056 if(RNA_boolean_get(op->ptr, "all"))
2057 vgroup_delete_all(ob);
2061 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2062 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2063 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2065 return OPERATOR_FINISHED;
2068 void OBJECT_OT_vertex_group_remove(wmOperatorType *ot)
2071 ot->name= "Remove Vertex Group";
2072 ot->idname= "OBJECT_OT_vertex_group_remove";
2075 ot->poll= vertex_group_poll;
2076 ot->exec= vertex_group_remove_exec;
2079 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2082 RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups.");
2085 static int vertex_group_assign_exec(bContext *C, wmOperator *op)
2087 ToolSettings *ts= CTX_data_tool_settings(C);
2088 Object *ob= CTX_data_edit_object(C);
2090 if(RNA_boolean_get(op->ptr, "new"))
2093 vgroup_assign_verts(ob, ts->vgroup_weight);
2094 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2095 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2097 return OPERATOR_FINISHED;
2100 void OBJECT_OT_vertex_group_assign(wmOperatorType *ot)
2103 ot->name= "Assign Vertex Group";
2104 ot->idname= "OBJECT_OT_vertex_group_assign";
2107 ot->poll= vertex_group_poll_edit;
2108 ot->exec= vertex_group_assign_exec;
2111 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2114 RNA_def_boolean(ot->srna, "new", 0, "New", "Assign vertex to new vertex group.");
2117 static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
2119 Object *ob= CTX_data_edit_object(C);
2121 if(RNA_boolean_get(op->ptr, "all"))
2122 vgroup_remove_verts(ob, 0);
2124 bDeformGroup *dg= BLI_findlink(&ob->defbase, ob->actdef - 1);
2127 return OPERATOR_CANCELLED;
2130 vgroup_active_remove_verts(ob, FALSE, dg);
2133 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2134 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2136 return OPERATOR_FINISHED;
2139 void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot)
2142 ot->name= "Remove from Vertex Group";
2143 ot->idname= "OBJECT_OT_vertex_group_remove_from";
2146 ot->poll= vertex_group_poll_edit;
2147 ot->exec= vertex_group_remove_from_exec;
2150 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2153 RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups.");
2156 static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
2158 Object *ob= CTX_data_edit_object(C);
2160 if(!ob || ob->id.lib)
2161 return OPERATOR_CANCELLED;
2163 vgroup_select_verts(ob, 1);
2164 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
2166 return OPERATOR_FINISHED;
2169 void OBJECT_OT_vertex_group_select(wmOperatorType *ot)
2172 ot->name= "Select Vertex Group";
2173 ot->idname= "OBJECT_OT_vertex_group_select";
2176 ot->poll= vertex_group_poll_edit;
2177 ot->exec= vertex_group_select_exec;
2180 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2183 static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
2185 Object *ob= CTX_data_edit_object(C);
2187 vgroup_select_verts(ob, 0);
2188 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
2190 return OPERATOR_FINISHED;
2193 void OBJECT_OT_vertex_group_deselect(wmOperatorType *ot)
2196 ot->name= "Deselect Vertex Group";
2197 ot->idname= "OBJECT_OT_vertex_group_deselect";
2200 ot->poll= vertex_group_poll_edit;
2201 ot->exec= vertex_group_deselect_exec;
2204 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2207 static int vertex_group_copy_exec(bContext *C, wmOperator *UNUSED(op))
2209 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2211 vgroup_duplicate(ob);
2212 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2213 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2214 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2216 return OPERATOR_FINISHED;
2219 void OBJECT_OT_vertex_group_copy(wmOperatorType *ot)
2222 ot->name= "Copy Vertex Group";
2223 ot->idname= "OBJECT_OT_vertex_group_copy";
2226 ot->poll= vertex_group_poll;
2227 ot->exec= vertex_group_copy_exec;
2230 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2233 static int vertex_group_levels_exec(bContext *C, wmOperator *op)
2235 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2237 float offset= RNA_float_get(op->ptr,"offset");
2238 float gain= RNA_float_get(op->ptr,"gain");
2240 vgroup_levels(ob, offset, gain);
2242 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2243 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2244 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2246 return OPERATOR_FINISHED;
2249 void OBJECT_OT_vertex_group_levels(wmOperatorType *ot)
2252 ot->name= "Vertex Group Levels";
2253 ot->idname= "OBJECT_OT_vertex_group_levels";
2256 ot->poll= vertex_group_poll;
2257 ot->exec= vertex_group_levels_exec;
2260 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2262 RNA_def_float(ot->srna, "offset", 0.f, -1.0, 1.0, "Offset", "Value to add to weights.", -1.0f, 1.f);
2263 RNA_def_float(ot->srna, "gain", 1.f, 0.f, FLT_MAX, "Gain", "Value to multiply weights by.", 0.0f, 10.f);
2266 static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op))
2268 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2270 vgroup_normalize(ob);
2272 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2273 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2274 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2276 return OPERATOR_FINISHED;
2279 void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot)
2282 ot->name= "Normalize Vertex Group";
2283 ot->idname= "OBJECT_OT_vertex_group_normalize";
2286 ot->poll= vertex_group_poll;
2287 ot->exec= vertex_group_normalize_exec;
2290 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2293 static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
2295 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2296 int lock_active= RNA_boolean_get(op->ptr,"lock_active");
2298 vgroup_normalize_all(ob, lock_active);
2300 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2301 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2302 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2304 return OPERATOR_FINISHED;
2307 void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
2310 ot->name= "Normalize All Vertex Groups";
2311 ot->idname= "OBJECT_OT_vertex_group_normalize_all";
2314 ot->poll= vertex_group_poll;
2315 ot->exec= vertex_group_normalize_all_exec;
2318 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2320 RNA_def_boolean(ot->srna, "lock_active", TRUE, "Lock Active", "Keep the values of the active group while normalizing others.");
2323 static int vertex_group_fix_exec(bContext *C, wmOperator *op)
2325 Object *ob= CTX_data_active_object(C);
2326 Scene *scene= CTX_data_scene(C);
2328 float distToBe= RNA_float_get(op->ptr,"dist");
2329 float strength= RNA_float_get(op->ptr,"strength");
2330 float cp= RNA_float_get(op->ptr,"cp");
2331 ModifierData *md = ob->modifiers.first;
2334 if(md->type == eModifierType_Mirror && (md->mode&eModifierMode_Realtime)) {
2340 if(md && md->type == eModifierType_Mirror) {
2341 BKE_report(op->reports, RPT_ERROR_INVALID_CONTEXT, "This operator does not support an active mirror modifier");
2342 return OPERATOR_CANCELLED;
2344 vgroup_fix(scene, ob, distToBe, strength, cp);
2346 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2347 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2348 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2350 return OPERATOR_FINISHED;
2353 void OBJECT_OT_vertex_group_fix(wmOperatorType *ot)
2356 ot->name= "Fix Vertex Group Deform";
2357 ot->idname= "OBJECT_OT_vertex_group_fix";
2360 ot->poll= vertex_group_poll;
2361 ot->exec= vertex_group_fix_exec;
2364 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2365 RNA_def_float(ot->srna, "dist", 0.0f, -FLT_MAX, FLT_MAX, "Distance", "The distance to move to.", -10.0f, 10.0f);
2366 RNA_def_float(ot->srna, "strength", 1.f, -2.0f, FLT_MAX, "Strength", "The distance moved can be changed by this multiplier.", -2.0f, 2.0f);
2367 RNA_def_float(ot->srna, "cp", 1.0f, 0.05f, FLT_MAX, "Change Sensitivity", "Changes the amount weights are altered with each iteration: lower values are slower.", 0.05f, 1.f);
2370 /* Jason was here */
2371 static int vertex_group_lock_exec(bContext *C, wmOperator *op)
2373 Object *ob= CTX_data_active_object(C);
2375 int action = RNA_enum_get(op->ptr, "action");
2377 vgroup_lock_all(ob, action);
2379 return OPERATOR_FINISHED;
2381 /* Jason was here */
2382 void OBJECT_OT_vertex_group_lock(wmOperatorType *ot)
2385 ot->name= "Change the Lock On Vertex Groups";
2386 ot->idname= "OBJECT_OT_vertex_group_lock";
2389 ot->poll= vertex_group_poll;
2390 ot->exec= vertex_group_lock_exec;
2393 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2395 WM_operator_properties_select_all(ot);
2398 static int vertex_group_invert_exec(bContext *C, wmOperator *op)
2400 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2401 int auto_assign= RNA_boolean_get(op->ptr,"auto_assign");
2402 int auto_remove= RNA_boolean_get(op->ptr,"auto_remove");
2404 vgroup_invert(ob, auto_assign, auto_remove);
2405 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2406 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2407 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2409 return OPERATOR_FINISHED;
2412 void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
2415 ot->name= "Invert Vertex Group";
2416 ot->idname= "OBJECT_OT_vertex_group_invert";
2419 ot->poll= vertex_group_poll;
2420 ot->exec= vertex_group_invert_exec;
2423 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2425 RNA_def_boolean(ot->srna, "auto_assign", TRUE, "Add Weights", "Add verts from groups that have zero weight before inverting.");
2426 RNA_def_boolean(ot->srna, "auto_remove", TRUE, "Remove Weights", "Remove verts from groups that have zero weight after inverting.");
2430 static int vertex_group_blend_exec(bContext *C, wmOperator *UNUSED(op))
2432 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2436 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2437 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2438 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2440 return OPERATOR_FINISHED;
2443 void OBJECT_OT_vertex_group_blend(wmOperatorType *ot)
2446 ot->name= "Blend Vertex Group";
2447 ot->idname= "OBJECT_OT_vertex_group_blend";
2448 ot->description= "";
2451 ot->poll= vertex_group_poll;
2452 ot->exec= vertex_group_blend_exec;
2455 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2459 static int vertex_group_clean_exec(bContext *C, wmOperator *op)
2461 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2463 float limit= RNA_float_get(op->ptr,"limit");
2464 int all_groups= RNA_boolean_get(op->ptr,"all_groups");
2465 int keep_single= RNA_boolean_get(op->ptr,"keep_single");
2467 if(all_groups) vgroup_clean_all(ob, limit, keep_single);
2468 else vgroup_clean(ob, limit, keep_single);
2470 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2471 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2472 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2474 return OPERATOR_FINISHED;
2477 void OBJECT_OT_vertex_group_clean(wmOperatorType *ot)
2480 ot->name= "Clean Vertex Group";
2481 ot->idname= "OBJECT_OT_vertex_group_clean";
2482 ot->description= "Remove Vertex Group assignments which aren't required";
2485 ot->poll= vertex_group_poll;
2486 ot->exec= vertex_group_clean_exec;
2489 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2491 RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, 1.0, "Limit", "Remove weights under this limit.", 0.001f, 0.99f);
2492 RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Clean all vertex groups.");
2493 RNA_def_boolean(ot->srna, "keep_single", FALSE, "Keep Single", "Keep verts assigned to at least one group when cleaning.");
2497 static int vertex_group_mirror_exec(bContext *C, wmOperator *op)
2499 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2501 ED_vgroup_mirror(ob, RNA_boolean_get(op->ptr,"mirror_weights"), RNA_boolean_get(op->ptr,"flip_group_names"));
2503 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2504 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2505 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
2507 return OPERATOR_FINISHED;
2510 void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot)
2513 ot->name= "Mirror Vertex Group";
2514 ot->idname= "OBJECT_OT_vertex_group_mirror";
2515 ot->description= "Mirror all vertex groups, flip weights and/or names, editing only selected vertices, flipping when both sides are selected otherwise copy from unselected";
2518 ot->poll= vertex_group_poll_edit;
2519 ot->exec= vertex_group_mirror_exec;
2522 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2525 RNA_def_boolean(ot->srna, "mirror_weights", TRUE, "Mirror Weights", "Mirror weights.");
2526 RNA_def_boolean(ot->srna, "flip_group_names", TRUE, "Flip Groups", "Flip vertex group names.");
2530 static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op))
2532 Scene *scene= CTX_data_scene(C);
2533 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2535 int retval= OPERATOR_CANCELLED;
2537 for(base=scene->base.first; base; base= base->next) {
2538 if(base->object->type==ob->type) {
2539 if(base->object!=ob && base->object->data==ob->data) {
2540 BLI_freelistN(&base->object->defbase);
2541 BLI_duplicatelist(&base->object->defbase, &ob->defbase);
2542 base->object->actdef= ob->actdef;
2544 DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
2545 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, base->object);
2546 WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
2548 retval = OPERATOR_FINISHED;
2556 void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot)
2559 ot->name= "Copy Vertex Groups to Linked";
2560 ot->idname= "OBJECT_OT_vertex_group_copy_to_linked";
2561 ot->description= "Copy Vertex Groups to all users of the same Geometry data";
2564 ot->poll= vertex_group_poll;
2565 ot->exec= vertex_group_copy_to_linked_exec;
2568 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2571 static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
2573 Object *obact= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2577 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects)
2580 if(ED_vgroup_copy_array(ob, obact)) change++;
2586 if((change == 0 && fail == 0) || fail) {
2587 BKE_reportf(op->reports, RPT_ERROR, "Copy to VGroups to Selected warning done %d, failed %d, object data must have matching indicies", change, fail);
2590 return OPERATOR_FINISHED;
2594 void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot)
2597 ot->name= "Copy Vertex Group to Selected";
2598 ot->idname= "OBJECT_OT_vertex_group_copy_to_selected";
2599 ot->description= "Copy Vertex Groups to other selected objects with matching indices";
2602 ot->poll= vertex_group_poll;
2603 ot->exec= vertex_group_copy_to_selected_exec;
2606 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2609 static EnumPropertyItem vgroup_items[]= {
2610 {0, NULL, 0, NULL, NULL}};
2612 static int set_active_group_exec(bContext *C, wmOperator *op)
2614 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2615 int nr= RNA_enum_get(op->ptr, "group");
2619 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2620 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2622 return OPERATOR_FINISHED;
2625 static EnumPropertyItem *vgroup_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
2627 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2628 EnumPropertyItem tmp = {0, "", 0, "", ""};
2629 EnumPropertyItem *item= NULL;
2634 return vgroup_items;
2636 for(a=0, def=ob->defbase.first; def; def=def->next, a++) {
2638 tmp.icon= ICON_GROUP_VERTEX;
2639 tmp.identifier= def->name;
2640 tmp.name= def->name;
2641 RNA_enum_item_add(&item, &totitem, &tmp);
2644 RNA_enum_item_end(&item, &totitem);
2650 void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot)
2655 ot->name= "Set Active Vertex Group";
2656 ot->idname= "OBJECT_OT_vertex_group_set_active";
2657 ot->description= "Set the active vertex group";
2660 ot->poll= vertex_group_poll;
2661 ot->exec= set_active_group_exec;
2662 ot->invoke= WM_menu_invoke;
2665 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2668 prop= RNA_def_enum(ot->srna, "group", vgroup_items, 0, "Group", "Vertex group to set as active.");
2669 RNA_def_enum_funcs(prop, vgroup_itemf);
2673 /*creates the name_array parameter for vgroup_do_remap, call this before fiddling
2674 with the order of vgroups then call vgroup_do_remap after*/
2675 static char *vgroup_init_remap(Object *ob)
2678 int def_tot = BLI_countlist(&ob->defbase);
2679 char *name_array= MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * def_tot, "sort vgroups");
2683 for(def = ob->defbase.first; def; def=def->next) {
2684 BLI_strncpy(name, def->name, MAX_VGROUP_NAME);
2685 name += MAX_VGROUP_NAME;
2691 static int vgroup_do_remap(Object *ob, char *name_array, wmOperator *op)
2693 MDeformVert *dvert= NULL;
2695 int def_tot = BLI_countlist(&ob->defbase);
2696 int *sort_map_update= MEM_mallocN(MAX_VGROUP_NAME * sizeof(int) * def_tot + 1, "sort vgroups"); /* needs a dummy index at the start*/
2697 int *sort_map= sort_map_update + 1;
2702 for(def= ob->defbase.first, i=0; def; def=def->next, i++){
2703 sort_map[i]= BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name));
2704 name += MAX_VGROUP_NAME;
2707 if(ob->mode == OB_MODE_EDIT) {
2708 if(ob->type==OB_MESH) {
2709 EditMesh *em = BKE_mesh_get_editmesh(ob->data);
2712 for(eve=em->verts.first; eve; eve=eve->next){
2713 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
2714 if(dvert && dvert->totweight){
2715 defvert_remap(dvert, sort_map);
2720 BKE_report(op->reports, RPT_ERROR, "Editmode lattice isnt supported yet.");
2721 MEM_freeN(sort_map_update);
2722 return OPERATOR_CANCELLED;
2728 ED_vgroup_give_array(ob->data, &dvert, &dvert_tot);
2730 /*create as necassary*/
2731 while(dvert && dvert_tot--) {
2732 if(dvert->totweight)
2733 defvert_remap(dvert, sort_map);
2739 for(i=0; i<def_tot; i++)
2742 sort_map_update[0]= 0;
2743 vgroup_remap_update_users(ob, sort_map_update);
2745 ob->actdef= sort_map_update[ob->actdef];
2747 MEM_freeN(sort_map_update);
2749 return OPERATOR_FINISHED;
2752 static int vgroup_sort(void *def_a_ptr, void *def_b_ptr)
2754 bDeformGroup *def_a= (bDeformGroup *)def_a_ptr;
2755 bDeformGroup *def_b= (bDeformGroup *)def_b_ptr;
2757 return BLI_natstrcmp(def_a->name, def_b->name);
2760 static int vertex_group_sort_exec(bContext *C, wmOperator *op)
2762 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2767 name_array = vgroup_init_remap(ob);
2769 /*sort vgroup names*/
2770 BLI_sortlist(&ob->defbase, vgroup_sort);
2772 /*remap vgroup data to map to correct names*/
2773 ret = vgroup_do_remap(ob, name_array, op);
2775 if (ret != OPERATOR_CANCELLED) {
2776 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2777 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2780 if (name_array) MEM_freeN(name_array);
2785 void OBJECT_OT_vertex_group_sort(wmOperatorType *ot)
2787 ot->name= "Sort Vertex Groups";
2788 ot->idname= "OBJECT_OT_vertex_group_sort";
2789 ot->description= "Sorts vertex groups alphabetically";
2792 ot->poll= vertex_group_poll;
2793 ot->exec= vertex_group_sort_exec;
2796 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2799 static int vgroup_move_exec(bContext *C, wmOperator *op)
2801 Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
2804 int dir= RNA_enum_get(op->ptr, "direction"), ret;
2806 def = BLI_findlink(&ob->defbase, ob->actdef - 1);
2808 return OPERATOR_CANCELLED;
2811 name_array = vgroup_init_remap(ob);
2813 if (dir == 1) { /*up*/
2814 void *prev = def->prev;
2816 BLI_remlink(&ob->defbase, def);
2817 BLI_insertlinkbefore(&ob->defbase, prev, def);
2819 void *next = def->next;
2821 BLI_remlink(&ob->defbase, def);
2822 BLI_insertlinkafter(&ob->defbase, next, def);
2825 ret = vgroup_do_remap(ob, name_array, op);
2827 if (name_array) MEM_freeN(name_array);
2829 if (ret != OPERATOR_CANCELLED) {
2830 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2831 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob);
2837 void OBJECT_OT_vertex_group_move(wmOperatorType *ot)
2839 static EnumPropertyItem vgroup_slot_move[] = {
2840 {1, "UP", 0, "Up", ""},
2841 {-1, "DOWN", 0, "Down", ""},
2842 {0, NULL, 0, NULL, NULL}
2846 ot->name= "Move Vertex Group";
2847 ot->idname= "OBJECT_OT_vertex_group_move";
2850 ot->poll= vertex_group_poll;
2851 ot->exec= vgroup_move_exec;
2854 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2856 RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction", "Direction to move, UP or DOWN");