LibOverride: Add initial support for adding new NLA tracks.

Also makes NLA tracks and strips overridable.

User can either edit existing strips in existing NLA tracks (but not add or remove them), and/or add new NLA tracks after those comming from the linked data.

Most of the work was as usual checking operators and adding protections against illegal operations in override context.

Note that since we can only rely on indices to deal with local added tracks, we forbid any local track being before any linked/original track.

Maniphest Tasks: T72629

Differential Revision: https://developer.blender.org/D9611
This commit is contained in:
Bastien Montagne 2020-12-07 16:58:18 +01:00 committed by Bastien Montagne
parent 78080337f8
commit c0bd240ad0
Notes: blender-bot 2023-12-22 20:14:11 +01:00
Referenced by commit 913b6b9ec1, Fix T96624: NLA crash when reordering tracks if no object is selected.
Referenced by commit 89ae4a7a2a, Fix NLA liboverride issues re tracks handling.
Referenced by issue #101930, NLA Actions Stash remove doesn't work on overriden linked data
Referenced by issue #91393, Duplicating an action with python crashes Blender
Referenced by issue #72629, Library Override: Support editing of animation data in overriden data-blocks.
16 changed files with 305 additions and 68 deletions

View File

@ -60,9 +60,13 @@ struct NlaTrack *BKE_nlatrack_copy(struct Main *bmain,
const int flag);
void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, ListBase *src, const int flag);
struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt, struct NlaTrack *prev);
struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt,
struct NlaTrack *prev,
bool is_liboverride);
struct NlaStrip *BKE_nlastrip_new(struct bAction *act);
struct NlaStrip *BKE_nlastack_add_strip(struct AnimData *adt, struct bAction *act);
struct NlaStrip *BKE_nlastack_add_strip(struct AnimData *adt,
struct bAction *act,
const bool is_liboverride);
struct NlaStrip *BKE_nla_add_soundstrip(struct Main *bmain,
struct Scene *scene,
struct Speaker *speaker);
@ -95,10 +99,14 @@ void BKE_nlatrack_solo_toggle(struct AnimData *adt, struct NlaTrack *nlt);
bool BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end);
void BKE_nlatrack_sort_strips(struct NlaTrack *nlt);
bool BKE_nlatrack_add_strip(struct NlaTrack *nlt, struct NlaStrip *strip);
bool BKE_nlatrack_add_strip(struct NlaTrack *nlt,
struct NlaStrip *strip,
const bool is_liboverride);
bool BKE_nlatrack_get_bounds(struct NlaTrack *nlt, float bounds[2]);
bool BKE_nlatrack_is_nonlocal_in_liboverride(const struct ID *id, const struct NlaTrack *nlt);
/* ............ */
struct NlaStrip *BKE_nlastrip_find_active(struct NlaTrack *nlt);
@ -124,11 +132,11 @@ void BKE_nla_validate_state(struct AnimData *adt);
/* ............ */
bool BKE_nla_action_is_stashed(struct AnimData *adt, struct bAction *act);
bool BKE_nla_action_stash(struct AnimData *adt);
bool BKE_nla_action_stash(struct AnimData *adt, const bool is_liboverride);
/* ............ */
void BKE_nla_action_pushdown(struct AnimData *adt);
void BKE_nla_action_pushdown(struct AnimData *adt, const bool is_liboverride);
bool BKE_nla_tweakmode_enter(struct AnimData *adt);
void BKE_nla_tweakmode_exit(struct AnimData *adt);

View File

@ -1999,12 +1999,12 @@ static void nlastrips_to_animdata(ID *id, ListBase *strips)
}
/* try to add this strip to the current NLA-Track (i.e. the 'last' one on the stack atm) */
if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
if (BKE_nlatrack_add_strip(nlt, strip, false) == 0) {
/* trying to add to the current failed (no space),
* so add a new track to the stack, and add to that...
*/
nlt = BKE_nlatrack_add(adt, NULL);
BKE_nlatrack_add_strip(nlt, strip);
nlt = BKE_nlatrack_add(adt, NULL, false);
BKE_nlatrack_add_strip(nlt, strip, false);
}
/* ensure that strip has a name */

View File

