Keying Sets: Initial commit of skeleton code
authorJoshua Leung <aligorith@gmail.com>
Wed, 11 Feb 2009 12:19:42 +0000 (12:19 +0000)
committerJoshua Leung <aligorith@gmail.com>
Wed, 11 Feb 2009 12:19:42 +0000 (12:19 +0000)
When fully implemented, these will be the clearest demonstration of 'Everything is Animateable', as they will allow users to define an arbitary group of settings through selecting items in the Datablocks (RNA-Viewer) View of the Outliner to define custom 'sets'. Such Keying Sets are known as the 'absolute' ones, which are created for a custom purpose.

Of course, 'builtin' Keying Sets will still be provided. Such built-in ones will not work on any particular paths, but will use context info to maintain the legacy method of inserting keyframes (via IKEY menu).

Currently, KeyingSets cannot be created/edited through the UI, though the backend code is in place to do this.

18 files changed:
source/blender/blenkernel/BKE_animsys.h
source/blender/blenkernel/intern/anim_sys.c
source/blender/blenkernel/intern/blender.c
source/blender/blenkernel/intern/scene.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/animation/keyframing.c
source/blender/editors/include/ED_keyframing.h
source/blender/editors/space_action/action_draw.c
source/blender/editors/space_graph/graph_draw.c
source/blender/editors/space_outliner/outliner.c
source/blender/editors/space_outliner/outliner_header.c
source/blender/editors/space_outliner/outliner_intern.h
source/blender/editors/space_outliner/outliner_ops.c
source/blender/editors/space_time/time_header.c
source/blender/editors/space_view3d/view3d_buttons.c
source/blender/makesdna/DNA_anim_types.h
source/blender/makesdna/DNA_scene_types.h

index 3b6b01a2341cde82035bf57ddfb0be2cc48c0048..47eaf68cc83f6885f2713d8412fba5696d73b5c3 100644 (file)
@@ -9,6 +9,7 @@ struct ID;
 struct ListBase;
 struct Main;
 struct AnimData;
+struct KeyingSet;
 
 /* ************************************* */
 /* AnimData API */
@@ -25,6 +26,21 @@ void BKE_free_animdata(struct ID *id);
 /* Copy AnimData */
 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
 
index a7e65a9c58530f740f8b0c7745b49aef77a6cc11..55597b635c9b19becde288efbb92cd52aab19d9f 100644 (file)
@@ -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 */
index 94a460ee0a043138c46e1f3e0ab1179bd4baecd4..4ad7d6da6088b92d0bc174be8c7ad0260fdff4ca 100644 (file)
@@ -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"
index 7b3ac9e4ec2bd872da2fb16dc5a4bfc49d6d99fc..7db96c0759225fc3461f66687778ba760afe6508 100644 (file)
@@ -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);
index 2a0f98cfe8d9dbe0ef8ef06d72f6cc4013499304..b3eee6e552e2c38f73f1d90b2542e9e9c0932eac 100644 (file)
@@ -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);
index 9c94842ac082b1c08f56e676b32fa13fae324091..623d1eebe31e88e93fe9fe460cbdffee60b04911 100644 (file)
@@ -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);
index df3a7b85a45b0ed8ddf62c838f6ae9f8d73344f7..42ed4fddc99008c1cf53610f03ba8d40eddbc52c 100644 (file)
@@ -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;
        
index 91dbbec873f7d1e8e2e35fefd6138593087bba1d..e7441188fc30160b1b07da506281dc39fc8db161 100644 (file)
@@ -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.
index 9b3852e63bf5aa71832b112eaa13ab9462e13716..ccee97ad60504ed6f438ca72b44c77776e88a08d 100644 (file)
@@ -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;
                                }
index 7adb90e74649f5617a449b8c479109364646267d..8df483b9048c9f1bfb4a1de3dde67790fd7d5337 100644 (file)
@@ -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;
                                }
index fbc475d3bdd7e9b56c2ff55cc6599ecb355a3c49..11d8cf50d4b313d121f2078947b7584c066246b9 100644 (file)
@@ -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 *************** */
 
index 2c114f3099b0acd7e38dcb5e93793f2046b2a506..7add3f85ea0a73b162367fa0f8166e335b8fc0ad 100644 (file)
@@ -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"
index e7e75833d43292723a3b1fd5233865d393ab0407..067c14dc257e0f28cc7b512d0ef24d5759f50b59 100644 (file)
@@ -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);
index 7d1155cb5d73f024098817c4faf4cb06ab12b35e..295d7ade97c68d3eeae929946ed21f95039e0b67 100644 (file)
@@ -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);
 
 }
 
index 65946a4288b635baad4c1243e9d90b709d2955b1..1f03530b6807997dfae97fb6a7e2999295ec25d5 100644 (file)
@@ -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;
        
index 556d52e4affe5a5ed38e8c936ab21403f4a40cdb..c1c5dec52a768bd733e21460c08a1ae6e38852a7 100644 (file)
@@ -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"
index 17a552ad7e0e8207b394e5a8e1a6ec4dee8cd18b..68564b1ee73a7ffa894ee5488f1ef625da61c4f4 100644 (file)
@@ -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 */
 
index ac3f7e69399f01f474f686c01b59452700869bac..7b618502089d48383945f1e5a29aaccad4b2c305 100644 (file)
@@ -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;