editarmature.c and paint_vertex.c
authorJason Hays <jason_hays22@mymail.eku.edu>
Tue, 7 Jun 2011 17:59:38 +0000 (17:59 +0000)
committerJason Hays <jason_hays22@mymail.eku.edu>
Tue, 7 Jun 2011 17:59:38 +0000 (17:59 +0000)
I added the first version of multi-bone selection for faster, temporary locking/unlocking; right now, if multiple bones are selected, the selection is considered unlocked, despite any vgroup checkbox status.
Every other group is considered locked.

paint_vertex.c
A modified Auto Normalize was inserted to normalize the active group normally instead of locking the values: it was causing the active group to steal weights from locked groups if the active group had a weight of 1.0, and that destroyed the locked groups deformations.

source/blender/editors/armature/editarmature.c
source/blender/editors/sculpt_paint/paint_vertex.c

index b31bcc710f4bd97a14668d32c447b795ad2d3fc8..48cbb3e2c3d64af6d03e3b9361bf5070f1eb45da 100644 (file)
@@ -4385,6 +4385,21 @@ static int bone_looper(Object *ob, Bone *bone, void *data,
        
        return count;
 }
+// Jason
+Bone* get_other_selected_bone(Object *ob) {
+       Bone *bone;
+       int i;
+       bone = get_indexed_bone(ob, 0);
+       for(i = 0; bone;){
+               if(bone->flag & BONE_SELECTED) {
+                       return bone;
+               }
+               i++;
+               bone = get_indexed_bone(ob, i);
+       }
+
+       return NULL;
+}
 
 /* called from editview.c, for mode-less pose selection */
 /* assumes scene obact and basact is still on old situation */
@@ -4392,7 +4407,8 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor
 {
        Object *ob= base->object;
        Bone *nearBone;
-       
+       // Jason
+       Bone *new_act_bone;
        if (!ob || !ob->pose) return 0;
 
        nearBone= get_bone_from_selectbuffer(scene, base, buffer, hits, 1);
@@ -4402,11 +4418,37 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor
                bArmature *arm= ob->data;
                
                /* since we do unified select, we don't shift+select a bone if the armature object was not active yet */
-               if (!(extend) || (base != scene->basact)) {
-                       ED_pose_deselectall(ob, 0);
-                       nearBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
-                       arm->act_bone= nearBone;
-                       
+               /* Jason was here, I'm doing a unified select for locking now */
+               if ((base != scene->basact)) {//if (!(extend) || (base != scene->basact)) {
+                       /* Jason was here */
+                       /* only deselect all if they aren't using 'shift' */
+                       if(!extend) {
+                               ED_pose_deselectall(ob, 0);
+                               nearBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+                               arm->act_bone= nearBone;
+                               ED_vgroup_select_by_name(OBACT, nearBone->name);
+                               DAG_id_tag_update(&OBACT->id, OB_RECALC_DATA);
+                       }
+                       // Jason deselect this bone specifically if it is selected already
+                       else {
+                               if (nearBone->flag & BONE_SELECTED) {
+                                       nearBone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+                                       if(nearBone == arm->act_bone) {
+                                               // make a different bone the active one if it exists
+                                               
+                                               new_act_bone = get_other_selected_bone(ob);
+                                               if(new_act_bone) {
+                                                       new_act_bone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+                                                       arm->act_bone = new_act_bone;
+                                                       ED_vgroup_select_by_name(OBACT, new_act_bone->name);
+                                                       DAG_id_tag_update(&OBACT->id, OB_RECALC_DATA);
+                                               }
+                                       }
+                               } else {
+                                       nearBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+                                       arm->act_bone= nearBone;
+                               }
+                       } 
                                // XXX old cruft! use notifiers instead
                        //select_actionchannel_by_name(ob->action, nearBone->name, 1);
                }
index 4793b5687d18b3dd026f981eb0ac291e15067d68..8a03d46fe19a09a1331436a0599683aee37f5459 100644 (file)
@@ -1028,6 +1028,35 @@ static void do_weight_paint_auto_normalize(MDeformVert *dvert,
                }
        }
 }
+// Jason was here: the active group should be involved in auto normalize
+static void do_weight_paint_auto_normalize_change_act_group(MDeformVert *dvert, char *map)
+{
+//     MDeformWeight *dw = dvert->dw;
+       float sum=0.0f, fac=0.0f;
+       int i, tot=0;
+
+       if (!map)
+               return;
+
+       for (i=0; i<dvert->totweight; i++) {
+               if (map[dvert->dw[i].def_nr]) {
+                       tot += 1;
+                       sum += dvert->dw[i].weight;
+               }
+       }
+       
+       if (!tot || sum == 1.0f)
+               return;
+
+       fac = sum;
+       fac = fac==0.0f ? 1.0f : 1.0f / fac;
+
+       for (i=0; i<dvert->totweight; i++) {
+               if (map[dvert->dw[i].def_nr]) {
+                       dvert->dw[i].weight *= fac;
+               }
+       }
+}
 /* Jason was here 
 this function will handle normalize with locked groups 
 it assumes that the current ratios (of locked groups)
@@ -1109,7 +1138,7 @@ dividing can cause the weights to drop to 0
 }*/
 /* Jason was here */
 /*
-See if the current deform group has a locked group
+See if the current deform vertex has a locked group
 */
 static char has_locked_group(MDeformVert *dvert, char *flags)
 {
@@ -1122,30 +1151,57 @@ static char has_locked_group(MDeformVert *dvert, char *flags)
        return FALSE;
 }
 /*Jason was here
-not sure where the prototypes belong at the moment
-static char* gen_lck_flags(Object* ob);
-
 gen_lck_flags gets the status of "flag" for each bDeformGroup
 in ob->defbase and returns an array containing them
+
+if there are multiple bones selected, however, they are the only ones that are treated as "unlocked"
 */
