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:
-rw-r--r--source/blender/blenkernel/BKE_animsys.h9
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c230
-rw-r--r--source/blender/blenkernel/nla_private.h15
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c30
-rw-r--r--source/blender/editors/animation/keyframing.c31
-rw-r--r--source/blender/editors/animation/keyingsets.c5
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c10
-rw-r--r--source/blender/editors/include/ED_keyframing.h6
-rw-r--r--source/blender/editors/interface/interface_anim.c6
-rw-r--r--source/blender/editors/space_action/action_edit.c6
-rw-r--r--source/blender/editors/space_graph/graph_edit.c6
-rw-r--r--source/blender/editors/transform/transform_conversions.c12
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c4
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)