== Armature Animation Fixes ==
authorJoshua Leung <aligorith@gmail.com>
Tue, 25 Sep 2007 05:04:34 +0000 (05:04 +0000)
committerJoshua Leung <aligorith@gmail.com>
Tue, 25 Sep 2007 05:04:34 +0000 (05:04 +0000)
This commit fixes several bugs related to animating armatures. I've also tidied up the formatting in a few files along the way, and also commented the flags for this pose->flag.

What's new/fixed:
* Undo will no longer destroy entire un-keyframed poses. Now it behaves as expected, and only reverses the most recent change.
* On some files, POSE_DO_UNLOCK somehow got set on files and never cleared. The symptom of this was a file in which you suddenly could no longer pose an armature at all without using auto-keyframing. A check to prevent this from happening again has been added (it will also fix old files too)

Notes:
- Now, all PoseChannels get tagged with BONE_UNKEYED after they have been transformed. This flag prevents IPO data being flushed over these new values, even after undo.
- These tags only get removed on frame-changes or inserting new keyframes.

source/blender/blenkernel/BKE_action.h
source/blender/blenkernel/intern/action.c
source/blender/blenkernel/intern/scene.c
source/blender/makesdna/DNA_action_types.h
source/blender/makesdna/DNA_armature_types.h
source/blender/src/edit.c
source/blender/src/editarmature.c
source/blender/src/editipo.c
source/blender/src/poseobject.c
source/blender/src/transform_conversions.c

index 3caf0ad2cc64529bbeb20676a8814b9ad493bed2..68a6be047351d36d8f6efd4a9cec2bac50157241 100644 (file)
@@ -101,6 +101,9 @@ struct bPoseChannel *verify_pose_channel(struct bPose* pose,
 /* sets constraint flags */
 void update_pose_constraint_flags(struct bPose *pose);
 
+/* clears BONE_UNKEYED flags for frame changing */
+void framechange_poses_clear_unkeyed(void);
+
 /**
  * Allocate a new bAction on the heap and copy 
  * the contents of src into it. If src is NULL NULL is returned.
index c333ece497d928a175c3a98b3a77b40d8582fccf..8274e3253a9e9d5e8e2c2574a669dc7c75d32e0d 100644 (file)
@@ -351,6 +351,28 @@ void update_pose_constraint_flags(bPose *pose)
        }
 }
 
+/* Clears all BONE_UNKEYED flags for every pose channel in every pose 
+ * This should only be called on frame changing, when it is acceptable to
+ * do this. Otherwise, these flags should not get cleared as poses may get lost.
+ */
+void framechange_poses_clear_unkeyed(void)
+{
+       Object *ob;
+       bPose *pose;
+       bPoseChannel *pchan;
+       
+       /* This needs to be done for each object that has a pose */
+       // TODO: proxies may/may not be correctly handled here... (this needs checking) 
+       for (ob= G.main->object.first; ob; ob= ob->id.next) {
+               /* we only need to do this on objects with a pose */
+               if ( (pose= ob->pose) ) {
+                       for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
+                               if (pchan->bone) 
+                                       pchan->bone->flag &= ~BONE_UNKEYED;
+                       }
+               }
+       }
+}
 
 /* ************************ END Pose channels *************** */
 
