diff options
author | Wayde Moss <wbmoss_dev@yahoo.com> | 2021-03-09 03:44:20 +0300 |
---|---|---|
committer | Wayde Moss <wbmoss_dev@yahoo.com> | 2021-03-09 03:44:36 +0300 |
commit | 6a3ae75656a4247d39050c54ce5a6edf4f67d29f (patch) | |
tree | e5df116f2ec84e07cb563059c17fa3b8439e9569 /source | |
parent | d25ab68cf4b28c01281dd689a3926887fa7d32a4 (diff) |
manual patchtemp_D10504-2_nla_keyframe_remap_upper_strips
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_animsys.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/anim_sys.c | 874 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/nla.c | 7 | ||||
-rw-r--r-- | source/blender/blenkernel/nla_private.h | 63 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframing.c | 17 | ||||
-rw-r--r-- | source/blender/editors/space_nla/nla_edit.c | 15 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_anim_types.h | 2 |
7 files changed, 841 insertions, 140 deletions
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 8666291cec8..84f644a810a 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -219,7 +219,8 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, float *values, int count, int index, - bool *r_force_all); + bool *r_force_all, + const struct AnimationEvalContext *anim_eval_context); void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache); /* ************************************* */ diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 9a890fd02be..685fe0b7ac6 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -1040,6 +1040,7 @@ static NlaEvalChannelSnapshot *nlaevalchan_snapshot_new(NlaEvalChannel *nec) nec_snapshot->channel = nec; nec_snapshot->length = length; nlavalidmask_init(&nec_snapshot->blend_domain, length); + nlavalidmask_init(&nec_snapshot->remap_domain, length); return nec_snapshot; } @@ -1050,6 +1051,7 @@ static void nlaevalchan_snapshot_free(NlaEvalChannelSnapshot *nec_snapshot) BLI_assert(!nec_snapshot->is_base); nlavalidmask_free(&nec_snapshot->blend_domain); + nlavalidmask_free(&nec_snapshot->remap_domain); MEM_freeN(nec_snapshot); } @@ -1428,6 +1430,141 @@ static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, NlaEvalData *nlaeval, /* ---------------------- */ +/** \returns true if solution exists and output written to. */ +static bool nla_blend_get_inverted_lower_value(const int blendmode, + const float strip_value, + const float blended_value, + const float influence, + float *r_lower_value) +{ + if (IS_EQF(influence, 0.0f)) { + *r_lower_value = blended_value; + return true; + } + + switch (blendmode) { + case NLASTRIP_MODE_ADD: + /* Simply subtract the scaled value on to the stack. */ + *r_lower_value = blended_value - (strip_value * influence); + return true; + + case NLASTRIP_MODE_SUBTRACT: + /* Simply add the scaled value from the stack. */ + *r_lower_value = blended_value + (strip_value * influence); + return true; + + case NLASTRIP_MODE_MULTIPLY: + + /** Division by zero. */ + if (IS_EQF(-strip_value * influence, 1.0f - influence)) { + /** Resolve 0/0 to 1. */ + if (IS_EQF(blended_value, 0.0f)) { + *r_lower_value = 1; + return true; + } + /** Division by zero. */ + return false; + } + /* Math: + * blended_value = inf * (lower_value * strip_value) + (1 - inf) * lower_value + * = lower_value * (inf * strip_value + (1-inf)) + * lower_value = blended_value / (inf * strip_value + (1-inf)) + */ + *r_lower_value = blended_value / (influence * strip_value + (1.0f - influence)); + return true; + + case NLASTRIP_MODE_COMBINE: + BLI_assert(!"combine mode"); + return false; + + default: + + /** No solution if lower strip has 0 influence. */ + if (IS_EQF(influence, 1.0f)) { + return false; + } + + /** Math: + * + * blended_value = lower_value * (1.0f - inf) + (strip_value * inf) + * blended_value - (strip_value * inf) = lower_value * (1.0f - inf) + * blended_value - (strip_value * inf) / (1.0f - inf) = lower_value + * + * lower_value = blended_value - (strip_value * inf) / (1.0f - inf) + */ + *r_lower_value = (blended_value - (strip_value * influence)) / (1.0f - influence); + return true; + } +} + +/** \returns true if solution exists and output written to. */ +static bool nla_combine_get_inverted_lower_value(const int mix_mode, + float base_value, + const float strip_value, + const float blended_value, + const float influence, + float *r_lower_value) +{ + if (IS_EQF(influence, 0.0f)) { + *r_lower_value = blended_value; + return true; + } + + /* Perform blending. */ + switch (mix_mode) { + case NEC_MIX_ADD: + case NEC_MIX_AXIS_ANGLE: + *r_lower_value = blended_value - (strip_value - base_value) * influence; + return true; + case NEC_MIX_MULTIPLY: + /** Division by zero. */ + if (IS_EQF(strip_value, 0.0f)) { + /** Resolve 0/0 to 1. */ + if (IS_EQF(blended_value, 0.0f)) { + *r_lower_value = 1.0f; + return true; + } + return false; + } + + if (IS_EQF(base_value, 0.0f)) { + base_value = 1.0f; + } + + *r_lower_value = blended_value / powf(strip_value / base_value, influence); + return true; + + default: + BLI_assert(!"invalid mix mode"); + return false; + } +} + +static void nla_combine_quaternion_get_inverted_lower_values(const float strip_values[4], + const float blended_values[4], + const float influence, + float r_lower_value[4]) +{ + if (IS_EQF(influence, 0.0f)) { + normalize_qt_qt(r_lower_value, blended_values); + return; + } + + /* blended_value = lower_values @ strip_values^infl + * blended_value @ inv(strip_values^inf) = lower_values + * + * Returns: lower_values = blended_value @ inv(strip_values^inf) */ + float tmp_strip_values[4], tmp_blended[4]; + + normalize_qt_qt(tmp_strip_values, strip_values); + normalize_qt_qt(tmp_blended, blended_values); + + pow_qt_fl_normalized(tmp_strip_values, influence); + invert_qt_normalized(tmp_strip_values); + + mul_qt_qtqt(r_lower_value, tmp_blended, tmp_strip_values); +} + /* Blend the lower nla stack value and upper strip value of a channel according to mode and * influence. */ static float nla_blend_value(const int blendmode, @@ -1762,7 +1899,8 @@ static void nlasnapshot_from_action(PointerRNA *ptr, } /* evaluate action-clip strip */ -static void nlastrip_evaluate_actionclip(PointerRNA *ptr, +static void nlastrip_evaluate_actionclip(const int evaluation_mode, + PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, @@ -1786,22 +1924,49 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr, /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); - NlaEvalSnapshot strip_snapshot; - nlaeval_snapshot_init(&strip_snapshot, channels, NULL); + switch (evaluation_mode) { + case STRIP_EVAL_BLEND: { + + NlaEvalSnapshot strip_snapshot; + nlaeval_snapshot_init(&strip_snapshot, channels, NULL); + + nlasnapshot_from_action( + ptr, channels, &tmp_modifiers, strip->act, strip->strip_time, &strip_snapshot); + nlasnapshot_blend( + channels, snapshot, &strip_snapshot, strip->blendmode, strip->influence, snapshot); + + nlaeval_snapshot_free_data(&strip_snapshot); + + break; + } + case STRIP_EVAL_BLEND_GET_INVERTED_LOWER_SNAPSHOT: { + + NlaEvalSnapshot strip_snapshot; + nlaeval_snapshot_init(&strip_snapshot, channels, NULL); - nlasnapshot_from_action( - ptr, channels, &tmp_modifiers, strip->act, strip->strip_time, &strip_snapshot); - nlasnapshot_blend( - channels, snapshot, &strip_snapshot, strip->blendmode, strip->influence, snapshot); + nlasnapshot_from_action( + ptr, channels, &tmp_modifiers, strip->act, strip->strip_time, &strip_snapshot); + nlasnapshot_blend_get_inverted_lower_snapshot( + channels, snapshot, &strip_snapshot, strip->blendmode, strip->influence, snapshot); - nlaeval_snapshot_free_data(&strip_snapshot); + nlaeval_snapshot_free_data(&strip_snapshot); + + break; + } + case STRIP_EVAL_NOBLEND: { + nlasnapshot_from_action( + ptr, channels, &tmp_modifiers, strip->act, strip->strip_time, snapshot); + break; + } + } /* unlink this strip's modifiers from the parent's modifiers again */ nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers); } /* evaluate transition strip */ -static void nlastrip_evaluate_transition(PointerRNA *ptr, +static void nlastrip_evaluate_transition(const int evaluation_mode, + PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, @@ -1833,49 +1998,128 @@ static void nlastrip_evaluate_transition(PointerRNA *ptr, s2 = nes->strip->next; } - /* prepare template for 'evaluation strip' - * - based on the transition strip's evaluation strip data - * - strip_mode is NES_TIME_TRANSITION_* based on which endpoint - * - strip_time is the 'normalized' (i.e. in-strip) time for evaluation, - * which doubles up as an additional weighting factor for the strip influences - * which allows us to appear to be 'interpolating' between the two extremes - */ - tmp_nes = *nes; - - /* evaluate these strips into a temp-buffer (tmp_channels) */ - /* FIXME: modifier evaluation here needs some work... */ - /* first strip */ - tmp_nes.strip_mode = NES_TIME_TRANSITION_START; - tmp_nes.strip = s1; - tmp_nes.strip_time = s1->strip_time; - nlaeval_snapshot_init(&snapshot1, channels, snapshot); - nlastrip_evaluate( - ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot1, anim_eval_context, flush_to_original); + switch (evaluation_mode) { + case STRIP_EVAL_BLEND: { - /* second strip */ - tmp_nes.strip_mode = NES_TIME_TRANSITION_END; - tmp_nes.strip = s2; - tmp_nes.strip_time = s2->strip_time; - nlaeval_snapshot_init(&snapshot2, channels, snapshot); - nlastrip_evaluate( - ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot2, anim_eval_context, flush_to_original); + /* prepare template for 'evaluation strip' + * - based on the transition strip's evaluation strip data + * - strip_mode is NES_TIME_TRANSITION_* based on which endpoint + * - strip_time is the 'normalized' (i.e. in-strip) time for evaluation, + * which doubles up as an additional weighting factor for the strip influences + * which allows us to appear to be 'interpolating' between the two extremes + */ + tmp_nes = *nes; + + /* evaluate these strips into a temp-buffer (tmp_channels) */ + /* FIXME: modifier evaluation here needs some work... */ + /* first strip */ + tmp_nes.strip_mode = NES_TIME_TRANSITION_START; + tmp_nes.strip = s1; + tmp_nes.strip_time = s1->strip_time; + nlaeval_snapshot_init(&snapshot1, channels, snapshot); + nlasnapshot_blend_strip(ptr, + channels, + &tmp_modifiers, + &tmp_nes, + &snapshot1, + anim_eval_context, + flush_to_original); + + /* second strip */ + tmp_nes.strip_mode = NES_TIME_TRANSITION_END; + tmp_nes.strip = s2; + tmp_nes.strip_time = s2->strip_time; + nlaeval_snapshot_init(&snapshot2, channels, snapshot); + nlasnapshot_blend_strip(ptr, + channels, + &tmp_modifiers, + &tmp_nes, + &snapshot2, + anim_eval_context, + flush_to_original); + + /** Replace \a snapshot2 NULL channels with base or default values so all channels blend. */ + nlasnapshot_ensure_channels(channels, &snapshot2); + /** Mark all \a snapshot2 channel's values to blend. */ + nlasnapshot_enable_all_blend_domain(&snapshot2); + nlasnapshot_blend( + channels, &snapshot1, &snapshot2, NLASTRIP_MODE_REPLACE, nes->strip_time, snapshot); + + nlaeval_snapshot_free_data(&snapshot1); + nlaeval_snapshot_free_data(&snapshot2); + + break; + } + case STRIP_EVAL_BLEND_GET_INVERTED_LOWER_SNAPSHOT: { + /* No support for remapping values through a transition. Mark all channel values affected by + * transition as non-remappable. */ + tmp_nes = *nes; + + /** Process first strip. */ + tmp_nes.strip_mode = NES_TIME_TRANSITION_START; + tmp_nes.strip = s1; + tmp_nes.strip_time = s1->strip_time; + nlaeval_snapshot_init(&snapshot1, channels, snapshot); + nlasnapshot_blend_strip_no_blend( + ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot1, anim_eval_context); + + /** Remove channel values affected by transition from the remap domain. */ + LISTBASE_FOREACH (NlaEvalChannel *, nec, &channels->channels) { + NlaEvalChannelSnapshot *necs = nlaeval_snapshot_get(&snapshot1, nec->index); + if (necs == NULL) { + continue; + } + NlaEvalChannelSnapshot *output_necs = nlaeval_snapshot_ensure_channel(snapshot, nec); + for (int i = 0; i < necs->length; i++) { + if (BLI_BITMAP_TEST_BOOL(necs->blend_domain.ptr, i)) { + BLI_BITMAP_DISABLE(output_necs->remap_domain.ptr, i); + } + } + } + + nlaeval_snapshot_free_data(&snapshot1); - /** Replace \a snapshot2 NULL channels with base or default values so all channels blend. */ - nlasnapshot_ensure_channels(channels, &snapshot2); - /** Mark all \a snapshot2 channel's values to blend. */ - nlasnapshot_enable_all_blend_domain(&snapshot2); - nlasnapshot_blend( - channels, &snapshot1, &snapshot2, NLASTRIP_MODE_REPLACE, nes->strip_time, snapshot); + /** Process second strip. */ + tmp_nes.strip_mode = NES_TIME_TRANSITION_END; + tmp_nes.strip = s2; + tmp_nes.strip_time = s2->strip_time; + nlaeval_snapshot_init(&snapshot2, channels, snapshot); + nlasnapshot_blend_strip_no_blend( + ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot2, anim_eval_context); + + /** Remove channel values affected by transition from the remap domain. */ + LISTBASE_FOREACH (NlaEvalChannel *, nec, &channels->channels) { + NlaEvalChannelSnapshot *necs = nlaeval_snapshot_get(&snapshot2, nec->index); + if (necs == NULL) { + continue; + } + NlaEvalChannelSnapshot *output_necs = nlaeval_snapshot_ensure_channel(snapshot, nec); + for (int i = 0; i < necs->length; i++) { + if (BLI_BITMAP_TEST_BOOL(necs->blend_domain.ptr, i)) { + BLI_BITMAP_DISABLE(output_necs->remap_domain.ptr, i); + } + } + } - nlaeval_snapshot_free_data(&snapshot1); - nlaeval_snapshot_free_data(&snapshot2); + nlaeval_snapshot_free_data(&snapshot2); + + break; + } + case STRIP_EVAL_NOBLEND: { + BLI_assert( + "This case shouldn't occur. Transitions assumed to not reference other " + "transitions. "); + break; + } + } /* unlink this strip's modifiers from the parent's modifiers again */ nlaeval_fmodifiers_split_stacks(&nes->strip->modifiers, modifiers); } /* evaluate meta-strip */ -static void nlastrip_evaluate_meta(PointerRNA *ptr, +static void nlastrip_evaluate_meta(const int evaluation_mode, + PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, @@ -1905,12 +2149,31 @@ static void nlastrip_evaluate_meta(PointerRNA *ptr, evaltime); tmp_nes = nlastrips_ctime_get_strip(NULL, &strip->strips, -1, &child_context, flush_to_original); + /* Assert currently supported modes. If new mode added, then assertion marks potentially missed + * area. + * + * Note: In the future if support is ever added to metastrips to support nested tracks, then + * STRIP_EVAL_BLEND and STRIP_EVAL_BLEND_GET_INVERTED_LOWER_SNAPSHOT cases are no longer + * equivalent. The output of nlastrips_ctime_get_strip() may return a list of strips. The only + * case difference should be the evaluation order. + */ + BLI_assert(ELEM(evaluation_mode, + STRIP_EVAL_BLEND, + STRIP_EVAL_BLEND_GET_INVERTED_LOWER_SNAPSHOT, + STRIP_EVAL_NOBLEND)); + /* directly evaluate child strip into accumulation buffer... * - there's no need to use a temporary buffer (as it causes issues [T40082]) */ if (tmp_nes) { - nlastrip_evaluate( - ptr, channels, &tmp_modifiers, tmp_nes, snapshot, &child_context, flush_to_original); + nlastrip_evaluate(evaluation_mode, + ptr, + channels, + &tmp_modifiers, + tmp_nes, + snapshot, + &child_context, + flush_to_original); /* free temp eval-strip */ MEM_freeN(tmp_nes); @@ -1921,7 +2184,8 @@ static void nlastrip_evaluate_meta(PointerRNA *ptr, } /* evaluates the given evaluation strip */ -void nlastrip_evaluate(PointerRNA *ptr, +void nlastrip_evaluate(const int evaluation_mode, + PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, @@ -1946,15 +2210,27 @@ void nlastrip_evaluate(PointerRNA *ptr, /* actions to take depend on the type of strip */ switch (strip->type) { case NLASTRIP_TYPE_CLIP: /* action-clip */ - nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes, snapshot); + nlastrip_evaluate_actionclip(evaluation_mode, ptr, channels, modifiers, nes, snapshot); break; case NLASTRIP_TYPE_TRANSITION: /* transition */ - nlastrip_evaluate_transition( - ptr, channels, modifiers, nes, snapshot, anim_eval_context, flush_to_original); + nlastrip_evaluate_transition(evaluation_mode, + ptr, + channels, + modifiers, + nes, + snapshot, + anim_eval_context, + flush_to_original); break; case NLASTRIP_TYPE_META: /* meta */ - nlastrip_evaluate_meta( - ptr, channels, modifiers, nes, snapshot, anim_eval_context, flush_to_original); + nlastrip_evaluate_meta(evaluation_mode, + ptr, + channels, + modifiers, + nes, + snapshot, + anim_eval_context, + flush_to_original); break; default: /* do nothing */ @@ -1965,6 +2241,53 @@ void nlastrip_evaluate(PointerRNA *ptr, strip->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED; } +void nlasnapshot_blend_strip(PointerRNA *ptr, + NlaEvalData *channels, + ListBase *modifiers, + NlaEvalStrip *nes, + NlaEvalSnapshot *snapshot, + const struct AnimationEvalContext *anim_eval_context, + const bool flush_to_original) +{ + nlastrip_evaluate(STRIP_EVAL_BLEND, + ptr, + channels, + modifiers, + nes, + snapshot, + anim_eval_context, + flush_to_original); +} + +void nlasnapshot_blend_strip_get_inverted_lower_snapshot( + PointerRNA *ptr, + NlaEvalData *channels, + ListBase *modifiers, + NlaEvalStrip *nes, + NlaEvalSnapshot *snapshot, + const struct AnimationEvalContext *anim_eval_context) +{ + nlastrip_evaluate(STRIP_EVAL_BLEND_GET_INVERTED_LOWER_SNAPSHOT, + ptr, + channels, + modifiers, + nes, + snapshot, + anim_eval_context, + false); +} + +void nlasnapshot_blend_strip_no_blend(PointerRNA *ptr, + NlaEvalData *channels, + ListBase *modifiers, + NlaEvalStrip *nes, + NlaEvalSnapshot *snapshot, + const struct AnimationEvalContext *anim_eval_context) +{ + nlastrip_evaluate( + STRIP_EVAL_NOBLEND, ptr, channels, modifiers, nes, snapshot, anim_eval_context, false); +} + /* write the accumulated settings to */ void nladata_flush_channels(PointerRNA *ptr, NlaEvalData *channels, @@ -2065,8 +2388,14 @@ static void animsys_evaluate_nla_domain(PointerRNA *ptr, NlaEvalData *channels, { GSet *touched_actions = BLI_gset_ptr_new(__func__); - if (adt->action) { - nla_eval_domain_action(ptr, channels, adt->action, touched_actions); + /** Include domain of Action Track. */ + if ((adt->flag & ADT_NLA_EDIT_ON) == 0) { + if (adt->action) { + nla_eval_domain_action(ptr, channels, adt->action, touched_actions); + } + } + else if (adt->tmpact && (adt->flag & ADT_NLA_EVAL_UPPER_TRACKS)) { + nla_eval_domain_action(ptr, channels, adt->tmpact, touched_actions); } /* NLA Data - Animation Data for Strips */ @@ -2173,7 +2502,8 @@ static void animsys_create_action_track_strip(const AnimData *adt, 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; + const bool eval_upper = !tweaking || (adt->flag & ADT_NLA_EVAL_UPPER_TRACKS) != 0; + const bool actionstrip_evaluated = r_action_strip->act && !soloing && eval_upper; if (!actionstrip_evaluated) { r_action_strip->flag |= NLASTRIP_FLAG_MUTED; } @@ -2316,13 +2646,13 @@ static bool animsys_evaluate_nla_for_flush(NlaEvalData *echannels, /* 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); + nlasnapshot_blend_strip(ptr, + echannels, + NULL, + nes, + &echannels->eval_snapshot, + anim_eval_context, + flush_to_original); } /* Free temporary evaluation data that's not used elsewhere. */ @@ -2353,6 +2683,7 @@ static void animsys_evaluate_nla_for_keyframing(PointerRNA *ptr, short track_index = 0; bool has_strips = false; + ListBase *upper_estrips = &r_context->upper_estrips; ListBase lower_estrips = {NULL, NULL}; NlaEvalStrip *nes; @@ -2382,6 +2713,30 @@ static void animsys_evaluate_nla_for_keyframing(PointerRNA *ptr, } } + /* Get the upper stack of strips to evaluate at current time (influence calculated here). */ + /* Var nlt exists only if tweak strip exists. */ + if (nlt) { + + /* Skip tweaked strip. */ + nlt = nlt->next; + track_index++; + + for (; nlt; nlt = nlt->next, track_index++) { + + if (!is_nlatrack_evaluatable(adt, nlt)) { + continue; + } + + if (nlt->strips.first) { + has_strips = true; + } + + /* Get strip to evaluate for this channel. */ + nes = nlastrips_ctime_get_strip( + upper_estrips, &nlt->strips, track_index, anim_eval_context, false); + } + } + /** 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. @@ -2393,6 +2748,10 @@ static void animsys_evaluate_nla_for_keyframing(PointerRNA *ptr, /* Write r_context->eval_strip. */ if (adt->flag & ADT_NLA_EDIT_ON) { + /* Append action_track_strip to upper estrips. */ + NlaStrip *action_strip = &r_context->action_track_strip; + animsys_create_action_track_strip(adt, false, action_strip); + nlastrips_ctime_get_strip_single(upper_estrips, action_strip, anim_eval_context, false); NlaStrip *tweak_strip = &r_context->strip; animsys_create_tweak_strip(adt, true, tweak_strip); @@ -2422,13 +2781,13 @@ static void animsys_evaluate_nla_for_keyframing(PointerRNA *ptr, /* For each strip, evaluate then accumulate on top of existing channels. */ for (nes = lower_estrips.first; nes; nes = nes->next) { - nlastrip_evaluate(ptr, - &r_context->lower_eval_data, - NULL, - nes, - &r_context->lower_eval_data.eval_snapshot, - anim_eval_context, - false); + nlasnapshot_blend_strip(ptr, + &r_context->lower_eval_data, + NULL, + nes, + &r_context->lower_eval_data.eval_snapshot, + anim_eval_context, + false); } /* Free temporary evaluation data that's not used elsewhere. */ @@ -2484,6 +2843,18 @@ void nlasnapshot_enable_all_blend_domain(NlaEvalSnapshot *snapshot) } } +void nlasnapshot_enable_all_remap_domain(NlaEvalSnapshot *snapshot) +{ + for (int i = 0; i < snapshot->size; i++) { + NlaEvalChannelSnapshot *necs = nlaeval_snapshot_get(snapshot, i); + if (necs == NULL) { + continue; + } + + BLI_bitmap_set_all(necs->remap_domain.ptr, true, necs->length); + } +} + void nlasnapshot_ensure_channels(NlaEvalData *eval_data, NlaEvalSnapshot *snapshot) { LISTBASE_FOREACH (NlaEvalChannel *, nec, &eval_data->channels) { @@ -2544,6 +2915,8 @@ void nlasnapshot_blend(NlaEvalData *eval_data, lower_necs->values, upper_necs->values, upper_influence, result_necs->values); } else { + BLI_assert(ELEM(mix_mode, NEC_MIX_ADD, NEC_MIX_AXIS_ANGLE, NEC_MIX_MULTIPLY)); + for (int j = 0; j < length; j++) { if (!BLI_BITMAP_TEST_BOOL(upper_necs->blend_domain.ptr, j)) { continue; @@ -2558,6 +2931,12 @@ void nlasnapshot_blend(NlaEvalData *eval_data, } } else { + BLI_assert(ELEM(upper_blendmode, + NLASTRIP_MODE_ADD, + NLASTRIP_MODE_SUBTRACT, + NLASTRIP_MODE_MULTIPLY, + NLASTRIP_MODE_REPLACE)); + for (int j = 0; j < length; j++) { if (!BLI_BITMAP_TEST_BOOL(upper_necs->blend_domain.ptr, j)) { continue; @@ -2570,6 +2949,231 @@ void nlasnapshot_blend(NlaEvalData *eval_data, } } +/** Using \a blended_snapshot and \a lower_snapshot, we can solve for the \a r_upper_snapshot. + * + * Only channels that exist within \a blended_snapshot are inverted. + * + * For \a r_upper_snapshot, disables \a NlaEvalChannelSnapshot->remap_domain for failed inversions. + * Only values within the \a remap_domain are processed. + */ +void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data, + NlaEvalSnapshot *lower_snapshot, + NlaEvalSnapshot *blended_snapshot, + const short upper_blendmode, + const float upper_influence, + NlaEvalSnapshot *r_upper_snapshot) +{ + nlaeval_snapshot_ensure_size(r_upper_snapshot, eval_data->num_channels); + + LISTBASE_FOREACH (NlaEvalChannel *, nec, &eval_data->channels) { + const int length = nec->base_snapshot.length; + + NlaEvalChannelSnapshot *blended_necs = nlaeval_snapshot_get(blended_snapshot, nec->index); + if (blended_necs == NULL) { + /** We assume the caller only wants a subset of channels to be inverted, those that exist + * within \a blended_snapshot. */ + continue; + } + + NlaEvalChannelSnapshot *lower_necs = nlaeval_snapshot_get(lower_snapshot, nec->index); + if (lower_necs == NULL) { + lower_necs = nlaeval_snapshot_find_channel(lower_snapshot->base, nec); + } + + NlaEvalChannelSnapshot *result_necs = nlaeval_snapshot_ensure_channel(r_upper_snapshot, nec); + if (upper_blendmode == NLASTRIP_MODE_COMBINE) { + const int mix_mode = nec->mix_mode; + + if (mix_mode == NEC_MIX_QUATERNION) { + if (!BLI_BITMAP_TEST_BOOL(blended_necs->remap_domain.ptr, 0)) { + BLI_bitmap_set_all(result_necs->remap_domain.ptr, false, 4); + continue; + } + + const bool success = nla_combine_quaternion_get_inverted_strip_values( + lower_necs->values, blended_necs->values, upper_influence, result_necs->values); + BLI_bitmap_set_all(result_necs->remap_domain.ptr, success, 4); + } + else { + BLI_assert(ELEM(mix_mode, NEC_MIX_ADD, NEC_MIX_AXIS_ANGLE, NEC_MIX_MULTIPLY)); + + for (int j = 0; j < length; j++) { + if (!BLI_BITMAP_TEST_BOOL(blended_necs->remap_domain.ptr, j)) { + BLI_BITMAP_DISABLE(result_necs->remap_domain.ptr, j); + continue; + } + + const bool success = nla_combine_get_inverted_strip_value(mix_mode, + nec->base_snapshot.values[j], + lower_necs->values[j], + blended_necs->values[j], + upper_influence, + &result_necs->values[j]); + BLI_BITMAP_SET(result_necs->remap_domain.ptr, j, success); + } + } + } + else { + BLI_assert(ELEM(upper_blendmode, + NLASTRIP_MODE_ADD, + NLASTRIP_MODE_SUBTRACT, + NLASTRIP_MODE_MULTIPLY, + NLASTRIP_MODE_REPLACE)); + + for (int j = 0; j < length; j++) { + if (!BLI_BITMAP_TEST_BOOL(blended_necs->remap_domain.ptr, j)) { + BLI_BITMAP_DISABLE(result_necs->remap_domain.ptr, j); + continue; + } + + const bool success = nla_blend_get_inverted_strip_value(upper_blendmode, + lower_necs->values[j], + blended_necs->values[j], + upper_influence, + &result_necs->values[j]); + BLI_BITMAP_SET(result_necs->remap_domain.ptr, j, success); + } + } + } +} + +/** Using \a blended_snapshot and \a upper_snapshot, we can solve for the \a r_lower_snapshot. + * + * Only channels that exist within \a blended_snapshot are processed. + * Only blended values within the \a remap_domain are processed. + * + * Writes to \a r_upper_snapshot NlaEvalChannelSnapshot->remap_domain to match remapping success. + * + * Assumes caller marked upper values that are in the \a blend_domain. This determines whether the + * blended value came directly from the lower snapshot or a result of blending. + **/ +void nlasnapshot_blend_get_inverted_lower_snapshot(NlaEvalData *eval_data, + NlaEvalSnapshot *blended_snapshot, + NlaEvalSnapshot *upper_snapshot, + const short upper_blendmode, + const float upper_influence, + NlaEvalSnapshot *r_lower_snapshot) +{ + nlaeval_snapshot_ensure_size(r_lower_snapshot, eval_data->num_channels); + + const bool zero_upper_influence = IS_EQF(upper_influence, 0.0f); + + LISTBASE_FOREACH (NlaEvalChannel *, nec, &eval_data->channels) { + const int length = nec->base_snapshot.length; + + NlaEvalChannelSnapshot *blended_necs = nlaeval_snapshot_get(blended_snapshot, nec->index); + if (blended_necs == NULL) { + /** We assume the caller only wants a subset of channels to be inverted, those that exist + * within \a blended_snapshot. */ + continue; + } + + NlaEvalChannelSnapshot *result_necs = nlaeval_snapshot_ensure_channel(r_lower_snapshot, nec); + + NlaEvalChannelSnapshot *upper_necs = nlaeval_snapshot_get(upper_snapshot, nec->index); + if (upper_necs == NULL || zero_upper_influence) { + for (int j = 0; j < length; j++) { + result_necs->values[j] = blended_necs->values[j]; + + const bool in_remap_domain = BLI_BITMAP_TEST_BOOL(blended_necs->remap_domain.ptr, j); + BLI_BITMAP_SET(result_necs->remap_domain.ptr, j, in_remap_domain); + } + continue; + } + + if (upper_blendmode == NLASTRIP_MODE_COMBINE) { + const int mix_mode = nec->mix_mode; + + if (mix_mode == NEC_MIX_QUATERNION) { + if (!BLI_BITMAP_TEST_BOOL(blended_necs->remap_domain.ptr, 0)) { + BLI_bitmap_set_all(result_necs->remap_domain.ptr, false, 4); + continue; + } + + /* If blended values are not a result of blending the lower snapshot with the upper + * snapshot, then they should be equal. + * + * Just directly copy blended_necs to result_necs. + */ + if (!BLI_BITMAP_TEST_BOOL(upper_necs->blend_domain.ptr, 0)) { + memcpy(result_necs->values, blended_necs->values, 4 * sizeof(float)); + BLI_bitmap_set_all(result_necs->remap_domain.ptr, true, 4); + continue; + } + + nla_combine_quaternion_get_inverted_lower_values( + upper_necs->values, blended_necs->values, upper_influence, result_necs->values); + + BLI_bitmap_set_all(result_necs->remap_domain.ptr, true, 4); + continue; + } + else { + BLI_assert(ELEM(mix_mode, NEC_MIX_ADD, NEC_MIX_AXIS_ANGLE, NEC_MIX_MULTIPLY)); + + for (int j = 0; j < length; j++) { + if (!BLI_BITMAP_TEST_BOOL(blended_necs->remap_domain.ptr, j)) { + BLI_BITMAP_DISABLE(result_necs->remap_domain.ptr, j); + continue; + } + + /* If blended values are not a result of blending the lower snapshot with the upper + * snapshot, then they should be equal. + * + * Just directly copy blended_necs to result_necs. + */ + if (!BLI_BITMAP_TEST_BOOL(upper_necs->blend_domain.ptr, j)) { + result_necs->values[j] = blended_necs->values[j]; + BLI_BITMAP_ENABLE(result_necs->remap_domain.ptr, j); + continue; + } + + const bool success = nla_combine_get_inverted_lower_value(mix_mode, + nec->base_snapshot.values[j], + upper_necs->values[j], + blended_necs->values[j], + upper_influence, + &result_necs->values[j]); + + BLI_BITMAP_SET(result_necs->remap_domain.ptr, j, success); + } + } + } + else { + BLI_assert(ELEM(upper_blendmode, + NLASTRIP_MODE_ADD, + NLASTRIP_MODE_SUBTRACT, + NLASTRIP_MODE_MULTIPLY, + NLASTRIP_MODE_REPLACE)); + + for (int j = 0; j < length; j++) { + if (!BLI_BITMAP_TEST_BOOL(blended_necs->remap_domain.ptr, j)) { + BLI_BITMAP_DISABLE(result_necs->remap_domain.ptr, j); + continue; + } + + /* If blended values are not a result of blending the lower snapshot with the upper + * snapshot, then they should be equal. + * + * Just directly copy blended_necs to result_necs. + */ + if (!BLI_BITMAP_TEST_BOOL(upper_necs->blend_domain.ptr, j)) { + result_necs->values[j] = blended_necs->values[j]; + BLI_BITMAP_ENABLE(result_necs->remap_domain.ptr, j); + continue; + } + + const bool success = nla_blend_get_inverted_lower_value(upper_blendmode, + upper_necs->values[j], + blended_necs->values[j], + upper_influence, + &result_necs->values[j]); + + BLI_BITMAP_SET(result_necs->remap_domain.ptr, j, success); + } + } + } +} + /* ---------------------- */ /** @@ -2593,9 +3197,11 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context( return NULL; } - /* No remapping if editing an ordinary Replace action with full influence. */ + /* No remapping if editing an ordinary Replace action with full influence and upper tracks not + * evaluated. */ if (!(adt->flag & ADT_NLA_EDIT_ON) && - (adt->act_blendmode == NLASTRIP_MODE_REPLACE && adt->act_influence == 1.0f)) { + (adt->act_blendmode == NLASTRIP_MODE_REPLACE && adt->act_influence == 1.0f) && + (adt->flag & ADT_NLA_EVAL_UPPER_TRACKS) == 0) { return NULL; } @@ -2635,7 +3241,8 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, float *values, int count, int index, - bool *r_force_all) + bool *r_force_all, + const struct AnimationEvalContext *anim_eval_context) { if (r_force_all != NULL) { *r_force_all = false; @@ -2651,11 +3258,13 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, return false; } - /* Full influence Replace strips also require no correction. */ + /* Full influence Replace strips also require no correction if there are no upper tracks + * evaluating. */ int blend_mode = context->strip.blendmode; float influence = context->strip.influence; - if (blend_mode == NLASTRIP_MODE_REPLACE && influence == 1.0f) { + if (blend_mode == NLASTRIP_MODE_REPLACE && influence == 1.0f && + BLI_listbase_is_empty(&context->upper_estrips)) { return true; } @@ -2664,74 +3273,78 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, return false; } - /* Find the evaluation channel for the NLA stack below current strip. */ - NlaEvalChannelKey key = { - .ptr = *prop_ptr, - .prop = prop, - }; - /** - * Remove lower NLA stack effects. - * - * Using the tweak strip's blended result and the lower snapshot value, we can solve for the - * tweak strip value it must evaluate to. - */ - NlaEvalData *const lower_eval_data = &context->lower_eval_data; - NlaEvalChannel *const lower_nec = nlaevalchan_verify_key(lower_eval_data, NULL, &key); + /** Create \a blended_snapshot and fill with input \a values. */ + NlaEvalData *eval_data = &context->lower_eval_data; + NlaEvalSnapshot blended_snapshot; + nlaeval_snapshot_init(&blended_snapshot, eval_data, NULL); + NlaEvalChannelSnapshot *blended_necs; + { + NlaEvalChannelKey key = { + .ptr = *prop_ptr, + .prop = prop, + }; + + NlaEvalChannel *nec = nlaevalchan_verify_key(eval_data, NULL, &key); + BLI_assert(nec); + if (nec->base_snapshot.length != count) { + BLI_assert(!"invalid value count"); + nlaeval_snapshot_free_data(&blended_snapshot); + return false; + } - if ((lower_nec->base_snapshot.length != count)) { - BLI_assert(!"invalid value count"); - return false; + blended_necs = nlaeval_snapshot_ensure_channel(&blended_snapshot, nec); + memcpy(blended_necs->values, values, sizeof(float) * count); + BLI_bitmap_set_all(blended_necs->remap_domain.ptr, true, count); } - /* Invert the blending operation to compute the desired strip values. */ - NlaEvalChannelSnapshot *const lower_nec_snapshot = nlaeval_snapshot_find_channel( - &lower_eval_data->eval_snapshot, lower_nec); - - float *lower_values = lower_nec_snapshot->values; - - if (blend_mode == NLASTRIP_MODE_COMBINE) { - /* Quaternion combine handles all sub-channels as a unit. */ - if (lower_nec->mix_mode == NEC_MIX_QUATERNION) { - if (r_force_all == NULL) { - return false; - } - + /** Need to send id_ptr instead of prop_ptr so fcurve RNA paths resolve properly. */ + PointerRNA id_ptr; + RNA_id_pointer_create(prop_ptr->owner_id, &id_ptr); + + /** Per iteration, remove effect of upper strip which gives output of nla stack below it. */ + LISTBASE_FOREACH_BACKWARD (NlaEvalStrip *, nes, &context->upper_estrips) { + /** This will disable blended_necs->remap_domain bits if an upper strip is not invertible + * (full replace, multiply zero, or transition). Then there is no remap solution. */ + nlasnapshot_blend_strip_get_inverted_lower_snapshot( + &id_ptr, eval_data, NULL, nes, &blended_snapshot, anim_eval_context); + } + + /** Remove lower NLA stack effects. */ + nlasnapshot_blend_get_inverted_upper_snapshot(eval_data, + &context->lower_eval_data.eval_snapshot, + &blended_snapshot, + blend_mode, + influence, + &blended_snapshot); + + /** Write results into \a values. */ + bool successful_remap = true; + if (blended_necs->channel->mix_mode == NEC_MIX_QUATERNION && + blend_mode == NLASTRIP_MODE_COMBINE) { + + if (r_force_all != NULL) { *r_force_all = true; - - if (!nla_combine_quaternion_get_inverted_strip_values( - lower_values, values, influence, values)) { - return false; - } + index = -1; } else { - float *base_values = lower_nec->base_snapshot.values; - - for (int i = 0; i < count; i++) { - if (ELEM(index, i, -1)) { - if (!nla_combine_get_inverted_strip_value(lower_nec->mix_mode, - base_values[i], - lower_values[i], - values[i], - influence, - &values[i])) { - return false; - } - } - } + successful_remap = false; } } - else { - for (int i = 0; i < count; i++) { - if (ELEM(index, i, -1)) { - if (!nla_blend_get_inverted_strip_value( - blend_mode, lower_values[i], values[i], influence, &values[i])) { - return false; - } - } + + for (int i = 0; i < count; i++) { + if (!ELEM(index, i, -1)) { + continue; } + if (!BLI_BITMAP_TEST_BOOL(blended_necs->remap_domain.ptr, i)) { + successful_remap = false; + } + + values[i] = blended_necs->values[i]; } - return true; + nlaeval_snapshot_free_data(&blended_snapshot); + + return successful_remap; } /** @@ -2741,6 +3354,7 @@ void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache) { LISTBASE_FOREACH (NlaKeyframingContext *, ctx, cache) { MEM_SAFE_FREE(ctx->eval_strip); + BLI_freelistN(&ctx->upper_estrips); nlaeval_free(&ctx->lower_eval_data); } diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 63b14c30b3c..25272a13857 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -2117,8 +2117,11 @@ bool BKE_nla_tweakmode_enter(AnimData *adt) /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled * - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on */ - for (nlt = activeTrack; nlt; nlt = nlt->next) { - nlt->flag |= NLATRACK_DISABLED; + activeTrack->flag |= NLATRACK_DISABLED; + if ((adt->flag & ADT_NLA_EVAL_UPPER_TRACKS) == 0) { + for (nlt = activeTrack->next; nlt; nlt = nlt->next) { + nlt->flag |= NLATRACK_DISABLED; + } } /* handle AnimData level changes: diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h index 706bcac4f17..47a029ad948 100644 --- a/source/blender/blenkernel/nla_private.h +++ b/source/blender/blenkernel/nla_private.h @@ -82,6 +82,10 @@ typedef struct NlaEvalChannelSnapshot { /** For an upper snapshot channel, marks values that should be blended. */ NlaValidMask blend_domain; + /** Only used for keyframe remapping. Any values not in the \a remap_domain will not be used + * for keyframe remapping. */ + NlaValidMask remap_domain; + int length; /* Number of values in the property. */ bool is_base; /* Base snapshot of the channel. */ @@ -154,7 +158,11 @@ typedef struct NlaKeyframingContext { /* Data of the currently edited strip (copy, or fake strip for the main action). */ NlaStrip strip; NlaEvalStrip *eval_strip; + /** Storage for the action track as a strip. */ + NlaStrip action_track_strip; + /* Strips above tweaked strip. */ + ListBase upper_estrips; /* Evaluated NLA stack below the tweak strip. */ NlaEvalData lower_eval_data; } NlaKeyframingContext; @@ -173,13 +181,27 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, short index, const struct AnimationEvalContext *anim_eval_context, const bool flush_to_original); -void nlastrip_evaluate(PointerRNA *ptr, + +enum eNlaStripEvaluate_Mode { + /** Blend strip with lower stack. */ + STRIP_EVAL_BLEND, + /** Given upper strip, solve for lower stack. */ + STRIP_EVAL_BLEND_GET_INVERTED_LOWER_SNAPSHOT, + /** Store strip fcurve values in snapshot. + * Currently only used for transitions to distinguish fcurve sampled values from existing + * default or lower stack values. The values of interest are in the blend_domain. */ + STRIP_EVAL_NOBLEND, +}; + +void nlastrip_evaluate(const int evaluation_mode, + PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, NlaEvalSnapshot *snapshot, const struct AnimationEvalContext *anim_eval_context, const bool flush_to_original); + void nladata_flush_channels(PointerRNA *ptr, NlaEvalData *channels, NlaEvalSnapshot *snapshot, @@ -187,6 +209,8 @@ void nladata_flush_channels(PointerRNA *ptr, void nlasnapshot_enable_all_blend_domain(NlaEvalSnapshot *snapshot); +void nlasnapshot_enable_all_remap_domain(NlaEvalSnapshot *snapshot); + void nlasnapshot_ensure_channels(NlaEvalData *eval_data, NlaEvalSnapshot *snapshot); void nlasnapshot_blend(NlaEvalData *eval_data, @@ -196,6 +220,43 @@ void nlasnapshot_blend(NlaEvalData *eval_data, const float upper_influence, NlaEvalSnapshot *r_blended_snapshot); +void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data, + NlaEvalSnapshot *lower_snapshot, + NlaEvalSnapshot *blended_snapshot, + const short upper_blendmode, + const float upper_influence, + NlaEvalSnapshot *r_upper_snapshot); + +void nlasnapshot_blend_get_inverted_lower_snapshot(NlaEvalData *eval_data, + NlaEvalSnapshot *blended_snapshot, + NlaEvalSnapshot *upper_snapshot, + const short upper_blendmode, + const float upper_influence, + NlaEvalSnapshot *r_lower_snapshot); + +void nlasnapshot_blend_strip(PointerRNA *ptr, + NlaEvalData *channels, + ListBase *modifiers, + NlaEvalStrip *nes, + NlaEvalSnapshot *snapshot, + const struct AnimationEvalContext *anim_eval_context, + const bool flush_to_original); + +void nlasnapshot_blend_strip_get_inverted_lower_snapshot( + PointerRNA *ptr, + NlaEvalData *eval_data, + ListBase *modifiers, + NlaEvalStrip *nes, + NlaEvalSnapshot *snapshot, + const struct AnimationEvalContext *anim_eval_context); + +void nlasnapshot_blend_strip_no_blend(PointerRNA *ptr, + NlaEvalData *channels, + ListBase *modifiers, + NlaEvalStrip *nes, + NlaEvalSnapshot *snapshot, + const struct AnimationEvalContext *anim_eval_context); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 4cc0413be5b..10df3804cbd 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1122,7 +1122,8 @@ static float *get_keyframe_values(ReportList *reports, float *buffer, int buffer_size, int *r_count, - bool *r_force_all) + bool *r_force_all, + const struct AnimationEvalContext *anim_eval_context) { float *values; @@ -1140,9 +1141,11 @@ static float *get_keyframe_values(ReportList *reports, /* adjust the value for NLA factors */ if (!BKE_animsys_nla_remap_keyframe_values( - nla_context, &ptr, prop, values, *r_count, index, r_force_all)) { - BKE_report( - reports, RPT_ERROR, "Could not insert keyframe due to zero NLA influence or base value"); + nla_context, &ptr, prop, values, *r_count, index, r_force_all, anim_eval_context)) { + BKE_report(reports, + RPT_ERROR, + "Could not insert keyframe due to zero NLA influence, base value, or value " + "remapping failed"); if (values != buffer) { MEM_freeN(values); @@ -1306,7 +1309,8 @@ bool insert_keyframe_direct(ReportList *reports, value_buffer, RNA_MAX_ARRAY_LENGTH, &value_count, - NULL); + NULL, + anim_eval_context); if (values == NULL) { /* This happens if NLA rejects this insertion. */ @@ -1480,7 +1484,8 @@ int insert_keyframe(Main *bmain, value_buffer, RNA_MAX_ARRAY_LENGTH, &value_count, - &force_all); + &force_all, + anim_eval_context); if (values != NULL) { /* Key the entire array. */ diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index dd381cc92fb..88beb21f228 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -114,6 +114,7 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op) int filter; const bool do_solo = RNA_boolean_get(op->ptr, "isolate_action"); + const bool use_upper_stack_evaluation = RNA_boolean_get(op->ptr, "use_upper_stack_evaluation"); bool ok = false; /* get editor data */ @@ -135,6 +136,13 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op) for (ale = anim_data.first; ale; ale = ale->next) { AnimData *adt = ale->data; + if (use_upper_stack_evaluation) { + adt->flag |= ADT_NLA_EVAL_UPPER_TRACKS; + } + else { + adt->flag &= ~ADT_NLA_EVAL_UPPER_TRACKS; + } + /* try entering tweakmode if valid */ ok |= BKE_nla_tweakmode_enter(adt); @@ -198,6 +206,13 @@ void NLA_OT_tweakmode_enter(wmOperatorType *ot) "Enable 'solo' on the NLA Track containing the active strip, " "to edit it without seeing the effects of the NLA stack"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_boolean(ot->srna, + "use_upper_stack_evaluation", + false, + "Evaluate Upper Stack", + "In tweak mode, display the effects of the tracks above the tweak strip"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /** \} */ diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index dffb3588de4..52e932e88de 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -1143,6 +1143,8 @@ typedef enum eAnimData_Flag { ADT_NLA_EDIT_NOMAP = (1 << 3), /** NLA-Strip F-Curves are expanded in UI. */ ADT_NLA_SKEYS_COLLAPSED = (1 << 4), + /** Evaluate tracks above tweaked strip. Only relevant in tweak mode. */ + ADT_NLA_EVAL_UPPER_TRACKS = (1 << 5), /** Drivers expanded in UI. */ ADT_DRIVERS_COLLAPSED = (1 << 10), |