1
1

Compare commits

...

1 Commits

Author SHA1 Message Date
d1e3ba22a0 Collections: Initial support for animating/driving collection properties (T55233)
(Just committing this now to a temp branch so that I can continue working on this
from another machine later. This is a re-based+squashed, re-pushed version of what
I just pushed earlier, but now based on current 2.8 code, not from several days ago)

Rationale:
The Spring team needs a way to hide objects from the viewport, so that parts of
the rig can be enabled/disabled per shot. An example of this is how the cornea
meshes are typically hidden from the viewport so that the animators can see
the irises, and hence, where the character is looking.

(Another reason we may want this in future is to make it so that a bunch of
objects/rigs can be keyframed together in the same action, making it easier
to manage their actions)

Status:
* Currently all necessary data and animation editor support changes should be
  in place and working. Hopefully I haven't missed any - the checklist may need
  updating for 2.8

* Depsgraph support however is still incomplete. We still need to figure out what
  needs to happen with the animated values to make objects actually appear/disappear
  when triggered via the animation system, just like they do now from the UIwip
2018-06-02 20:03:29 +02:00
15 changed files with 324 additions and 4 deletions

View File

@@ -104,6 +104,7 @@ bool id_type_can_have_animdata(const short id_type)
case ID_MSK:
case ID_GD:
case ID_CF:
case ID_GR:
return true;
/* no AnimData */
@@ -1135,6 +1136,9 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u
/* masks */
ANIMDATA_IDS_CB(mainptr->mask.first);
/* collections */
ANIMDATA_IDS_CB(mainptr->collection.first);
/* worlds */
ANIMDATA_NODETREE_IDS_CB(mainptr->world.first, World);
@@ -1234,6 +1238,9 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const cha
/* worlds */
RENAMEFIX_ANIM_NODETREE_IDS(mainptr->world.first, World);
/* collections */
RENAMEFIX_ANIM_IDS(mainptr->collection.first);
/* linestyles */
RENAMEFIX_ANIM_IDS(mainptr->linestyle.first);
@@ -2935,6 +2942,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, Scene
/* masks */
EVAL_ANIM_IDS(main->mask.first, ADT_RECALC_ANIM);
/* collections */
EVAL_ANIM_IDS(main->collection.first, ADT_RECALC_ANIM);
/* worlds */
EVAL_ANIM_NODETREE_IDS(main->world.first, World, ADT_RECALC_ANIM);

View File

@@ -35,6 +35,7 @@
#include "BLT_translation.h"
#include "BLI_string_utils.h"
#include "BKE_animsys.h"
#include "BKE_collection.h"
#include "BKE_icons.h"
#include "BKE_idprop.h"
@@ -112,7 +113,8 @@ Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const
/** Free (or release) any data used by this collection (does not free the collection itself). */
void BKE_collection_free(Collection *collection)
{
/* No animdata here. */
BKE_animdata_free(&collection->id, false);
BKE_previewimg_free(&collection->preview);
BLI_freelistN(&collection->gobject);

View File

@@ -5679,6 +5679,9 @@ static void direct_link_collection(FileData *fd, Collection *collection)
link_list(fd, &collection->gobject);
link_list(fd, &collection->children);
collection->adt = newdataadr(fd, collection->adt);
direct_link_animdata(fd, collection->adt);
collection->preview = direct_link_preview_image(fd, collection->preview);
collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
@@ -5733,6 +5736,7 @@ static void lib_link_collection(FileData *fd, Main *main)
if (collection->id.tag & LIB_TAG_NEED_LINK) {
collection->id.tag &= ~LIB_TAG_NEED_LINK;
IDP_LibLinkProperty(collection->id.properties, fd);
lib_link_animdata(fd, &collection->id, collection->adt);
#ifdef USE_COLLECTION_COMPAT_28
if (collection->collection) {
@@ -9272,6 +9276,10 @@ static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSetting
static void expand_collection(FileData *fd, Main *mainvar, Collection *collection)
{
if (collection->adt) {
expand_animdata(fd, mainvar, collection->adt);
}
for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
expand_doit(fd, mainvar, cob->ob);
}

View File

@@ -2376,6 +2376,10 @@ static void write_collection(WriteData *wd, Collection *collection)
/* write LibData */
writestruct(wd, ID_GR, Collection, 1, collection);
write_iddata(wd, &collection->id);
if (collection->adt) {
write_animdata(wd, collection->adt);
}
write_collection_nolib(wd, collection);
}

View File

@@ -435,6 +435,8 @@ void DepsgraphNodeBuilder::build_collection(Collection *collection)
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
build_collection(child->collection);
}
/* Build animation data. */
build_animdata(&collection->id);
add_id_node(&collection->id);
}

