diff options
-rw-r--r-- | source/blender/blenkernel/BKE_animsys.h | 9 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/anim_sys.c | 230 | ||||
-rw-r--r-- | source/blender/blenkernel/nla_private.h | 15 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_channels_defines.c | 30 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframing.c | 31 | ||||
-rw-r--r-- | source/blender/editors/animation/keyingsets.c | 5 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_convert.c | 10 | ||||
-rw-r--r-- | source/blender/editors/include/ED_keyframing.h | 6 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_anim.c | 6 | ||||
-rw-r--r-- | source/blender/editors/space_action/action_edit.c | 6 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_edit.c | 6 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_conversions.c | 12 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna_anim.c | 4 |
13 files changed, 309 insertions, 61 deletions
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 43618109e91..f85782d9caa 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -48,6 +48,7 @@ struct Scene; struct bAction; struct bActionGroup; struct bContext; +struct NlaKeyframingContext; /* ************************************* */ /* AnimData API */ @@ -171,6 +172,14 @@ void BKE_fcurves_main_cb(struct Main *bmain, ID_FCurve_Edit_Callback func, void /* ************************************* */ // TODO: overrides, remapping, and path-finding api's +/* ------------ NLA Keyframing --------------- */ + +typedef struct NlaKeyframingContext NlaKeyframingContext; + +struct NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(struct ListBase *cache, struct Depsgraph *depsgraph, struct PointerRNA *ptr, struct AnimData *adt, float ctime); +bool BKE_animsys_nla_remap_keyframe_value(struct NlaKeyframingContext *context, struct PointerRNA *prop_ptr, struct PropertyRNA *prop, int index, float *r_value); +void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache); + /* ************************************* */ /* Evaluation API */ diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 9cdf94b3253..579509608c3 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -2120,6 +2120,8 @@ static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, ListBase *channels, F return nec; } +static float nla_blend_value(int blendmode, float old_value, float value, float inf); + /* accumulate (i.e. blend) the given value on to the channel it affects */ static void nlaevalchan_accumulate(NlaEvalChannel *nec, NlaEvalStrip *nes, float value, bool newChan) { @@ -2140,28 +2142,33 @@ static void nlaevalchan_accumulate(NlaEvalChannel *nec, NlaEvalStrip *nes, float if (nes->strip_mode == NES_TIME_TRANSITION_END) inf *= nes->strip_time; + nec->value = nla_blend_value(blendmode, nec->value, value, inf); +} + +/* accumulate the old and new values of a channel according to mode and influence */ +static float nla_blend_value(int blendmode, float old_value, float value, float inf) +{ /* optimisation: no need to try applying if there is no influence */ - if (IS_EQF(inf, 0.0f)) return; + if (IS_EQF(inf, 0.0f)) { + return old_value; + } /* perform blending */ switch (blendmode) { case NLASTRIP_MODE_ADD: /* simply add the scaled value on to the stack */ - nec->value += (value * inf); - break; + return old_value + (value * inf); case NLASTRIP_MODE_SUBTRACT: /* simply subtract the scaled value from the stack */ - nec->value -= (value * inf); - break; + return old_value - (value * inf); case NLASTRIP_MODE_MULTIPLY: /* multiply the scaled value with the stack */ /* Formula Used: * result = fac * (a * b) + (1 - fac) * a */ - nec->value = inf * (nec->value * value) + (1 - inf) * nec->value; - break; + return inf * (old_value * value) + (1 - inf) * old_value; case NLASTRIP_MODE_REPLACE: default: /* TODO: do we really want to blend by default? it seems more uses might prefer add... */ @@ -2169,8 +2176,41 @@ static void nlaevalchan_accumulate(NlaEvalChannel *nec, NlaEvalStrip *nes, float * - the influence of the accumulated data (elsewhere, that is called dstweight) * is 1 - influence, since the strip's influence is srcweight */ - nec->value = nec->value * (1.0f - inf) + (value * inf); - break; + return old_value * (1.0f - inf) + (value * inf); + } +} + +/* compute the value that would blend to the desired target value using nla_blend_value */ +static bool nla_invert_blend_value(int blend_mode, float old_value, float target_value, float influence, float *r_value) +{ + switch (blend_mode) { + case NLASTRIP_MODE_ADD: + *r_value = (target_value - old_value) / influence; + return true; + + case NLASTRIP_MODE_SUBTRACT: + *r_value = (old_value - target_value) / influence; + return true; + + case NLASTRIP_MODE_MULTIPLY: + if (old_value == 0.0f) { + /* Resolve 0/0 to 1. */ + if (target_value == 0.0f) { + *r_value = 1.0f; + return true; + } + /* Division by zero. */ + return false; + } + else { + *r_value = (target_value - old_value) / influence / old_value + 1.0f; + return true; + } + + case NLASTRIP_MODE_REPLACE: + default: + *r_value = (target_value - old_value) / influence + old_value; + return true; } } @@ -2481,11 +2521,10 @@ void nladata_flush_channels(Depsgraph *depsgraph, PointerRNA *ptr, ListBase *cha /** * NLA Evaluation function - values are calculated and stored in temporary "NlaEvalChannels" * - * \note This is exported so that keyframing code can use this for make use of it for anim layers support - * * \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. */ -static void animsys_evaluate_nla(Depsgraph *depsgraph, ListBase *echannels, PointerRNA *ptr, AnimData *adt, float ctime) +static void animsys_evaluate_nla(Depsgraph *depsgraph, ListBase *echannels, PointerRNA *ptr, AnimData *adt, float ctime, NlaKeyframingContext *r_context) { NlaTrack *nlt; short track_index = 0; @@ -2493,9 +2532,12 @@ static void animsys_evaluate_nla(Depsgraph *depsgraph, ListBase *echannels, Poin ListBase estrips = {NULL, NULL}; NlaEvalStrip *nes; + NlaStrip dummy_strip_buf; - NlaStrip dummy_strip = {NULL}; /* dummy strip for active action */ + /* dummy strip for active action */ + NlaStrip *dummy_strip = r_context ? &r_context->strip : &dummy_strip_buf; + memset(dummy_strip, 0, sizeof(*dummy_strip)); /* 1. 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++) { @@ -2538,39 +2580,69 @@ static void animsys_evaluate_nla(Depsgraph *depsgraph, ListBase *echannels, Poin /* make dummy NLA strip, and add that to the stack */ ListBase dummy_trackslist; - dummy_trackslist.first = dummy_trackslist.last = &dummy_strip; + dummy_trackslist.first = dummy_trackslist.last = dummy_strip; - if ((nlt) && !(adt->flag & ADT_NLA_EDIT_NOMAP)) { + /* 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)); - dummy_strip.next = dummy_strip.prev = NULL; + memcpy(dummy_strip, adt->actstrip, sizeof(NlaStrip)); + dummy_strip->next = dummy_strip->prev = NULL; } else { /* set settings of dummy NLA strip from AnimData settings */ - dummy_strip.act = adt->action; + 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); + 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 = adt->actstrip->extendmode; + } + else { + dummy_strip->blendmode = adt->act_blendmode; + dummy_strip->extendmode = adt->act_extendmode; + } - dummy_strip.blendmode = adt->act_blendmode; - dummy_strip.extendmode = adt->act_extendmode; - dummy_strip.influence = adt->act_influence; + dummy_strip->influence = adt->act_influence; /* NOTE: must set this, or else the default setting overrides, and this setting doesn't work */ - dummy_strip.flag |= NLASTRIP_FLAG_USR_INFLUENCE; + dummy_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE; } /* add this to our list of evaluation strips */ - nlastrips_ctime_get_strip(depsgraph, &estrips, &dummy_trackslist, -1, ctime); + if (r_context == NULL) { + nlastrips_ctime_get_strip(depsgraph, &estrips, &dummy_trackslist, -1, ctime); + } + /* 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 keyframe beyond the ends. */ + dummy_strip->extendmode = is_inplace_tweak ? NLASTRIP_EXTEND_NOTHING : NLASTRIP_EXTEND_HOLD; + + r_context->eval_strip = nes = nlastrips_ctime_get_strip(depsgraph, NULL, &dummy_trackslist, -1, ctime); + + /* 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; + } + } } else { /* special case - evaluate as if there isn't any NLA data */ /* TODO: this is really just a stop-gap measure... */ if (G.debug & G_DEBUG) printf("NLA Eval: Stopgap for active action on NLA Stack - no strips case\n"); - animsys_evaluate_action(depsgraph, ptr, adt->action, ctime); + if (r_context == NULL) { + animsys_evaluate_action(depsgraph, ptr, adt->action, ctime); + } + BLI_freelistN(&estrips); return; } @@ -2601,7 +2673,7 @@ static void animsys_calculate_nla(Depsgraph *depsgraph, PointerRNA *ptr, AnimDat * and also when the user jumps between different times instead of moving sequentially... */ /* evaluate the NLA stack, obtaining a set of values to flush */ - animsys_evaluate_nla(depsgraph, &echannels, ptr, adt, ctime); + animsys_evaluate_nla(depsgraph, &echannels, ptr, adt, ctime, NULL); /* flush effects of accumulating channels in NLA to the actual data they affect */ nladata_flush_channels(depsgraph, ptr, &echannels); @@ -2610,6 +2682,108 @@ static void animsys_calculate_nla(Depsgraph *depsgraph, PointerRNA *ptr, AnimDat BLI_freelistN(&echannels); } +/* ---------------------- */ + +/** + * Prepare data necessary to compute correct keyframe values for NLA strips + * with non-Replace mode or influence different from 1. + * + * @param cache List used to cache contexts for reuse when keying multiple channels in one operation. + * @param ptr RNA pointer to the Object with the animation. + * @return Keyframing context, or NULL if not necessary. + */ +NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context( + struct ListBase *cache, struct Depsgraph *depsgraph, struct PointerRNA *ptr, struct AnimData *adt, float ctime) +{ + /* No remapping needed if NLA is off or no action. */ + if ((adt == NULL) || (adt->action == NULL) || (adt->nla_tracks.first == NULL) || (adt->flag & ADT_NLA_EVAL_OFF)) { + return NULL; + } + + /* No remapping if editing an ordinary Replace action with full influence. */ + if (!(adt->flag & ADT_NLA_EDIT_ON) && (adt->act_blendmode == NLASTRIP_MODE_REPLACE && adt->act_influence == 1.0f)) { + return NULL; + } + + /* Try to find a cached context. */ + NlaKeyframingContext *ctx = BLI_findptr(cache, adt, offsetof(NlaKeyframingContext, adt)); + + if (ctx == NULL) { + /* Allocate and evaluate a new context. */ + ctx = MEM_callocN(sizeof(*ctx), "NlaKeyframingContext"); + ctx->adt = adt; + + animsys_evaluate_nla(depsgraph, &ctx->nla_channels, ptr, adt, ctime, ctx); + + BLI_assert(ELEM(ctx->strip.act, NULL, adt->action)); + BLI_addtail(cache, ctx); + } + + return ctx; +} + +/** + * Apply correction from the NLA context to the value about to be keyframed. + * + * @param context Context to use (may be NULL). + * @param prop_ptr Property about to be keyframed. + * @param index Array index within the property. + * @param[in,out] r_value Value to correct. + * @return False if correction fails due to a division by zero. + */ +bool BKE_animsys_nla_remap_keyframe_value(struct NlaKeyframingContext *context, struct PointerRNA *prop_ptr, struct PropertyRNA *prop, int index, float *r_value) +{ + /* No context means no correction. */ + if (context == NULL || context->strip.act == NULL) { + return true; + } + + /* If the strip is not evaluated, it is the same as zero influence. */ + if (context->eval_strip == NULL) { + return false; + } + + /* Full influence Replace strips also require no correction. */ + int blend_mode = context->strip.blendmode; + float influence = context->strip.influence; + + if (blend_mode == NLASTRIP_MODE_REPLACE && influence == 1.0f) { + return true; + } + + /* Zero influence is division by zero. */ + if (influence <= 0.0f) { + return false; + } + + /* Find the evaluation channel for the NLA stack below current strip. */ + PathResolvedRNA rna = { .ptr = *prop_ptr, .prop = prop, .prop_index = index }; + NlaEvalChannel *nec = nlaevalchan_find_match(&context->nla_channels, &rna); + + /* Replace strips ignore influence when they are the first to modify this channel. */ + if (nec == NULL && blend_mode == NLASTRIP_MODE_REPLACE) { + return true; + } + + /* Invert the effect of blending modes. */ + float old_value = nec ? nec->value : nlaevalchan_init_value(&rna); + + return nla_invert_blend_value(blend_mode, old_value, *r_value, influence, r_value); +} + +/** + * Free all cached contexts from the list. + */ +void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache) +{ + for (NlaKeyframingContext *ctx = cache->first; ctx; ctx = ctx->next) { + MEM_SAFE_FREE(ctx->eval_strip); + BLI_freelistN(&ctx->nla_channels); + } + + BLI_freelistN(cache); +} + /* ***************************************** */ /* Overrides System - Public API */ diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h index 67728445f3a..0ab48b5ef2c 100644 --- a/source/blender/blenkernel/nla_private.h +++ b/source/blender/blenkernel/nla_private.h @@ -79,6 +79,21 @@ typedef struct NlaEvalChannel { float value; /* value of this channel */ } NlaEvalChannel; +/* Information about the currently edited strip and ones below it for keyframing. */ +typedef struct NlaKeyframingContext { + struct NlaKeyframingContext *next, *prev; + + /* AnimData for which this context was built. */ + struct AnimData *adt; + + /* Data of the currently edited strip (copy, or fake strip for the main action). */ + NlaStrip strip; + NlaEvalStrip *eval_strip; + + /* Evaluated NLA stack below the current strip. */ + ListBase nla_channels; +} NlaKeyframingContext; + /* --------------- NLA Functions (not to be used as a proper API) ----------------------- */ /* convert from strip time <-> global time */ diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 9bd7e277098..341bc25875e 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -4125,21 +4125,25 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi ReportList *reports = CTX_wm_reports(C); Scene *scene = CTX_data_scene(C); ToolSettings *ts = scene->toolsettings; + ListBase nla_cache = {NULL, NULL}; PointerRNA id_ptr, ptr; PropertyRNA *prop; short flag = 0; bool done = false; float cfra; + /* Get RNA pointer */ + RNA_id_pointer_create(id, &id_ptr); + + /* Get NLA context for value remapping */ + NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context(&nla_cache, depsgraph, &id_ptr, adt, (float)CFRA); + /* get current frame and apply NLA-mapping to it (if applicable) */ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); /* get flags for keyframing */ flag = ANIM_get_keyframing_flags(scene, 1); - /* get RNA pointer, and resolve the path */ - RNA_id_pointer_create(id, &id_ptr); - /* try to resolve the path stored in the F-Curve */ if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) { /* set the special 'replace' flag if on a keyframe */ @@ -4147,11 +4151,13 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi flag |= INSERTKEY_REPLACE; /* insert a keyframe for this F-Curve */ - done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag); + done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, nla_context, flag); if (done) WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); } + + BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); } /* callback for shapekey widget sliders - insert keyframes */ @@ -4166,21 +4172,25 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi ReportList *reports = CTX_wm_reports(C); Scene *scene = CTX_data_scene(C); ToolSettings *ts = scene->toolsettings; + ListBase nla_cache = {NULL, NULL}; PointerRNA id_ptr, ptr; PropertyRNA *prop; short flag = 0; bool done = false; float cfra; + /* Get RNA pointer */ + RNA_id_pointer_create((ID *)key, &id_ptr); + + /* Get NLA context for value remapping */ + NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context(&nla_cache, depsgraph, &id_ptr, key->adt, (float)CFRA); + /* get current frame and apply NLA-mapping to it (if applicable) */ cfra = BKE_nla_tweakedit_remap(key->adt, (float)CFRA, NLATIME_CONVERT_UNMAP); /* get flags for keyframing */ flag = ANIM_get_keyframing_flags(scene, 1); - /* get RNA pointer, and resolve the path */ - RNA_id_pointer_create((ID *)key, &id_ptr); - /* try to resolve the path stored in the F-Curve */ if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop)) { /* find or create new F-Curve */ @@ -4193,7 +4203,7 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi flag |= INSERTKEY_REPLACE; /* insert a keyframe for this F-Curve */ - done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag); + done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, nla_context, flag); if (done) WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); @@ -4202,6 +4212,8 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi /* free the path */ if (rna_path) MEM_freeN(rna_path); + + BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); } /* callback for NLA Control Curve widget sliders - insert keyframes */ @@ -4237,7 +4249,7 @@ static void achannel_setting_slider_nla_curve_cb(bContext *C, void *UNUSED(id_po flag |= INSERTKEY_REPLACE; /* insert a keyframe for this F-Curve */ - done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag); + done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, NULL, flag); if (done) WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 77dcc17c42a..b93c2ae5c7b 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -965,7 +965,7 @@ static float visualkey_get_value(Depsgraph *depsgraph, PointerRNA *ptr, Property * the keyframe insertion. These include the 'visual' keyframing modes, quick refresh, * and extra keyframe filtering. */ -bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag) +bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, eBezTriple_KeyframeType keytype, struct NlaKeyframingContext *nla_context, eInsertKeyFlags flag) { float curval = 0.0f; @@ -1038,6 +1038,12 @@ bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRN curval = setting_get_rna_value(depsgraph, &ptr, prop, fcu->array_index, false); } + /* adjust the value for NLA factors */ + if (!BKE_animsys_nla_remap_keyframe_value(nla_context, &ptr, prop, fcu->array_index, &curval)) { + BKE_report(reports, RPT_ERROR, "Could not insert keyframe due to zero NLA influence or base value"); + return false; + } + /* adjust coordinates for cycle aware insertion */ if (flag & INSERTKEY_CYCLE_AWARE) { if (remap_cyclic_keyframe_location(fcu, &cfra, &curval) != FCU_CYCLE_PERFECT) { @@ -1094,12 +1100,14 @@ bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRN */ short insert_keyframe( Main *bmain, Depsgraph *depsgraph, ReportList *reports, ID *id, bAction *act, - const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag) + const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, ListBase *nla_cache, eInsertKeyFlags flag) { PointerRNA id_ptr, ptr; PropertyRNA *prop = NULL; AnimData *adt; FCurve *fcu; + ListBase tmp_nla_cache = {NULL, NULL}; + NlaKeyframingContext *nla_context = NULL; int array_index_max = array_index + 1; int ret = 0; @@ -1132,7 +1140,14 @@ short insert_keyframe( /* apply NLA-mapping to frame to use (if applicable) */ adt = BKE_animdata_from_id(id); - cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); + + if (adt && adt->action == act) { + /* Get NLA context for value remapping. */ + nla_context = BKE_animsys_get_nla_keyframing_context(nla_cache ? nla_cache : &tmp_nla_cache, depsgraph, &id_ptr, adt, cfra); + + /* Apply NLA-mapping to frame. */ + cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); + } /* key entire array convenience method */ if (array_index == -1) { @@ -1172,10 +1187,12 @@ short insert_keyframe( } /* insert keyframe */ - ret += insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, keytype, flag); + ret += insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, keytype, nla_context, flag); } } + BKE_animsys_free_nla_keyframing_context_cache(&tmp_nla_cache); + if (ret) { if (act != NULL) { DEG_id_tag_update(&act->id, ID_RECALC_COPY_ON_WRITE); @@ -1904,7 +1921,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op) FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); if (fcu) { - success = insert_keyframe_direct(depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0); + success = insert_keyframe_direct(depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, NULL, 0); } else { BKE_report(op->reports, RPT_ERROR, @@ -1919,7 +1936,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op) fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special); if (fcu && driven) { - success = insert_keyframe_direct(depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER); + success = insert_keyframe_direct(depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, NULL, INSERTKEY_DRIVER); } } else { @@ -1955,7 +1972,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op) index = -1; } - success = insert_keyframe(bmain, depsgraph, op->reports, ptr.id.data, NULL, group, path, index, cfra, ts->keyframe_type, flag); + success = insert_keyframe(bmain, depsgraph, op->reports, ptr.id.data, NULL, group, path, index, cfra, ts->keyframe_type, NULL, flag); MEM_freeN(path); } diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index 1fe8a34d166..d980e4322dd 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -962,6 +962,7 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe Scene *scene = CTX_data_scene(C); ReportList *reports = CTX_wm_reports(C); KS_Path *ksp; + ListBase nla_cache = {NULL, NULL}; const short base_kflags = ANIM_get_keyframing_flags(scene, 1); const char *groupname = NULL; short kflag = 0, success = 0; @@ -1039,7 +1040,7 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe for (; i < arraylen; i++) { /* action to take depends on mode */ if (mode == MODIFYKEY_MODE_INSERT) - success += insert_keyframe(bmain, depsgraph, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, keytype, kflag2); + success += insert_keyframe(bmain, depsgraph, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, keytype, &nla_cache, kflag2); else if (mode == MODIFYKEY_MODE_DELETE) success += delete_keyframe(bmain, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2); } @@ -1063,6 +1064,8 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); } + BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); + /* return the number of channels successfully affected */ return success; } diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 915e678ee34..9b13fb7d3ce 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -423,7 +423,7 @@ static void gp_stroke_path_animation_add_keyframes( if ((cfra - last_valid_time) < MIN_TIME_DELTA) { cfra = last_valid_time + MIN_TIME_DELTA; } - insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); + insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, NULL, INSERTKEY_FAST); last_valid_time = cfra; } else if (G.debug & G_DEBUG) { @@ -435,7 +435,7 @@ static void gp_stroke_path_animation_add_keyframes( if ((cfra - last_valid_time) < MIN_TIME_DELTA) { cfra = last_valid_time + MIN_TIME_DELTA; } - insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); + insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, NULL, INSERTKEY_FAST); last_valid_time = cfra; } else { @@ -443,7 +443,7 @@ static void gp_stroke_path_animation_add_keyframes( * and also far enough from (not yet added!) end_stroke keyframe! */ if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) { - insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_BREAKDOWN, INSERTKEY_FAST); + insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_BREAKDOWN, NULL, INSERTKEY_FAST); last_valid_time = cfra; } else if (G.debug & G_DEBUG) { @@ -499,7 +499,7 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu cu->ctime = 0.0f; cfra = (float)gtd->start_frame; - insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); + insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, NULL, INSERTKEY_FAST); cu->ctime = cu->pathlen; if (gtd->realtime) { @@ -508,7 +508,7 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu else { cfra = (float)gtd->end_frame; } - insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); + insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, NULL, INSERTKEY_FAST); } else { /* Use actual recorded timing! */ diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index b42fdf456e0..aba381f7989 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -56,6 +56,8 @@ struct PointerRNA; struct PropertyRNA; struct EnumPropertyItem; +struct NlaKeyframingContext; + #include "DNA_anim_types.h" #include "RNA_types.h" @@ -109,7 +111,7 @@ int insert_vert_fcurve(struct FCurve *fcu, float x, float y, eBezTriple_Keyframe * Use this to insert a keyframe using the current value being keyframed, in the * nominated F-Curve (no creation of animation data performed). Returns success. */ -bool insert_keyframe_direct(struct Depsgraph *depsgraph, struct ReportList *reports, struct PointerRNA ptr, struct PropertyRNA *prop, struct FCurve *fcu, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag); +bool insert_keyframe_direct(struct Depsgraph *depsgraph, struct ReportList *reports, struct PointerRNA ptr, struct PropertyRNA *prop, struct FCurve *fcu, float cfra, eBezTriple_KeyframeType keytype, struct NlaKeyframingContext *nla, eInsertKeyFlags flag); /* -------- */ @@ -119,7 +121,7 @@ bool insert_keyframe_direct(struct Depsgraph *depsgraph, struct ReportList *repo */ short insert_keyframe( struct Main *bmain, struct Depsgraph *depsgraph, struct ReportList *reports, struct ID *id, struct bAction *act, - const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag); + const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, struct ListBase *nla_cache, eInsertKeyFlags flag); /* Main Keyframing API call: * Use this to delete keyframe on current frame for relevant channel. Will perform checks just in case. diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 42615821ee0..9ec238d7b5e 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -274,7 +274,7 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra) ReportList *reports = CTX_wm_reports(C); ToolSettings *ts = scene->toolsettings; - insert_keyframe_direct(depsgraph, reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, 0); + insert_keyframe_direct(depsgraph, reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, NULL, 0); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } } @@ -287,7 +287,7 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra) ReportList *reports = CTX_wm_reports(C); ToolSettings *ts = scene->toolsettings; - insert_keyframe_direct(depsgraph, reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER); + insert_keyframe_direct(depsgraph, reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, NULL, INSERTKEY_DRIVER); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } } @@ -309,7 +309,7 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra) BLI_assert((fcu->array_index == but->rnaindex) || (but->rnaindex == -1)); insert_keyframe(bmain, depsgraph, reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)), - fcu->rna_path, but->rnaindex, cfra, ts->keyframe_type, flag); + fcu->rna_path, but->rnaindex, cfra, ts->keyframe_type, NULL, flag); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index c2376b506d4..e960c32cf0c 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -54,6 +54,7 @@ #include "RNA_enum_types.h" #include "BKE_action.h" +#include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_fcurve.h" #include "BKE_gpencil.h" @@ -679,6 +680,7 @@ static const EnumPropertyItem prop_actkeys_insertkey_types[] = { static void insert_action_keys(bAnimContext *ac, short mode) { ListBase anim_data = {NULL, NULL}; + ListBase nla_cache = {NULL, NULL}; bAnimListElem *ale; int filter; @@ -711,7 +713,7 @@ static void insert_action_keys(bAnimContext *ac, short mode) */ if (ale->id && !ale->owner) { insert_keyframe(ac->bmain, depsgraph, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), - fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag); + fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, &nla_cache, flag); } else { AnimData *adt = ANIM_nla_mapping_get(ac, ale); @@ -727,6 +729,8 @@ static void insert_action_keys(bAnimContext *ac, short mode) ale->update |= ANIM_UPDATE_DEFAULT; } + BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); + ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); } diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index e610aee4810..00418d6482a 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -54,6 +54,7 @@ #include "BLT_translation.h" +#include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_fcurve.h" #include "BKE_global.h" @@ -521,6 +522,7 @@ static const EnumPropertyItem prop_graphkeys_insertkey_types[] = { static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode) { ListBase anim_data = {NULL, NULL}; + ListBase nla_cache = {NULL, NULL}; bAnimListElem *ale; int filter; size_t num_items; @@ -602,7 +604,7 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode) */ if (ale->id && !ale->owner && !fcu->driver) { insert_keyframe(ac->bmain, depsgraph, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), - fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag); + fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, &nla_cache, flag); } else { AnimData *adt = ANIM_nla_mapping_get(ac, ale); @@ -621,6 +623,8 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode) } } + BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); + ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); } diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 83a336f6a7c..1702fd8fcd3 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -62,6 +62,7 @@ #include "BLI_rect.h" #include "BKE_action.h" +#include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_context.h" @@ -6019,13 +6020,17 @@ void autokeyframe_object(bContext *C, Scene *scene, ViewLayer *view_layer, Objec /* only key on available channels */ if (adt && adt->action) { + ListBase nla_cache = {NULL, NULL}; + for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) { fcu->flag &= ~FCURVE_SELECTED; insert_keyframe(bmain, depsgraph, reports, id, adt->action, (fcu->grp ? fcu->grp->name : NULL), fcu->rna_path, fcu->array_index, cfra, - ts->keyframe_type, flag); + ts->keyframe_type, &nla_cache, flag); } + + BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); } } else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) { @@ -6124,6 +6129,7 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t ReportList *reports = CTX_wm_reports(C); ToolSettings *ts = scene->toolsettings; KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene); + ListBase nla_cache = {NULL, NULL}; float cfra = (float)CFRA; short flag = 0; @@ -6167,7 +6173,7 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t insert_keyframe(bmain, depsgraph, reports, id, act, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, - ts->keyframe_type, flag); + ts->keyframe_type, &nla_cache, flag); } if (pchanName) MEM_freeN(pchanName); @@ -6228,6 +6234,8 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t BLI_freelistN(&dsources); } } + + BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); } else { /* tag channels that should have unkeyed data */ diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 3ba604d5271..5a18fd8b177 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -255,7 +255,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb NlaStrip *strip = (NlaStrip *)ptr.data; FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); - result = insert_keyframe_direct(depsgraph, &reports, ptr, prop, fcu, cfra, keytype, options); + result = insert_keyframe_direct(depsgraph, &reports, ptr, prop, fcu, cfra, keytype, NULL, options); } else { BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full); @@ -276,7 +276,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb BKE_reports_init(&reports, RPT_STORE); BLI_assert(BKE_id_is_in_global_main(id)); - result = insert_keyframe(G_MAIN, depsgraph, &reports, id, NULL, group_name, path_full, index, cfra, keytype, options); + result = insert_keyframe(G_MAIN, depsgraph, &reports, id, NULL, group_name, path_full, index, cfra, keytype, NULL, options); MEM_freeN((void *)path_full); if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) |