diff options
18 files changed, 524 insertions, 103 deletions
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 3b6b01a2341..47eaf68cc83 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -9,6 +9,7 @@ struct ID; struct ListBase; struct Main; struct AnimData; +struct KeyingSet; /* ************************************* */ /* AnimData API */ @@ -26,6 +27,21 @@ void BKE_free_animdata(struct ID *id); struct AnimData *BKE_copy_animdata(struct AnimData *adt); /* ************************************* */ +/* KeyingSets API */ + +/* Used to create a new 'custom' KeyingSet for the user, that will be automatically added to the stack */ +struct KeyingSet *BKE_keyingset_add(struct ListBase *list, const char name[], short flag, short keyingflag); + +/* Add a destination to a KeyingSet */ +void BKE_keyingset_add_destination(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, int flag); + +/* Free data for KeyingSet but not set itself */ +void BKE_keyingset_free(struct KeyingSet *ks); + +/* Free all the KeyingSets in the given list */ +void BKE_keyingsets_free(struct ListBase *list); + +/* ************************************* */ // TODO: overrides, remapping, and path-finding api's /* ************************************* */ diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index a7e65a9c585..55597b635c9 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -158,6 +158,118 @@ AnimData *BKE_copy_animdata (AnimData *adt) return dadt; } +/* *********************************** */ +/* KeyingSet API */ + +/* NOTES: + * It is very likely that there will be two copies of the api - one for internal use, + * and one 'operator' based wrapper of the internal API, which should allow for access + * from Python/scripts so that riggers can automate the creation of KeyingSets for their rigs. + */ + +/* Defining Tools --------------------------- */ + +/* Used to create a new 'custom' KeyingSet for the user, that will be automatically added to the stack */ +KeyingSet *BKE_keyingset_add (ListBase *list, const char name[], short flag, short keyingflag) +{ + KeyingSet *ks; + + /* allocate new KeyingSet */ + ks= MEM_callocN(sizeof(KeyingSet), "KeyingSet"); + + BLI_snprintf(ks->name, 64, name); + + ks->flag= flag; + ks->keyingflag= keyingflag; + + /* add KeyingSet to list */ + BLI_addtail(list, ks); + + /* return new KeyingSet for further editing */ + return ks; +} + +/* Add a destination to a KeyingSet. Nothing is returned for now... + * Checks are performed to ensure that destination is appropriate for the KeyingSet in question + */ +void BKE_keyingset_add_destination (KeyingSet *ks, ID *id, const char group_name[], const char rna_path[], int array_index, int flag) +{ + KS_Path *ksp; + + /* sanity checks */ + if ELEM(NULL, ks, rna_path) + return; + + /* ID is optional, and should only be provided for absolute KeyingSets */ + if (id) { + if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) + return; + } + + /* allocate a new KeyingSet Path */ + ksp= MEM_callocN(sizeof(KS_Path), "KeyingSet Path"); + + /* just store absolute info */ + if (ks->flag & KEYINGSET_ABSOLUTE) { + ksp->id= id; + BLI_snprintf(ksp->group, 64, group_name); + } + + /* just copy path info */ + // XXX no checks are performed for templates yet + // should array index be checked too? + ksp->rna_path= BLI_strdupn(rna_path, strlen(rna_path)); + ksp->array_index= array_index; + + /* store flags */ + ksp->flag= flag; + + /* add KeyingSet path to KeyingSet */ + BLI_addtail(&ks->paths, ksp); +} + + +/* Freeing Tools --------------------------- */ + +/* Free data for KeyingSet but not set itself */ +void BKE_keyingset_free (KeyingSet *ks) +{ + KS_Path *ksp, *kspn; + + /* sanity check */ + if (ks == NULL) + return; + + /* free each path as we go to avoid looping twice */ + for (ksp= ks->paths.first; ksp; ksp= kspn) { + kspn= ksp->next; + + /* free RNA-path info */ + MEM_freeN(ksp->rna_path); + + /* free path itself */ + BLI_freelinkN(&ks->paths, ks); + } +} + +/* Free all the KeyingSets in the given list */ +void BKE_keyingsets_free (ListBase *list) +{ + KeyingSet *ks, *ksn; + + /* sanity check */ + if (list == NULL) + return; + + /* loop over KeyingSets freeing them + * - BKE_keyingset_free() doesn't free the set itself, but it frees its sub-data + */ + for (ks= list->first; ks; ks= ksn) { + ksn= ks->next; + BKE_keyingset_free(ks); + BLI_freelinkN(list, ks); + } +} /* ***************************************** */ /* Evaluation Data-Setting Backend */ diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 94a460ee0a0..4ad7d6da608 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -65,6 +65,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_blender.h" #include "BKE_context.h" diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 7b3ac9e4ec2..7db96c07592 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -150,6 +150,7 @@ void free_scene(Scene *sce) #endif BKE_free_animdata((ID *)sce); + BKE_keyingsets_free(&sce->keyingsets); if (sce->r.avicodecdata) { free_avicodecdata(sce->r.avicodecdata); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 2a0f98cfe8d..b3eee6e552e 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1929,6 +1929,39 @@ static void direct_link_action(FileData *fd, bAction *act) /* ------- */ +static void lib_link_keyingsets(FileData *fd, ID *id, ListBase *list) +{ + KeyingSet *ks; + KS_Path *ksp; + + /* here, we're only interested in the ID pointer stored in some of the paths */ + for (ks= list->first; ks; ks= ks->next) { + for (ksp= ks->paths.first; ksp; ksp= ksp->next) { + ksp->id= newlibadr(fd, id->lib, ksp->id); + } + } +} + +/* NOTE: this assumes that link_list has already been called on the list */ +static void direct_link_keyingsets(FileData *fd, ListBase *list) +{ + KeyingSet *ks; + KS_Path *ksp; + + /* link KeyingSet data to KeyingSet again (non ID-libs) */ + for (ks= list->first; ks; ks= ks->next) { + /* paths */ + link_list(fd, &ks->paths); + + for (ksp= ks->paths.first; ksp; ksp= ksp->next) { + /* rna path */ + ksp->rna_path= newdataadr(fd, ksp->rna_path); + } + } +} + +/* ------- */ + static void lib_link_animdata(FileData *fd, ID *id, AnimData *adt) { if (adt == NULL) @@ -3698,6 +3731,8 @@ static void lib_link_scene(FileData *fd, Main *main) if (sce->id.properties) IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); if (sce->adt) lib_link_animdata(fd, &sce->id, sce->adt); + lib_link_keyingsets(fd, &sce->id, &sce->keyingsets); + sce->camera= newlibadr(fd, sce->id.lib, sce->camera); sce->world= newlibadr_us(fd, sce->id.lib, sce->world); sce->set= newlibadr(fd, sce->id.lib, sce->set); @@ -3791,6 +3826,9 @@ static void direct_link_scene(FileData *fd, Scene *sce) sce->adt= newdataadr(fd, sce->adt); direct_link_animdata(fd, sce->adt); + link_list(fd, &sce->keyingsets); + direct_link_keyingsets(fd, &sce->keyingsets); + sce->basact= newdataadr(fd, sce->basact); sce->radio= newdataadr(fd, sce->radio); @@ -9124,6 +9162,19 @@ static void expand_action(FileData *fd, Main *mainvar, bAction *act) } } +static void expand_keyingsets(FileData *fd, Main *mainvar, ListBase *list) +{ + KeyingSet *ks; + KS_Path *ksp; + + /* expand the ID-pointers in KeyingSets's paths */ + for (ks= list->first; ks; ks= ks->next) { + for (ksp= ks->paths.first; ksp; ksp= ksp->next) { + expand_doit(fd, mainvar, ksp->id); + } + } +} + static void expand_animdata(FileData *fd, Main *mainvar, AnimData *adt) { FCurve *fcd; @@ -9655,6 +9706,7 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce) if(sce->adt) expand_animdata(fd, mainvar, sce->adt); + expand_keyingsets(fd, mainvar, &sce->keyingsets); if(sce->nodetree) expand_nodetree(fd, mainvar, sce->nodetree); diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 9c94842ac08..623d1eebe31 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -855,6 +855,26 @@ static void write_actions(WriteData *wd, ListBase *idbase) mywrite(wd, MYWRITE_FLUSH, 0); } +static void write_keyingsets(WriteData *wd, ListBase *list) +{ + KeyingSet *ks; + KS_Path *ksp; + + for (ks= list->first; ks; ks= ks->next) { + /* KeyingSet */ + writestruct(wd, DATA, "KeyingSet", 1, ks); + + /* Paths */ + for (ksp= ks->paths.first; ksp; ksp= ksp->next) { + /* Path */ + writestruct(wd, DATA, "KS_Path", 1, ksp); + + if (ksp->rna_path) + writedata(wd, DATA, strlen(ksp->rna_path)+1, ksp->rna_path); + } + } +} + static void write_animdata(WriteData *wd, AnimData *adt) { AnimOverride *aor; @@ -1533,6 +1553,7 @@ static void write_scenes(WriteData *wd, ListBase *scebase) if (sce->id.properties) IDP_WriteProperty(sce->id.properties, wd); if (sce->adt) write_animdata(wd, sce->adt); + write_keyingsets(wd, &sce->keyingsets); /* direct data */ base= sce->base.first; @@ -1616,9 +1637,9 @@ static void write_scenes(WriteData *wd, ListBase *scebase) writestruct(wd, DATA, "MetaStack", 1, ms); } } - + write_scriptlink(wd, &sce->scriptlink); - + if (sce->r.avicodecdata) { writestruct(wd, DATA, "AviCodecData", 1, sce->r.avicodecdata); if (sce->r.avicodecdata->lpFormat) writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat); diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index df3a7b85a45..42ed4fddc99 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -30,6 +30,7 @@ #include "BKE_fcurve.h" #include "BKE_utildefines.h" #include "BKE_context.h" +#include "BKE_report.h" #include "BKE_key.h" #include "BKE_material.h" @@ -39,6 +40,8 @@ #include "ED_screen.h" #include "ED_util.h" +#include "UI_interface.h" + #include "WM_api.h" #include "WM_types.h" @@ -63,35 +66,6 @@ typedef struct bCommonKeySrc { bPoseChannel *pchan; /* only needed when doing recalcs... */ } bCommonKeySrc; -/* -------------- Keying Sets ------------------- */ - -#if 0 // XXX I'm not sure how these will work for now... - -/* keying set - a set of channels that will be keyframed together */ -// TODO: move this to a header to allow custom sets someday? -typedef struct bKeyingSet { - /* callback func to consider if keyingset should be included - * (by default, if this is undefined, item will be shown) - */ - short (*include_cb)(struct bKeyingSet *, const char *); - - char name[48]; /* name of keyingset */ - int blocktype; /* nearest ID-blocktype to where data can be found */ - short flag; /* flags to use when setting keyframes */ - - short chan_num; /* number of channels to insert keyframe in */ - char (*paths)[256]; /* adrcodes for channels to insert keys for (ideally would be variable-len, but limit of 32 will suffice) */ -} bKeyingSet; - -/* keying set context - an array of keying sets and the number of them */ -typedef struct bKeyingContext { - bKeyingSet *keyingsets; /* array containing the keyingsets of interest */ - bKeyingSet *lastused; /* item that was chosen last time*/ - int tot; /* number of keyingsets in */ -} bKeyingContext; - -#endif - /* ******************************************* */ /* Animation Data Validation */ @@ -184,7 +158,7 @@ FCurve *verify_fcurve (ID *id, const char group[], const char rna_path[], const /* -------------- BezTriple Insertion -------------------- */ /* threshold for inserting keyframes - threshold here should be good enough for now, but should become userpref */ -#define BEZT_INSERT_THRESH 0.00001 +#define BEZT_INSERT_THRESH 0.00001f /* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_icu) * Returns the index to insert at (data already at that index will be offset if replace is 0) @@ -899,6 +873,37 @@ enum { COMMONKEY_MODE_DELETE, } eCommonModifyKey_Modes; + +/* Build menu-string of available keying-sets (allocates memory for string) + * NOTE: mode must not be longer than 64 chars + */ +char *ANIM_build_keyingsets_menu (ListBase *list) +{ + DynStr *pupds= BLI_dynstr_new(); + KeyingSet *ks; + char buf[64]; + char *str; + + /* add title first */ + BLI_dynstr_append(pupds, "Keying Sets%t|"); + + /* add dummy entry for none-active */ + BLI_dynstr_append(pupds, "<No Keying Set Active>%x0|"); + + /* loop through keyingsets, adding them */ + for (ks= list->first; ks; ks= ks->next) { + BLI_dynstr_append(pupds, ks->name); + BLI_snprintf( buf, 64, "%s", ((ks->next)?"|":"") ); + BLI_dynstr_append(pupds, buf); + } + + /* convert to normal MEM_malloc'd string */ + str= BLI_dynstr_get_cstring(pupds); + BLI_dynstr_free(pupds); + + return str; +} + #if 0 // XXX old keyingsets code based on adrcodes... to be restored in due course /* --------- KeyingSet Adrcode Getters ------------ */ @@ -1786,57 +1791,6 @@ static void commonkey_context_refresh (bContext *C) /* --- */ -/* Build menu-string of available keying-sets (allocates memory for string) - * NOTE: mode must not be longer than 64 chars - */ -static char *build_keyingsets_menu (bKeyingContext *ksc, const char mode[48]) -{ - DynStr *pupds= BLI_dynstr_new(); - bKeyingSet *ks; - char buf[64]; - char *str; - int i, n; - - /* add title first */ - BLI_snprintf(buf, 64, "%s Key %%t|", mode); - BLI_dynstr_append(pupds, buf); - - /* loop through keyingsets, adding them */ - for (ks=ksc->keyingsets, i=0, n=1; i < ksc->tot; ks++, i++, n++) { - /* check if keyingset can be used */ - if (ks->flag == -1) { - /* optional separator? */ - if (ks->include_cb) { - if (ks->include_cb(ks, mode)) { - BLI_snprintf( buf, 64, "%s%s", ks->name, ((n < ksc->tot)?"|":"") ); - BLI_dynstr_append(pupds, buf); - } - } - else { - BLI_snprintf( buf, 64, "%%l%s", ((n < ksc->tot)?"|":"") ); - BLI_dynstr_append(pupds, buf); - } - } - else if ( (ks->include_cb==NULL) || (ks->include_cb(ks, mode)) ) { - /* entry can be included */ - BLI_dynstr_append(pupds, ks->name); - - /* check if special "shapekey" entry */ - if (ks->flag == -3) - BLI_snprintf( buf, 64, "%%x0%s", ((n < ksc->tot)?"|":"") ); - else - BLI_snprintf( buf, 64, "%%x%d%s", n, ((n < ksc->tot)?"|":"") ); - BLI_dynstr_append(pupds, buf); - } - } - - /* convert to normal MEM_malloc'd string */ - str= BLI_dynstr_get_cstring(pupds); - BLI_dynstr_free(pupds); - - return str; -} - /* Get the keying set that was chosen by the user from the menu */ static bKeyingSet *get_keyingset_fromcontext (bKeyingContext *ksc, short index) { @@ -2033,6 +1987,68 @@ void common_modifykey (bContext *C, short mode) #endif // XXX old keyingsets code based on adrcodes... to be restored in due course +/* Given a KeyingSet and context info (if required), modify keyframes for the channels specified + * by the KeyingSet. This takes into account many of the different combinations of using KeyingSets. + * Returns the number of channels that keyframes were added to + */ +static int commonkey_modifykey (ListBase *dsources, KeyingSet *ks, short mode, float cfra) +{ + KS_Path *ksp; + int kflag, success= 0; + char *groupname= NULL; + + /* get flags to use */ + if (mode == COMMONKEY_MODE_INSERT) { + /* use KeyingSet's flags as base */ + kflag= ks->keyingflag; + + /* suppliment with info from the context */ + if (IS_AUTOKEY_FLAG(AUTOMATKEY)) kflag |= INSERTKEY_MATRIX; + if (IS_AUTOKEY_FLAG(INSERTNEEDED)) kflag |= INSERTKEY_NEEDED; + // if (IS_AUTOKEY_MODE(EDITKEYS)) flag |= INSERTKEY_REPLACE; + } + else if (mode == COMMONKEY_MODE_DELETE) + kflag= 0; + + + /* check if the KeyingSet is absolute or not (i.e. does it requires sources info) */ + if (ks->flag & KEYINGSET_ABSOLUTE) { + /* Absolute KeyingSets are simpler to use, as all the destination info has already been + * provided by the user, and is stored, ready to use, in the KeyingSet paths. + */ + for (ksp= ks->paths.first; ksp; ksp= ksp->next) { + /* get pointer to name of group to add channels to */ + if (ksp->flag & KSP_FLAG_GROUP_NONE) + groupname= NULL; + else if (ksp->flag & KSP_FLAG_GROUP_KSNAME) + groupname= ks->name; + else + groupname= ksp->group; + + /* action to take depends on mode */ + if (mode == COMMONKEY_MODE_INSERT) + success+= insertkey(ksp->id, groupname, ksp->rna_path, ksp->array_index, cfra, kflag); + else if (mode == COMMONKEY_MODE_DELETE) + success+= deletekey(ksp->id, groupname, ksp->rna_path, ksp->array_index, cfra, kflag); + } + } +#if 0 // XXX still need to figure out how to get such keyingsets working + else if (dsources) { + /* for each one of the 'sources', resolve the template markers and expand arrays, then insert keyframes */ + bCommonKeySrc *cks; + char *path = NULL; + int index=0, tot=0; + + /* for each 'source' for keyframe data, resolve each of the paths from the KeyingSet */ + for (cks= dsources->first; cks; cks= cks->next) { + + } + } +#endif // XXX still need to figure out how to get such + + return success; +} + /* Insert Key Operator ------------------------ */ /* XXX WARNING: @@ -2046,15 +2062,49 @@ void common_modifykey (bContext *C, short mode) /* defines for basic insert-key testing operator */ // XXX this will definitely be replaced EnumPropertyItem prop_insertkey_types[] = { - {0, "OBLOC", "Object Location", ""}, - {1, "OBROT", "Object Rotation", ""}, - {2, "OBSCALE", "Object Scale", ""}, - {3, "MAT_COL", "Active Material - Color", ""}, - {4, "PCHANLOC", "Pose-Channel Location", ""}, - {5, "PCHANROT", "Pose-Channel Rotation", ""}, - {6, "PCHANSCALE", "Pose-Channel Scale", ""}, + {0, "KEYINGSET", "Active KeyingSet", ""}, + {1, "OBLOC", "Object Location", ""}, + {2, "OBROT", "Object Rotation", ""}, + {3, "OBSCALE", "Object Scale", ""}, + {4, "MAT_COL", "Active Material - Color", ""}, + {5, "PCHANLOC", "Pose-Channel Location", ""}, + {6, "PCHANROT", "Pose-Channel Rotation", ""}, + {7, "PCHANSCALE", "Pose-Channel Scale", ""}, {0, NULL, NULL, NULL} }; + +static int insert_key_invoke (bContext *C, wmOperator *op, wmEvent *event) +{ + Object *ob= CTX_data_active_object(C); + uiMenuItem *head; + + if (ob == NULL) + return OPERATOR_CANCELLED; + + head= uiPupMenuBegin("Insert Keyframe", 0); + + /* active keyingset */ + uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 0); + + /* selective inclusion */ + if ((ob->pose) && (ob->flag & OB_POSEMODE)) { + /* bone types */ + uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 5); + uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 6); + uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 7); + } + else { + /* object types */ + uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 1); + uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 2); + uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 3); + uiMenuItemEnumO(head, "", 0, "ANIM_OT_insert_keyframe", "type", 4); + } + + uiPupMenuEnd(C, head); + + return OPERATOR_CANCELLED; +} static int insert_key_exec (bContext *C, wmOperator *op) { @@ -2062,6 +2112,34 @@ static int insert_key_exec (bContext *C, wmOperator *op) short mode= RNA_enum_get(op->ptr, "type"); float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap + /* for now, handle 'active keyingset' one separately */ + if (mode == 0) { + ListBase dsources = {NULL, NULL}; + KeyingSet *ks= NULL; + short success; + + /* try to get KeyingSet */ + if (scene->active_keyingset > 0) + ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1); + /* report failure */ + if (ks == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active Keying Set"); + return OPERATOR_CANCELLED; + } + + /* try to insert keyframes for the channels specified by KeyingSet */ + success= commonkey_modifykey(&dsources, ks, COMMONKEY_MODE_INSERT, cfra); + printf("KeyingSet '%s' - Successfully added %d Keyframes \n", ks->name, success); + + /* report failure */ + if (success == 0) { + BKE_report(op->reports, RPT_WARNING, "Keying Set failed to insert any keyframes"); + return OPERATOR_CANCELLED; // XXX? + } + else + return OPERATOR_FINISHED; + } + // XXX more comprehensive tests will be needed CTX_DATA_BEGIN(C, Base*, base, selected_bases) { @@ -2073,24 +2151,24 @@ static int insert_key_exec (bContext *C, wmOperator *op) if (mode < 4) { /* object-based keyframes */ switch (mode) { - case 3: /* color of active material (only for geometry...) */ + case 4: /* color of active material (only for geometry...) */ // NOTE: this is just a demo... but ideally we'd go through materials instead of active one only so reference stays same // XXX no group for now success+= insertkey(id, NULL, "active_material.diffuse_color", 0, cfra, 0); success+= insertkey(id, NULL, "active_material.diffuse_color", 1, cfra, 0); success+= insertkey(id, NULL, "active_material.diffuse_color", 2, cfra, 0); break; - case 2: /* object scale */ + case 3: /* object scale */ success+= insertkey(id, "Object Transforms", "scale", 0, cfra, 0); success+= insertkey(id, "Object Transforms", "scale", 1, cfra, 0); success+= insertkey(id, "Object Transforms", "scale", 2, cfra, 0); break; - case 1: /* object rotation */ + case 2: /* object rotation */ success+= insertkey(id, "Object Transforms", "rotation", 0, cfra, 0); success+= insertkey(id, "Object Transforms", "rotation", 1, cfra, 0); success+= insertkey(id, "Object Transforms", "rotation", 2, cfra, 0); break; - default: /* object location */ + case 1: /* object location */ success+= insertkey(id, "Object Transforms", "location", 0, cfra, 0); success+= insertkey(id, "Object Transforms", "location", 1, cfra, 0); success+= insertkey(id, "Object Transforms", "location", 2, cfra, 0); @@ -2167,7 +2245,7 @@ void ANIM_OT_insert_keyframe (wmOperatorType *ot) ot->idname= "ANIM_OT_insert_keyframe"; /* callbacks */ - ot->invoke= WM_menu_invoke; // XXX we will need our own one eventually, to cope with the dynamic menus... + ot->invoke= insert_key_invoke; ot->exec= insert_key_exec; ot->poll= ED_operator_areaactive; diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 91dbbec873f..e7441188fc3 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -31,6 +31,8 @@ struct ListBase; struct ID; +struct KeyingSet; + struct FCurve; struct BezTriple; @@ -81,6 +83,9 @@ short insertkey(struct ID *id, const char group[], const char rna_path[], int ar short deletekey(struct ID *id, const char group[], const char rna_path[], int array_index, float cfra, short flag); +/* Generate menu of KeyingSets */ +char *ANIM_build_keyingsets_menu(struct ListBase *list); + /* Main Keyframe Management operators: * These handle keyframes management from various spaces. They will handle the menus * required for each space. diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 9b3852e63bf..ccee97ad605 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -867,7 +867,7 @@ void draw_channel_names(bAnimContext *ac, SpaceAction *saction, ARegion *ar) offset += 17; } else { - /* for ipo/constraint channels */ + /* for normal channels */ UI_icon_draw(x+offset, yminc, special); offset += 17; } diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 7adb90e7464..8df483b9048 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -689,7 +689,6 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar) int items, i; /* build list of curves to draw */ - // XXX enable ANIMFILTER_CURVEVISIBLE when we have a method to set them filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CURVESONLY|ANIMFILTER_CURVEVISIBLE); items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); @@ -1135,7 +1134,7 @@ void graph_draw_channel_names(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar) offset += 17; } else { - /* for ipo/constraint channels */ + /* for normal channels */ UI_icon_draw(x+offset, yminc, special); offset += 17; } diff --git a/source/blender/editors/space_outliner/outliner.c b/source/blender/editors/space_outliner/outliner.c index fbc475d3bdd..11d8cf50d4b 100644 --- a/source/blender/editors/space_outliner/outliner.c +++ b/source/blender/editors/space_outliner/outliner.c @@ -64,6 +64,7 @@ #include "IMB_imbuf_types.h" +#include "BKE_animsys.h" #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_deform.h" @@ -3086,6 +3087,45 @@ void outliner_operation_menu(Scene *scene, ARegion *ar, SpaceOops *soops) } } +/* ***************** KEYINGSET OPERATIONS *************** */ + +/* These operators are only available in databrowser mode for now, as + * they depend on having RNA paths and/or hierarchies available. + */ + +/* find the 'active' KeyingSet, and add if not found (if adding is allowed) */ +// TODO: should this be an API func? +static KeyingSet *verify_active_keyingset(Scene *scene, short add) +{ + KeyingSet *ks= NULL; + + /* try to find one from scene */ + if (scene->active_keyingset > 0) + ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1); + + /* add if none found */ + // XXX the default settings have yet to evolve + if ((add) && (ks==NULL)) + ks= BKE_keyingset_add(&scene->keyingsets, "KeyingSet", KEYINGSET_ABSOLUTE, 0); + + return ks; +} + +/* ---------------------------------- */ + + +void OUTLINER_OT_keyingset_add_selected(wmOperatorType *ot) +{ + +} + + +/* ---------------------------------- */ + +void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot) +{ + +} /* ***************** DRAW *************** */ diff --git a/source/blender/editors/space_outliner/outliner_header.c b/source/blender/editors/space_outliner/outliner_header.c index 2c114f3099b..7add3f85ea0 100644 --- a/source/blender/editors/space_outliner/outliner_header.c +++ b/source/blender/editors/space_outliner/outliner_header.c @@ -44,6 +44,7 @@ #include "BKE_main.h" #include "BKE_screen.h" +#include "ED_keyframing.h" #include "ED_screen.h" #include "ED_util.h" #include "ED_types.h" diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index e7e75833d43..067c14dc257 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -119,6 +119,8 @@ void outliner_select(struct SpaceOops *soops, struct ListBase *lb, int *index, s void draw_outliner(const struct bContext *C); void OUTLINER_OT_activate_click(struct wmOperatorType *ot); +void OUTLINER_OT_keyingset_add_selected(struct wmOperatorType *ot); +void OUTLINER_OT_keyingset_remove_selected(struct wmOperatorType *ot); #if 0 extern void outliner_mouse_event(Scene *scene, ARegion *ar, SpaceOops *soops, short event); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 7d1155cb5d7..295d7ade97c 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -44,6 +44,9 @@ void outliner_operatortypes(void) { WM_operatortype_append(OUTLINER_OT_activate_click); + + WM_operatortype_append(OUTLINER_OT_keyingset_add_selected); + WM_operatortype_append(OUTLINER_OT_keyingset_remove_selected); } void outliner_keymap(wmWindowManager *wm) @@ -51,6 +54,10 @@ void outliner_keymap(wmWindowManager *wm) ListBase *keymap= WM_keymap_listbase(wm, "Outliner", SPACE_OOPS, 0); WM_keymap_verify_item(keymap, "OUTLINER_OT_activate_click", LEFTMOUSE, KM_PRESS, 0, 0); + + /* keying sets - only for databrowse */ + WM_keymap_verify_item(keymap, "OUTLINER_OT_keyingset_add_selected", KKEY, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "OUTLINER_OT_keyingset_remove_selected", KKEY, KM_PRESS, KM_ALT, 0); } diff --git a/source/blender/editors/space_time/time_header.c b/source/blender/editors/space_time/time_header.c index 65946a4288b..1f03530b680 100644 --- a/source/blender/editors/space_time/time_header.c +++ b/source/blender/editors/space_time/time_header.c @@ -43,6 +43,7 @@ #include "BKE_global.h" #include "BKE_screen.h" +#include "ED_keyframing.h" #include "ED_screen.h" #include "ED_types.h" #include "ED_util.h" @@ -429,6 +430,7 @@ void time_header_buttons(const bContext *C, ARegion *ar) Scene *scene= CTX_data_scene(C); uiBlock *block; int xco, yco= 3; + char *menustr= NULL; block= uiBeginBlock(C, ar, "header buttons", UI_EMBOSS, UI_HELV); uiBlockSetHandleFunc(block, do_time_buttons, NULL); @@ -539,12 +541,21 @@ void time_header_buttons(const bContext *C, ARegion *ar) xco+= 16; - uiDefIconBut(block, BUT, B_TL_INSERTKEY, ICON_KEY_HLT, - xco, yco, XIC, YIC, 0, 0, 0, 0, 0, "Insert Keyframe for the context of the largest area (IKEY)"); - xco+= XIC+4; + + menustr= ANIM_build_keyingsets_menu(&scene->keyingsets); + uiDefButI(block, MENU, B_DIFF, + menustr, + xco, yco, (int)5.5*XIC, YIC, &(scene->active_keyingset), 0, 1, 0, 0, + "Active Keying Set (i.e. set of channels to Insert Keyframes for)"); + MEM_freeN(menustr); + xco+= (6*XIC); + uiDefIconBut(block, BUT, B_TL_DELETEKEY, ICON_KEY_DEHLT, xco, yco, XIC, YIC, 0, 0, 0, 0, 0, "Delete Keyframe for the context of the largest area (ALTKEY-IKEY)"); xco+= XIC+4; + uiDefIconBut(block, BUT, B_TL_INSERTKEY, ICON_KEY_HLT, + xco, yco, XIC, YIC, 0, 0, 0, 0, 0, "Insert Keyframe for the context of the largest area (IKEY)"); + xco+= XIC+4; xco+= 16; diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 556d52e4aff..c1c5dec52a7 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -78,6 +78,7 @@ #include "ED_armature.h" #include "ED_curve.h" #include "ED_editparticle.h" +#include "ED_keyframing.h" #include "ED_mesh.h" #include "ED_object.h" #include "ED_screen.h" diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index 17a552ad7e0..68564b1ee73 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -421,6 +421,77 @@ enum { NLATRACK_TWEAK = (1<<5), } eNlaTrack_Flag; + +/* ************************************ */ +/* KeyingSet Datatypes */ + +/* Path for use in KeyingSet definitions (ksp) + * + * Paths may be either specific (specifying the exact sub-ID + * dynamic data-block - such as PoseChannels - to act upon, ala + * Maya's 'Character Sets' and XSI's 'Marking Sets'), or they may + * be generic (using various placeholder template tags that will be + * replaced with appropriate information from the context). + */ +// TODO: how should templates work exactly? For now, we only implement the specific KeyingSets... +typedef struct KS_Path { + struct KS_Path *next, *prev; + + /* absolute paths only */ + ID *id; /* ID block that keyframes are for */ + char group[64]; /* name of the group to add to */ + + /* all paths */ + char *rna_path; /* dynamically (or statically in the case of predefined sets) path */ + int array_index; /* index that path affects */ + + int flag; /* various settings, etc. */ +} KS_Path; + +/* KS_Path->flag */ +enum { + /* entire array (not just the specified index) gets keyframed */ + KSP_FLAG_WHOLE_ARRAY = (1<<0), + + /* path should not be grouped at all */ + KSP_FLAG_GROUP_NONE = (1<<10), + /* path should be grouped under an ActionGroup KeyingSet's name */ + KSP_FLAG_GROUP_KSNAME = (1<<11), +} eKSP_Settings; + +/* ---------------- */ + +/* KeyingSet definition (ks) + * + * A KeyingSet defines a group of properties that should + * be keyframed together, providing a convenient way for animators + * to insert keyframes without resorting to Auto-Keyframing. + * + * A few 'generic' (non-absolute and dependant on templates) KeyingSets + * are defined 'built-in' to facilitate easy animating for the casual + * animator without the need to add extra steps to the rigging process. + */ +typedef struct KeyingSet { + struct KeyingSet *next, *prev; + + ListBase paths; /* (KS_Path) paths to keyframe to */ + + char name[64]; /* user-viewable name for KeyingSet (for menus, etc.) */ + + int flag; /* settings for KeyingSet */ + int keyingflag; /* settings to supply insertkey() with */ +} KeyingSet; + +/* KeyingSet settings */ +enum { + /* keyingset cannot be removed (and doesn't need to be freed) */ + KEYINGSET_BUILTIN = (1<<0), + /* keyingset is the one currently in use */ + KEYINGSET_ACTIVE = (1<<1), + /* keyingset does not depend on context info (i.e. paths are absolute) */ + KEYINGSET_ABSOLUTE = (1<<2), +} eKS_Settings; + /* ************************************************ */ /* Animation Data */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index ac3f7e69399..7b618502089 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -537,7 +537,7 @@ typedef struct Scene { short proportional, prop_mode; short automerge, pad5, pad6; - short autokey_mode; /* mode for autokeying (defines in DNA_userdef_types.h */ + short autokey_mode; /* mode for autokeying (defines in DNA_userdef_types.h) */ short use_nodes; @@ -571,7 +571,10 @@ typedef struct Scene { /* frame step. */ int frame_step; - int pad; + + /* User-Defined KeyingSets */ + int active_keyingset; /* index of the active KeyingSet. first KeyingSet has index 1 */ + ListBase keyingsets; /* KeyingSets for the given frame */ } Scene; |