View File

@@ -444,6 +444,8 @@ void DepsgraphRelationBuilder::build_collection(Object *object, Collection *coll
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
build_collection(NULL, child->collection);
}
/* Animation data - should only need one set of relations per collection, not once per instance */
build_animdata(&collection->id);
}
if (object != NULL) {
const ListBase group_objects = BKE_collection_object_cache_get(collection);

View File

@@ -626,6 +626,111 @@ static bAnimChannelType ACF_SCENE =
acf_scene_setting_ptr /* pointer for setting */
};
/* Collection ------------------------------------------- */
// TODO: just get this from RNA?
static int acf_collection_icon(bAnimListElem *UNUSED(ale))
{
return ICON_GROUP;
}
/* check if some setting exists for this channel */
static bool acf_collection_setting_valid(bAnimContext *ac, bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting)
{
switch (setting) {
/* muted only in NLA */
case ACHANNEL_SETTING_MUTE:
return ((ac) && (ac->spacetype == SPACE_NLA));
/* visible only in Graph Editor */
case ACHANNEL_SETTING_VISIBLE:
return ((ac) && (ac->spacetype == SPACE_IPO));
/* only select and expand supported otherwise */
case ACHANNEL_SETTING_SELECT:
case ACHANNEL_SETTING_EXPAND:
return true;
case ACHANNEL_SETTING_ALWAYS_VISIBLE:
return false;
default:
return false;
}
}
/* get the appropriate flag(s) for the setting when it is valid */
static int acf_collection_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg)
{
/* clear extra return data first */
*neg = false;
switch (setting) {
case ACHANNEL_SETTING_SELECT: /* selected */
return COLLECTION_DS_SELECTED;
case ACHANNEL_SETTING_EXPAND: /* expanded */
*neg = true;
return COLLECTION_DS_COLLAPSED;
case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
return ADT_NLA_EVAL_OFF;
case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
*neg = true;
return ADT_CURVES_NOT_VISIBLE;
default: /* unsupported */
return 0;
}
}
/* get pointer to the setting */
static void *acf_collection_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
{
Collection *collection = (Collection *)ale->data;
/* clear extra return data first */
*type = 0;
switch (setting) {
case ACHANNEL_SETTING_SELECT: /* selected */
return GET_ACF_FLAG_PTR(collection->flag, type);
case ACHANNEL_SETTING_EXPAND: /* expanded */
return GET_ACF_FLAG_PTR(collection->flag, type);
case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
if (collection->adt)
return GET_ACF_FLAG_PTR(collection->adt->flag, type);
return NULL;
default: /* unsupported */
return NULL;
}
}
/* collection type define */
static bAnimChannelType ACF_COLLECTION =
{
"Collection", /* type name */
ACHANNEL_ROLE_EXPANDER, /* role */
acf_generic_root_color, /* backdrop color */
acf_generic_root_backdrop, /* backdrop */
acf_generic_indention_0, /* indent level */
NULL, /* offset */
acf_generic_idblock_name, /* name */
acf_generic_idblock_name_prop, /* name prop */
acf_collection_icon, /* icon */
acf_collection_setting_valid, /* has setting */
acf_collection_setting_flag, /* flag for setting */
acf_collection_setting_ptr /* pointer for setting */
};
/* Object ------------------------------------------- */
static int acf_object_icon(bAnimListElem *ale)
@@ -3567,8 +3672,9 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_SUMMARY; /* Motion Summary */
animchannelTypeInfo[type++] = &ACF_SCENE; /* Scene */
animchannelTypeInfo[type++] = &ACF_COLLECTION; /* Collection */
animchannelTypeInfo[type++] = &ACF_OBJECT; /* Object */
animchannelTypeInfo[type++] = &ACF_GROUP; /* Group */
animchannelTypeInfo[type++] = &ACF_GROUP; /* ActionGroup */
animchannelTypeInfo[type++] = &ACF_FCURVE; /* F-Curve */
animchannelTypeInfo[type++] = &ACF_NLACONTROLS; /* NLA Control FCurve Expander */

