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
diff options
context:
space:
mode:
authorWayde Moss <wbmoss_dev@yahoo.com>2021-01-15 02:25:01 +0300
committerWayde Moss <wbmoss_dev@yahoo.com>2021-01-15 02:25:01 +0300
commit09709a7e64ff0b225e16f97926b54c6441d94499 (patch)
treed1bb4f5f9d3e7be6eff70a184f55b779a5720666 /source/blender/blenkernel/intern/anim_sys.c
parentb75552ebbbf695e24eeee92767639b8d097e9626 (diff)
Nla Refactor: Split animsys_evaluate_nla()
No intended functional changes. Refactors animsys_evaluate_nla() into 2 versions: animsys_evaluate_nla_for_keyframing(), animsys_evaluate_nla_for_flush() to make it clear what data is being calculated and why. Dummy strip creation has been refactored to two separate functions, animsys_create_tweak_strip() and animsys_create_action_track_strip(). Both are evaluated differently from other strips and eachother. There's no need to interweave them. A future patch D8296, generally requires both strips. ___ XXX anim_sys.c) nlatrack_find_tweaked() is a temporary work around. If anyone has any insight into this problem, help is appreciated. Reviewed by: sybren Differential Revision: http://developer.blender.org/D9696
Diffstat (limited to 'source/blender/blenkernel/intern/anim_sys.c')
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c453
1 files changed, 309 insertions, 144 deletions
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 20956d6eb18..c8a4a125693 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -979,6 +979,19 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list,
return nes;
}
+static NlaEvalStrip *nlastrips_ctime_get_strip_single(
+ ListBase *dst_list,
+ NlaStrip *single_strip,
+ const AnimationEvalContext *anim_eval_context,
+ const bool flush_to_original)
+{
+ ListBase single_tracks_list;
+ single_tracks_list.first = single_tracks_list.last = single_strip;
+
+ return nlastrips_ctime_get_strip(
+ dst_list, &single_tracks_list, -1, anim_eval_context, flush_to_original);
+}
+
/* ---------------------- */
/* Initialize a valid mask, allocating memory if necessary. */
@@ -2212,190 +2225,344 @@ static void animsys_evaluate_nla_domain(PointerRNA *ptr, NlaEvalData *channels,
/* ---------------------- */
+/** Tweaked strip is evaluated differently from other strips. Adjacent strips are ignored
+ * and includes a workaround for when user is not editing in place. */
+static void animsys_create_tweak_strip(const AnimData *adt,
+ const bool keyframing_to_strip,
+ NlaStrip *r_tweak_strip)
+
+{
+ /* Copy active strip so we can modify how it evaluates without affecting user data. */
+ memcpy(r_tweak_strip, adt->actstrip, sizeof(NlaStrip));
+ r_tweak_strip->next = r_tweak_strip->prev = NULL;
+
+ /* If tweaked strip is syncing action length, then evaluate using action length. */
+ if (r_tweak_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH) {
+ BKE_nlastrip_recalculate_bounds_sync_action(r_tweak_strip);
+ }
+
+ /* Strips with a user-defined time curve don't get properly remapped for editing
+ * at the moment, so mapping them just for display may be confusing. */
+ const bool is_inplace_tweak = !(adt->flag & ADT_NLA_EDIT_NOMAP) &&
+ !(adt->actstrip->flag & NLASTRIP_FLAG_USR_TIME);
+
+ if (!is_inplace_tweak) {
+ /* Use Hold due to no proper remapping yet (the note above). */
+ r_tweak_strip->extendmode = NLASTRIP_EXTEND_HOLD;
+
+ /* Disable range. */
+ r_tweak_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP;
+ }
+
+ /** Controls whether able to keyframe outside range of tweaked strip. */
+ if (keyframing_to_strip) {
+ r_tweak_strip->extendmode = (is_inplace_tweak &&
+ !(r_tweak_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) ?
+ NLASTRIP_EXTEND_NOTHING :
+ NLASTRIP_EXTEND_HOLD;
+ }
+}
+
+/** Action track and strip are associated with the non-pushed action. */
+static void animsys_create_action_track_strip(const AnimData *adt,
+ const bool keyframing_to_strip,
+ NlaStrip *r_action_strip)
+{
+ memset(r_action_strip, 0, sizeof(NlaStrip));
+
+ bAction *action = adt->action;
+
+ if ((adt->flag & ADT_NLA_EDIT_ON)) {
+ action = adt->tmpact;
+ }
+
+ /* Set settings of dummy NLA strip from AnimData settings. */
+ r_action_strip->act = action;
+
+ /* Action range is calculated taking F-Modifiers into account
+ * (which making new strips doesn't do due to the troublesome nature of that). */
+ calc_action_range(r_action_strip->act, &r_action_strip->actstart, &r_action_strip->actend, 1);
+ r_action_strip->start = r_action_strip->actstart;
+ r_action_strip->end = (IS_EQF(r_action_strip->actstart, r_action_strip->actend)) ?
+ (r_action_strip->actstart + 1.0f) :
+ (r_action_strip->actend);
+
+ r_action_strip->blendmode = adt->act_blendmode;
+ r_action_strip->extendmode = adt->act_extendmode;
+ r_action_strip->influence = adt->act_influence;
+
+ /* NOTE: must set this, or else the default setting overrides,
+ * and this setting doesn't work. */
+ r_action_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
+
+ /* Unless extendmode is Nothing (might be useful for flattening NLA evaluation), disable range.
+ * Extendmode Nothing and Hold will behave as normal. Hold Forward will behave just like Hold.
+ */
+ if (r_action_strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ r_action_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP;
+ }
+
+ const bool tweaking = (adt->flag & ADT_NLA_EDIT_ON) != 0;
+ const bool soloing = (adt->flag & ADT_NLA_SOLO_TRACK) != 0;
+ const bool actionstrip_evaluated = r_action_strip->act && !soloing && !tweaking;
+ if (!actionstrip_evaluated) {
+ r_action_strip->flag |= NLASTRIP_FLAG_MUTED;
+ }
+
+ /** If we're keyframing, then we must allow keyframing outside fcurve bounds. */
+ if (keyframing_to_strip) {
+ r_action_strip->extendmode = NLASTRIP_EXTEND_HOLD;
+ }
+}
+
+static bool is_nlatrack_evaluatable(const AnimData *adt, const NlaTrack *nlt)
+{
+ /* Skip disabled tracks unless it contains the tweaked strip. */
+ const bool contains_tweak_strip = (adt->flag & ADT_NLA_EDIT_ON) &&
+ (nlt->index == adt->act_track->index);
+ if ((nlt->flag & NLATRACK_DISABLED) && !contains_tweak_strip) {
+ return false;
+ }
+
+ /* Solo and muting are mutually exclusive. */
+ if (adt->flag & ADT_NLA_SOLO_TRACK) {
+ /* Skip if there is a solo track, but this isn't it. */
+ if ((nlt->flag & NLATRACK_SOLO) == 0) {
+ return false;
+ }
+ }
+ else {
+ /* Skip track if muted. */
+ if (nlt->flag & NLATRACK_MUTED) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/** Check for special case of non-pushed action being evaluated with no NLA influence (off and no
+ * strips evaluated) nor NLA interference (ensure NLA not soloing). */
+static bool is_action_track_evaluated_without_nla(const AnimData *adt,
+ const bool any_strip_evaluated)
+{
+ if (adt->action == NULL) {
+ return false;
+ }
+
+ if (any_strip_evaluated) {
+ return false;
+ }
+
+ /** NLA settings interference. */
+ if ((adt->flag & (ADT_NLA_SOLO_TRACK | ADT_NLA_EDIT_ON)) == 0) {
+ return false;
+ }
+
+ /** Allow action track to evaluate as if there isn't any NLA data. */
+ return true;
+}
+
+/** XXX Wayde Moss: BKE_nlatrack_find_tweaked() exists within nla.c, but it doesn't appear to
+ * work as expected. From animsys_evaluate_nla_for_flush(), it returns NULL in tweak mode. I'm not
+ * sure why. Preferably, it would be as simple as checking for (adt->act_Track == nlt) but that
+ * doesn't work either, neither does comparing indices.
+ *
+ * This function is a temporary work around. The first disabled track is always the tweaked track.
+ */
+static NlaTrack *nlatrack_find_tweaked(const AnimData *adt)
+{
+ NlaTrack *nlt;
+
+ if (adt == NULL) {
+ return NULL;
+ }
+
+ /* Since the track itself gets disabled, we want the first disabled. */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ if (nlt->flag & NLATRACK_DISABLED) {
+ return nlt;
+ }
+ }
+
+ return NULL;
+}
+
/**
* NLA Evaluation function - values are calculated and stored in temporary "NlaEvalChannels"
- *
* \param[out] echannels: Evaluation channels with calculated values
- * \param[out] r_context: If not NULL,
- * data about the currently edited strip is stored here and excluded from value calculation.
- * \return false if NLA evaluation isn't actually applicable.
*/
-static bool animsys_evaluate_nla(NlaEvalData *echannels,
- PointerRNA *ptr,
- AnimData *adt,
- const AnimationEvalContext *anim_eval_context,
- const bool flush_to_original,
- NlaKeyframingContext *r_context)
+static bool animsys_evaluate_nla_for_flush(NlaEvalData *echannels,
+ PointerRNA *ptr,
+ const AnimData *adt,
+ const AnimationEvalContext *anim_eval_context,
+ const bool flush_to_original)
{
NlaTrack *nlt;
short track_index = 0;
bool has_strips = false;
-
ListBase estrips = {NULL, NULL};
NlaEvalStrip *nes;
- NlaStrip dummy_strip_buf;
- /* dummy strip for active action */
- NlaStrip *dummy_strip = r_context ? &r_context->strip : &dummy_strip_buf;
+ NlaStrip tweak_strip;
- memset(dummy_strip, 0, sizeof(*dummy_strip));
+ NlaTrack *tweaked_track = nlatrack_find_tweaked(adt);
- /* 1. get the stack of strips to evaluate at current time (influence calculated here) */
+ /* Get the stack of strips to evaluate at current time (influence calculated here). */
for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next, track_index++) {
- /* stop here if tweaking is on and this strip is the tweaking track
- * (it will be the first one that's 'disabled')... */
- if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED)) {
- break;
+
+ if (!is_nlatrack_evaluatable(adt, nlt)) {
+ continue;
}
- /* solo and muting are mutually exclusive... */
- if (adt->flag & ADT_NLA_SOLO_TRACK) {
- /* skip if there is a solo track, but this isn't it */
- if ((nlt->flag & NLATRACK_SOLO) == 0) {
- continue;
- }
- /* else - mute doesn't matter */
+ if (nlt->strips.first) {
+ has_strips = true;
+ }
+
+ /** Append strip to evaluate for this track. */
+ if (nlt == tweaked_track) {
+ /** Tweaked strip is evaluated differently. */
+ animsys_create_tweak_strip(adt, false, &tweak_strip);
+ nes = nlastrips_ctime_get_strip_single(
+ &estrips, &tweak_strip, anim_eval_context, flush_to_original);
}
else {
- /* no solo tracks - skip track if muted */
- if (nlt->flag & NLATRACK_MUTED) {
- continue;
- }
+ nes = nlastrips_ctime_get_strip(
+ &estrips, &nlt->strips, track_index, anim_eval_context, flush_to_original);
+ }
+ if (nes) {
+ nes->track = nlt;
+ }
+ }
+
+ if (is_action_track_evaluated_without_nla(adt, has_strips)) {
+ BLI_freelistN(&estrips);
+ return false;
+ }
+
+ NlaStrip action_strip = {0};
+ animsys_create_action_track_strip(adt, false, &action_strip);
+ nlastrips_ctime_get_strip_single(&estrips, &action_strip, anim_eval_context, flush_to_original);
+
+ /* Per strip, evaluate and accumulate on top of existing channels. */
+ for (nes = estrips.first; nes; nes = nes->next) {
+ nlastrip_evaluate(ptr,
+ echannels,
+ NULL,
+ nes,
+ &echannels->eval_snapshot,
+ anim_eval_context,
+ flush_to_original);
+ }
+
+ /* Free temporary evaluation data that's not used elsewhere. */
+ BLI_freelistN(&estrips);
+ return true;
+}
+
+/** Lower blended values are calculated and accumulated into r_context->lower_eval_data. */
+static void animsys_evaluate_nla_for_keyframing(PointerRNA *ptr,
+ const AnimData *adt,
+ const AnimationEvalContext *anim_eval_context,
+ NlaKeyframingContext *r_context)
+{
+ if (!r_context) {
+ return;
+ }
+
+ /* Early out. If NLA track is soloing and tweaked action isn't it, then don't allow keyframe
+ * insertion. */
+ if (adt->flag & ADT_NLA_SOLO_TRACK) {
+ if (!(adt->act_track && (adt->act_track->flag & NLATRACK_SOLO))) {
+ r_context->eval_strip = NULL;
+ return;
+ }
+ }
+
+ NlaTrack *nlt;
+ short track_index = 0;
+ bool has_strips = false;
+
+ ListBase lower_estrips = {NULL, NULL};
+ NlaEvalStrip *nes;
+
+ NlaTrack *tweaked_track = nlatrack_find_tweaked(adt);
+
+ /* Get the lower stack of strips to evaluate at current time (influence calculated here). */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next, track_index++) {
+
+ if (!is_nlatrack_evaluatable(adt, nlt)) {
+ continue;
+ }
+
+ /* Tweaked strip effect should not be stored in any snapshot. */
+ if (nlt == tweaked_track) {
+ break;
}
- /* if this track has strips (but maybe they won't be suitable), set has_strips
- * - used for mainly for still allowing normal action evaluation...
- */
if (nlt->strips.first) {
has_strips = true;
}
- /* otherwise, get strip to evaluate for this channel */
+ /* Get strip to evaluate for this channel. */
nes = nlastrips_ctime_get_strip(
- &estrips, &nlt->strips, track_index, anim_eval_context, flush_to_original);
+ &lower_estrips, &nlt->strips, track_index, anim_eval_context, false);
if (nes) {
nes->track = nlt;
}
}
- /* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack
- * - only do this if we're not exclusively evaluating the 'solo' NLA-track
- * - however, if the 'solo' track houses the current 'tweaking' strip,
- * then we should allow this to play, otherwise nothing happens
+ /** Note: Although we early out, we can still keyframe to the non-pushed action since the
+ * keyframe remap function detects (r_context->strip.act == NULL) and will keyframe without
+ * remapping.
*/
- if ((adt->action) && ((adt->flag & ADT_NLA_SOLO_TRACK) == 0 || (adt->flag & ADT_NLA_EDIT_ON))) {
- /* if there are strips, evaluate action as per NLA rules */
- if ((has_strips) || (adt->actstrip)) {
- /* make dummy NLA strip, and add that to the stack */
- ListBase dummy_trackslist;
-
- dummy_trackslist.first = dummy_trackslist.last = dummy_strip;
-
- /* Strips with a user-defined time curve don't get properly remapped for editing
- * at the moment, so mapping them just for display may be confusing. */
- bool is_inplace_tweak = (nlt) && !(adt->flag & ADT_NLA_EDIT_NOMAP) &&
- !(adt->actstrip->flag & NLASTRIP_FLAG_USR_TIME);
-
- if (is_inplace_tweak) {
- /* edit active action in-place according to its active strip, so copy the data */
- memcpy(dummy_strip, adt->actstrip, sizeof(NlaStrip));
- /* Prevents nla eval from considering active strip's adj strips.
- * For user, this means entering tweak mode on a strip ignores evaluating adjacent strips
- * in the same track. */
- dummy_strip->next = dummy_strip->prev = NULL;
-
- /* If tweaked strip is syncing action length, then evaluate using action length. */
- if (dummy_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH) {
- BKE_nlastrip_recalculate_bounds_sync_action(dummy_strip);
- }
- }
- else {
- /* set settings of dummy NLA strip from AnimData settings */
- dummy_strip->act = adt->action;
-
- /* action range is calculated taking F-Modifiers into account
- * (which making new strips doesn't do due to the troublesome nature of that) */
- calc_action_range(dummy_strip->act, &dummy_strip->actstart, &dummy_strip->actend, 1);
- dummy_strip->start = dummy_strip->actstart;
- dummy_strip->end = (IS_EQF(dummy_strip->actstart, dummy_strip->actend)) ?
- (dummy_strip->actstart + 1.0f) :
- (dummy_strip->actend);
-
- /* Always use the blend mode of the strip in tweak mode, even if not in-place. */
- if (nlt && adt->actstrip) {
- dummy_strip->blendmode = adt->actstrip->blendmode;
- dummy_strip->extendmode = NLASTRIP_EXTEND_HOLD;
- }
- else {
- dummy_strip->blendmode = adt->act_blendmode;
- dummy_strip->extendmode = adt->act_extendmode;
- }
+ if (is_action_track_evaluated_without_nla(adt, has_strips)) {
+ BLI_freelistN(&lower_estrips);
+ return;
+ }
- /* Unless extend-mode is Nothing (might be useful for flattening NLA evaluation),
- * disable range. */
- if (dummy_strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
- dummy_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP;
- }
+ /* Write r_context->eval_strip. */
+ if (adt->flag & ADT_NLA_EDIT_ON) {
- dummy_strip->influence = adt->act_influence;
+ NlaStrip *tweak_strip = &r_context->strip;
+ animsys_create_tweak_strip(adt, true, tweak_strip);
+ r_context->eval_strip = nlastrips_ctime_get_strip_single(
+ NULL, tweak_strip, anim_eval_context, false);
+ }
+ else {
- /* NOTE: must set this, or else the default setting overrides,
- * and this setting doesn't work. */
- dummy_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
- }
+ NlaStrip *action_strip = &r_context->strip;
+ animsys_create_action_track_strip(adt, true, action_strip);
+ r_context->eval_strip = nlastrips_ctime_get_strip_single(
+ NULL, action_strip, anim_eval_context, false);
+ }
- /* add this to our list of evaluation strips */
- if (r_context == NULL) {
- nlastrips_ctime_get_strip(
- &estrips, &dummy_trackslist, -1, anim_eval_context, flush_to_original);
- }
- /* If computing the context for keyframing, store data there instead of the list. */
- else {
- /* The extend mode here effectively controls
- * whether it is possible to key-frame beyond the ends.*/
- dummy_strip->extendmode = (is_inplace_tweak &&
- !(dummy_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) ?
- NLASTRIP_EXTEND_NOTHING :
- NLASTRIP_EXTEND_HOLD;
-
- r_context->eval_strip = nes = nlastrips_ctime_get_strip(
- NULL, &dummy_trackslist, -1, anim_eval_context, flush_to_original);
-
- /* These setting combinations require no data from strips below, so exit immediately. */
- if ((nes == NULL) ||
- (dummy_strip->blendmode == NLASTRIP_MODE_REPLACE && dummy_strip->influence == 1.0f)) {
- BLI_freelistN(&estrips);
- return true;
- }
- }
- }
- else {
- /* special case - evaluate as if there isn't any NLA data */
- BLI_freelistN(&estrips);
- return false;
- }
+ /* If NULL, then keyframing will fail. No need to do any more processing. */
+ if (!r_context->eval_strip) {
+ BLI_freelistN(&lower_estrips);
+ return;
}
- /* only continue if there are strips to evaluate */
- if (BLI_listbase_is_empty(&estrips)) {
- return true;
+ /* If tweak strip is full REPLACE, then lower strips not needed. */
+ if (r_context->strip.blendmode == NLASTRIP_MODE_REPLACE &&
+ IS_EQF(r_context->strip.influence, 1.0f)) {
+ BLI_freelistN(&lower_estrips);
+ return;
}
- /* 2. for each strip, evaluate then accumulate on top of existing channels,
- * but don't set values yet. */
- for (nes = estrips.first; nes; nes = nes->next) {
+ /* For each strip, evaluate then accumulate on top of existing channels. */
+ for (nes = lower_estrips.first; nes; nes = nes->next) {
nlastrip_evaluate(ptr,
- echannels,
+ &r_context->lower_eval_data,
NULL,
nes,
- &echannels->eval_snapshot,
+ &r_context->lower_eval_data.eval_snapshot,
anim_eval_context,
- flush_to_original);
+ false);
}
- /* 3. free temporary evaluation data that's not used elsewhere */
- BLI_freelistN(&estrips);
- return true;
+ /* Free temporary evaluation data that's not used elsewhere. */
+ BLI_freelistN(&lower_estrips);
}
/* NLA Evaluation function (mostly for use through do_animdata)
@@ -2412,7 +2579,7 @@ static void animsys_calculate_nla(PointerRNA *ptr,
nlaeval_init(&echannels);
/* evaluate the NLA stack, obtaining a set of values to flush */
- if (animsys_evaluate_nla(&echannels, ptr, adt, anim_eval_context, flush_to_original, NULL)) {
+ if (animsys_evaluate_nla_for_flush(&echannels, ptr, adt, anim_eval_context, flush_to_original)) {
/* reset any channels touched by currently inactive actions to default value */
animsys_evaluate_nla_domain(ptr, &echannels, adt);
@@ -2448,8 +2615,7 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
struct ListBase *cache,
struct PointerRNA *ptr,
struct AnimData *adt,
- const AnimationEvalContext *anim_eval_context,
- const bool flush_to_original)
+ const AnimationEvalContext *anim_eval_context)
{
/* No remapping needed if NLA is off or no action. */
if ((adt == NULL) || (adt->action == NULL) || (adt->nla_tracks.first == NULL) ||
@@ -2472,8 +2638,7 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
ctx->adt = adt;
nlaeval_init(&ctx->lower_eval_data);
- animsys_evaluate_nla(
- &ctx->lower_eval_data, ptr, adt, anim_eval_context, flush_to_original, ctx);
+ animsys_evaluate_nla_for_keyframing(ptr, adt, anim_eval_context, ctx);
BLI_assert(ELEM(ctx->strip.act, NULL, adt->action));
BLI_addtail(cache, ctx);