Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorRoland Hess <me@harkyman.com>2007-07-31 17:37:59 +0400
committerRoland Hess <me@harkyman.com>2007-07-31 17:37:59 +0400
commit876cfc837e2f065fa370940ca578983d84c48a11 (patch)
tree130225194e0e75d25190625b01149c5d1f5733b2 /source
parent5afc4e051f44804d2a00eb987fe07cb0bae59514 (diff)
Visual Keying refactor
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.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_global.h2
-rw-r--r--source/blender/include/BSE_editipo.h4
-rw-r--r--source/blender/src/editipo.c342
-rw-r--r--source/blender/src/space.c14
4 files changed, 290 insertions, 72 deletions
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 98a0cb99942..a1392bb0a98 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -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)
diff --git a/source/blender/include/BSE_editipo.h b/source/blender/include/BSE_editipo.h
index f861a2abd7a..66c9cef8693 100644
--- a/source/blender/include/BSE_editipo.h
+++ b/source/blender/include/BSE_editipo.h
@@ -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);
diff --git a/source/blender/src/editipo.c b/source/blender/src/editipo.c
index c2b38cf4aef..8cf16fb05e1 100644
--- a/source/blender/src/editipo.c
+++ b/source/blender/src/editipo.c
@@ -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;
}
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index 8c74a0f4694..215a6addee4 100644
--- a/source/blender/src/space.c
+++ b/source/blender/src/space.c
@@ -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",