@ -280,7 +280,7 @@ void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src, const int fl
/* Add a NLA Track to the given AnimData
* - prev: NLA-Track to add the new one after
*/
NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev)
NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev, const bool is_liboverride)
{
NlaTrack *nlt;
@ -293,11 +293,15 @@ NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev)
nlt = MEM_callocN(sizeof(NlaTrack), "NlaTrack");
/* set settings requiring the track to not be part of the stack yet */
nlt->flag = NLATRACK_SELECTED;
nlt->flag = NLATRACK_SELECTED | NLATRACK_OVERRIDELIBRARY_LOCAL;
nlt->index = BLI_listbase_count(&adt->nla_tracks);
/* add track to stack, and make it the active one */
if (prev) {
if (is_liboverride) {
for (; prev != NULL && (prev->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) == 0; prev = prev->next) {
}
}
if (prev != NULL) {
BLI_insertlinkafter(&adt->nla_tracks, prev, nlt);
}
else {
@ -359,7 +363,7 @@ NlaStrip *BKE_nlastrip_new(bAction *act)
/* Add new NLA-strip to the top of the NLA stack - i.e.
* into the last track if space, or a new one otherwise. */
NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act)
NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act, const bool is_liboverride)
{
NlaStrip *strip;
NlaTrack *nlt;
@ -376,12 +380,12 @@ NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act)
}
/* firstly try adding strip to last track, but if that fails, add to a new track */
if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) {
if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip, is_liboverride) == 0) {
/* trying to add to the last track failed (no track or no space),
* so add a new track to the stack, and add to that...
*/
nlt = BKE_nlatrack_add(adt, NULL);
BKE_nlatrack_add_strip(nlt, strip);
nlt = BKE_nlatrack_add(adt, NULL, is_liboverride);
BKE_nlatrack_add_strip(nlt, strip, is_liboverride);
}
/* automatically name it too */
@ -1138,15 +1142,16 @@ void BKE_nlatrack_sort_strips(NlaTrack *nlt)
/* Add the given NLA-Strip to the given NLA-Track, assuming that it
* isn't currently attached to another one
*/
bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip)
bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip, const bool is_liboverride)
{
/* sanity checks */
if (ELEM(NULL, nlt, strip)) {
return false;
}
/* do not allow adding strips if this track is locked */
if (nlt->flag & NLATRACK_PROTECTED) {
/* Do not allow adding strips if this track is locked, or not a local one in liboverride case. */
if (nlt->flag & NLATRACK_PROTECTED ||
(is_liboverride && (nlt->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) == 0)) {
return false;
}
@ -1186,6 +1191,18 @@ bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
return true;
}
/**
* Check whether given NLA track is not local (i.e. from linked data) when the object is a library
* override.
*
* \param nlt May be NULL, in which case we consider it as a non-local track case.
*/
bool BKE_nlatrack_is_nonlocal_in_liboverride(const ID *id, const NlaTrack *nlt)
{
return (ID_IS_OVERRIDE_LIBRARY(id) &&
(nlt == NULL || (nlt->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) == 0));
}
/* NLA Strips -------------------------------------- */
/* Find the active NLA-strip within the given track */
@ -1857,7 +1874,7 @@ bool BKE_nla_action_is_stashed(AnimData *adt, bAction *act)
/* "Stash" an action (i.e. store it as a track/layer in the NLA, but non-contributing)
* to retain it in the file for future uses
*/
bool BKE_nla_action_stash(AnimData *adt)
bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride)
{
NlaTrack *prev_track = NULL;
NlaTrack *nlt;
@ -1881,7 +1898,7 @@ bool BKE_nla_action_stash(AnimData *adt)
}
}
nlt = BKE_nlatrack_add(adt, prev_track);
nlt = BKE_nlatrack_add(adt, prev_track, is_liboverride);
BLI_assert(nlt != NULL);
/* We need to ensure that if there wasn't any previous instance,
@ -1901,7 +1918,7 @@ bool BKE_nla_action_stash(AnimData *adt)
strip = BKE_nlastrip_new(adt->action);
BLI_assert(strip != NULL);
BKE_nlatrack_add_strip(nlt, strip);
BKE_nlatrack_add_strip(nlt, strip, is_liboverride);
BKE_nlastrip_validate_name(adt, strip);
/* mark the stash track and strip so that they doesn't disturb the stack animation,
@ -1931,7 +1948,7 @@ bool BKE_nla_action_stash(AnimData *adt)
* so no checks for this are performed.
*/
/* TODO: maybe we should have checks for this too... */
void BKE_nla_action_pushdown(AnimData *adt)
void BKE_nla_action_pushdown(AnimData *adt, const bool is_liboverride)
{
NlaStrip *strip;
const bool is_first = (adt) && (adt->nla_tracks.first == NULL);
@ -1952,7 +1969,7 @@ void BKE_nla_action_pushdown(AnimData *adt)
}
/* add a new NLA strip to the track, which references the active action */
strip = BKE_nlastack_add_strip(adt, adt->action);
strip = BKE_nlastack_add_strip(adt, adt->action, is_liboverride);
if (strip == NULL) {
return;
}
@ -2273,6 +2290,11 @@ void BKE_nla_blend_read_lib(BlendLibReader *reader, ID *id, ListBase *tracks)
{
/* we only care about the NLA strips inside the tracks */
LISTBASE_FOREACH (NlaTrack *, nlt, tracks) {
/* If linking from a library, clear 'local' library override flag. */
if (id->lib != NULL) {
nlt->flag &= ~NLATRACK_OVERRIDELIBRARY_LOCAL;
}
blend_lib_read_nla_strips(reader, id, &nlt->strips);
}
}