-static char* gen_lck_flags(Object* ob, int defcnt)
+static char* gen_lck_flags(Object* ob, int defcnt, char *map)
 {
        char is_locked = FALSE;
        int i;
        //int defcnt = BLI_countlist(&ob->defbase);
        char *flags = MEM_mallocN(defcnt*sizeof(char), "defflags");
-       bDeformGroup *defgroup = ob->defbase.first;
-       for(i = 0; i < defcnt && defgroup; i++) {
-               flags[i] = defgroup->flag;
-               defgroup = defgroup->next;
-               if(flags[i]) {
-                       is_locked = TRUE;
+       bDeformGroup *defgroup;
+       char was_selected = FALSE;
+       int selected = 0;
+       bPose *pose;
+       bPoseChannel *chan;
+       Bone *bone;
+
+       Object *armob = ED_object_pose_armature(ob);
+
+       if(armob) {
+               pose = armob->pose;
+               for (chan=pose->chanbase.first; chan; chan=chan->next) {
+                       bone = chan->bone;
+                       was_selected = FALSE;
+                       for (i = 0, defgroup = ob->defbase.first; i < defcnt && defgroup; defgroup = defgroup->next, i++) {
+                               if(!strcmp(defgroup->name, bone->name)) {
+                                       flags[i] = !(bone->flag & BONE_SELECTED);
+                                       if(flags[i]) {
+                                               is_locked = TRUE;
+                                       } else if(!was_selected){
+                                               selected++;
+                                               was_selected = TRUE;
+                                       }
+                               }
+                       }
+               }
+       }
+       if(selected <= 1) {
+               is_locked = FALSE;
+               for(i = 0, defgroup = ob->defbase.first; i < defcnt && defgroup; defgroup = defgroup->next, i++) {
+                       flags[i] = defgroup->flag;
+                       if(flags[i]) {
+                               is_locked = TRUE;
+                       }
                }
        }
        if(is_locked){
                return flags;
        }
-       // don't forget to free it
+       // don't forget to free it if it is unneeded
        MEM_freeN(flags);
        return NULL;
 }
@@ -1204,18 +1260,17 @@ and to redistribute that weight to the unlocked groups
 (if it has to, then it will put some/all of the change
 back onto the original group)
 */
-static void redistribute_weight_change(MDeformVert *dvert, MDeformWeight *pnt_dw, float oldw, char* flags, int defcnt, char *map)
+static void redistribute_weight_change(Object *ob, MDeformVert *dvert, int index, MDeformWeight *pnt_dw, float oldw, char* flags, int defcnt, char *map)
 {
        int i;
+       float old_change_left;
        float change_left = oldw - pnt_dw->weight;
+       // make sure the redistribution the same per loop.
        float change;
        char was_a_change;
        int groups_left_that_can_change = 0;
-       // make sure there is no case for division by 0, and make the redistribution the same per loop.
-       int groups_currently_left;
        char* change_status = MEM_mallocN(defcnt*sizeof(char), "defflags");
        MDeformWeight *dw;
-       //printf("start\n");
        for(i = 0; i < defcnt; i++) {
                if(pnt_dw->def_nr == i || !map[i]) {
                        change_status[i] = FALSE;
@@ -1224,13 +1279,15 @@ static void redistribute_weight_change(MDeformVert *dvert, MDeformWeight *pnt_dw
                }
                if(change_status[i]) {
                        groups_left_that_can_change++;
+                       defvert_verify_index(dvert, i);
                }
-               //printf("group %d, change status: %d flag: %d active?: %d\n", i, change_status[i], flags[i], pnt_dw->def_nr == i);
        }
-       //printf("\n");
        if(groups_left_that_can_change > 0) {
-               groups_currently_left = groups_left_that_can_change;
                change = change_left/groups_left_that_can_change;
+               /* the division could cause it to be zero, so if it is, forget it*/
+               if(change == 0) {
+                       change = change_left;
+               }
                do {
                        was_a_change = FALSE;
                        for(i = 0; i < dvert->totweight; i++) {
@@ -1240,45 +1297,53 @@ static void redistribute_weight_change(MDeformVert *dvert, MDeformWeight *pnt_dw
                                }
 
                                dw->weight += change;
+                               old_change_left = change_left;
                                change_left -= change;
-                               //printf("group %d, change: %f weight: %f groups left: %d\n", dw->def_nr, change, dw->weight, groups_left_that_can_change);
+                               // sign change?
+                               if(change_left!=0 && change_left/fabs(change_left) != old_change_left/fabs(old_change_left)) {
+                                       dw->weight -= change;
+                                       change_left = old_change_left;
+                                       break;
+                               }
                                if(dw->weight >= 1.0f) {
 
                                        change_left += dw->weight-1.0f;
                                        dw->weight = 1.0f;
-                                       groups_currently_left--;
+                                       groups_left_that_can_change--;
                                        change_status[dw->def_nr] = FALSE;
 
                                }else if(dw->weight <= 0.0f) {
 
                                        change_left += dw->weight;
                                        dw->weight = 0.0f;
-                                       groups_currently_left--;
+                                       groups_left_that_can_change--;
                                        change_status[dw->def_nr] = FALSE;
                                }
                                was_a_change = TRUE;
+                               /* if it was too small, don't get stuck in an infinite loop! */
+                               if(old_change_left == change_left) {
+                                       change *= 2;
+                               }
                        }
-                       groups_left_that_can_change = groups_currently_left;
                } while(groups_left_that_can_change > 0 && change_left != 0.0f && was_a_change);
        }
        // add any remaining change back to the original weight
        pnt_dw->weight += change_left;
        MEM_freeN(change_status);
-       //printf("done\n");
 }
 /* Jason */
-static void check_locks_and_normalize(Mesh *me, int index, int vgroup, MDeformWeight *dw, float oldw, char *validmap, char *flags, int defcnt, char *bone_groups)
+static void check_locks_and_normalize(Object *ob, Mesh *me, int index, int vgroup, MDeformWeight *dw, float oldw, char *validmap, char *flags, int defcnt, char *bone_groups)
 {
        if(flags && has_locked_group(me->dvert+index, flags)) {
                if(flags[dw->def_nr]) {
                        // cannot change locked groups!
                        dw->weight = oldw;
                } else if(bone_groups[dw->def_nr]) {
-                       redistribute_weight_change(me->dvert+index, dw, oldw, flags, defcnt, bone_groups);
-                       do_weight_paint_auto_normalize(me->dvert+index, vgroup, validmap);//do_wp_auto_normalize_locked_groups(me, me->dvert, validmap);
+                       redistribute_weight_change(ob, me->dvert+index, index, dw, oldw, flags, defcnt, bone_groups);
+                       do_weight_paint_auto_normalize_change_act_group(me->dvert+index, validmap);//do_weight_paint_auto_normalize(me->dvert+index, vgroup, validmap);
                }
        } else if(bone_groups[dw->def_nr]) {// disable auto normalize if the active group is not a bone group
-               do_weight_paint_auto_normalize(me->dvert+index, vgroup, validmap);
+               do_weight_paint_auto_normalize_change_act_group(me->dvert+index, validmap);//do_weight_paint_auto_normalize(me->dvert+index, vgroup, validmap);
        }
 }
 // Jason
@@ -1291,7 +1356,7 @@ static void do_weight_paint_vertex(VPaint *wp, Object *ob, int index,
        Mesh *me= ob->data;
        MDeformWeight *dw, *uw;
        int vgroup= ob->actdef-1;
-       
+
        /* Jason was here */
        char* flags;
        char* bone_groups;
@@ -1314,13 +1379,12 @@ static void do_weight_paint_vertex(VPaint *wp, Object *ob, int index,
        if(dw==NULL || uw==NULL)
                return;
        /* Jason was here */
-       flags = gen_lck_flags(ob, defcnt = BLI_countlist(&ob->defbase));
+       flags = gen_lck_flags(ob, defcnt = BLI_countlist(&ob->defbase), bone_groups);
        oldw = dw->weight;
-
        wpaint_blend(wp, dw, uw, alpha, paintweight, flip);
-
        /* Jason was here */
-       check_locks_and_normalize(me, index, vgroup, dw, oldw, validmap, flags, defcnt, bone_groups);
+       check_locks_and_normalize(ob, me, index, vgroup, dw, oldw, validmap, flags, defcnt, bone_groups);
+
        if(me->editflag & ME_EDIT_MIRROR_X) {   /* x mirror painting */
                int j= mesh_get_x_mirror_vert(ob, index);
                if(j>=0) {
@@ -1334,7 +1398,7 @@ static void do_weight_paint_vertex(VPaint *wp, Object *ob, int index,
 
                        uw->weight= dw->weight;
                        /* Jason */
-                       check_locks_and_normalize(me, j, vgroup, dw, oldw, validmap, flags, defcnt, bone_groups);
+                       check_locks_and_normalize(ob, me, j, vgroup, uw, oldw, validmap, flags, defcnt, bone_groups);
                }
        }
        /* Jason */