@@ -680,9 +702,15 @@ void extract_pose_from_action(bPose *pose, bAction *act, float ctime)
        
        /* Copy the data from the action into the pose */
        for (pchan= pose->chanbase.first; pchan; pchan=pchan->next) {
+               /* skip this pose channel if it has been tagged as having unkeyed poses */
+               if ((pchan->bone) && (pchan->bone->flag & BONE_UNKEYED)) 
+                       continue;
+               
+               /* get action channel and clear pchan-transform flags */
                achan= get_action_channel(act, pchan->name);
                pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
-               if(achan) {
+               
+               if (achan) {
                        ipo = achan->ipo;
                        if (ipo) {
                                /* Evaluates and sets the internal ipo value */
@@ -1252,12 +1280,11 @@ static void do_nla(Object *ob, int blocktype)
 
 void do_all_pose_actions(Object *ob)
 {
-
-       // only to have safe calls from editor
+       /* only to have safe calls from editor */
        if(ob==NULL) return;
        if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
 
-       if(ob->pose->flag & POSE_LOCKED) {  // no actions to execute while transform
+       if(ob->pose->flag & POSE_LOCKED) {  /*  no actions to execute while transform */
                if(ob->pose->flag & POSE_DO_UNLOCK)
                        ob->pose->flag &= ~(POSE_LOCKED|POSE_DO_UNLOCK);
        }
@@ -1271,6 +1298,9 @@ void do_all_pose_actions(Object *ob)
        else if(ob->nlastrips.first) {
                do_nla(ob, ID_AR);
        }
+       
+       /* clear POSE_DO_UNLOCK flags that might have slipped through (just in case) */
+       ob->pose->flag &= ~POSE_DO_UNLOCK;
 }
 
 /* called from where_is_object */
index ea4911906bd053b828540349a8b097019cd466b8..7cce8c5e8c93a2e05f2ee83102b154c2cf27d65d 100644 (file)
@@ -530,6 +530,9 @@ void scene_update_for_newframe(Scene *sce, unsigned int lay)
 {
        Scene *scene= sce;
        
+       /* clears all BONE_UNKEYED flags for every pose's pchans */
+       framechange_poses_clear_unkeyed();
+       
        /* object ipos are calculated in where_is_object */
        do_all_data_ipos();
        
@@ -540,7 +543,6 @@ void scene_update_for_newframe(Scene *sce, unsigned int lay)
                scene_update(sce, lay);
 
        scene_update(scene, lay);
-       
 }
 
 /* return default layer, also used to patch old files */
index 9ff07aeb4532d3bb97096d8166ffa8dd4f6b92b3..5bdb4419b6ea92333cc429a4d6d4b3bbd2e3d845 100644 (file)
@@ -148,18 +148,27 @@ typedef struct SpaceAction {
 #define ACHAN_MOVED     0x80000000
 
 /* SpaceAction flag */
-#define SACTION_MOVING         1       /* during transform */
-#define SACTION_SLIDERS                2       /* show sliders (if relevant) - limited to shape keys for now */
-#define SACTION_DRAWTIME       4       /* draw time in seconds instead of time in frames */
+       /* during transform */
+#define SACTION_MOVING         1       
+       /* show sliders (if relevant) - limited to shape keys for now */
+#define SACTION_SLIDERS                2       
+       /* draw time in seconds instead of time in frames */
+#define SACTION_DRAWTIME       4       
 
 /* SpaceAction AutoSnap Settings (also used by SpaceNLA) */
-#define SACTSNAP_OFF   0       /* no auto-snap */
-#define SACTSNAP_STEP  1       /* snap to 1.0 frame/second intervals */
-#define SACTSNAP_FRAME 2       /* snap to actual frames/seconds (nla-action time) */
+       /* no auto-snap */
+#define SACTSNAP_OFF   0       
+       /* snap to 1.0 frame/second intervals */
+#define SACTSNAP_STEP  1
+       /* snap to actual frames/seconds (nla-action time) */
+#define SACTSNAP_FRAME 2       
 
 /* Pose->flag */
+       /* results in armature_rebuild_pose being called */
 #define POSE_RECALC            1
+       /* prevents any channel from getting overridden by anim from IPO */
 #define POSE_LOCKED            2
+       /* clears the POSE_LOCKED flag for the next time the pose is evaluated */
 #define POSE_DO_UNLOCK 4
 
 /* PoseChannel (transform) flags */
index 53a5f26033cbc6167150fe0db1412f59dd764bfc..31a95363802b5323f8aef127180d42626796e346 100644 (file)
@@ -145,6 +145,7 @@ typedef struct bArmature {
                        /* multiplies vgroup with envelope */
 #define                BONE_MULT_VG_ENV        2048
 #define                BONE_NO_DEFORM          4096
-
+                       /* set to prevent destruction of its unkeyframed pose (after transform) */
+#define        BONE_UNKEYED            8192
 
 #endif
index fb62c33abe82ed4ca0cb5b61a4058a1c91be8413..7d784dcecfd39dbe8b342033dbb815bd6a946fe6 100644 (file)
@@ -1158,13 +1158,13 @@ void snap_sel_to_grid()
                if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
                        make_trans_verts(bmat[0], bmat[1], 0);
                if(tottrans==0) return;
-
+               
                Mat3CpyMat4(bmat, G.obedit->obmat);
                Mat3Inv(imat, bmat);
-
+               
                tv= transvmain;
                for(a=0; a<tottrans; a++, tv++) {
-
+                       
                        VECCOPY(vec, tv->loc);
                        Mat3MulVecfl(bmat, vec);
                        VecAddf(vec, vec, G.obedit->obmat[3]);
@@ -1172,17 +1172,17 @@ void snap_sel_to_grid()
                        vec[1]= G.vd->gridview*floor(.5+ vec[1]/gridf);
                        vec[2]= G.vd->gridview*floor(.5+ vec[2]/gridf);
                        VecSubf(vec, vec, G.obedit->obmat[3]);
-
+                       
                        Mat3MulVecfl(imat, vec);
                        VECCOPY(tv->loc, vec);
-
+                       
                }
-
+               
                special_transvert_update();
                
                MEM_freeN(transvmain);
                transvmain= 0;
-
+       
                allqueue(REDRAWVIEW3D, 0);
                return;
        }
@@ -1274,31 +1274,29 @@ void snap_sel_to_curs()
 
        if(G.obedit) {
                tottrans= 0;
-
+               
                if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
                        make_trans_verts(bmat[0], bmat[1], 0);
                if(tottrans==0) return;
-
+               
                Mat3CpyMat4(bmat, G.obedit->obmat);
                Mat3Inv(imat, bmat);
-
+               
                tv= transvmain;
                for(a=0; a<tottrans; a++, tv++) {
-
                        vec[0]= curs[0]-G.obedit->obmat[3][0];
                        vec[1]= curs[1]-G.obedit->obmat[3][1];
                        vec[2]= curs[2]-G.obedit->obmat[3][2];
-
+                       
                        Mat3MulVecfl(imat, vec);
                        VECCOPY(tv->loc, vec);
-
                }
                
                special_transvert_update();
                
                MEM_freeN(transvmain);
                transvmain= 0;
-
+               
                allqueue(REDRAWVIEW3D, 0);
                return;
        }
@@ -1346,10 +1344,10 @@ void snap_sel_to_curs()
                                vec[0]= -ob->obmat[3][0] + curs[0];
                                vec[1]= -ob->obmat[3][1] + curs[1];
                                vec[2]= -ob->obmat[3][2] + curs[2];
-
+                               
                                if(ob->parent) {
                                        where_is_object(ob);
-
+                                       
                                        Mat3Inv(imat, originmat);
                                        Mat3MulVecfl(imat, vec);
                                        ob->loc[0]+= vec[0];
@@ -1388,7 +1386,6 @@ void snap_curs_to_grid()
        curs[2]= G.vd->gridview*floor(.5+curs[2]/gridf);
 
        allqueue(REDRAWVIEW3D, 0);
-
 }
 
 void snap_curs_to_sel()
@@ -1406,13 +1403,13 @@ void snap_curs_to_sel()
 
        if(G.obedit) {
                tottrans=0;
-
+               
                if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
                        make_trans_verts(bmat[0], bmat[1], 2);
                if(tottrans==0) return;
-
+               
                Mat3CpyMat4(bmat, G.obedit->obmat);
-
+               
                tv= transvmain;
                for(a=0; a<tottrans; a++, tv++) {
                        VECCOPY(vec, tv->loc);
@@ -1421,7 +1418,7 @@ void snap_curs_to_sel()
                        VecAddf(centroid, centroid, vec);
                        DO_MINMAX(vec, min, max);
                }
-
+               
                if(G.vd->around==V3D_CENTROID) {
                        VecMulf(centroid, 1.0/(float)tottrans);
                        VECCOPY(curs, centroid);
@@ -1492,20 +1489,20 @@ void snap_curs_to_firstsel()
 
        if(G.obedit) {
                tottrans=0;
-
+               
                if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
                        make_trans_verts(bmat[0], bmat[1], 0);
                if(tottrans==0) return;
-
+               
                Mat3CpyMat4(bmat, G.obedit->obmat);
-
+               
                tv= transvmain;
                VECCOPY(vec, tv->loc);
                        /*Mat3MulVecfl(bmat, vec);
                        VecAddf(vec, vec, G.obedit->obmat[3]);
                        VecAddf(centroid, centroid, vec);
                        DO_MINMAX(vec, min, max);*/
-
+               
                if(G.vd->around==V3D_CENTROID) {
                        VecMulf(vec, 1.0/(float)tottrans);
                        VECCOPY(curs, vec);
@@ -1561,14 +1558,14 @@ void snap_to_center()
 
        if(G.obedit) {
                tottrans= 0;
-
+               
                if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
                        make_trans_verts(bmat[0], bmat[1], 0);
                if(tottrans==0) return;
-
+               
                Mat3CpyMat4(bmat, G.obedit->obmat);
                Mat3Inv(imat, bmat);
-
+               
                tv= transvmain;
                for(a=0; a<tottrans; a++, tv++) {
                        VECCOPY(vec, tv->loc);
@@ -1577,7 +1574,7 @@ void snap_to_center()
                        VecAddf(centroid, centroid, vec);
                        DO_MINMAX(vec, min, max);
                }
-
+               
                if(G.vd->around==V3D_CENTROID) {
                        VecMulf(centroid, 1.0/(float)tottrans);
                        VECCOPY(snaploc, centroid);
@@ -1590,7 +1587,6 @@ void snap_to_center()
                
                MEM_freeN(transvmain);
                transvmain= 0;
-
        }
        else {
                base= (G.scene->base.first);
@@ -1638,21 +1634,20 @@ void snap_to_center()
        /* Snap the selection to the snaplocation (duh!) */
        if(G.obedit) {
                tottrans= 0;
-
+               
                if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
                        make_trans_verts(bmat[0], bmat[1], 0);
                if(tottrans==0) return;
-
+               
                Mat3CpyMat4(bmat, G.obedit->obmat);
                Mat3Inv(imat, bmat);
-
+               
                tv= transvmain;
                for(a=0; a<tottrans; a++, tv++) {
-
                        vec[0]= snaploc[0]-G.obedit->obmat[3][0];
                        vec[1]= snaploc[1]-G.obedit->obmat[3][1];
                        vec[2]= snaploc[2]-G.obedit->obmat[3][2];
-
+                       
                        Mat3MulVecfl(imat, vec);
                        VECCOPY(tv->loc, vec);
                }
@@ -1661,7 +1656,7 @@ void snap_to_center()
                
                MEM_freeN(transvmain);
                transvmain= 0;
-
+               
                allqueue(REDRAWVIEW3D, 0);
                return;
        }
@@ -1702,10 +1697,10 @@ void snap_to_center()
                                vec[0]= -ob->obmat[3][0] + snaploc[0];
                                vec[1]= -ob->obmat[3][1] + snaploc[1];
                                vec[2]= -ob->obmat[3][2] + snaploc[2];
-
+                               
                                if(ob->parent) {
                                        where_is_object(ob);
-
+                                       
                                        Mat3Inv(imat, originmat);
                                        Mat3MulVecfl(imat, vec);
                                        ob->loc[0]+= vec[0];
@@ -1725,7 +1720,7 @@ void snap_to_center()
                                autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
                        }
                }
-
+               
                base= base->next;
        }
        DAG_scene_flush_update(G.scene, screen_view3d_layers());
index 12d58ad535a677ab1f63796ba11ce0016db3de4f..81467b95297b3396af006a6f92dd7909aa4fb225 100644 (file)
@@ -2221,7 +2221,7 @@ void clear_armature(Object *ob, char mode)
        for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
                if(pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
                        if(arm->layer & pchan->bone->layer) {
-                               switch (mode){
+                               switch (mode) {
                                        case 'r':
                                                pchan->quat[1]=pchan->quat[2]=pchan->quat[3]=0.0F; pchan->quat[0]=1.0F;
                                                break;
@@ -2233,6 +2233,9 @@ void clear_armature(Object *ob, char mode)
                                                break;
                                                
                                }
+                               
+                               /* the current values from IPO's may not be zero, so tag as unkeyed */
+                               pchan->bone->flag |= BONE_UNKEYED;
                        }
                }
        }
index f65e70ce59e5208c974b0463bf464b8b80eddfc2..75cded52010ebe52681cbe063fa5ff77338a9c98 100644 (file)
@@ -3016,7 +3016,7 @@ void common_insertkey(void)
                if (ob && (ob->flag & OB_POSEMODE)) {
                        bPoseChannel *pchan;
                        
-                       set_pose_keys(ob);  // sets pchan->flag to POSE_KEY if bone selected
+                       set_pose_keys(ob);  /* sets pchan->flag to POSE_KEY if bone selected, and clears if not */
                        for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next)
                                if (pchan->flag & POSE_KEY)
                                        break;
@@ -3058,13 +3058,14 @@ void common_insertkey(void)
 
                        id= &ob->id;
                        for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
-                               if (pchan->flag & POSE_KEY){
+                               if (pchan->flag & POSE_KEY) {
+                                       /* insert relevant keyframes */
                                        if(event==0 || event==3 ||event==4) {
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X, 0);
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y, 0);
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z, 0);
                                        }
-                                       if(event==1 || event==3 ||event==4) {
+                                       if(event==1 || event==3 || event==4) {
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X, 0);
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y, 0);
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z, 0);
@@ -3077,7 +3078,7 @@ void common_insertkey(void)
                                        }
                                        if (event==9 && ob->action) {
                                                bActionChannel *achan;
-
+                                               
                                                for (achan = ob->action->chanbase.first; achan; achan=achan->next){
                                                        if (achan->ipo && !strcmp (achan->name, pchan->name)){
                                                                for (icu = achan->ipo->curve.first; icu; icu=icu->next){
@@ -3088,11 +3089,9 @@ void common_insertkey(void)
                                                }
                                        }
                                        if(event==11 || event==13) {
-                                               
                                                insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_LOC_X);
                                                insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y);
                                                insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z);
-                                               
                                        }
                                        if(event==12 || event==13) {
                                                int matsuccess=0; 
@@ -3111,7 +3110,7 @@ void common_insertkey(void)
                                        }
                                        if (event==15 && ob->action) {
                                                bActionChannel *achan;
-
+                                               
                                                for (achan = ob->action->chanbase.first; achan; achan=achan->next){
                                                        if (achan->ipo && !strcmp (achan->name, pchan->name)){
                                                                for (icu = achan->ipo->curve.first; icu; icu=icu->next){
@@ -3120,7 +3119,11 @@ void common_insertkey(void)
                                                                break;
                                                        }
                                                }
-                                       }       
+                                       }
+                                       
+                                       /* clear unkeyed flag (it doesn't matter if it's set or not) */
+                                       if (pchan->bone)
+                                               pchan->bone->flag &= ~BONE_UNKEYED;
                                }
                        }
                        if(ob->action)
index ab6d3f47eebf0ffd1fc1c57a9f4f678470ad25d4..f36b392775eabef8f0e7e0c49f56c2674cdd7954 100644 (file)
@@ -680,7 +680,7 @@ void paste_posebuf (int flip)
        
        /* Safely merge all of the channels in this pose into
        any existing pose */
-       for (chan=g_posebuf->chanbase.first; chan; chan=chan->next){
+       for (chan=g_posebuf->chanbase.first; chan; chan=chan->next) {
                if (chan->flag & POSE_KEY) {
                        BLI_strncpy(name, chan->name, sizeof(name));
                        if (flip)
@@ -689,7 +689,7 @@ void paste_posebuf (int flip)
                        /* only copy when channel exists, poses are not meant to add random channels to anymore */
                        pchan= get_pose_channel(ob->pose, name);
                        
-                       if(pchan) {
+                       if (pchan) {
                                /* only loc rot size */
                                /* only copies transform info for the pose */
                                VECCOPY(pchan->loc, chan->loc);
@@ -697,35 +697,44 @@ void paste_posebuf (int flip)
                                QUATCOPY(pchan->quat, chan->quat);
                                pchan->flag= chan->flag;
                                
-                               if (flip){
+                               if (flip) {
                                        pchan->loc[0]*= -1;
-
+                                       
                                        QuatToEul(pchan->quat, eul);
                                        eul[1]*= -1;
                                        eul[2]*= -1;
                                        EulToQuat(eul, pchan->quat);
                                }
-
-                               if (G.flags & G_RECORDKEYS){
+                               
+                               if (G.flags & G_RECORDKEYS) {
                                        ID *id= &ob->id;
-
+                                       
                                        /* Set keys on pose */
-                                       if (chan->flag & POSE_ROT){
+                                       if (chan->flag & POSE_ROT) {
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X, 0);
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y, 0);
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z, 0);
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W, 0);
                                        }
-                                       if (chan->flag & POSE_SIZE){
+                                       if (chan->flag & POSE_SIZE) {
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_X, 0);
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Y, 0);
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Z, 0);
                                        }
-                                       if (chan->flag & POSE_LOC){
+                                       if (chan->flag & POSE_LOC) {
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X, 0);
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y, 0);
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z, 0);
                                        }
+                                       
+                                       /* clear any unkeyed tags */
+                                       if (chan->bone)
+                                               chan->bone->flag &= ~BONE_UNKEYED;
+                               }
+                               else {
+                                       /* add unkeyed tags */
+                                       if (chan->bone)
+                                               chan->bone->flag |= BONE_UNKEYED;
                                }
                        }
                }
index 31002134d55c09978ea9422ef10fab303ad20378..058461806ce9bac4ddb70a9edcf4910217070591 100644 (file)
@@ -2607,15 +2607,19 @@ void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik)
                if (!act)
                        act= ob->action= add_empty_action("Action");
                
-               for (pchan=pose->chanbase.first; pchan; pchan=pchan->next){
-                       if (pchan->bone->flag & BONE_TRANSFORM){
-
+               for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) {
+                       if (pchan->bone->flag & BONE_TRANSFORM) {
+                               /* clear any 'unkeyed' flag it may have */
+                               pchan->bone->flag &= ~BONE_UNKEYED;
+                               
+                               /* only insert into available channels? */
                                if(U.uiflag & USER_KEYINSERTAVAI) {
                                        bActionChannel *achan; 
-
+                                       
                                        for (achan = act->chanbase.first; achan; achan=achan->next){
                                                if (achan->ipo && !strcmp (achan->name, pchan->name)){
                                                        for (icu = achan->ipo->curve.first; icu; icu=icu->next){
+                                                               /* only insert keyframe if needed? */
                                                                if (U.uiflag & USER_KEYINSERTNEED)
                                                                        insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, icu->adrcode);
                                                                else
@@ -2625,6 +2629,7 @@ void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik)
                                                }
                                        }
                                }
+                               /* only insert keyframe if needed? */
                                else if (U.uiflag & USER_KEYINSERTNEED) {
                                        if ((tmode==TFM_TRANSLATION) && (targetless_ik==0)) {
                                                insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_X);
@@ -2643,16 +2648,17 @@ void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik)
                                                insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_Z);
                                        }
                                }
