Visual Keying refactor
authorRoland Hess <me@harkyman.com>
Tue, 31 Jul 2007 13:37:59 +0000 (13:37 +0000)
committerRoland Hess <me@harkyman.com>
Tue, 31 Jul 2007 13:37:59 +0000 (13:37 +0000)
This code was always kludgy and this clean it up a bit.

insertmatrixkey() has been properly renamed insertkey_float().

Matrix calculations have been excised from the interface code,
and placed in insertmatrixkey(), so that you can call it from
anywhere without preliminaries and the proper values are calced
based on the passed adr code.

By much request, several semi-bug reports and discussion with
production animators, visual keying is now used automatic
for objects and bones that have constraints that cause them
to ignore their Ipos (CopyLoc, TrackTo, etc.). In those cases,
visual keying is used instead of the normal Ipo insertion
method. This "auto" functionality is toggled from the
"Use Visual Keying" button found along with "Needed" and
"Available" in the Edit Methods prefs.

Logic as to which constraints trigger visual keying on
which adrcodes can be tweaked in match_adr_constraint()
src/editipo.c

This has been tested by a couple of people, myself included,
but I may not have hit every constraint case, so evolutionary
feedback is welcome.

source/blender/blenkernel/BKE_global.h
source/blender/include/BSE_editipo.h
source/blender/src/editipo.c
source/blender/src/space.c

index 98a0cb99942d0e4f44a400ab290282ee7a4eb008..a1392bb0a983b3da8031d8318ee5ea79ce1ee06d 100644 (file)
@@ -191,6 +191,8 @@ typedef struct Global {
 #define G_DRAWSHARP     (1 << 28) /* draw edges with the sharp flag */
 #define G_SCULPTMODE    (1 << 29)
 
+#define G_AUTOMATKEYS  (1 << 30)
+
 /* G.fileflags */
 
 #define G_AUTOPACK               (1 << 0)
index f861a2abd7a109ba6fe9664a4d8ad016de4958e8..66c9cef8693be6d4433d1d89ec5d71714e9e826c 100644 (file)
@@ -158,8 +158,8 @@ void duplicate_ipo_keys(struct Ipo *ipo);
 void borderselect_ipo_key(struct Ipo *ipo, float xmin, float xmax, int val);
 void borderselect_icu_key(struct IpoCurve *icu, float xmin, float xmax, 
                                                  int (*select_function)(struct BezTriple *));
-void insertmatrixkey(ID *id, int blocktype, char *actname, char *constname, int adrcode, float matrixvalue);
-
+int insertmatrixkey(ID *id, int blocktype, char *actname, char *constname, int adrcode);
+void insertfloatkey(ID *id, int blocktype, char *actname, char *constname, int adrcode, float floatkey);
 void select_ipo_key(struct Ipo *ipo, float selx, int sel);
 void select_icu_key(struct IpoCurve *icu, float selx, int selectmode);
 void setexprap_ipoloop(struct Ipo *ipo, int code);
index c2b38cf4aef47697bc385cf6cc5b0b74ff721006..8cf16fb05e1be77d7b7aeb4172c00a36615a0e04 100644 (file)
@@ -20,7 +20,8 @@
  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  * All rights reserved.
  *
- * Contributor(s): Blender Foundation, 2005. Full recode
+ * Contributor(s): Blender Foundation, 2005. Full recode.
+ * Roland Hess, 2007. Visual Key refactor.
  *
  * ***** END GPL LICENSE BLOCK *****
  */
@@ -2154,42 +2155,271 @@ static int new_key_needed(IpoCurve *icu, float cFrame, float nValue)
                return KEYNEEDED_JUSTADD;
 }
 
