== Auto-Keyframing Refactor (Peach Request) ==

Refactored Auto-Keyframing to make it easier to add more options. There are now three "states" for auto-keying: off, add/replace keys, replace keys.

Description of modes:
1) No auto-keying is done
2) Add new keyframes or replace existing ones if possible (old behaviour)
3) Only modify existing keys, but not insert new ones. 

Internally, I've moved the auto-keying settings out of G.flag and U.uiflag and moved them into their own variables in Userdef, and provided some macros to access those easily. As a result, old auto-keying settings are currently lost.

Also, removed the manual calls to insertkey done in pose-relax. The reason auto-keying didn't work before was because the bones didn't have the BONE_TRANSFORM flag applied. Now, these are set temporarily.


Todo(s):
* Make icons for the TimeLine header menu (currently just a text menu)
* Add version-patches for old files
* Double-check code for all places that use auto-keying (i.e. PoseLib)
This commit is contained in:
2008-01-10 01:36:22 +00:00
parent 5b0b214407
commit 38a33eb7da
10 changed files with 136 additions and 93 deletions

View File

@@ -180,7 +180,7 @@ typedef struct Global {
#define G_DRAW_FACEAREA (1 << 23)
#define G_DRAW_EDGEANG (1 << 24)
#define G_RECORDKEYS (1 << 25)
/* #define G_RECORDKEYS (1 << 25) also removed */
/*#ifdef WITH_VERSE*/
#define G_VERSE_CONNECTED (1 << 26)
#define G_DRAW_VERSE_DEBUG (1 << 27)
@@ -189,7 +189,7 @@ typedef struct Global {
#define G_SCULPTMODE (1 << 29)
#define G_PARTICLEEDIT (1 << 30)
#define G_AUTOMATKEYS (1 << 30)
/* #define G_AUTOMATKEYS (1 << 30) also removed */
#define G_HIDDENHANDLES (1 << 31) /* used for curves only */
/* macro for testing face select mode

View File

@@ -382,6 +382,7 @@ void special_aftertrans_update(TransInfo *t);
void transform_autoik_update(TransInfo *t, short mode);
/* auto-keying stuff used by special_aftertrans_update */
short autokeyframe_cfra_can_key(struct Object *ob);
void autokeyframe_ob_cb_func(struct Object *ob, int tmode);
void autokeyframe_pose_cb_func(struct Object *ob, int tmode, short targetless_ik);

View File

@@ -197,7 +197,10 @@ typedef struct UserDef {
short glreslimit;
char versemaster[160];
char verseuser[160];
float glalphaclip, pad;
float glalphaclip;
short autokey_mode; /* autokeying mode */
short autokey_flag; /* flags for autokeying */
struct ColorBand coba_weight; /* from texture.h */
} UserDef;
@@ -229,16 +232,14 @@ extern UserDef U; /* from usiblender.c !!!! */
#define USER_ADD_VIEWALIGNED (1 << 19)
#define USER_ADD_VIEWALIGNED (1 << 19)
/* viewzom */
#define USER_ZOOM_CONT 0
#define USER_ZOOM_SCALE 1
#define USER_ZOOM_DOLLY 2
/* uiflag */
#define USER_KEYINSERTACT (1 << 0)
#define USER_KEYINSERTOBJ (1 << 1)
// old flag for #define USER_KEYINSERTACT (1 << 0)
// old flag for #define USER_KEYINSERTOBJ (1 << 1)
#define USER_WHEELZOOMDIR (1 << 2)
#define USER_FILTERFILEEXTS (1 << 3)
#define USER_DRAWVIEWINFO (1 << 4)
@@ -252,16 +253,33 @@ extern UserDef U; /* from usiblender.c !!!! */
#define USER_LOCKAROUND (1 << 12)
#define USER_GLOBALUNDO (1 << 13)
#define USER_ORBIT_SELECTION (1 << 14)
#define USER_KEYINSERTAVAI (1 << 15)
// old flag for #define USER_KEYINSERTAVAI (1 << 15)
#define USER_HIDE_DOT (1 << 16)
#define USER_SHOW_ROTVIEWICON (1 << 17)
#define USER_SHOW_VIEWPORTNAME (1 << 18)
#define USER_KEYINSERTNEED (1 << 19)
// old flag for #define USER_KEYINSERTNEED (1 << 19)
#define USER_ZOOM_TO_MOUSEPOS (1 << 20)
#define USER_SHOW_FPS (1 << 21)
#define USER_SHOW_FPS (1 << 21)
/* Auto-Keying mode */
enum {
AUTOKEY_MODE_OFF = 0,
AUTOKEY_MODE_NORMAL,
AUTOKEY_MODE_EDITKEYS
} eAutoKeyframe_Mode;
/* Auto-Keying flag */
enum {
AUTOKEY_FLAG_INSERTAVAIL = (1<<0),
AUTOKEY_FLAG_INSERTNEEDED = (1<<1),
AUTOKEY_FLAG_AUTOMATKEY = (1<<2)
} eAutoKeyframe_Flag;
/* Auto-Keying macros */
#define IS_AUTOKEY_MODE(mode) (U.autokey_mode == AUTOKEY_MODE_##mode)
#define IS_AUTOKEY_FLAG(flag) (U.autokey_flag == AUTOKEY_FLAG_##flag)
/* transopts */
#define USER_TR_TOOLTIPS (1 << 0)
#define USER_TR_BUTTONS (1 << 1)
#define USER_TR_MENUS (1 << 2)
@@ -272,7 +290,6 @@ extern UserDef U; /* from usiblender.c !!!! */
#define CONVERT_TO_UTF8 (1 << 7)
/* dupflag */
#define USER_DUP_MESH (1 << 0)
#define USER_DUP_CURVE (1 << 1)
#define USER_DUP_SURF (1 << 2)
@@ -286,13 +303,11 @@ extern UserDef U; /* from usiblender.c !!!! */
#define USER_DUP_ACT (1 << 10)
/* gameflags */
#define USER_VERTEX_ARRAYS 1
#define USER_DISABLE_SOUND 2
#define USER_DISABLE_MIPMAP 4
/* vrml flag */
#define USER_VRML_LAYERS 1
#define USER_VRML_AUTOSCALE 2
#define USER_VRML_TWOSIDED 4

View File

@@ -2533,7 +2533,7 @@ void insertkey(ID *id, int blocktype, char *actname, char *constname, int adrcod
int vartype;
int matset=0;
if ((G.flags&G_AUTOMATKEYS)&&(match_adr_constraint(id, blocktype, actname, adrcode))) {
if ((IS_AUTOKEY_FLAG(AUTOMATKEY))&&(match_adr_constraint(id, blocktype, actname, adrcode))) {
matset=insertmatrixkey(id, blocktype, actname, constname, adrcode);
}
if (matset==0) {

View File

@@ -2636,7 +2636,7 @@ void fly(void)
G.vd->persp= 2;
/* record the motion */
if (G.flags & G_RECORDKEYS && (!playing_anim || cfra != G.scene->r.cfra)) {
if (IS_AUTOKEY_MODE(NORMAL) && (!playing_anim || cfra != G.scene->r.cfra)) {
cfra = G.scene->r.cfra;
if (xlock || zlock || moffset[0] || moffset[1]) {
@@ -2683,7 +2683,7 @@ void fly(void)
DAG_object_flush_update(G.scene, G.vd->camera, OB_RECALC_OB);
if (G.flags & G_RECORDKEYS) {
if (IS_AUTOKEY_MODE(NORMAL)) {
allqueue(REDRAWIPO, 0);
allspace(REMAKEIPO, 0);
allqueue(REDRAWNLA, 0);

View File

@@ -524,10 +524,13 @@ void time_buttons(ScrArea *sa)
xco, 0, XIC, YIC, 0, 0, 0, 0, 0, "Skip to End frame (Shift UpArrow)");
xco+= XIC+8;
uiDefIconButBitI(block, TOG, G_RECORDKEYS, REDRAWINFO, ICON_REC,
xco, 0, XIC, YIC, &(G.flags), 0, 0, 0, 0, "Automatically insert keyframes in Object and Action Ipo curves");
// FIXME: give this icons (and maybe make it XIC wide again) - it used to use the "ICON_REC" (red dot)
uiDefButS(block, MENU, REDRAWINFO,
"Auto-Keying Mode %t|No Auto-Keying %x0|Add/Replace Keys%x1|Replace Keys %x2",
xco, 0, 4*XIC, YIC, &(U.autokey_mode), 0, 1, 0, 0,
"Automatic keyframe insertion for Objects and Bones");
xco+= XIC+16;
xco+= (4*XIC)+16;
uiDefIconButBitI(block, TOG, TIME_WITH_SEQ_AUDIO, B_DIFF, ICON_SPEAKER,
xco, 0, XIC, YIC, &(stime->redraws), 0, 0, 0, 0, "Play back and sync with audio from Sequence Editor");

View File

@@ -48,6 +48,7 @@
#include "DNA_object_types.h"
#include "DNA_object_force.h"
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -692,7 +693,8 @@ static void poselib_keytag_pose (tPoseLib_PreviewData *pld)
pchan= get_pose_channel(pose, achan->name);
if (pchan) {
if (G.flags & G_RECORDKEYS) {
// TODO: use a standard autokeying function in future (to allow autokeying-editkeys to work)
if (IS_AUTOKEY_MODE(NORMAL)) {
ID *id= &pld->ob->id;
/* Set keys on pose */
@@ -1120,7 +1122,7 @@ static void poselib_preview_cleanup (tPoseLib_PreviewData *pld)
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
/* updates */
if (G.flags & G_RECORDKEYS) {
if (IS_AUTOKEY_MODE(NORMAL)) {
remake_action_ipos(ob->action);
allqueue(REDRAWIPO, 0);

View File

@@ -45,6 +45,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "DNA_userdef_types.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -826,7 +827,7 @@ void paste_posebuf (int flip)
EulToQuat(eul, pchan->quat);
}
if (G.flags & G_RECORDKEYS) {
if (autokeyframe_cfra_can_key(ob)) {
ID *id= &ob->id;
/* Set keys on pose */
@@ -863,7 +864,7 @@ void paste_posebuf (int flip)
/* Update event for pose and deformation children */
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
if (G.flags & G_RECORDKEYS) {
if ((IS_AUTOKEY_MODE(NORMAL))) {
remake_action_ipos(ob->action);
allqueue (REDRAWIPO, 0);
allqueue (REDRAWVIEW3D, 0);
@@ -1153,10 +1154,10 @@ void pose_relax()
float frame_prev, frame_next;
float quat_prev[4], quat_next[4], quat_interp[4], quat_orig[4];
/*int do_scale = 0;
int do_scale = 0;
int do_loc = 0;
int do_quat = 0;
int flag = 0;*/
int flag = 0;
int do_x, do_y, do_z;
if (!ob) return;
@@ -1167,36 +1168,25 @@ void pose_relax()
if (!pose || !act || !arm) return;
for (pchan=pose->chanbase.first; pchan; pchan= pchan->next){
if(pchan->bone->layer & arm->layer) {
if(pchan->bone->flag & BONE_SELECTED) {
for (pchan=pose->chanbase.first; pchan; pchan= pchan->next) {
if (pchan->bone->layer & arm->layer) {
if (pchan->bone->flag & BONE_SELECTED) {
/* do we have an ipo curve? */
achan= get_action_channel(act, pchan->name);
if(achan && achan->ipo) {
if (achan && achan->ipo) {
/*calc_ipo(achan->ipo, ctime);*/
do_x = pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_X), framef, &pchan->loc[0], NULL, NULL);
do_y = pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_Y), framef, &pchan->loc[1], NULL, NULL);
do_z = pose_relax_icu(find_ipocurve(achan->ipo, AC_LOC_Z), framef, &pchan->loc[2], NULL, NULL);
/* do_loc = do_x + do_y + do_z */
if (G.flags & G_RECORDKEYS) {
if (do_x) insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_X, 0);
if (do_y) insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_Y, 0);
if (do_z) insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_Z, 0);
}
do_loc += do_x + do_y + do_z;
do_x = pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_X), framef, &pchan->size[0], NULL, NULL);
do_y = pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_Y), framef, &pchan->size[1], NULL, NULL);
do_z = pose_relax_icu(find_ipocurve(achan->ipo, AC_SIZE_Z), framef, &pchan->size[2], NULL, NULL);
/* do_scale = do_x + do_y + do_z */
if (G.flags & G_RECORDKEYS) {
if (do_x) insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_X, 0);
if (do_y) insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_Y, 0);
if (do_z) insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_Z, 0);
}
do_scale += do_x + do_y + do_z;
if( ((icu_w = find_ipocurve(achan->ipo, AC_QUAT_W))) &&
((icu_x = find_ipocurve(achan->ipo, AC_QUAT_X))) &&
((icu_y = find_ipocurve(achan->ipo, AC_QUAT_Y))) &&
@@ -1225,20 +1215,12 @@ void pose_relax()
QuatInterpol(pchan->quat, quat_orig, quat_interp, 1.0f/6.0f);
/* done */
#endif
/*do_quat++;*/
if (G.flags & G_RECORDKEYS) {
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_QUAT_W, 0);
}
do_quat++;
}
}
if (G.flags & G_RECORDKEYS) {
pchan->bone->flag &= ~BONE_UNKEYED;
}
/* apply BONE_TRANSFORM tag so that autokeying will pick it up */
pchan->bone->flag |= BONE_TRANSFORM;
}
}
}
@@ -1246,16 +1228,17 @@ void pose_relax()
ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
#if 0
// /* auto-keyframing - dosnt work, no idea why, do manually above */
/* do auto-keying */
if (do_loc) flag |= TFM_TRANSLATION;
if (do_scale) flag |= TFM_RESIZE;
if (do_quat) flag |= TFM_ROTATION;
autokeyframe_pose_cb_func(ob, flag, 0);
#endif
/* clear BONE_TRANSFORM flags */
for (pchan=pose->chanbase.first; pchan; pchan= pchan->next)
pchan->bone->flag &= ~ BONE_TRANSFORM;
/* do depsgraph flush */
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
BIF_undo_push("Relax Pose");
}

View File

@@ -3667,34 +3667,28 @@ void drawinfospace(ScrArea *sa, void *spacedata)
uiBlockEndAlign(block);
uiDefBut(block, LABEL,0,"Auto keyframe",
uiDefBut(block, LABEL,0,"Auto Keyframe",
(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)),y4,mpref, buth,
&(G.flags), 0, 0, 0, 0, "Automatic keyframe insertion in Object and Action Ipo curves");
uiDefButS(block, MENU, REDRAWTIME,
"Auto-Keying Mode %t|No Auto-Keying %x0|Add/Replace Keys%x1|Replace Keys %x2",
(xpos+edgsp+(2*mpref)+(2*midsp)),y4,mpref, buth,
&(U.autokey_mode), 0, 1, 0, 0,
"Automatic keyframe insertion for Objects and Bones");
uiBlockBeginAlign(block);
uiDefButBitI(block, TOG, USER_KEYINSERTAVAI, REDRAWTIME, "Available",
uiDefButBitS(block, TOG, AUTOKEY_FLAG_INSERTAVAIL, REDRAWTIME, "Available",
(xpos+edgsp+(2*mpref)+(2*midsp)),y3,mpref, buth,
&(U.uiflag), 0, 0, 0, 0, "Automatic keyframe insertion in available curves");
&(U.autokey_flag), 0, 0, 0, 0, "Automatic keyframe insertion in available curves");
uiDefButBitI(block, TOG, USER_KEYINSERTNEED, REDRAWTIME, "Needed",
uiDefButBitS(block, TOG, AUTOKEY_FLAG_INSERTNEEDED, REDRAWTIME, "Needed",
(xpos+edgsp+(2*mpref)+(2*midsp)),y2,mpref, buth,
&(U.uiflag), 0, 0, 0, 0, "Automatic keyframe insertion only when keyframe needed");
&(U.autokey_flag), 0, 0, 0, 0, "Automatic keyframe insertion only when keyframe needed");
uiDefButBitI(block, TOG, G_AUTOMATKEYS, REDRAWTIME, "Use Visual Keying",
uiDefButBitS(block, TOG, AUTOKEY_FLAG_AUTOMATKEY, 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");
&(U.autokey_flag), 0, 0, 0, 0, "Use Visual keying automatically for constrained objects");
uiBlockEndAlign(block);
/* uiDefButBitS(block, TOG, USER_KEYINSERTACT, 0, "Action",
(xpos+edgsp+(2*mpref)+(2*midsp)),y2,(spref+edgsp),buth,
&(U.uiflag), 0, 0, 0, 0, "Automatic keyframe insertion in Action Ipo curve");
uiDefButBitS(block, TOG, USER_KEYINSERTOBJ, 0, "Object",
(xpos+edgsp+(2*mpref)+(3*midsp)+spref-edgsp),y2,(spref+edgsp),buth,
&(U.uiflag), 0, 0, 0, 0, "Automatic keyframe insertion in Object Ipo curve"); */
uiDefBut(block, LABEL,0,"Duplicate with object:",

View File

@@ -122,6 +122,7 @@
#include "BSE_editipo_types.h"
#include "BSE_editaction_types.h"
#include "BDR_drawaction.h" // list of keyframes in action
#include "BDR_editobject.h" // reset_slowparents()
#include "BDR_unwrapper.h"
@@ -2957,6 +2958,51 @@ static void clear_trans_object_base_flags(void)
}
}
/* auto-keyframing feature - checks for whether anything should be done for the current frame */
short autokeyframe_cfra_can_key(Object *ob)
{
ListBase keys = {NULL, NULL};
ActKeyColumn *ak;
float cfra;
short found= 0;
/* only filter if auto-key mode requires this */
if (IS_AUTOKEY_MODE(OFF))
return 0;
else if (IS_AUTOKEY_MODE(NORMAL))
return 1;
/* sanity check */
if (ob == NULL)
return 0;
/* get keyframes that object has (bone anim is stored on ob too) */
if (ob->action)
action_to_keylist(ob->action, &keys, NULL);
else if (ob->ipo)
ipo_to_keylist(ob->ipo, &keys, NULL);
else
return 0;
/* get current frame (will apply nla-scaling as necessary) */
// ack... this is messy...
cfra= frame_to_float(CFRA);
cfra= get_action_frame(ob, cfra);
/* check if a keyframe occurs on current frame */
for (ak= keys.first; ak; ak= ak->next) {
if (IS_EQ(cfra, ak->cfra)) {
found= 1;
break;
}
}
/* free temp list */
BLI_freelistN(&keys);
return found;
}
/* auto-keyframing feature - for objects
* tmode: should be a transform mode
*/
@@ -2965,11 +3011,11 @@ void autokeyframe_ob_cb_func(Object *ob, int tmode)
IpoCurve *icu;
char *actname="";
if (G.flags & G_RECORDKEYS) {
if (autokeyframe_cfra_can_key(ob)) {
if (ob->ipoflag & OB_ACTION_OB)
actname= "Object";
if (U.uiflag & USER_KEYINSERTAVAI) {
if (IS_AUTOKEY_FLAG(INSERTAVAIL)) {
if (ob->ipo || ob->action) {
ID *id= (ID *)(ob);
@@ -2988,7 +3034,7 @@ void autokeyframe_ob_cb_func(Object *ob, int tmode)
while (icu) {
icu->flag &= ~IPO_SELECT;
if (U.uiflag & USER_KEYINSERTNEED)
if (IS_AUTOKEY_FLAG(INSERTNEEDED))
insertkey_smarter(id, ID_OB, actname, NULL, icu->adrcode);
else
insertkey(id, ID_OB, actname, NULL, icu->adrcode, 0);
@@ -2996,7 +3042,7 @@ void autokeyframe_ob_cb_func(Object *ob, int tmode)
}
}
}
else if (U.uiflag & USER_KEYINSERTNEED) {
else if (IS_AUTOKEY_FLAG(INSERTNEEDED)) {
short doLoc=0, doRot=0, doScale=0;
/* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */
@@ -3076,8 +3122,8 @@ void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik)
pose= ob->pose;
act= ob->action;
if (G.flags & G_RECORDKEYS) {
if (!act)
if (autokeyframe_cfra_can_key(ob)) {
if (act == NULL)
act= ob->action= add_empty_action("Action");
for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) {
@@ -3086,14 +3132,14 @@ void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik)
pchan->bone->flag &= ~BONE_UNKEYED;
/* only insert into available channels? */
if (U.uiflag & USER_KEYINSERTAVAI) {
if (IS_AUTOKEY_FLAG(INSERTAVAIL)) {
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){
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)
if (IS_AUTOKEY_FLAG(INSERTNEEDED))
insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, icu->adrcode);
else
insertkey(&ob->id, ID_PO, pchan->name, NULL, icu->adrcode, 0);
@@ -3103,7 +3149,7 @@ void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik)
}
}
/* only insert keyframe if needed? */
else if (U.uiflag & USER_KEYINSERTNEED) {
else if (IS_AUTOKEY_FLAG(INSERTNEEDED)) {
short doLoc=0, doRot=0, doScale=0;
/* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */
@@ -3173,8 +3219,7 @@ void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik)
if (arm->pathflag & ARM_PATH_ACFRA) {
//pose_clear_paths(ob);
pose_recalculate_paths(ob);
}
}
}
else {
/* tag channels that should have unkeyed data */