View File

@ -49,6 +49,7 @@
#include "BKE_gpencil.h"
#include "BKE_lib_id.h"
#include "BKE_mask.h"
#include "BKE_nla.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
@ -1063,18 +1064,27 @@ static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible,
eAnim_ChannelType type)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale, *ale_next;
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
eAnimFilter_Flags filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
ANIMFILTER_LIST_CHANNELS);
/* get all visible channels */
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* now, only keep the ones that are of the types we are interested in */
for (ale = anim_data.first; ale; ale = ale_next) {
ale_next = ale->next;
LISTBASE_FOREACH_MUTABLE (bAnimListElem *, ale, &anim_data) {
if (ale->type != type) {
BLI_freelinkN(&anim_data, ale);
continue;
}
if (type == ANIMTYPE_NLATRACK) {
NlaTrack *nlt = (NlaTrack *)ale->data;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
/* No re-arrangement of non-local tracks of override data. */
BLI_freelinkN(&anim_data, ale);
continue;
}
}
}
@ -1146,6 +1156,7 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn
{
AnimChanRearrangeFp rearrange_func;
ListBase anim_data_visible = {NULL, NULL};
const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ac->obact);
/* hack: invert mode so that functions will work in right order */
mode *= -1;
@ -1156,6 +1167,29 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn
return;
}
/* In liboverride case, we need to extract non-local NLA tracks from current anim data before we
* can perform the move, and add then back afterwards. It's the only way to prevent them from
* being affected by the reordering.
*
* Note that both override apply code for NLA tracks collection, and NLA editing code, are
* responsible to ensure that non-local tracks always remain first in the list. */
ListBase extracted_nonlocal_nla_tracks = {NULL, NULL};
if (is_liboverride) {
NlaTrack *nla_track;
for (nla_track = adt->nla_tracks.first; nla_track != NULL; nla_track = nla_track->next) {
if (!BKE_nlatrack_is_nonlocal_in_liboverride(&ac->obact->id, nla_track)) {
break;
}
}
if (nla_track != NULL && nla_track->prev != NULL) {
extracted_nonlocal_nla_tracks.first = adt->nla_tracks.first;
extracted_nonlocal_nla_tracks.last = nla_track->prev;
adt->nla_tracks.first = nla_track;
nla_track->prev->next = NULL;
nla_track->prev = NULL;
}
}
/* Filter visible data. */
rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLATRACK);
@ -1163,6 +1197,14 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn
rearrange_animchannel_islands(
&adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK, &anim_data_visible);
/* Add back non-local NLA tracks at the begining of the animation data's list. */
if (!BLI_listbase_is_empty(&extracted_nonlocal_nla_tracks)) {
BLI_assert(is_liboverride);
((NlaTrack *)extracted_nonlocal_nla_tracks.last)->next = adt->nla_tracks.first;
((NlaTrack *)adt->nla_tracks.first)->prev = extracted_nonlocal_nla_tracks.last;
adt->nla_tracks.first = extracted_nonlocal_nla_tracks.first;
}
/* free temp data */
BLI_freelistN(&anim_data_visible);
}

View File

@ -1618,6 +1618,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
Object *ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, local_view_bits);
const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ob);
/* to make it easier to start using this immediately in NLA, a default sound clip is created
* ready to be moved around to retime the sound and/or make new sound clips
@ -1625,13 +1626,13 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
{
/* create new data for NLA hierarchy */
AnimData *adt = BKE_animdata_add_id(&ob->id);
NlaTrack *nlt = BKE_nlatrack_add(adt, NULL);
NlaTrack *nlt = BKE_nlatrack_add(adt, NULL, is_liboverride);
NlaStrip *strip = BKE_nla_add_soundstrip(bmain, scene, ob->data);
strip->start = CFRA;
strip->end += strip->start;
/* hook them up */
BKE_nlatrack_add_strip(nlt, strip);
BKE_nlatrack_add_strip(nlt, strip, is_liboverride);
/* auto-name the strip, and give the track an interesting name */
BLI_strncpy(nlt->name, DATA_("SoundTrack"), sizeof(nlt->name));

View File