-void insertkey(ID *id, int blocktype, char *actname, char *constname, int adrcode)
+/* a duplicate of insertkey that does not check for routing to insertmatrixkey 
+       to avoid recursion problems */
+static void insertkey_nonrecurs(ID *id, int blocktype, char *actname, char *constname, int adrcode)
 {
        IpoCurve *icu;
        Object *ob;
        void *poin= NULL;
        float curval, cfra;
        int vartype;
+       int matset=0;
        
-       icu= verify_ipocurve(id, blocktype, actname, constname, adrcode);
-       
-       if(icu) {
+       if (matset==0) {
+               icu= verify_ipocurve(id, blocktype, actname, constname, adrcode);
                
-               poin= get_context_ipo_poin(id, blocktype, actname, icu, &vartype);
-               
-               if(poin) {
-                       curval= read_ipo_poin(poin, vartype);
+               if(icu) {
                        
-                       cfra= frame_to_float(CFRA);
+                       poin= get_context_ipo_poin(id, blocktype, actname, icu, &vartype);
                        
-                       /* if action is mapped in NLA, it returns a correction */
-                       if(actname && actname[0] && GS(id->name)==ID_OB)
-                               cfra= get_action_frame((Object *)id, cfra);
+                       if(poin) {
+                               curval= read_ipo_poin(poin, vartype);
+                               
+                               cfra= frame_to_float(CFRA);
+                               
+                               /* if action is mapped in NLA, it returns a correction */
+                               if(actname && actname[0] && GS(id->name)==ID_OB)
+                                       cfra= get_action_frame((Object *)id, cfra);
+                               
+                               if( GS(id->name)==ID_OB ) {
+                                       ob= (Object *)id;
+                                       if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
+                                               /* actually frametofloat calc again! */
+                                               cfra-= ob->sf*G.scene->r.framelen;
+                                       }
+                               }
+                               
+                               insert_vert_ipo(icu, cfra, curval);
+                       }
+               }
+       }
+}
+
+int insertmatrixkey(ID *id, int blocktype, char *actname, char *constname, int adrcode)
+{
+       int matindex=0;
+       /* branch on adrcode and blocktype, generating the proper matrix-based
+       values to send to insertfloatkey */
+       if (GS(id->name)==ID_OB) {
+               Object *ob= (Object *)id;
+
+               if ( blocktype==ID_OB ){ //working with an object
+                       if ((ob)&&!(ob->parent)) {
+                               if ((adrcode==OB_ROT_X)||(adrcode==OB_ROT_Y)||(adrcode==OB_ROT_Z)) { //get a rotation
+                                       switch (adrcode) {
+                                               case OB_ROT_X:
+                                                       matindex=0;
+                                                       break;
+                                               case OB_ROT_Y:
+                                                       matindex=1;
+                                                       break;
+                                               case OB_ROT_Z:
+                                                       matindex=2;
+                                                       break;
+                                       }
+                                       float eul[3];
+                                       Mat4ToEul(ob->obmat, eul);
+                                       insertfloatkey(id, ID_OB, actname, NULL, adrcode, eul[matindex]*(5.72958));
+                                       return 1;
+                               } else if ((adrcode==OB_LOC_X)||(adrcode==OB_LOC_Y)||(adrcode==OB_LOC_Z)) {//get a translation
+                                       switch (adrcode) {
+                                               case OB_LOC_X:
+                                                       matindex=0;
+                                                       break;
+                                               case OB_LOC_Y:
+                                                       matindex=1;
+                                                       break;
+                                               case OB_LOC_Z:
+                                                       matindex=2;
+                                                       break;
+                                       }
+                                       insertfloatkey(id, ID_OB, actname, NULL, adrcode, ob->obmat[3][matindex]);
+                                       return 1;
+                               }
+                       }
+               } else if ( blocktype==ID_PO) { //working with a pose channel
+                       bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
+                       if (pchan) {
+                               if ((adrcode==AC_LOC_X)||(adrcode==AC_LOC_Y)||(adrcode==AC_LOC_Z)) {
+                                       switch (adrcode) {
+                                               case AC_LOC_X:
+                                                       matindex=0;
+                                                       break;
+                                               case AC_LOC_Y:
+                                                       matindex=1;
+                                                       break;
+                                               case AC_LOC_Z:
+                                                       matindex=2;
+                                                       break;
+                                       }
+                                       if (!(pchan->bone->parent)||((pchan->bone->parent)&&!(pchan->bone->flag&BONE_CONNECTED))) { /* don't use for non-connected child bones */
+                                               float delta_mat[4][4]; 
+                                               armature_mat_pose_to_delta(delta_mat, pchan->pose_mat, pchan->bone->arm_mat);
+                                               insertfloatkey(id, ID_PO, pchan->name, NULL, adrcode, delta_mat[3][matindex]);
+                                               return 1;
+                                       }
+                               } else if ((adrcode==AC_QUAT_W)||(adrcode==AC_QUAT_X)||(adrcode==AC_QUAT_Y)||(adrcode==AC_QUAT_Z)) { 
+                                       switch (adrcode) {
+                                               case AC_QUAT_W:
+                                                       matindex=0;
+                                                       break;
+                                               case AC_QUAT_X:
+                                                       matindex=1;
+                                                       break;
+                                               case AC_QUAT_Y:
+                                                       matindex=2;
+                                                       break;
+                                               case AC_QUAT_Z:
+                                                       matindex=3;
+                                                       break;
+                                       }
+                                       if (!(pchan->bone->parent)||((pchan->bone->parent)&&!(pchan->bone->flag&BONE_HINGE))) {  /* don't use for non-hinged child bones */
+                                               float delta_mat[4][4],trimat[3][3];
+                                               float localQuat[4];
+                                               armature_mat_pose_to_delta(delta_mat, pchan->pose_mat, pchan->bone->arm_mat);
+                                               /* Fixed this bit up from the old "hacky" version, as it was called.
+                                                       Not sure of the origin of Mat3ToQuat_is_ok or why its in there. In most cases, this
+                                                       produces the same result of the "hacky" version, and in some
+                                                       cases the results seem to be better. But whatever the case, this is unideal, as
+                                                       we're decomposing a 3x3 rotation matrix into a quat, which is
+                                                       not a discrete operation.                                                                                       */
+                                               Mat3CpyMat4(trimat, delta_mat);
+                                               Mat3ToQuat_is_ok(trimat, localQuat);
+                                               insertfloatkey(id, ID_PO, pchan->name, NULL, adrcode, localQuat[matindex]);
+                                               return 1;
+                                       }
+                               }
+                       }
+               }
+       }
+       /* failed to set a matrix key -- use traditional, but the non-recursing version */
+       insertkey_nonrecurs(id,blocktype,actname,constname,adrcode);
+       return 0;
+}
+
+static int match_adr_constraint(ID * id, int blocktype, char *actname, int adrcode)
+{      /* This function matches constraint blocks with adrcodes to see if the
+               visual keying method should be used. For example, an object looking to key
+               location and having a CopyLoc constraint would return true. */
+               
+       Object *ob=NULL;
+       int foundmatch=0;
+       int searchtype=0;
+       bConstraint *conref=NULL, *con=NULL;
+       
+       /*Retrieve constraint list*/
+       if( GS(id->name)==ID_OB ) 
+               ob= (Object *)id;
+       if (ob) {
+               if (blocktype==ID_PO) {
+                       bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
+                       conref=pchan->constraints.first;
+               } else if (blocktype==ID_OB) {
+                       conref=ob->constraints.first;
+               }
+               
+               if (conref) {
+                       /*Set search type: 1 is for translation contraints, 2 is for rotation*/
+                       if ((adrcode==OB_LOC_X)||(adrcode==OB_LOC_Y)||(adrcode==OB_LOC_Z)||(adrcode==AC_LOC_X)||(adrcode==AC_LOC_Y)||(adrcode==AC_LOC_Z)) {
+                               searchtype=1;
+                       } else if ((adrcode==OB_ROT_X)||(adrcode==OB_ROT_Y)||(adrcode==OB_ROT_Z)||(adrcode==AC_QUAT_W)||(adrcode==AC_QUAT_X)||(adrcode==AC_QUAT_Y)||(adrcode==AC_QUAT_Z)) {
+                               searchtype=2;
+                       }
                        
-                       if( GS(id->name)==ID_OB ) {
-                               ob= (Object *)id;
-                               if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
-                                       /* actually frametofloat calc again! */
-                                       cfra-= ob->sf*G.scene->r.framelen;
+                       if (searchtype>0) {
+                               for (con=conref; (con)&&(foundmatch==0); con=con->next) {
+                                       switch (con->type) {
+                                       /* match constraint types to which kinds of keying they would affect */
+                                               case CONSTRAINT_TYPE_CHILDOF:
+                                                       foundmatch=1;
+                                                       break;
+                                               case CONSTRAINT_TYPE_TRACKTO:
+                                                       if (searchtype==2) foundmatch=1;
+                                                       break;
+                                               case CONSTRAINT_TYPE_FOLLOWPATH:
+                                                       foundmatch=1;
+                                                       break;
+                                               case CONSTRAINT_TYPE_ROTLIMIT:
+                                                       if (searchtype==2) foundmatch=1;
+                                                       break;
+                                               case CONSTRAINT_TYPE_LOCLIMIT:
+                                                       if (searchtype==1) foundmatch=1;
+                                                       break;
+                                               case CONSTRAINT_TYPE_ROTLIKE:
+                                                       if (searchtype==2) foundmatch=1;
+                                                       break;
+                                               case CONSTRAINT_TYPE_LOCLIKE:
+                                                       if (searchtype==1) foundmatch=1;
+                                                       break;
+                                               case CONSTRAINT_TYPE_LOCKTRACK:
+                                                       if (searchtype==2) foundmatch=1;
+                                                       break;
+                                               case CONSTRAINT_TYPE_DISTANCELIMIT:
+                                                       if (searchtype==1) foundmatch=1;
+                                                       break;
+                                               case CONSTRAINT_TYPE_MINMAX:
+                                                       if (searchtype==1) foundmatch=1;
+                                                       break;
+                                               case CONSTRAINT_TYPE_TRANSFORM:
+                                                       foundmatch=1;
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
                                }
                        }
+               }
+       }
+       
+       return foundmatch;
                        
-                       insert_vert_ipo(icu, cfra, curval);
+}
+
+void insertkey(ID *id, int blocktype, char *actname, char *constname, int adrcode)
+{
+       IpoCurve *icu;
+       Object *ob;
+       void *poin= NULL;
+       float curval, cfra;
+       int vartype;
+       int matset=0;
+       
+       if ((G.flags&G_AUTOMATKEYS)&&(match_adr_constraint(id, blocktype, actname, adrcode))) {
+               matset=insertmatrixkey(id, blocktype, actname, constname, adrcode);
+       } 
+       if (matset==0) {
+               icu= verify_ipocurve(id, blocktype, actname, constname, adrcode);
+               
+               if(icu) {
+                       
+                       poin= get_context_ipo_poin(id, blocktype, actname, icu, &vartype);
+                       
+                       if(poin) {
+                               curval= read_ipo_poin(poin, vartype);
+                               
+                               cfra= frame_to_float(CFRA);
+                               
+                               /* if action is mapped in NLA, it returns a correction */
+                               if(actname && actname[0] && GS(id->name)==ID_OB)
+                                       cfra= get_action_frame((Object *)id, cfra);
+                               
+                               if( GS(id->name)==ID_OB ) {
+                                       ob= (Object *)id;
+                                       if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
+                                               /* actually frametofloat calc again! */
+                                               cfra-= ob->sf*G.scene->r.framelen;
+                                       }
+                               }
+                               
+                               insert_vert_ipo(icu, cfra, curval);
+                       }
                }
        }
 }
 
+
+
 /* This function is a 'smarter' version of the insert key code.
  * It uses an auxilliary function to check whether a keyframe is really needed */
 void insertkey_smarter(ID *id, int blocktype, char *actname, char *constname, int adrcode)
@@ -2244,9 +2474,8 @@ void insertkey_smarter(ID *id, int blocktype, char *actname, char *constname, in
        }
 }
 
-/* For inserting keys based on the object matrix - not on the current IPO value
-   Generically - it inserts the passed float value into the appropriate IPO */
-void insertmatrixkey(ID *id, int blocktype, char *actname, char *constname, int adrcode, float matrixvalue)
+/* For inserting keys based on an arbitrary float value */
+void insertfloatkey(ID *id, int blocktype, char *actname, char *constname, int adrcode, float floatkey)
 {
        IpoCurve *icu;
        Object *ob;
@@ -2275,7 +2504,9 @@ void insertmatrixkey(ID *id, int blocktype, char *actname, char *constname, int
                                        cfra-= ob->sf*G.scene->r.framelen;
                                }
                        }
-                       insert_vert_ipo(icu, cfra, matrixvalue);
+                       
+                       /* insert new keyframe at current frame */
+                       insert_vert_ipo(icu, cfra, floatkey);
                }
        }
 }