View File

@@ -280,6 +280,10 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
if (ale->flag & SCE_DS_SELECTED)
sel = ACHANNEL_SETFLAG_CLEAR;
break;
case ANIMTYPE_COLLECTION:
if (ale->flag & COLLECTION_DS_SELECTED)
sel = ACHANNEL_SETFLAG_CLEAR;
break;
case ANIMTYPE_OBJECT:
#if 0 /* for now, do not take object selection into account, since it gets too annoying */
if (ale->flag & SELECT)
@@ -354,6 +358,17 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
}
break;
}
case ANIMTYPE_COLLECTION:
{
Collection *collection = (Collection *)ale->data;
ACHANNEL_SET_FLAG(collection, sel, COLLECTION_DS_SELECTED);
if (collection->adt) {
ACHANNEL_SET_FLAG(collection, sel, ADT_UI_SELECTED);
}
break;
}
case ANIMTYPE_OBJECT:
{
#if 0 /* for now, do not take object selection into account, since it gets too annoying */
@@ -2681,6 +2696,25 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
case ANIMTYPE_COLLECTION:
{
Collection *collection = (Collection *)ale->data;
AnimData *adt = collection->adt;
/* set selection status */
if (selectmode == SELECT_INVERT) {
/* swap select */
collection->flag ^= COLLECTION_DS_SELECTED;
if (adt) adt->flag ^= ADT_UI_SELECTED;
}
else {
collection->flag |= COLLECTION_DS_SELECTED;
if (adt) adt->flag |= ADT_UI_SELECTED;
}
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
case ANIMTYPE_OBJECT:
{
#if 0

View File

@@ -614,6 +614,19 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
ale->adt = BKE_animdata_from_id(data);
break;
}
case ANIMTYPE_COLLECTION:
{
Collection *collection = (Collection *)data;
ale->flag = collection->flag;
/* XXX: Nothing to include here for now... to be populated later */
ale->key_data = NULL;
ale->datatype = ALE_NONE;
ale->adt = BKE_animdata_from_id(data);
break;
}
case ANIMTYPE_OBJECT:
{
Base *base = (Base *)data;
@@ -2630,6 +2643,102 @@ static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data
return items;
}
/* animation channels for collection */
static size_t animdata_filter_ds_collection(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Collection *collection, int filter_mode)
{
ListBase tmp_data = {NULL, NULL};
size_t tmp_items = 0;
size_t items = 0;
AnimData *adt = collection->adt;
short type = 0, expanded = 1;
void *cdata = NULL;
/* determine the type of expander channels to use */
// this is the best way to do this for now...
ANIMDATA_FILTER_CASES(collection,
{ /* AnimData - no channel, but consider data */},
{ /* NLA - no channel, but consider data */},
{ /* Drivers */
type = ANIMTYPE_FILLDRIVERS;
cdata = adt;
expanded = EXPANDED_DRVD(adt);
},
{ /* NLA Strip Controls - no dedicated channel for now (XXX) */ },
{ /* Keyframes */
type = ANIMTYPE_FILLACTD;
cdata = adt->action;
expanded = EXPANDED_ACTC(adt->action);
});
/* add scene-level animation channels */
BEGIN_ANIMFILTER_SUBCHANNELS(expanded)
{
/* animation data filtering */
tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)collection, filter_mode);
}
END_ANIMFILTER_SUBCHANNELS;
/* did we find anything? */
if (tmp_items) {
/* include anim-expand widget first */
if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
if (type != ANIMTYPE_NONE) {
/* NOTE: active-status (and the associated checks) don't apply here... */
ANIMCHANNEL_NEW_CHANNEL(cdata, type, collection);
}
}
/* now add the list of collected channels */
BLI_movelisttolist(anim_data, &tmp_data);
BLI_assert(BLI_listbase_is_empty(&tmp_data));
items += tmp_items;
}
/* return the number of items added to the list */
return items;
}
/* collection animation */
static size_t animdata_filter_dopesheet_collection(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Collection *collection, int filter_mode)
{
ListBase tmp_data = {NULL, NULL};
size_t tmp_items = 0;
size_t items = 0;
/* filter data contained under collection first */
BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_COLLECTIONC(collection))
{
/* Action, Drivers, or NLA for Collection itself */
//if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) {
tmp_items += animdata_filter_ds_collection(ac, &tmp_data, ads, collection, filter_mode);
//}
/* TODO: Allow showing for stuff inside collection? */
}
END_ANIMFILTER_SUBCHANNELS;
/* if we collected some channels, add these to the new list... */
if (tmp_items) {
/* firstly add object expander if required */
if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
/* check if filtering by selection */
if (ANIMCHANNEL_SELOK((collection->flag & COLLECTION_DS_SELECTED))) {
/* NOTE: active-status doesn't matter for this! */
ANIMCHANNEL_NEW_CHANNEL(collection, ANIMTYPE_COLLECTION, collection);
}
}
/* now add the list of collected channels */
BLI_movelisttolist(anim_data, &tmp_data);
BLI_assert(BLI_listbase_is_empty(&tmp_data));
items += tmp_items;
}
/* return the number of items added */
return items;
}
static size_t animdata_filter_ds_world(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, World *wo, int filter_mode)
{
ListBase tmp_data = {NULL, NULL};
@@ -2729,7 +2838,7 @@ static size_t animdata_filter_dopesheet_scene(bAnimContext *ac, ListBase *anim_d
size_t tmp_items = 0;
size_t items = 0;
/* filter data contained under object first */
/* filter data contained under scene first */
BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_SCEC(sce))
{
bNodeTree *ntree = sce->nodetree;
@@ -2969,7 +3078,13 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b
/* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */
items += animdata_filter_dopesheet_scene(ac, anim_data, ads, scene, filter_mode);
/* collection animation */
/* XXX: Just list all collections for now */
for (Collection *collection = G.main->collection.first; collection; collection = collection->id.next) {
items += animdata_filter_dopesheet_collection(ac, anim_data, ads, collection, filter_mode);
}
/* If filtering for channel drawing, we want the objects in alphabetical order,
* to make it easier to predict where items are in the hierarchy
* - This order only really matters if we need to show all channels in the list (e.g. for drawing)
@@ -3074,6 +3189,10 @@ static size_t animdata_filter_animchan(bAnimContext *ac, ListBase *anim_data, bD
case ANIMTYPE_SCENE:
items += animdata_filter_dopesheet_scene(ac, anim_data, ads, channel->data, filter_mode);
break;
case ANIMTYPE_COLLECTION:
items += animdata_filter_dopesheet_collection(ac, anim_data, ads, channel->data, filter_mode);
break;
case ANIMTYPE_OBJECT:
items += animdata_filter_dopesheet_ob(ac, anim_data, ads, channel->data, filter_mode);

View File

@@ -155,6 +155,7 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_SUMMARY,
ANIMTYPE_SCENE,
ANIMTYPE_COLLECTION,
ANIMTYPE_OBJECT,
ANIMTYPE_GROUP,
ANIMTYPE_FCURVE,
@@ -281,6 +282,9 @@ typedef enum eAnimFilter_Flags {
/* 'Sub-Scene' channels (flags stored in Data block) */
#define FILTER_WOR_SCED(wo) (CHECK_TYPE_INLINE(wo, World *), (wo->flag & WO_DS_EXPAND))
#define FILTER_LS_SCED(linestyle) ((linestyle->flag & LS_DS_EXPAND))
/* 'Collection' channels */
#define SEL_COLLECTIONC(collection) (CHECK_TYPE_INLINE(collection, Collection *), ((collection->flag & COLLECTION_DS_SELECTED)))
#define EXPANDED_COLLECTIONC(collection) (CHECK_TYPE_INLINE(collection, Collection *), ((collection->flag & COLLECTION_DS_COLLAPSED) == 0))
/* 'Object' channels */
#define SEL_OBJC(base) (CHECK_TYPE_INLINE(base, Base *), ((base->flag & SELECT)))
#define EXPANDED_OBJC(ob) (CHECK_TYPE_INLINE(ob, Object *), ((ob->nlaflag & OB_ADS_COLLAPSED) == 0))

View File

@@ -243,6 +243,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
break;
}
case ANIMTYPE_SCENE:
case ANIMTYPE_COLLECTION:
case ANIMTYPE_OBJECT:
{
immUniformColor3ubvAlpha(col1b, sel ? 0x45 : 0x22);

View File

@@ -127,6 +127,7 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p
break;
}
case ANIMTYPE_SCENE: /* Top-Level Widgets doubling up as datablocks */
case ANIMTYPE_COLLECTION:
case ANIMTYPE_OBJECT:
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
case ANIMTYPE_DSLAM:

View File

@@ -122,6 +122,25 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
case ANIMTYPE_COLLECTION:
{
Collection *collection = (Collection *)ale->data;
AnimData *adt = collection->adt;
/* set selection status */
if (selectmode == SELECT_INVERT) {
/* swap select */
collection->flag ^= COLLECTION_DS_SELECTED;
if (adt) adt->flag ^= ADT_UI_SELECTED;
}
else {
collection->flag |= COLLECTION_DS_SELECTED;
if (adt) adt->flag |= ADT_UI_SELECTED;
}
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
case ANIMTYPE_OBJECT:
{
ViewLayer *view_layer = ac->view_layer;

View File

@@ -40,6 +40,7 @@
struct Object;
struct Collection;
struct AnimData;
typedef struct CollectionObject {
struct CollectionObject *next, *prev;
@@ -55,6 +56,7 @@ typedef struct CollectionChild {
typedef struct Collection {
ID id;
struct AnimData *adt;
ListBase gobject; /* CollectionObject */
ListBase children; /* CollectionChild */
@@ -89,6 +91,9 @@ enum {
COLLECTION_RESTRICT_RENDER = (1 << 3), /* Hidden in renders. */
COLLECTION_HAS_OBJECT_CACHE = (1 << 4), /* Runtime: object_cache is populated. */
COLLECTION_IS_MASTER = (1 << 5), /* Is master collection embedded in the scene. */
COLLECTION_DS_SELECTED = (1 << 10), /* Channel is selected in animation editors */
COLLECTION_DS_COLLAPSED = (1 << 11), /* Channel is collapsed in animation editors (defaults open) */
};
#endif /* __DNA_GROUP_TYPES_H__ */

View File

@@ -275,6 +275,9 @@ void RNA_def_collections(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
RNA_def_property_ui_text(prop, "Restrict Render", "Hide collection objects in renders");
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update");
/* Animation Data */
rna_def_animdata_common(srna);
}
#endif