@ -240,7 +240,7 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
/* Perform stashing operation - But only if there is an action */
if (adt && oldact) {
/* stash the action */
if (BKE_nla_action_stash(adt)) {
if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ptr.owner_id))) {
/* The stash operation will remove the user already
* (and unlink the action from the AnimData action slot).
* Hence, we must unset the ref to the action in the
@ -339,7 +339,8 @@ static int action_pushdown_exec(bContext *C, wmOperator *op)
}
/* action can be safely added */
BKE_nla_action_pushdown(adt);
const Object *ob = CTX_data_active_object(C);
BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(ob));
/* Stop displaying this action in this editor
* NOTE: The editor itself doesn't set a user...
@ -384,7 +385,8 @@ static int action_stash_exec(bContext *C, wmOperator *op)
}
/* stash the action */
if (BKE_nla_action_stash(adt)) {
Object *ob = CTX_data_active_object(C);
if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ob))) {
/* The stash operation will remove the user already,
* so the flushing step later shouldn't double up
* the user-count fixes. Hence, we must unset this ref
@ -486,7 +488,8 @@ static int action_stash_create_exec(bContext *C, wmOperator *op)
}
/* stash the action */
if (BKE_nla_action_stash(adt)) {
Object *ob = CTX_data_active_object(C);
if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ob))) {
bAction *new_action = NULL;
/* Create new action not based on the old one

View File

@ -292,7 +292,7 @@ static int mouse_nla_channels(
/* TODO: make this use the operator instead of calling the function directly
* however, calling the operator requires that we supply the args,
* and that works with proper buttons only */
BKE_nla_action_pushdown(adt);
BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(ale->id));
}
else {
/* when in tweakmode, this button becomes the toggle for mapped editing */
@ -516,7 +516,7 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
}
/* 'push-down' action - only usable when not in TweakMode */
BKE_nla_action_pushdown(adt);
BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(id));
struct Main *bmain = CTX_data_main(C);
DEG_id_tag_update_ex(bmain, id, ID_RECALC_ANIMATION);
@ -648,19 +648,21 @@ bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
NlaTrack *nlt = (NlaTrack *)ale->data;
AnimData *adt = ale->adt;
const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
/* check if just adding a new track above this one,
* or whether we're adding a new one to the top of the stack that this one belongs to
*/
if (above_sel) {
/* just add a new one above this one */
BKE_nlatrack_add(adt, nlt);
BKE_nlatrack_add(adt, nlt, is_liboverride);
ale->update = ANIM_UPDATE_DEPS;
added = true;
}
else if ((lastAdt == NULL) || (adt != lastAdt)) {
/* add one track to the top of the owning AnimData's stack,
* then don't add anymore to this stack */
BKE_nlatrack_add(adt, NULL);
BKE_nlatrack_add(adt, NULL, is_liboverride);
lastAdt = adt;
ale->update = ANIM_UPDATE_DEPS;
added = true;
@ -698,7 +700,7 @@ bool nlaedit_add_tracks_empty(bAnimContext *ac)
/* ensure it is empty */
if (BLI_listbase_is_empty(&adt->nla_tracks)) {
/* add new track to this AnimData block then */
BKE_nlatrack_add(adt, NULL);
BKE_nlatrack_add(adt, NULL, ID_IS_OVERRIDE_LIBRARY(ale->id));
ale->update = ANIM_UPDATE_DEPS;
added = true;
}
@ -796,6 +798,11 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op))
NlaTrack *nlt = (NlaTrack *)ale->data;
AnimData *adt = ale->adt;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
/* No deletion of non-local tracks of override data. */
continue;
}
/* if track is currently 'solo', then AnimData should have its
* 'has solo' flag disabled
*/

View File