@@ -2829,42 +3060,26 @@ void common_insertkey(void)
                                                }
                                        }
                                        if(event==11 || event==13) {
-                                               float delta_mat[4][4]; 
                                                
-                                               armature_mat_pose_to_delta(delta_mat, pchan->pose_mat, pchan->bone->arm_mat);
-                                               insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_LOC_X, delta_mat[3][0]);
-                                               insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y, delta_mat[3][1]);
-                                               insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z, delta_mat[3][2]);
+                                               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) {
-                                               float delta_mat[4][4];
-                                               float localQuat[4], oldQuat[4];
-                                               
-                                               /* obtain rotation caused by constraints/IK*/
-                                               armature_mat_pose_to_delta(delta_mat, pchan->pose_mat, pchan->bone->arm_mat);
-                                               Mat4ToQuat(delta_mat, localQuat);
-                                               
-                                               /* bad hack warning:
-                                                * Write the 'visual' rotation onto the
-                                                * bone's quat/rotation values and use standard 
-                                                * keyframing method to insert a keyframe with this
-                                                * value. 
-                                                *
-                                                * Needed, as rotation wouldn't get keyed correctly
-                                                * otherwise for some strange reason. As a side-effect,
-                                                * sometimes there may be slightly un-updated bones, but
-                                                * still, it is better that this worked.
-                                                */
-                                                
-                                               QUATCOPY(oldQuat, pchan->quat);
-                                               QUATCOPY(pchan->quat, localQuat);
-                                               
-                                               insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W);
-                                               insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X);
-                                               insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y);
-                                               insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z);
-                                               
-                                               QUATCOPY(pchan->quat, oldQuat);
+                                               int matsuccess=0; 
+                                               /* check one to make sure we're not trying to set visual rot keys on
+                                                       bones inside of a chain, which only leads to tears. */
+                                               matsuccess=insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W);
+                                               insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X);
+                                               insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y);
+                                               insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z);
+                                               if (matsuccess==0) {
+                                                       insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X);
+                                                       insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y);
+                                                       insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z);
+                                                       insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W);
+                                               }
                                        }
                                        if (event==15 && ob->action) {
                                                bActionChannel *achan;
@@ -2951,17 +3166,14 @@ void common_insertkey(void)
                                                base->object->lay= tlay;
                                        }
                                        if(event==11 || event==13) {
-                                               insertmatrixkey(id, ID_OB, actname, NULL, OB_LOC_X, ob->obmat[3][0]);
-                                               insertmatrixkey(id, ID_OB, actname, NULL, OB_LOC_Y, ob->obmat[3][1]);
-                                               insertmatrixkey(id, ID_OB, actname, NULL, OB_LOC_Z, ob->obmat[3][2]);
+                                               insertmatrixkey(id, ID_OB, actname, NULL, OB_LOC_X);
+                                               insertmatrixkey(id, ID_OB, actname, NULL, OB_LOC_Y);
+                                               insertmatrixkey(id, ID_OB, actname, NULL, OB_LOC_Z);
                                        }
                                        if(event==12 || event==13) {
-                                               float eul[3];
-                                               
-                                               Mat4ToEul(ob->obmat, eul);
-                                               insertmatrixkey(id, ID_OB, actname, NULL, OB_ROT_X, eul[0]*(5.72958));
-                                               insertmatrixkey(id, ID_OB, actname, NULL, OB_ROT_Y, eul[1]*(5.72958));
-                                               insertmatrixkey(id, ID_OB, actname, NULL, OB_ROT_Z, eul[2]*(5.72958));
+                                               insertmatrixkey(id, ID_OB, actname, NULL, OB_ROT_X);
+                                               insertmatrixkey(id, ID_OB, actname, NULL, OB_ROT_Y);
+                                               insertmatrixkey(id, ID_OB, actname, NULL, OB_ROT_Z);
                                        }
                                        base->object->recalc |= OB_RECALC_OB;
                                }
