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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2009-02-11 15:19:42 +0300
committerJoshua Leung <aligorith@gmail.com>2009-02-11 15:19:42 +0300
commit7d3c88772b4cdf9cec8966390e84bdd21802395f (patch)
tree9b3545b7c16ff34b7dcc25b1b59348221f1d9b29 /source
parentba32199b23fb1b745109d7b25b8d7c6cdf903cd1 (diff)
Keying Sets: Initial commit of skeleton code
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.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_animsys.h16
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c112
-rw-r--r--source/blender/blenkernel/intern/blender.c1
-rw-r--r--source/blender/blenkernel/intern/scene.c1
-rw-r--r--source/blender/blenloader/intern/readfile.c52
-rw-r--r--source/blender/blenloader/intern/writefile.c25
-rw-r--r--source/blender/editors/animation/keyframing.c264
-rw-r--r--source/blender/editors/include/ED_keyframing.h5
-rw-r--r--source/blender/editors/space_action/action_draw.c2
-rw-r--r--source/blender/editors/space_graph/graph_draw.c3
-rw-r--r--source/blender/editors/space_outliner/outliner.c40
-rw-r--r--source/blender/editors/space_outliner/outliner_header.c1
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h2
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c7
-rw-r--r--source/blender/editors/space_time/time_header.c17
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c1
-rw-r--r--source/blender/makesdna/DNA_anim_types.h71
-rw-r--r--source/blender/makesdna/DNA_scene_types.h7
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;