@ -649,6 +649,7 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
NlaTrack *nlt = (NlaTrack *)ale->data;
AnimData *adt = ale->adt;
NlaStrip *strip = NULL;
const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
/* Sanity check: only apply actions of the right type for this ID.
* NOTE: in the case that this hasn't been set,
@ -671,12 +672,12 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
strip->start = cfra;
/* firstly try adding strip to our current track, but if that fails, add to a new track */
if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
if (BKE_nlatrack_add_strip(nlt, strip, is_liboverride) == 0) {
/* trying to add to the current failed (no space),
* so add a new track to the stack, and add to that...
*/
nlt = BKE_nlatrack_add(adt, NULL);
BKE_nlatrack_add_strip(nlt, strip);
nlt = BKE_nlatrack_add(adt, NULL, is_liboverride);
BKE_nlatrack_add_strip(nlt, strip, is_liboverride);
}
/* auto-name it */
@ -886,6 +887,7 @@ static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op))
AnimData *adt = ale->adt;
NlaTrack *nlt = (NlaTrack *)ale->data;
NlaStrip *strip;
const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
/* does this belong to speaker - assumed to live on Object level only */
if ((GS(ale->id->name) != ID_OB) || (ob->type != OB_SPEAKER)) {
@ -899,12 +901,12 @@ static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op))
strip->end += cfra;
/* firstly try adding strip to our current track, but if that fails, add to a new track */
if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
if (BKE_nlatrack_add_strip(nlt, strip, is_liboverride) == 0) {
/* trying to add to the current failed (no space),
* so add a new track to the stack, and add to that...
*/
nlt = BKE_nlatrack_add(adt, NULL);
BKE_nlatrack_add_strip(nlt, strip);
nlt = BKE_nlatrack_add(adt, NULL, is_liboverride);
BKE_nlatrack_add_strip(nlt, strip, is_liboverride);
}
/* auto-name it */
@ -966,6 +968,11 @@ static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op))
AnimData *adt = ale->adt;
NlaStrip *strip;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
/* No making metastrips in non-local tracks of override data. */
continue;
}
/* create meta-strips from the continuous chains of selected strips */
BKE_nlastrips_make_metas(&nlt->strips, 0);
@ -1030,6 +1037,11 @@ static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op))
for (ale = anim_data.first; ale; ale = ale->next) {
NlaTrack *nlt = (NlaTrack *)ale->data;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
/* No removing metastrips from non-local tracks of override data. */
continue;
}
/* clear all selected meta-strips, regardless of whether they are temporary or not */
BKE_nlastrips_clear_metas(&nlt->strips, 1, 0);
@ -1096,6 +1108,11 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op)
NlaStrip *strip, *nstrip, *next;
NlaTrack *track;
/* Note: We allow this operator in override context because it is almost always (from possible
* default user interactions) paired with the transform one, which will ensure that the new
* strip ends up in a valid (local) track. */
const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
for (strip = nlt->strips.first; strip; strip = next) {
next = strip->next;
@ -1106,13 +1123,13 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op)
/* in case there's no space in the track above,
* or we haven't got a reference to it yet, try adding */
if (BKE_nlatrack_add_strip(nlt->next, nstrip) == 0) {
if (BKE_nlatrack_add_strip(nlt->next, nstrip, is_liboverride) == 0) {
/* need to add a new track above the one above the current one
* - if the current one is the last one, nlt->next will be NULL, which defaults to adding
* at the top of the stack anyway...
*/
track = BKE_nlatrack_add(adt, nlt->next);
BKE_nlatrack_add_strip(track, nstrip);
track = BKE_nlatrack_add(adt, nlt->next, is_liboverride);
BKE_nlatrack_add_strip(track, nstrip, is_liboverride);
}
/* deselect the original and the active flag */
@ -1209,6 +1226,11 @@ static int nlaedit_delete_exec(bContext *C, wmOperator *UNUSED(op))
NlaTrack *nlt = (NlaTrack *)ale->data;
NlaStrip *strip, *nstrip;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
/* No deletion of strips in non-local tracks of override data. */
continue;
}
for (strip = nlt->strips.first; strip; strip = nstrip) {
nstrip = strip->next;
@ -1359,6 +1381,11 @@ static int nlaedit_split_exec(bContext *C, wmOperator *UNUSED(op))
AnimData *adt = ale->adt;
NlaStrip *strip, *next;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
/* No splitting of strips in non-local tracks of override data. */
continue;
}
for (strip = nlt->strips.first; strip; strip = next) {
next = strip->next;
@ -1502,6 +1529,12 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
NlaStrip *strip, *stripN = NULL;
NlaStrip *area = NULL, *sb = NULL;
const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
/* No re-ordering of strips whithin non-local tracks of override data. */
continue;
}
/* make temporary metastrips so that entire islands of selections can be moved around */
BKE_nlastrips_make_metas(&nlt->strips, 1);
@ -1610,8 +1643,8 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
}
/* add strips back to track now */
BKE_nlatrack_add_strip(nlt, area);
BKE_nlatrack_add_strip(nlt, sb);
BKE_nlatrack_add_strip(nlt, area, is_liboverride);
BKE_nlatrack_add_strip(nlt, sb, is_liboverride);
}
/* clear (temp) metastrips */
@ -1674,11 +1707,19 @@ static int nlaedit_move_up_exec(bContext *C, wmOperator *UNUSED(op))
NlaTrack *nltn = nlt->next;
NlaStrip *strip, *stripn;
const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
/* if this track has no tracks after it, skip for now... */
if (nltn == NULL) {
continue;
}
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt) ||
BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nltn)) {
/* No moving of strips in non-local tracks of override data. */
continue;
}
/* for every selected strip, try to move */
for (strip = nlt->strips.first; strip; strip = stripn) {
stripn = strip->next;
@ -1689,7 +1730,7 @@ static int nlaedit_move_up_exec(bContext *C, wmOperator *UNUSED(op))
/* remove from its current track, and add to the one above
* (it 'should' work, so no need to worry) */
BLI_remlink(&nlt->strips, strip);
BKE_nlatrack_add_strip(nltn, strip);
BKE_nlatrack_add_strip(nltn, strip, is_liboverride);
}
}
}
@ -1751,11 +1792,19 @@ static int nlaedit_move_down_exec(bContext *C, wmOperator *UNUSED(op))
NlaTrack *nltp = nlt->prev;
NlaStrip *strip, *stripn;
const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
/* if this track has no tracks before it, skip for now... */
if (nltp == NULL) {
continue;
}
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt) ||
BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nltp)) {
/* No moving of strips in non-local tracks of override data. */
continue;
}
/* for every selected strip, try to move */
for (strip = nlt->strips.first; strip; strip = stripn) {
stripn = strip->next;
@ -1766,7 +1815,7 @@ static int nlaedit_move_down_exec(bContext *C, wmOperator *UNUSED(op))
/* remove from its current track, and add to the one above
* (it 'should' work, so no need to worry) */
BLI_remlink(&nlt->strips, strip);
BKE_nlatrack_add_strip(nltp, strip);
BKE_nlatrack_add_strip(nltp, strip, is_liboverride);
}
}
}
@ -2023,11 +2072,11 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
/* strip must be selected, and must be action-clip only
* (transitions don't have scale) */
if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
/* if the referenced action is used by other strips,
* make this strip use its own copy */
if (strip->act == NULL) {
if (strip->act == NULL || ID_IS_OVERRIDE_LIBRARY(strip->act) || ID_IS_LINKED(strip->act)) {
continue;
}
/* if the referenced action is used by other strips,
* make this strip use its own copy */
if (strip->act->id.us > 1) {
/* make a copy of the Action to work on */
bAction *act = (bAction *)BKE_id_copy(bmain, &strip->act->id);
@ -2200,6 +2249,8 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op)
NlaStrip *strip, *stripn;
NlaTrack *track;
const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id);
/* create meta-strips from the continuous chains of selected strips */
BKE_nlastrips_make_metas(&nlt->strips, 1);
@ -2255,10 +2306,10 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op)
BLI_remlink(&tmp_strips, strip);
/* in case there's no space in the current track, try adding */
if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
if (BKE_nlatrack_add_strip(nlt, strip, is_liboverride) == 0) {
/* need to add a new track above the current one */
track = BKE_nlatrack_add(adt, nlt);
BKE_nlatrack_add_strip(track, strip);
track = BKE_nlatrack_add(adt, nlt, is_liboverride);
BKE_nlatrack_add_strip(track, strip, is_liboverride);
/* clear temp meta-strips on this new track,
* as we may not be able to get back to it */
@ -2375,6 +2426,11 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
NlaTrack *nlt = (NlaTrack *)ale->data;
NlaStrip *strip;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
/* No adding f-modifiers to strips in non-local tracks of override data. */
continue;
}
for (strip = nlt->strips.first; strip; strip = strip->next) {
/* can F-Modifier be added to the current strip? */
if (active_only) {
@ -2552,6 +2608,11 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
NlaTrack *nlt = (NlaTrack *)ale->data;
NlaStrip *strip;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
/* No pasting in non-local tracks of override data. */
continue;
}
for (strip = nlt->strips.first; strip; strip = strip->next) {
/* can F-Modifier be added to the current strip? */
if (active_only) {

View File

@ -1438,7 +1438,7 @@ void animrecord_check_state(TransInfo *t, struct Object *ob)
/* only push down if action is more than 1-2 frames long */
calc_action_range(adt->action, &astart, &aend, 1);
if (aend > astart + 2.0f) {
NlaStrip *strip = BKE_nlastack_add_strip(adt, adt->action);
NlaStrip *strip = BKE_nlastack_add_strip(adt, adt->action, ID_IS_OVERRIDE_LIBRARY(id));
/* clear reference to action now that we've pushed it onto the stack */
id_us_min(&adt->action->id);

View File

@ -462,6 +462,12 @@ void recalcData_nla(TransInfo *t)
* - we need to calculate both,
* as only one may have been altered by transform if only 1 handle moved.
*/
/* In LibOverride case, we cannot move strips across tracks that come from the linked data. */
const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(tdn->id);
if (BKE_nlatrack_is_nonlocal_in_liboverride(tdn->id, tdn->nlt)) {
continue;
}
delta_y1 = ((int)tdn->h1[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
delta_y2 = ((int)tdn->h2[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
@ -477,10 +483,11 @@ void recalcData_nla(TransInfo *t)
if (delta > 0) {
for (track = tdn->nlt->next, n = 0; (track) && (n < delta); track = track->next, n++) {
/* check if space in this track for the strip */
if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
if (BKE_nlatrack_has_space(track, strip->start, strip->end) &&
!BKE_nlatrack_is_nonlocal_in_liboverride(tdn->id, tdn->nlt)) {
/* move strip to this track */
BLI_remlink(&tdn->nlt->strips, strip);
BKE_nlatrack_add_strip(track, strip);
BKE_nlatrack_add_strip(track, strip, is_liboverride);
tdn->nlt = track;
tdn->trackIndex++;
@ -496,10 +503,11 @@ void recalcData_nla(TransInfo *t)
for (track = tdn->nlt->prev, n = 0; (track) && (n < delta); track = track->prev, n++) {
/* check if space in this track for the strip */
if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
if (BKE_nlatrack_has_space(track, strip->start, strip->end) &&
!BKE_nlatrack_is_nonlocal_in_liboverride(tdn->id, tdn->nlt)) {
/* move strip to this track */
BLI_remlink(&tdn->nlt->strips, strip);
BKE_nlatrack_add_strip(track, strip);
BKE_nlatrack_add_strip(track, strip, is_liboverride);
tdn->nlt = track;
tdn->trackIndex--;

View File

@ -875,6 +875,10 @@ typedef enum eNlaTrack_Flag {
/** track is not allowed to execute,
* usually as result of tweaking being enabled (internal flag) */
NLATRACK_DISABLED = (1 << 10),
/** This NLA track is added to an override ID, which means it is fully editable.
* Irrelevant in case the owner ID is not an override. */
NLATRACK_OVERRIDELIBRARY_LOCAL = 1 << 16,
} eNlaTrack_Flag;
/* ************************************ */

View File

@ -23,6 +23,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
#include "DNA_anim_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_key_types.h"
@ -84,6 +85,12 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
return true;
}
}
else if (RNA_struct_is_a(ptr->type, &RNA_NlaTrack)) {
NlaTrack *nla_track = ptr->data;
if (nla_track->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) {
return true;
}
}
/* If this is a RNA-defined property (real or 'virtual' IDProp),
* we want to use RNA prop flag. */
return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) &&

View File

@ -587,7 +587,7 @@ static void rna_KeyingSet_paths_clear(KeyingSet *keyingset, ReportList *reports)
/* needs wrapper function to push notifier */
static NlaTrack *rna_NlaTrack_new(ID *id, AnimData *adt, Main *bmain, bContext *C, NlaTrack *track)
{
NlaTrack *new_track = BKE_nlatrack_add(adt, track);
NlaTrack *new_track = BKE_nlatrack_add(adt, track, ID_IS_OVERRIDE_LIBRARY(id));
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_ADDED, NULL);
@ -732,6 +732,60 @@ bool rna_AnimaData_override_apply(Main *UNUSED(bmain),
return false;
}
bool rna_NLA_tracks_override_apply(Main *bmain,
PointerRNA *ptr_dst,
PointerRNA *ptr_src,
PointerRNA *UNUSED(ptr_storage),
PropertyRNA *UNUSED(prop_dst),
PropertyRNA *UNUSED(prop_src),
PropertyRNA *UNUSED(prop_storage),
const int UNUSED(len_dst),
const int UNUSED(len_src),
const int UNUSED(len_storage),
PointerRNA *UNUSED(ptr_item_dst),
PointerRNA *UNUSED(ptr_item_src),
PointerRNA *UNUSED(ptr_item_storage),
IDOverrideLibraryPropertyOperation *opop)
{
BLI_assert(opop->operation == IDOVERRIDE_LIBRARY_OP_INSERT_AFTER &&
"Unsupported RNA override operation on constraints collection");
AnimData *anim_data_dst = (AnimData *)ptr_dst->data;
AnimData *anim_data_src = (AnimData *)ptr_src->data;
/* Remember that insertion operations are defined and stored in correct order, which means that
* even if we insert several items in a row, we always insert first one, then second one, etc.
* So we should always find 'anchor' track in both _src *and* _dst. */
NlaTrack *nla_track_anchor = NULL;
# if 0
/* This is not working so well with index-based insertion, especially in case some tracks get
* added to lib linked data. So we simply add locale tracks at the end of the list always, order
* of override operations should ensure order of local tracks is preserved properly. */
if (opop->subitem_local_index >= 0) {
nla_track_anchor = BLI_findlink(&anim_data_dst->nla_tracks, opop->subitem_local_index);
}
/* Otherwise we just insert in first position. */
# else
nla_track_anchor = anim_data_dst->nla_tracks.last;
# endif
NlaTrack *nla_track_src = NULL;
if (opop->subitem_local_index >= 0) {
nla_track_src = BLI_findlink(&anim_data_src->nla_tracks, opop->subitem_local_index);
}
nla_track_src = nla_track_src ? nla_track_src->next : anim_data_src->nla_tracks.first;
BLI_assert(nla_track_src != NULL);
NlaTrack *nla_track_dst = BKE_nlatrack_copy(bmain, nla_track_src, true, 0);
/* This handles NULL anchor as expected by adding at head of list. */
BLI_insertlinkafter(&anim_data_dst->nla_tracks, nla_track_anchor, nla_track_dst);
// printf("%s: We inserted a NLA Track...\n", __func__);
return true;
}
#else
/* helper function for Keying Set -> keying settings */
@ -1251,14 +1305,19 @@ static void rna_def_animdata(BlenderRNA *brna)
RNA_def_property_collection_sdna(prop, NULL, "nla_tracks", NULL);
RNA_def_property_struct_type(prop, "NlaTrack");
RNA_def_property_ui_text(prop, "NLA Tracks", "NLA Tracks (i.e. Animation Layers)");
RNA_def_property_override_flag(prop,
PROPOVERRIDE_OVERRIDABLE_LIBRARY |
PROPOVERRIDE_LIBRARY_INSERTION | PROPOVERRIDE_NO_PROP_NAME);
RNA_def_property_override_funcs(prop, NULL, NULL, "rna_NLA_tracks_override_apply");
rna_api_animdata_nla_tracks(brna, prop);
RNA_define_lib_overridable(true);
/* Active Action */
prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE);
/* this flag as well as the dynamic test must be defined for this to be editable... */
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_pointer_funcs(
prop, NULL, "rna_AnimData_action_set", NULL, "rna_Action_id_poll");
RNA_def_property_editable_func(prop, "rna_AnimData_action_editable");
@ -1297,11 +1356,14 @@ static void rna_def_animdata(BlenderRNA *brna)
prop = RNA_def_property(srna, "drivers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "drivers", NULL);
RNA_def_property_struct_type(prop, "FCurve");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Drivers", "The Drivers/Expressions for this data-block");
RNA_define_lib_overridable(false);
rna_api_animdata_drivers(brna, prop);
RNA_define_lib_overridable(true);
/* General Settings */
prop = RNA_def_property(srna, "use_nla", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ADT_NLA_EVAL_OFF);
@ -1322,6 +1384,8 @@ static void rna_def_animdata(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Pin in Graph Editor", "");
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
RNA_define_lib_overridable(false);
/* Animation Data API */
RNA_api_animdata(srna);
}

View File

@ -607,6 +607,8 @@ static void rna_def_nlastrip(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_NlaStrip_path");
RNA_def_struct_ui_icon(srna, ICON_NLA); /* XXX */
RNA_define_lib_overridable(true);
/* name property */
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Name", "");
@ -820,6 +822,8 @@ static void rna_def_nlastrip(BlenderRNA *brna)
"Update range of frames referenced from action "
"after tweaking strip and its keyframes");
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
RNA_define_lib_overridable(false);
}
static void rna_api_nlatrack_strips(BlenderRNA *brna, PropertyRNA *cprop)
@ -877,10 +881,14 @@ static void rna_def_nlatrack(BlenderRNA *brna)
/* strips collection */
prop = RNA_def_property(srna, "strips", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "NlaStrip");
/* We do not support inserting or removing strips in overrides of tracks for now. */
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "NLA Strips", "NLA Strips on this NLA-track");
rna_api_nlatrack_strips(brna, prop);
RNA_define_lib_overridable(true);
/* name property */
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Name", "");
@ -920,6 +928,8 @@ static void rna_def_nlatrack(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_PROTECTED);
RNA_def_property_ui_text(prop, "Locked", "NLA Track is locked");
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
RNA_define_lib_overridable(false);
}
/* --------- */

View File

@ -1858,7 +1858,7 @@ int rna_property_override_diff_default(Main *bmain,
is_id,
is_valid_for_diffing,
is_valid_for_insertion,
(RNA_property_override_flag(prop_a) & PROPOVERRIDE_LIBRARY_INSERTION) != 0,
use_collection_insertion,
do_create);
}
# endif

View File

@ -2113,7 +2113,7 @@ static void rna_SpaceDopeSheetEditor_action_update(bContext *C, PointerRNA *ptr)
* and the user then uses the browse menu to get back to this action,
* assigning it as the active action (i.e. the stash strip gets out of sync)
*/
BKE_nla_action_stash(adt);
BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(id));
}
BKE_animdata_set_action(NULL, id, saction->action);