== Fill Bones ==
authorJoshua Leung <aligorith@gmail.com>
Fri, 14 Dec 2007 00:09:07 +0000 (00:09 +0000)
committerJoshua Leung <aligorith@gmail.com>
Fri, 14 Dec 2007 00:09:07 +0000 (00:09 +0000)
This commit fixes/implements this feature. It is restricted to using 1-2 joints selected joints only.

source/blender/src/editarmature.c

index 51acac45b3fe984e2d1fc3590bc02411ee94ec9f..923d7638495ff8f8f759d8ec46d25c50e44e877b 100644 (file)
@@ -1930,24 +1930,69 @@ static void chains_find_tips (ListBase *list)
        }
 }
 
+
+static void fill_add_joint (EditBone *ebo, short eb_tail, ListBase *points)
+{
+       EditBonePoint *ebp;
+       float vec[3];
+       short found= 0;
+       
+       if (eb_tail) {
+               VECCOPY(vec, ebo->tail);
+       }
+       else {
+               VECCOPY(vec, ebo->head);
+       }
+       
+       for (ebp= points->first; ebp; ebp= ebp->next) {
+               if (VecEqual(ebp->vec, vec)) {                  
+                       if (eb_tail) {
+                               if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) {
+                                       /* so this bone's tail owner is this bone*/
+                                       ebp->tail_owner= ebo;
+                                       found= 1;
+                                       break;
+                               }
+                       }
+                       else {
+                               if ((ebp->tail_owner) && (ebp->tail_owner->parent == ebo)) {
+                                       /* so this bone's head owner is this bone */
+                                       ebp->head_owner= ebo;
+                                       found = 1;
+                                       break;
+                               }
+                       }
+               }
+       }
+       
+       /* allocate a new point if no existing point was related */
+       if (found == 0) {
+               ebp= MEM_callocN(sizeof(EditBonePoint), "EditBonePoint");
+               
+               if (eb_tail) {
+                       VECCOPY(ebp->vec, ebo->tail);
+                       ebp->tail_owner= ebo;
+               }
+               else {
+                       VECCOPY(ebp->vec, ebo->head);
+                       ebp->head_owner= ebo;
+               }
+               
+               BLI_addtail(points, ebp);
+       }
+}
+
 /* bone adding between selected joints */
 void fill_bones_armature(void)
 {
-       bArmature *arm= G.obedit->data;
+       EditBone *ebo, *newbone=NULL;
        
        ListBase chains = {NULL, NULL};
        LinkData *chain;
        
        ListBase points = {NULL, NULL};
-       EditBonePoint *ebp;
        int count;
        
-       EditBone *ebo, *newbone=NULL;
-       
-       
-       // temp... warning about this not being coded (will be fixed)
-       error("This tool hasn't been coded!");
-       return;
        
        /* get chains */
        chains_find_tips(&chains);
@@ -1956,18 +2001,16 @@ void fill_bones_armature(void)
        /* traverse chains to find selected joints */
        for (chain= chains.first; chain; chain= chain->next) {
                for (ebo= chain->data; ebo; ebo= ebo->parent) {
-                       if (ebo->flag & (BONE_SELECTED|BONE_ACTIVE)) {
-                               
-                       }
-                       else if (ebo->flag & BONE_ROOTSEL) {
-                       
-                       }
-                       else if (ebo->flag & BONE_TIPSEL) {
-                       
-                       }
+                       if (ebo->flag & BONE_ROOTSEL)
+                               fill_add_joint(ebo, 0, &points);
+                       if (ebo->flag & BONE_TIPSEL) 
+                               fill_add_joint(ebo, 1, &points);
                }
        }
        
+       /* free chains - not needed anymore */
+       BLI_freelistN(&chains);
+       
        /* the number of joints determines how we fill:
         *      1) between joint and cursor (joint=head, cursor=tail)
         *      2) between the two joints (order is dependent on active-bone/hierachy)
@@ -1976,6 +2019,7 @@ void fill_bones_armature(void)
        count= BLI_countlist(&points);
        
        if (count == 1) {
+               EditBonePoint *ebp;
                float curs[3];
                
                /* Get Points - selected joint */
@@ -1991,19 +2035,78 @@ void fill_bones_armature(void)
                newbone= add_points_bone(ebp->vec, curs);
        }
        else if (count == 2) {
+               EditBonePoint *ebp, *ebp2;
+               float head[3], tail[3];
+               
+               /* check that the points don't belong to the same bone */
+               ebp= (EditBonePoint *)points.first;
+               ebp2= ebp->next;
                
+               if ((ebp->head_owner==ebp2->tail_owner) && (ebp->head_owner!=NULL)) {
+                       error("Same bone selected...");
+                       BLI_freelistN(&points);
+                       return;
+               }
+               if ((ebp->tail_owner==ebp2->head_owner) && (ebp->tail_owner!=NULL)) {
+                       error("Same bone selected...");
+                       BLI_freelistN(&points);
+                       return;
+               }
+               
+               /* find which one should be the 'head' */
+               if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) {
+                       /* rule: whichever one is closer to 3d-cursor */
+                       float curs[3];
+                       float vecA[3], vecB[3];
+                       float distA, distB;
+                       
+                       /* get cursor location */
+                       VECCOPY (curs, give_cursor());  
+                       
+                       Mat4Invert(G.obedit->imat, G.obedit->obmat);
+                       Mat4MulVecfl(G.obedit->imat, curs);
+                       
+                       /* get distances */
+                       VecSubf(vecA, ebp->vec, curs);
+                       VecSubf(vecB, ebp2->vec, curs);
+                       distA= VecLength(vecA);
+                       distB= VecLength(vecB);
+                       
+                       /* compare distances - closer one therefore acts as direction for bone to go */
+                       if (distA < distB) {
+                               VECCOPY(head, ebp2->vec);
+                               VECCOPY(tail, ebp->vec);
+                       }
+                       else {
+                               VECCOPY(head, ebp->vec);
+                               VECCOPY(tail, ebp2->vec);
+                       }
+               }
+               else if (ebp->head_owner) {
+                       VECCOPY(head, ebp->vec);
+                       VECCOPY(tail, ebp2->vec);
+               }
+               else if (ebp2->head_owner) {
+                       VECCOPY(head, ebp2->vec);
+                       VECCOPY(tail, ebp->vec);
+               }
+               
+               /* add new bone */
+               newbone= add_points_bone(head, tail);
        }
        else {
-               error("Too many points selected"); // FIXME..
+               // FIXME.. figure out a method for multiple bones
+               error("Too many points selected"); 
+               return;
        }
        
-       /* free chains */
-       BLI_freelistN(&chains);
+       /* free points */
+       BLI_freelistN(&points);
        
        /* undo + updates */
        allqueue(REDRAWVIEW3D, 0);
        allqueue(REDRAWBUTSEDIT, 0);
-       BIF_undo_push("Merge Bones");
+       BIF_undo_push("Fill Bones");
 }
 
 /* this function merges between two bones, removes them and those in-between,