index 8c74a0f46943441ef27fc31153e51c09fd3199a7..215a6addee46162db152c9ee6ca810b4d371d7ea 100644 (file)
@@ -3486,21 +3486,25 @@ void drawinfospace(ScrArea *sa, void *spacedata)
 
 
                uiDefBut(block, LABEL,0,"Auto keyframe",
-                       (xpos+(2*edgsp)+(2*mpref)+midsp),y4label,mpref,buth,
+                       (xpos+(2*edgsp)+(2*mpref)+midsp),y5label,mpref,buth,
                        0, 0, 0, 0, 0, "");
 
                uiDefButBitI(block, TOG, G_RECORDKEYS, REDRAWTIME, "Action and Object", 
-                                       (xpos+edgsp+(2*mpref)+(2*midsp)),y3,mpref, buth,
+                                       (xpos+edgsp+(2*mpref)+(2*midsp)),y4,mpref, buth,
                                         &(G.flags), 0, 0, 0, 0, "Automatic keyframe insertion in Object and Action Ipo curves");
-
+       
                uiBlockBeginAlign(block);
                uiDefButBitI(block, TOG, USER_KEYINSERTAVAI, REDRAWTIME, "Available", 
-                       (xpos+edgsp+(2*mpref)+(2*midsp)),y2,mpref, buth,
+                       (xpos+edgsp+(2*mpref)+(2*midsp)),y3,mpref, buth,
                        &(U.uiflag), 0, 0, 0, 0, "Automatic keyframe insertion in available curves");
                        
                uiDefButBitI(block, TOG, USER_KEYINSERTNEED, REDRAWTIME, "Needed", 
-                       (xpos+edgsp+(2*mpref)+(2*midsp)),y1,mpref, buth,
+                       (xpos+edgsp+(2*mpref)+(2*midsp)),y2,mpref, buth,
                        &(U.uiflag), 0, 0, 0, 0, "Automatic keyframe insertion only when keyframe needed");
+                       
+               uiDefButBitI(block, TOG, G_AUTOMATKEYS, REDRAWTIME, "Use Visual Keying", 
+                       (xpos+edgsp+(2*mpref)+(2*midsp)),y1,mpref, buth,
+                        &(G.flags), 0, 0, 0, 0, "Use Visual keying automatically for constrained objects");
                uiBlockEndAlign(block);
                        
 /*             uiDefButBitS(block, TOG, USER_KEYINSERTACT, 0, "Action",