+                               /* insert keyframe in any channel that's appropriate */
                                else {
                                        insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_X, 0);
                                        insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_Y, 0);
                                        insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_Z, 0);
-
+                                       
                                        insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_W, 0);
                                        insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_X, 0);
                                        insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_Y, 0);
                                        insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_Z, 0);
-
+                                       
                                        insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_X, 0);
                                        insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_Y, 0);
                                        insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_Z, 0);
@@ -2667,6 +2673,15 @@ void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik)
                allqueue(REDRAWNLA, 0);
                allqueue(REDRAWTIME, 0);
        }
+       else {
+               /* tag channels that should have unkeyed data */
+               for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) {
+                       if (pchan->bone->flag & BONE_TRANSFORM) {
+                               /* tag this channel */
+                               pchan->bone->flag |= BONE_UNKEYED;
+                       }
+               }
+       }
 }
 
 /* very bad call!!! - copied from editnla.c!  */
@@ -2775,8 +2790,8 @@ void special_aftertrans_update(TransInfo *t)
                
                if(t->mode==TFM_TRANSLATION)
                        pose_grab_with_ik_clear(ob);
-               
-               /* automatic inserting of keys */
+                       
+               /* automatic inserting of keys and unkeyed tagging - only if transform wasn't cancelled */
                if(!cancelled) {
                        autokeyframe_pose_cb_func(ob, t->mode, targetless_ik);
                        DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);