Merge from Harmonic Skeleton branch
[blender.git] / source / blender / src / editarmature.c
index 9e4e3f0d89cec535620993818defec18f5a2e555..a77c965768dea88c946e8d9f2080a103ffcf08e9 100644 (file)
@@ -1079,6 +1079,19 @@ void delete_armature(void)
        
        TEST_EDITARMATURE;
        if (okee("Erase selected bone(s)")==0) return;
+
+       /* Select mirrored bones */
+       if (arm->flag & ARM_MIRROR_EDIT) {
+               for (curBone=G.edbo.first; curBone; curBone=curBone->next) {
+                       if (arm->layer & curBone->layer) {
+                               if (curBone->flag & BONE_SELECTED) {
+                                       next = armature_bone_get_mirrored(curBone);
+                                       if (next)
+                                               next->flag |= BONE_SELECTED;
+                               }
+                       }
+               }
+       }
        
        /*  First erase any associated pose channel */
        if (G.obedit->pose) {
@@ -1324,13 +1337,19 @@ void auto_align_armature(short mode)
 {
        bArmature *arm= G.obedit->data;
        EditBone *ebone;
+       EditBone *flipbone = NULL;
        float   delta[3];
        float   curmat[3][3];
        float   *cursor= give_cursor();
                
        for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
-               if(arm->layer & ebone->layer) {
-                       if (ebone->flag & BONE_SELECTED) {
+               if (arm->layer & ebone->layer) {
+                       if (arm->flag & ARM_MIRROR_EDIT)
+                               flipbone = armature_bone_get_mirrored(ebone);
+                       
+                       if ((ebone->flag & BONE_SELECTED) || 
+                               (flipbone && flipbone->flag & BONE_SELECTED)) 
+                       {
                                /* specific method used to calculate roll depends on mode */
                                if (mode == 1) {
                                        /* Z-Axis point towards cursor */
@@ -1389,7 +1408,7 @@ void auto_align_armature(short mode)
                                        Mat3MulMat3(diffmat, imat, curmat);
                                        
                                        ebone->roll = atan2(diffmat[2][0], diffmat[2][2]);
-                               }
+                               }                               
                        }
                }
        }
@@ -1716,11 +1735,24 @@ void adduplicate_armature(void)
        EditBone        *firstDup=NULL; /*      The beginning of the duplicated bones in the edbo list */
        
        countall(); // flushes selection!
+
+       /* Select mirrored bones */
+       if (arm->flag & ARM_MIRROR_EDIT) {
+               for (curBone=G.edbo.first; curBone; curBone=curBone->next) {
+                       if (arm->layer & curBone->layer) {
+                               if (curBone->flag & BONE_SELECTED) {
+                                       eBone = armature_bone_get_mirrored(curBone);
+                                       if (eBone)
+                                               eBone->flag |= BONE_SELECTED;
+                               }
+                       }
+               }
+       }
        
        /*      Find the selected bones and duplicate them as needed */
        for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next){
-               if(arm->layer & curBone->layer) {
-                       if (curBone->flag & BONE_SELECTED){
+               if (arm->layer & curBone->layer) {
+                       if (curBone->flag & BONE_SELECTED) {
                                
                                eBone=MEM_callocN(sizeof(EditBone), "addup_editbone");
                                eBone->flag |= BONE_SELECTED;
@@ -1887,12 +1919,68 @@ void show_all_armature_bones(void)
        BIF_undo_push("Reveal Bones");
 }
 
+/* check for null, before calling! */
+static void bone_connect_to_existing_parent(EditBone *bone)
+{
+       bone->flag |= BONE_CONNECTED;
+       VECCOPY(bone->head, bone->parent->tail);
+       bone->rad_head = bone->parent->rad_tail;
+}
+
+static void bone_connect_to_new_parent(EditBone *selbone, EditBone *actbone, short mode)
+{
+       EditBone *ebone;
+       float offset[3];
+       
+       if ((selbone->parent) && (selbone->flag & BONE_CONNECTED))
+               selbone->parent->flag &= ~(BONE_TIPSEL);
+       
+       /* make actbone the parent of selbone */
+       selbone->parent= actbone;
+       
+       /* in actbone tree we cannot have a loop */
+       for (ebone= actbone->parent; ebone; ebone= ebone->parent) {
+               if (ebone->parent==selbone) {
+                       ebone->parent= NULL;
+                       ebone->flag &= ~BONE_CONNECTED;
+               }
+       }
+       
+       if (mode == 1) {        
+               /* Connected: Child bones will be moved to the parent tip */
+               selbone->flag |= BONE_CONNECTED;
+               VecSubf(offset, actbone->tail, selbone->head);
+               
+               VECCOPY(selbone->head, actbone->tail);
+               selbone->rad_head= actbone->rad_tail;
+               
+               VecAddf(selbone->tail, selbone->tail, offset);
+               
+               /* offset for all its children */
+               for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
+                       EditBone *par;
+                       
+                       for (par= ebone->parent; par; par= par->parent) {
+                               if (par==selbone) {
+                                       VecAddf(ebone->head, ebone->head, offset);
+                                       VecAddf(ebone->tail, ebone->tail, offset);
+                                       break;
+                               }
+                       }
+               }
+       }
+       else {
+               /* Offset: Child bones will retain their distance from the parent tip */
+               selbone->flag &= ~BONE_CONNECTED;
+       }
+}
+
 void make_bone_parent(void)
 {
        bArmature *arm= G.obedit->data;
        EditBone *actbone, *ebone, *selbone;
+       EditBone *flipbone, *flippar;
        short allchildbones= 0, foundselbone= 0;
-       float offset[3];
        short val;
        
        /* find active bone to parent to */
@@ -1934,59 +2022,40 @@ void make_bone_parent(void)
                /* When only the active bone is selected, and it has a parent,
                 * connect it to the parent, as that is the only possible outcome. 
                 */
-               actbone->flag |= BONE_CONNECTED;
-               VECCOPY(actbone->head, actbone->parent->tail);
-               actbone->rad_head= actbone->parent->rad_tail;
+               bone_connect_to_existing_parent(actbone);
+               
+               if (arm->flag & ARM_MIRROR_EDIT) {
+                       flipbone = armature_bone_get_mirrored(actbone);
+                       if (flipbone)
+                               bone_connect_to_existing_parent(flipbone);
+               }
        }
        else {
                /* loop through all editbones, parenting all selected bones to the active bone */
                for (selbone = G.edbo.first; selbone; selbone=selbone->next) {
                        if (arm->layer & selbone->layer) {
                                if ((selbone->flag & BONE_SELECTED) && (selbone!=actbone)) {
-                                       /* if selbone had a parent we clear parent tip */
-                                       if (selbone->parent && (selbone->flag & BONE_CONNECTED))
-                                               selbone->parent->flag &= ~(BONE_TIPSEL);
-                                       
-                                       /* make actbone the parent of selbone */
-                                       selbone->parent= actbone;
+                                       /* parent selbone to actbone */
+                                       bone_connect_to_new_parent(selbone, actbone, val);
                                        
-                                       /* in actbone tree we cannot have a loop */
-                                       for (ebone= actbone->parent; ebone; ebone= ebone->parent) {
-                                               if (ebone->parent==selbone) {
-                                                       ebone->parent= NULL;
-                                                       ebone->flag &= ~BONE_CONNECTED;
-                                               }
-                                       }
-                                       
-                                       if (val == 1) { 
-                                               /* Connected: Child bones will be moved to the parent tip */
-                                               selbone->flag |= BONE_CONNECTED;
-                                               VecSubf(offset, actbone->tail, selbone->head);
+                                       if (arm->flag & ARM_MIRROR_EDIT) {
+                                               /* - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone 
+                                                *      (i.e.  selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
+                                                *      This is useful for arm-chains, for example parenting lower arm to upper arm
+                                                * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
+                                                *      then just use actbone. Useful when doing upper arm to spine.
+                                                */
+                                               flipbone = armature_bone_get_mirrored(selbone);
+                                               flippar = armature_bone_get_mirrored(actbone);
                                                
-                                               VECCOPY(selbone->head, actbone->tail);
-                                               selbone->rad_head= actbone->rad_tail;
-                                               
-                                               VecAddf(selbone->tail, selbone->tail, offset);
-                                               
-                                               /* offset for all its children */
-                                               for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
-                                                       EditBone *par;
-                                                       
-                                                       for (par= ebone->parent; par; par= par->parent) {
-                                                               if (par==selbone) {
-                                                                       VecAddf(ebone->head, ebone->head, offset);
-                                                                       VecAddf(ebone->tail, ebone->tail, offset);
-                                                                       break;
-                                                               }
-                                                       }
+                                               if (flipbone) {
+                                                       if (flippar)
+                                                               bone_connect_to_new_parent(flipbone, flippar, val);
+                                                       else
+                                                               bone_connect_to_new_parent(flipbone, actbone, val);
                                                }
                                        }
-                                       else {
-                                               /* Offset: Child bones will retain their distance from the parent tip */
-                                               selbone->flag &= ~BONE_CONNECTED;
-                                       }
                                }
-                               
                        }
                }
        }
@@ -2000,10 +2069,22 @@ void make_bone_parent(void)
        return;
 }
 
+static void editbone_clear_parent(EditBone *ebone, int mode)
+{
+       if (ebone->parent) {
+               /* for nice selection */
+               ebone->parent->flag &= ~(BONE_TIPSEL);
+       }
+       
+       if(mode==1) ebone->parent= NULL;
+       ebone->flag &= ~BONE_CONNECTED;
+}
+
 void clear_bone_parent(void)
 {
        bArmature *arm= G.obedit->data;
        EditBone *ebone;
+       EditBone *flipbone = NULL;
        short val;
        
        val= pupmenu("Clear Parent%t|Clear Parent%x1|Disconnect Bone%x2");
@@ -2012,13 +2093,13 @@ void clear_bone_parent(void)
        for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
                if(arm->layer & ebone->layer) {
                        if(ebone->flag & BONE_SELECTED) {
-                               if(ebone->parent) {
-                                       /* for nice selection */
-                                       ebone->parent->flag &= ~(BONE_TIPSEL);
+                       
+                               if(arm->flag & ARM_MIRROR_EDIT)
+                                       flipbone = armature_bone_get_mirrored(ebone);
                                        
-                                       if(val==1) ebone->parent= NULL;
-                                       ebone->flag &= ~BONE_CONNECTED;
-                               }
+                               if (flipbone)
+                                       editbone_clear_parent(flipbone, val);
+                               editbone_clear_parent(ebone, val);
                        }
                }
        }
@@ -2337,6 +2418,8 @@ int do_pose_selectbuffer(Base *base, unsigned int *buffer, short hits)
        nearBone= get_bone_from_selectbuffer(base, buffer, hits, 1);
 
        if (nearBone) {
+               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 (!(G.qual & LR_SHIFTKEY) || base!=BASACT){
                        deselectall_posearmature(ob, 0, 0);
@@ -2347,9 +2430,7 @@ int do_pose_selectbuffer(Base *base, unsigned int *buffer, short hits)
                        if (nearBone->flag & BONE_SELECTED) {
                                /* if not active, we make it active */
                                if((nearBone->flag & BONE_ACTIVE)==0) {
-                                       bArmature *arm= ob->data;
                                        bone_looper(ob, arm->bonebase.first, NULL, clear_active_flag);
-                                       
                                        nearBone->flag |= BONE_ACTIVE;
                                }
                                else {
@@ -2358,7 +2439,6 @@ int do_pose_selectbuffer(Base *base, unsigned int *buffer, short hits)
                                }
                        }
                        else{
-                               bArmature *arm= ob->data;
                                bone_looper(ob, arm->bonebase.first, NULL, clear_active_flag);
                                
                                nearBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL|BONE_ACTIVE);
@@ -2475,7 +2555,7 @@ int bone_looper(Object *ob, Bone *bone, void *data,
 }
 
 
-static int bone_skinnable(Object *ob, Bone *bone, void *data)
+static int bone_skinnable(Object *ob, Bone *bone, void *datap)
 {
     /* Bones that are deforming
      * are regarded to be "skinnable" and are eligible for
@@ -2499,16 +2579,26 @@ static int bone_skinnable(Object *ob, Bone *bone, void *data)
      *      pointers to bones that point to all
      *      skinnable bones.
      */
-    Bone ***hbone;
+       Bone ***hbone;
+       int a, segments;
+       struct { Object *armob; void *list; int heat; } *data = datap;
 
        if(!(G.f & G_WEIGHTPAINT) || !(bone->flag & BONE_HIDDEN_P)) {
                if (!(bone->flag & BONE_NO_DEFORM)) {
-                       if (data != NULL) {
-                               hbone = (Bone ***) data;
-                               **hbone = bone;
-                               ++*hbone;
+                       if(data->heat && data->armob->pose && get_pose_channel(data->armob->pose, bone->name))
+                               segments = bone->segments;
+                       else
+                               segments = 1;
+
+                       if (data->list != NULL) {
+                               hbone = (Bone ***) &data->list;
+                               
+                               for(a=0; a<segments; a++) {
+                                       **hbone = bone;
+                                       ++*hbone;
+                               }
                        }
-                       return 1;
+                       return segments;
                }
        }
     return 0;
@@ -2529,7 +2619,7 @@ static int add_defgroup_unique_bone(Object *ob, Bone *bone, void *data)
     return 0;
 }
 
-static int dgroup_skinnable(Object *ob, Bone *bone, void *data) 
+static int dgroup_skinnable(Object *ob, Bone *bone, void *datap
 {
     /* Bones that are deforming
      * are regarded to be "skinnable" and are eligible for
@@ -2555,19 +2645,28 @@ static int dgroup_skinnable(Object *ob, Bone *bone, void *data)
      *      of skinnable bones.
      */
     bDeformGroup ***hgroup, *defgroup;
+       int a, segments;
+       struct { Object *armob; void *list; int heat; } *data= datap;
 
        if(!(G.f & G_WEIGHTPAINT) || !(bone->flag & BONE_HIDDEN_P)) {
           if (!(bone->flag & BONE_NO_DEFORM)) {
-                       if ( !(defgroup = get_named_vertexgroup(ob, bone->name)) ) {
+                       if(data->heat && data->armob->pose && get_pose_channel(data->armob->pose, bone->name))
+                               segments = bone->segments;
+                       else
+                               segments = 1;
+
+                       if(!(defgroup = get_named_vertexgroup(ob, bone->name)))
                                defgroup = add_defgroup_name(ob, bone->name);
-                       }
 
-                       if (data != NULL) {
-                               hgroup = (bDeformGroup ***) data;
-                               **hgroup = defgroup;
-                               ++*hgroup;
+                       if (data->list != NULL) {
+                               hgroup = (bDeformGroup ***) &data->list;
+
+                               for(a=0; a<segments; a++) {
+                                       **hgroup = defgroup;
+                                       ++*hgroup;
+                               }
                        }
-                       return 1;
+                       return segments;
                }
        }
     return 0;
@@ -2605,7 +2704,7 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i
                        /* store the distance-factor from the vertex to the bone */
                        distance = distfactor_to_bone (verts[i], root[j], tip[j],
                                bone->rad_head * scale, bone->rad_tail * scale, bone->dist * scale);
-
+                       
                        /* add the vert to the deform group if weight!=0.0 */
                        if (distance!=0.0)
                                add_vert_to_defgroup (ob, dgroup, i, distance, WEIGHT_REPLACE);
@@ -2636,59 +2735,95 @@ void add_verts_to_dgroups(Object *ob, Object *par, int heat, int mirror)
         * The mesh vertex positions used are either the final deformed coords
         * from the derivedmesh in weightpaint mode, the final subsurf coords
         * when parenting, or simply the original mesh coords.
-     */
+        */
 
-    bArmature *arm;
-    Bone **bonelist, **bonehandle, *bone;
-    bDeformGroup **dgrouplist, **dgroupflip, **dgrouphandle;
+       bArmature *arm;
+       Bone **bonelist, *bone;
+       bDeformGroup **dgrouplist, **dgroupflip;
        bDeformGroup *dgroup, *curdg;
-    Mesh *mesh;
-    float (*root)[3], (*tip)[3], (*verts)[3];
+       bPoseChannel *pchan;
+       Mesh *mesh;
+       Mat4 *bbone = NULL;
+       float (*root)[3], (*tip)[3], (*verts)[3];
        int *selected;
-    int numbones, vertsfilled = 0, i, j;
+       int numbones, vertsfilled = 0, i, j, segments = 0;
        int wpmode = (G.f & G_WEIGHTPAINT);
+       struct { Object *armob; void *list; int heat; } looper_data;
 
-    /* If the parent object is not an armature exit */
-    arm = get_armature(par);
-    if (!arm)
-        return;
+       /* If the parent object is not an armature exit */
+       arm = get_armature(par);
+       if (!arm)
+               return;
+       
+       looper_data.armob = par;
+       looper_data.heat= heat;
+       looper_data.list= NULL;
 
-    /* count the number of skinnable bones */
-    numbones = bone_looper(ob, arm->bonebase.first, NULL, bone_skinnable);
+       /* count the number of skinnable bones */
+       numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable);
        
        if (numbones == 0)
                return;
        
-    /* create an array of pointer to bones that are skinnable
-     * and fill it with all of the skinnable bones */
-    bonelist = MEM_callocN(numbones*sizeof(Bone *), "bonelist");
-    bonehandle = bonelist;
-    bone_looper(ob, arm->bonebase.first, &bonehandle, bone_skinnable);
+       /* create an array of pointer to bones that are skinnable
+        * and fill it with all of the skinnable bones */
+       bonelist = MEM_callocN(numbones*sizeof(Bone *), "bonelist");
+       looper_data.list= bonelist;
+       bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable);
 
-    /* create an array of pointers to the deform groups that
-     * coorespond to the skinnable bones (creating them
-     * as necessary. */
-    dgrouplist = MEM_callocN(numbones*sizeof(bDeformGroup *), "dgrouplist");
-    dgroupflip = MEM_callocN(numbones*sizeof(bDeformGroup *), "dgroupflip");
+       /* create an array of pointers to the deform groups that
+        * coorespond to the skinnable bones (creating them
+        * as necessary. */
+       dgrouplist = MEM_callocN(numbones*sizeof(bDeformGroup *), "dgrouplist");
+       dgroupflip = MEM_callocN(numbones*sizeof(bDeformGroup *), "dgroupflip");
 
-    dgrouphandle = dgrouplist;
-    bone_looper(ob, arm->bonebase.first, &dgrouphandle, dgroup_skinnable);
+       looper_data.list= dgrouplist;
+       bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable);
 
-    /* create an array of root and tip positions transformed into
+       /* create an array of root and tip positions transformed into
         * global coords */
-    root = MEM_callocN(numbones*sizeof(float)*3, "root");
-    tip = MEM_callocN(numbones*sizeof(float)*3, "tip");
+       root = MEM_callocN(numbones*sizeof(float)*3, "root");
+       tip = MEM_callocN(numbones*sizeof(float)*3, "tip");
        selected = MEM_callocN(numbones*sizeof(int), "selected");
 
        for (j=0; j < numbones; ++j) {
                bone = bonelist[j];
                dgroup = dgrouplist[j];
 
+               /* handle bbone */
+               if(heat) {
+                       if(segments == 0) {
+                               segments = 1;
+                               bbone = NULL;
+
+                               if(par->pose && (pchan=get_pose_channel(par->pose, bone->name))) {
+                                       if(bone->segments > 1) {
+                                               segments = bone->segments;
+                                               bbone = b_bone_spline_setup(pchan, 1);
+                                       }
+                               }
+                       }
+
+                       segments--;
+               }
+
                /* compute root and tip */
-               VECCOPY(root[j], bone->arm_head);
-               Mat4MulVecfl(par->obmat, root[j]);
+               if(bbone) {
+                       VECCOPY(root[j], bbone[segments].mat[3]);
+                       Mat4MulVecfl(bone->arm_mat, root[j]);
+                       if(segments+1 < bone->segments) {
+                               VECCOPY(tip[j], bbone[segments+1].mat[3])
+                               Mat4MulVecfl(bone->arm_mat, tip[j]);
+                       }
+                       else
+                               VECCOPY(tip[j], bone->arm_tail)
+               }
+               else {
+                       VECCOPY(root[j], bone->arm_head);
+                       VECCOPY(tip[j], bone->arm_tail);
+               }
 
-               VECCOPY(tip[j], bone->arm_tail);
+               Mat4MulVecfl(par->obmat, root[j]);
                Mat4MulVecfl(par->obmat, tip[j]);
 
                /* set selected */
@@ -2815,7 +2950,7 @@ static int hide_selected_pose_bone(Object *ob, Bone *bone, void *ptr)
        if(arm->layer & bone->layer) {
                if (bone->flag & BONE_SELECTED) {
                        bone->flag |= BONE_HIDDEN_P;
-                       bone->flag &= ~BONE_SELECTED;
+                       bone->flag &= ~(BONE_SELECTED|BONE_ACTIVE);
                }
        }
        return 0;
@@ -2845,6 +2980,7 @@ static int hide_unselected_pose_bone(Object *ob, Bone *bone, void *ptr)
        if(arm->layer & bone->layer) {
                if (~bone->flag & BONE_SELECTED) {
                        bone->flag |= BONE_HIDDEN_P;
+                       bone->flag &= ~BONE_ACTIVE;
                }
        }
        return 0;
@@ -3145,7 +3281,6 @@ void transform_armature_mirror_update(void)
 }
 
 
-
 /*****************************************************************************************************/
 /*************************************** SKELETON GENERATOR ******************************************/
 /*****************************************************************************************************/