Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/anim_sys.c
| Show First 20 Lines • Show All 532 Lines • ▼ Show 20 Lines | |||||
| /** | /** | ||||
| * Evaluate all the F-Curves in the given list | * Evaluate all the F-Curves in the given list | ||||
| * This performs a set of standard checks. If extra checks are required, | * This performs a set of standard checks. If extra checks are required, | ||||
| * separate code should be used. | * separate code should be used. | ||||
| */ | */ | ||||
| static void animsys_evaluate_fcurves(PointerRNA *ptr, | static void animsys_evaluate_fcurves(PointerRNA *ptr, | ||||
| ListBase *list, | ListBase *list, | ||||
| float ctime, | const AnimationEvalContext *anim_eval_context, | ||||
| bool flush_to_original) | bool flush_to_original) | ||||
| { | { | ||||
| /* Calculate then execute each curve. */ | /* Calculate then execute each curve. */ | ||||
| LISTBASE_FOREACH (FCurve *, fcu, list) { | LISTBASE_FOREACH (FCurve *, fcu, list) { | ||||
| /* Check if this F-Curve doesn't belong to a muted group. */ | /* Check if this F-Curve doesn't belong to a muted group. */ | ||||
| if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) { | if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Check if this curve should be skipped. */ | /* Check if this curve should be skipped. */ | ||||
| if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) { | if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Skip empty curves, as if muted. */ | /* Skip empty curves, as if muted. */ | ||||
| if (BKE_fcurve_is_empty(fcu)) { | if (BKE_fcurve_is_empty(fcu)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| PathResolvedRNA anim_rna; | PathResolvedRNA anim_rna; | ||||
| if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { | if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { | ||||
| const float curval = calculate_fcurve(&anim_rna, fcu, ctime); | const float curval = calculate_fcurve(&anim_rna, fcu, anim_eval_context); | ||||
| BKE_animsys_write_rna_setting(&anim_rna, curval); | BKE_animsys_write_rna_setting(&anim_rna, curval); | ||||
| if (flush_to_original) { | if (flush_to_original) { | ||||
| animsys_write_orig_anim_rna(ptr, fcu->rna_path, fcu->array_index, curval); | animsys_write_orig_anim_rna(ptr, fcu->rna_path, fcu->array_index, curval); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* ***************************************** */ | /* ***************************************** */ | ||||
| /* Driver Evaluation */ | /* Driver Evaluation */ | ||||
| AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, | |||||
| float eval_time) | |||||
| { | |||||
| AnimationEvalContext ctx = { | |||||
| .depsgraph = depsgraph, | |||||
| .eval_time = eval_time, | |||||
| }; | |||||
| return ctx; | |||||
| } | |||||
| AnimationEvalContext BKE_animsys_eval_context_construct_at( | |||||
| const AnimationEvalContext *anim_eval_context, float eval_time) | |||||
| { | |||||
| return BKE_animsys_eval_context_construct(anim_eval_context->depsgraph, eval_time); | |||||
| } | |||||
| /* Evaluate Drivers */ | /* Evaluate Drivers */ | ||||
| static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime) | static void animsys_evaluate_drivers(PointerRNA *ptr, | ||||
| AnimData *adt, | |||||
| const AnimationEvalContext *anim_eval_context) | |||||
| { | { | ||||
| FCurve *fcu; | FCurve *fcu; | ||||
| /* drivers are stored as F-Curves, but we cannot use the standard code, as we need to check if | /* drivers are stored as F-Curves, but we cannot use the standard code, as we need to check if | ||||
| * the depsgraph requested that this driver be evaluated... | * the depsgraph requested that this driver be evaluated... | ||||
| */ | */ | ||||
| for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { | for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { | ||||
| ChannelDriver *driver = fcu->driver; | ChannelDriver *driver = fcu->driver; | ||||
| bool ok = false; | bool ok = false; | ||||
| /* check if this driver's curve should be skipped */ | /* check if this driver's curve should be skipped */ | ||||
| if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { | if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { | ||||
| /* check if driver itself is tagged for recalculation */ | /* check if driver itself is tagged for recalculation */ | ||||
| /* XXX driver recalc flag is not set yet by depsgraph! */ | /* XXX driver recalc flag is not set yet by depsgraph! */ | ||||
| if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID)) { | if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID)) { | ||||
| /* evaluate this using values set already in other places | /* evaluate this using values set already in other places | ||||
| * NOTE: for 'layering' option later on, we should check if we should remove old value | * NOTE: for 'layering' option later on, we should check if we should remove old value | ||||
| * before adding new to only be done when drivers only changed. */ | * before adding new to only be done when drivers only changed. */ | ||||
| PathResolvedRNA anim_rna; | PathResolvedRNA anim_rna; | ||||
| if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { | if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { | ||||
| const float curval = calculate_fcurve(&anim_rna, fcu, ctime); | const float curval = calculate_fcurve(&anim_rna, fcu, anim_eval_context); | ||||
| ok = BKE_animsys_write_rna_setting(&anim_rna, curval); | ok = BKE_animsys_write_rna_setting(&anim_rna, curval); | ||||
| } | } | ||||
| /* set error-flag if evaluation failed */ | /* set error-flag if evaluation failed */ | ||||
| if (ok == 0) { | if (ok == 0) { | ||||
| driver->flag |= DRIVER_FLAG_INVALID; | driver->flag |= DRIVER_FLAG_INVALID; | ||||
| } | } | ||||
| } | } | ||||
| Show All 39 Lines | if (G.debug & G_DEBUG) { | ||||
| id->name); | id->name); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* ----------------------------------------- */ | /* ----------------------------------------- */ | ||||
| /* Evaluate Action Group */ | /* Evaluate Action Group */ | ||||
| void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *agrp, float ctime) | void animsys_evaluate_action_group(PointerRNA *ptr, | ||||
| bAction *act, | |||||
| bActionGroup *agrp, | |||||
| const AnimationEvalContext *anim_eval_context) | |||||
| { | { | ||||
| FCurve *fcu; | FCurve *fcu; | ||||
| /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ | /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ | ||||
| if (ELEM(NULL, act, agrp)) { | if (ELEM(NULL, act, agrp)) { | ||||
| return; | return; | ||||
| } | } | ||||
| action_idcode_patch_check(ptr->owner_id, act); | action_idcode_patch_check(ptr->owner_id, act); | ||||
| /* if group is muted, don't evaluated any of the F-Curve */ | /* if group is muted, don't evaluated any of the F-Curve */ | ||||
| if (agrp->flag & AGRP_MUTED) { | if (agrp->flag & AGRP_MUTED) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* calculate then execute each curve */ | /* calculate then execute each curve */ | ||||
| for (fcu = agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu = fcu->next) { | for (fcu = agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu = fcu->next) { | ||||
| /* check if this curve should be skipped */ | /* check if this curve should be skipped */ | ||||
| if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0 && !BKE_fcurve_is_empty(fcu)) { | if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0 && !BKE_fcurve_is_empty(fcu)) { | ||||
| PathResolvedRNA anim_rna; | PathResolvedRNA anim_rna; | ||||
| if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { | if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { | ||||
| const float curval = calculate_fcurve(&anim_rna, fcu, ctime); | const float curval = calculate_fcurve(&anim_rna, fcu, anim_eval_context); | ||||
| BKE_animsys_write_rna_setting(&anim_rna, curval); | BKE_animsys_write_rna_setting(&anim_rna, curval); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Evaluate Action (F-Curve Bag) */ | /* Evaluate Action (F-Curve Bag) */ | ||||
| static void animsys_evaluate_action_ex(PointerRNA *ptr, | static void animsys_evaluate_action_ex(PointerRNA *ptr, | ||||
| bAction *act, | bAction *act, | ||||
| float ctime, | const AnimationEvalContext *anim_eval_context, | ||||
| const bool flush_to_original) | const bool flush_to_original) | ||||
| { | { | ||||
| /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ | /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ | ||||
| if (act == NULL) { | if (act == NULL) { | ||||
| return; | return; | ||||
| } | } | ||||
| action_idcode_patch_check(ptr->owner_id, act); | action_idcode_patch_check(ptr->owner_id, act); | ||||
| /* calculate then execute each curve */ | /* calculate then execute each curve */ | ||||
| animsys_evaluate_fcurves(ptr, &act->curves, ctime, flush_to_original); | animsys_evaluate_fcurves(ptr, &act->curves, anim_eval_context, flush_to_original); | ||||
| } | } | ||||
| void animsys_evaluate_action(PointerRNA *ptr, | void animsys_evaluate_action(PointerRNA *ptr, | ||||
| bAction *act, | bAction *act, | ||||
| float ctime, | const AnimationEvalContext *anim_eval_context, | ||||
| const bool flush_to_original) | const bool flush_to_original) | ||||
| { | { | ||||
| animsys_evaluate_action_ex(ptr, act, ctime, flush_to_original); | animsys_evaluate_action_ex(ptr, act, anim_eval_context, flush_to_original); | ||||
| } | } | ||||
| /* ***************************************** */ | /* ***************************************** */ | ||||
| /* NLA System - Evaluation */ | /* NLA System - Evaluation */ | ||||
| /* calculate influence of strip based for given frame based on blendin/out values */ | /* calculate influence of strip based for given frame based on blendin/out values */ | ||||
| static float nlastrip_get_influence(NlaStrip *strip, float cframe) | static float nlastrip_get_influence(NlaStrip *strip, float cframe) | ||||
| { | { | ||||
| Show All 11 Lines | if (IS_EQF(strip->blendout, 0.0f) == false && (cframe >= (strip->end - strip->blendout))) { | ||||
| return fabsf(strip->end - cframe) / (strip->blendout); | return fabsf(strip->end - cframe) / (strip->blendout); | ||||
| } | } | ||||
| /* in the middle of the strip, we should be full strength */ | /* in the middle of the strip, we should be full strength */ | ||||
| return 1.0f; | return 1.0f; | ||||
| } | } | ||||
| /* evaluate the evaluation time and influence for the strip, storing the results in the strip */ | /* evaluate the evaluation time and influence for the strip, storing the results in the strip */ | ||||
| static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime, const bool flush_to_original) | static void nlastrip_evaluate_controls(NlaStrip *strip, | ||||
| const AnimationEvalContext *anim_eval_context, | |||||
| const bool flush_to_original) | |||||
| { | { | ||||
| /* now strip's evaluate F-Curves for these settings (if applicable) */ | /* now strip's evaluate F-Curves for these settings (if applicable) */ | ||||
| if (strip->fcurves.first) { | if (strip->fcurves.first) { | ||||
| PointerRNA strip_ptr; | PointerRNA strip_ptr; | ||||
| /* create RNA-pointer needed to set values */ | /* create RNA-pointer needed to set values */ | ||||
| RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr); | RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr); | ||||
| /* execute these settings as per normal */ | /* execute these settings as per normal */ | ||||
| animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, ctime, flush_to_original); | animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, anim_eval_context, flush_to_original); | ||||
| } | } | ||||
| /* analytically generate values for influence and time (if applicable) | /* analytically generate values for influence and time (if applicable) | ||||
| * - we do this after the F-Curves have been evaluated to override the effects of those | * - we do this after the F-Curves have been evaluated to override the effects of those | ||||
| * in case the override has been turned off. | * in case the override has been turned off. | ||||
| */ | */ | ||||
| if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0) { | if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0) { | ||||
| strip->influence = nlastrip_get_influence(strip, ctime); | strip->influence = nlastrip_get_influence(strip, anim_eval_context->eval_time); | ||||
| } | } | ||||
| /* Bypass evaluation time computation if time mapping is disabled. */ | /* Bypass evaluation time computation if time mapping is disabled. */ | ||||
| if ((strip->flag & NLASTRIP_FLAG_NO_TIME_MAP) != 0) { | if ((strip->flag & NLASTRIP_FLAG_NO_TIME_MAP) != 0) { | ||||
| strip->strip_time = ctime; | strip->strip_time = anim_eval_context->eval_time; | ||||
| return; | return; | ||||
| } | } | ||||
| if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0) { | if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0) { | ||||
| strip->strip_time = nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL); | strip->strip_time = nlastrip_get_frame( | ||||
| strip, anim_eval_context->eval_time, NLATIME_CONVERT_EVAL); | |||||
| } | } | ||||
| /* if user can control the evaluation time (using F-Curves), consider the option which allows | /* if user can control the evaluation time (using F-Curves), consider the option which allows | ||||
| * this time to be clamped to lie within extents of the action-clip, so that a steady changing | * this time to be clamped to lie within extents of the action-clip, so that a steady changing | ||||
| * rate of progress through several cycles of the clip can be achieved easily. | * rate of progress through several cycles of the clip can be achieved easily. | ||||
| */ | */ | ||||
| /* NOTE: if we add any more of these special cases, we better group them up nicely... */ | /* NOTE: if we add any more of these special cases, we better group them up nicely... */ | ||||
| if ((strip->flag & NLASTRIP_FLAG_USR_TIME) && (strip->flag & NLASTRIP_FLAG_USR_TIME_CYCLIC)) { | if ((strip->flag & NLASTRIP_FLAG_USR_TIME) && (strip->flag & NLASTRIP_FLAG_USR_TIME_CYCLIC)) { | ||||
| strip->strip_time = fmod(strip->strip_time - strip->actstart, strip->actend - strip->actstart); | strip->strip_time = fmod(strip->strip_time - strip->actstart, strip->actend - strip->actstart); | ||||
| } | } | ||||
| } | } | ||||
| /* gets the strip active at the current time for a list of strips for evaluation purposes */ | /* gets the strip active at the current time for a list of strips for evaluation purposes */ | ||||
| NlaEvalStrip *nlastrips_ctime_get_strip( | NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, | ||||
| ListBase *list, ListBase *strips, short index, float ctime, const bool flush_to_original) | ListBase *strips, | ||||
| short index, | |||||
| const AnimationEvalContext *anim_eval_context, | |||||
| const bool flush_to_original) | |||||
| { | { | ||||
| NlaStrip *strip, *estrip = NULL; | NlaStrip *strip, *estrip = NULL; | ||||
| NlaEvalStrip *nes; | NlaEvalStrip *nes; | ||||
| short side = 0; | short side = 0; | ||||
| float ctime = anim_eval_context->eval_time; | |||||
| /* loop over strips, checking if they fall within the range */ | /* loop over strips, checking if they fall within the range */ | ||||
| for (strip = strips->first; strip; strip = strip->next) { | for (strip = strips->first; strip; strip = strip->next) { | ||||
| /* check if current time occurs within this strip */ | /* check if current time occurs within this strip */ | ||||
| if (IN_RANGE_INCL(ctime, strip->start, strip->end) || | if (IN_RANGE_INCL(ctime, strip->start, strip->end) || | ||||
| (strip->flag & NLASTRIP_FLAG_NO_TIME_MAP)) { | (strip->flag & NLASTRIP_FLAG_NO_TIME_MAP)) { | ||||
| /* this strip is active, so try to use it */ | /* this strip is active, so try to use it */ | ||||
| estrip = strip; | estrip = strip; | ||||
| ▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, | ||||
| } | } | ||||
| /* evaluate strip's evaluation controls | /* evaluate strip's evaluation controls | ||||
| * - skip if no influence (i.e. same effect as muting the strip) | * - skip if no influence (i.e. same effect as muting the strip) | ||||
| * - negative influence is not supported yet... how would that be defined? | * - negative influence is not supported yet... how would that be defined? | ||||
| */ | */ | ||||
| /* TODO: this sounds a bit hacky having a few isolated F-Curves | /* TODO: this sounds a bit hacky having a few isolated F-Curves | ||||
| * stuck on some data it operates on... */ | * stuck on some data it operates on... */ | ||||
| nlastrip_evaluate_controls(estrip, ctime, flush_to_original); | AnimationEvalContext clamped_eval_context = BKE_animsys_eval_context_construct_at( | ||||
| anim_eval_context, ctime); | |||||
| nlastrip_evaluate_controls(estrip, &clamped_eval_context, flush_to_original); | |||||
| if (estrip->influence <= 0.0f) { | if (estrip->influence <= 0.0f) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* check if strip has valid data to evaluate, | /* check if strip has valid data to evaluate, | ||||
| * and/or perform any additional type-specific actions | * and/or perform any additional type-specific actions | ||||
| */ | */ | ||||
| switch (estrip->type) { | switch (estrip->type) { | ||||
| case NLASTRIP_TYPE_CLIP: | case NLASTRIP_TYPE_CLIP: | ||||
| /* clip must have some action to evaluate */ | /* clip must have some action to evaluate */ | ||||
| if (estrip->act == NULL) { | if (estrip->act == NULL) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| break; | break; | ||||
| case NLASTRIP_TYPE_TRANSITION: | case NLASTRIP_TYPE_TRANSITION: | ||||
| /* there must be strips to transition from and to (i.e. prev and next required) */ | /* there must be strips to transition from and to (i.e. prev and next required) */ | ||||
| if (ELEM(NULL, estrip->prev, estrip->next)) { | if (ELEM(NULL, estrip->prev, estrip->next)) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* evaluate controls for the relevant extents of the bordering strips... */ | /* evaluate controls for the relevant extents of the bordering strips... */ | ||||
| nlastrip_evaluate_controls(estrip->prev, estrip->start, flush_to_original); | AnimationEvalContext start_eval_context = BKE_animsys_eval_context_construct_at( | ||||
| nlastrip_evaluate_controls(estrip->next, estrip->end, flush_to_original); | anim_eval_context, estrip->start); | ||||
| AnimationEvalContext end_eval_context = BKE_animsys_eval_context_construct_at( | |||||
| anim_eval_context, estrip->end); | |||||
| nlastrip_evaluate_controls(estrip->prev, &start_eval_context, flush_to_original); | |||||
| nlastrip_evaluate_controls(estrip->next, &end_eval_context, flush_to_original); | |||||
| break; | break; | ||||
| } | } | ||||
| /* add to list of strips we need to evaluate */ | /* add to list of strips we need to evaluate */ | ||||
| nes = MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip"); | nes = MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip"); | ||||
| nes->strip = estrip; | nes->strip = estrip; | ||||
| nes->strip_mode = side; | nes->strip_mode = side; | ||||
| ▲ Show 20 Lines • Show All 903 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /* evaluate transition strip */ | /* evaluate transition strip */ | ||||
| static void nlastrip_evaluate_transition(PointerRNA *ptr, | static void nlastrip_evaluate_transition(PointerRNA *ptr, | ||||
| NlaEvalData *channels, | NlaEvalData *channels, | ||||
| ListBase *modifiers, | ListBase *modifiers, | ||||
| NlaEvalStrip *nes, | NlaEvalStrip *nes, | ||||
| NlaEvalSnapshot *snapshot, | NlaEvalSnapshot *snapshot, | ||||
| const AnimationEvalContext *anim_eval_context, | |||||
| const bool flush_to_original) | const bool flush_to_original) | ||||
| { | { | ||||
| ListBase tmp_modifiers = {NULL, NULL}; | ListBase tmp_modifiers = {NULL, NULL}; | ||||
| NlaEvalSnapshot snapshot1, snapshot2; | NlaEvalSnapshot snapshot1, snapshot2; | ||||
| NlaEvalStrip tmp_nes; | NlaEvalStrip tmp_nes; | ||||
| NlaStrip *s1, *s2; | NlaStrip *s1, *s2; | ||||
| /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ | /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ | ||||
| Show All 25 Lines | static void nlastrip_evaluate_transition(PointerRNA *ptr, | ||||
| tmp_nes = *nes; | tmp_nes = *nes; | ||||
| /* evaluate these strips into a temp-buffer (tmp_channels) */ | /* evaluate these strips into a temp-buffer (tmp_channels) */ | ||||
| /* FIXME: modifier evaluation here needs some work... */ | /* FIXME: modifier evaluation here needs some work... */ | ||||
| /* first strip */ | /* first strip */ | ||||
| tmp_nes.strip_mode = NES_TIME_TRANSITION_START; | tmp_nes.strip_mode = NES_TIME_TRANSITION_START; | ||||
| tmp_nes.strip = s1; | tmp_nes.strip = s1; | ||||
| nlaeval_snapshot_init(&snapshot1, channels, snapshot); | nlaeval_snapshot_init(&snapshot1, channels, snapshot); | ||||
| nlastrip_evaluate(ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot1, flush_to_original); | nlastrip_evaluate( | ||||
| ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot1, anim_eval_context, flush_to_original); | |||||
| /* second strip */ | /* second strip */ | ||||
| tmp_nes.strip_mode = NES_TIME_TRANSITION_END; | tmp_nes.strip_mode = NES_TIME_TRANSITION_END; | ||||
| tmp_nes.strip = s2; | tmp_nes.strip = s2; | ||||
| nlaeval_snapshot_init(&snapshot2, channels, snapshot); | nlaeval_snapshot_init(&snapshot2, channels, snapshot); | ||||
| nlastrip_evaluate(ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot2, flush_to_original); | nlastrip_evaluate( | ||||
| ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot2, anim_eval_context, flush_to_original); | |||||
| /* accumulate temp-buffer and full-buffer, using the 'real' strip */ | /* accumulate temp-buffer and full-buffer, using the 'real' strip */ | ||||
| nlaeval_snapshot_mix_and_free(channels, snapshot, &snapshot1, &snapshot2, nes->strip_time); | nlaeval_snapshot_mix_and_free(channels, snapshot, &snapshot1, &snapshot2, nes->strip_time); | ||||
| /* unlink this strip's modifiers from the parent's modifiers again */ | /* unlink this strip's modifiers from the parent's modifiers again */ | ||||
| nlaeval_fmodifiers_split_stacks(&nes->strip->modifiers, modifiers); | nlaeval_fmodifiers_split_stacks(&nes->strip->modifiers, modifiers); | ||||
| } | } | ||||
| /* evaluate meta-strip */ | /* evaluate meta-strip */ | ||||
| static void nlastrip_evaluate_meta(PointerRNA *ptr, | static void nlastrip_evaluate_meta(PointerRNA *ptr, | ||||
| NlaEvalData *channels, | NlaEvalData *channels, | ||||
| ListBase *modifiers, | ListBase *modifiers, | ||||
| NlaEvalStrip *nes, | NlaEvalStrip *nes, | ||||
| NlaEvalSnapshot *snapshot, | NlaEvalSnapshot *snapshot, | ||||
| const AnimationEvalContext *anim_eval_context, | |||||
| const bool flush_to_original) | const bool flush_to_original) | ||||
| { | { | ||||
| ListBase tmp_modifiers = {NULL, NULL}; | ListBase tmp_modifiers = {NULL, NULL}; | ||||
| NlaStrip *strip = nes->strip; | NlaStrip *strip = nes->strip; | ||||
| NlaEvalStrip *tmp_nes; | NlaEvalStrip *tmp_nes; | ||||
| float evaltime; | float evaltime; | ||||
| /* meta-strip was calculated normally to have some time to be evaluated at | /* meta-strip was calculated normally to have some time to be evaluated at | ||||
| * and here we 'look inside' the meta strip, treating it as a decorated window to | * and here we 'look inside' the meta strip, treating it as a decorated window to | ||||
| * it's child strips, which get evaluated as if they were some tracks on a strip | * it's child strips, which get evaluated as if they were some tracks on a strip | ||||
| * (but with some extra modifiers to apply). | * (but with some extra modifiers to apply). | ||||
| * | * | ||||
| * NOTE: keep this in sync with animsys_evaluate_nla() | * NOTE: keep this in sync with animsys_evaluate_nla() | ||||
| */ | */ | ||||
| /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ | /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ | ||||
| nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); | nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); | ||||
| /* find the child-strip to evaluate */ | /* find the child-strip to evaluate */ | ||||
| evaltime = (nes->strip_time * (strip->end - strip->start)) + strip->start; | evaltime = (nes->strip_time * (strip->end - strip->start)) + strip->start; | ||||
| tmp_nes = nlastrips_ctime_get_strip(NULL, &strip->strips, -1, evaltime, flush_to_original); | AnimationEvalContext child_context = BKE_animsys_eval_context_construct_at(anim_eval_context, | ||||
| evaltime); | |||||
| tmp_nes = nlastrips_ctime_get_strip(NULL, &strip->strips, -1, &child_context, flush_to_original); | |||||
| /* directly evaluate child strip into accumulation buffer... | /* directly evaluate child strip into accumulation buffer... | ||||
| * - there's no need to use a temporary buffer (as it causes issues [T40082]) | * - there's no need to use a temporary buffer (as it causes issues [T40082]) | ||||
| */ | */ | ||||
| if (tmp_nes) { | if (tmp_nes) { | ||||
| nlastrip_evaluate(ptr, channels, &tmp_modifiers, tmp_nes, snapshot, flush_to_original); | nlastrip_evaluate( | ||||
| ptr, channels, &tmp_modifiers, tmp_nes, snapshot, &child_context, flush_to_original); | |||||
| /* free temp eval-strip */ | /* free temp eval-strip */ | ||||
| MEM_freeN(tmp_nes); | MEM_freeN(tmp_nes); | ||||
| } | } | ||||
| /* unlink this strip's modifiers from the parent's modifiers again */ | /* unlink this strip's modifiers from the parent's modifiers again */ | ||||
| nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers); | nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers); | ||||
| } | } | ||||
| /* evaluates the given evaluation strip */ | /* evaluates the given evaluation strip */ | ||||
| void nlastrip_evaluate(PointerRNA *ptr, | void nlastrip_evaluate(PointerRNA *ptr, | ||||
| NlaEvalData *channels, | NlaEvalData *channels, | ||||
| ListBase *modifiers, | ListBase *modifiers, | ||||
| NlaEvalStrip *nes, | NlaEvalStrip *nes, | ||||
| NlaEvalSnapshot *snapshot, | NlaEvalSnapshot *snapshot, | ||||
| const AnimationEvalContext *anim_eval_context, | |||||
| const bool flush_to_original) | const bool flush_to_original) | ||||
| { | { | ||||
| NlaStrip *strip = nes->strip; | NlaStrip *strip = nes->strip; | ||||
| /* To prevent potential infinite recursion problems | /* To prevent potential infinite recursion problems | ||||
| * (i.e. transition strip, beside meta strip containing a transition | * (i.e. transition strip, beside meta strip containing a transition | ||||
| * several levels deep inside it), | * several levels deep inside it), | ||||
| * we tag the current strip as being evaluated, and clear this when we leave. | * we tag the current strip as being evaluated, and clear this when we leave. | ||||
| */ | */ | ||||
| /* TODO: be careful with this flag, since some edit tools may be running and have | /* TODO: be careful with this flag, since some edit tools may be running and have | ||||
| * set this while animation playback was running. */ | * set this while animation playback was running. */ | ||||
| if (strip->flag & NLASTRIP_FLAG_EDIT_TOUCHED) { | if (strip->flag & NLASTRIP_FLAG_EDIT_TOUCHED) { | ||||
| return; | return; | ||||
| } | } | ||||
| strip->flag |= NLASTRIP_FLAG_EDIT_TOUCHED; | strip->flag |= NLASTRIP_FLAG_EDIT_TOUCHED; | ||||
| /* actions to take depend on the type of strip */ | /* actions to take depend on the type of strip */ | ||||
| switch (strip->type) { | switch (strip->type) { | ||||
| case NLASTRIP_TYPE_CLIP: /* action-clip */ | case NLASTRIP_TYPE_CLIP: /* action-clip */ | ||||
| nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes, snapshot); | nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes, snapshot); | ||||
| break; | break; | ||||
| case NLASTRIP_TYPE_TRANSITION: /* transition */ | case NLASTRIP_TYPE_TRANSITION: /* transition */ | ||||
| nlastrip_evaluate_transition(ptr, channels, modifiers, nes, snapshot, flush_to_original); | nlastrip_evaluate_transition( | ||||
| ptr, channels, modifiers, nes, snapshot, anim_eval_context, flush_to_original); | |||||
| break; | break; | ||||
| case NLASTRIP_TYPE_META: /* meta */ | case NLASTRIP_TYPE_META: /* meta */ | ||||
| nlastrip_evaluate_meta(ptr, channels, modifiers, nes, snapshot, flush_to_original); | nlastrip_evaluate_meta( | ||||
| ptr, channels, modifiers, nes, snapshot, anim_eval_context, flush_to_original); | |||||
| break; | break; | ||||
| default: /* do nothing */ | default: /* do nothing */ | ||||
| break; | break; | ||||
| } | } | ||||
| /* clear temp recursion safe-check */ | /* clear temp recursion safe-check */ | ||||
| strip->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED; | strip->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED; | ||||
| ▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | |||||
| * \param[out] echannels: Evaluation channels with calculated values | * \param[out] echannels: Evaluation channels with calculated values | ||||
| * \param[out] r_context: If not NULL, | * \param[out] r_context: If not NULL, | ||||
| * data about the currently edited strip is stored here and excluded from value calculation. | * data about the currently edited strip is stored here and excluded from value calculation. | ||||
| * \return false if NLA evaluation isn't actually applicable. | * \return false if NLA evaluation isn't actually applicable. | ||||
| */ | */ | ||||
| static bool animsys_evaluate_nla(NlaEvalData *echannels, | static bool animsys_evaluate_nla(NlaEvalData *echannels, | ||||
| PointerRNA *ptr, | PointerRNA *ptr, | ||||
| AnimData *adt, | AnimData *adt, | ||||
| float ctime, | const AnimationEvalContext *anim_eval_context, | ||||
| const bool flush_to_original, | const bool flush_to_original, | ||||
| NlaKeyframingContext *r_context) | NlaKeyframingContext *r_context) | ||||
| { | { | ||||
| NlaTrack *nlt; | NlaTrack *nlt; | ||||
| short track_index = 0; | short track_index = 0; | ||||
| bool has_strips = false; | bool has_strips = false; | ||||
| ListBase estrips = {NULL, NULL}; | ListBase estrips = {NULL, NULL}; | ||||
| Show All 31 Lines | for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next, track_index++) { | ||||
| /* if this track has strips (but maybe they won't be suitable), set has_strips | /* if this track has strips (but maybe they won't be suitable), set has_strips | ||||
| * - used for mainly for still allowing normal action evaluation... | * - used for mainly for still allowing normal action evaluation... | ||||
| */ | */ | ||||
| if (nlt->strips.first) { | if (nlt->strips.first) { | ||||
| has_strips = true; | has_strips = true; | ||||
| } | } | ||||
| /* otherwise, get strip to evaluate for this channel */ | /* otherwise, get strip to evaluate for this channel */ | ||||
| nes = nlastrips_ctime_get_strip(&estrips, &nlt->strips, track_index, ctime, flush_to_original); | nes = nlastrips_ctime_get_strip( | ||||
| &estrips, &nlt->strips, track_index, anim_eval_context, flush_to_original); | |||||
| if (nes) { | if (nes) { | ||||
| nes->track = nlt; | nes->track = nlt; | ||||
| } | } | ||||
| } | } | ||||
| /* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack | /* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack | ||||
| * - only do this if we're not exclusively evaluating the 'solo' NLA-track | * - only do this if we're not exclusively evaluating the 'solo' NLA-track | ||||
| * - however, if the 'solo' track houses the current 'tweaking' strip, | * - however, if the 'solo' track houses the current 'tweaking' strip, | ||||
| ▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | if ((has_strips) || (adt->actstrip)) { | ||||
| /* NOTE: must set this, or else the default setting overrides, | /* NOTE: must set this, or else the default setting overrides, | ||||
| * and this setting doesn't work. */ | * 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 */ | /* add this to our list of evaluation strips */ | ||||
| if (r_context == NULL) { | if (r_context == NULL) { | ||||
| nlastrips_ctime_get_strip(&estrips, &dummy_trackslist, -1, ctime, flush_to_original); | nlastrips_ctime_get_strip( | ||||
| &estrips, &dummy_trackslist, -1, anim_eval_context, flush_to_original); | |||||
| } | } | ||||
| /* If computing the context for keyframing, store data there instead of the list. */ | /* If computing the context for keyframing, store data there instead of the list. */ | ||||
| else { | else { | ||||
| /* The extend mode here effectively controls | /* The extend mode here effectively controls | ||||
| * whether it is possible to key-frame beyond the ends. */ | * whether it is possible to key-frame beyond the ends. */ | ||||
| dummy_strip->extendmode = is_inplace_tweak ? NLASTRIP_EXTEND_NOTHING : | dummy_strip->extendmode = is_inplace_tweak ? NLASTRIP_EXTEND_NOTHING : | ||||
| NLASTRIP_EXTEND_HOLD; | NLASTRIP_EXTEND_HOLD; | ||||
| r_context->eval_strip = nes = nlastrips_ctime_get_strip( | r_context->eval_strip = nes = nlastrips_ctime_get_strip( | ||||
| NULL, &dummy_trackslist, -1, ctime, flush_to_original); | NULL, &dummy_trackslist, -1, anim_eval_context, flush_to_original); | ||||
| /* These setting combinations require no data from strips below, so exit immediately. */ | /* These setting combinations require no data from strips below, so exit immediately. */ | ||||
| if ((nes == NULL) || | if ((nes == NULL) || | ||||
| (dummy_strip->blendmode == NLASTRIP_MODE_REPLACE && dummy_strip->influence == 1.0f)) { | (dummy_strip->blendmode == NLASTRIP_MODE_REPLACE && dummy_strip->influence == 1.0f)) { | ||||
| BLI_freelistN(&estrips); | BLI_freelistN(&estrips); | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* special case - evaluate as if there isn't any NLA data */ | /* special case - evaluate as if there isn't any NLA data */ | ||||
| BLI_freelistN(&estrips); | BLI_freelistN(&estrips); | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| /* only continue if there are strips to evaluate */ | /* only continue if there are strips to evaluate */ | ||||
| if (BLI_listbase_is_empty(&estrips)) { | if (BLI_listbase_is_empty(&estrips)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* 2. for each strip, evaluate then accumulate on top of existing channels, | /* 2. for each strip, evaluate then accumulate on top of existing channels, | ||||
| * but don't set values yet. */ | * but don't set values yet. */ | ||||
| for (nes = estrips.first; nes; nes = nes->next) { | for (nes = estrips.first; nes; nes = nes->next) { | ||||
| nlastrip_evaluate(ptr, echannels, NULL, nes, &echannels->eval_snapshot, flush_to_original); | nlastrip_evaluate(ptr, | ||||
| echannels, | |||||
| NULL, | |||||
| nes, | |||||
| &echannels->eval_snapshot, | |||||
| anim_eval_context, | |||||
| flush_to_original); | |||||
| } | } | ||||
| /* 3. free temporary evaluation data that's not used elsewhere */ | /* 3. free temporary evaluation data that's not used elsewhere */ | ||||
| BLI_freelistN(&estrips); | BLI_freelistN(&estrips); | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* NLA Evaluation function (mostly for use through do_animdata) | /* NLA Evaluation function (mostly for use through do_animdata) | ||||
| * - All channels that will be affected are not cleared anymore. Instead, we just evaluate into | * - All channels that will be affected are not cleared anymore. Instead, we just evaluate into | ||||
| * some temp channels, where values can be accumulated in one go. | * some temp channels, where values can be accumulated in one go. | ||||
| */ | */ | ||||
| static void animsys_calculate_nla(PointerRNA *ptr, | static void animsys_calculate_nla(PointerRNA *ptr, | ||||
| AnimData *adt, | AnimData *adt, | ||||
| float ctime, | const AnimationEvalContext *anim_eval_context, | ||||
| const bool flush_to_original) | const bool flush_to_original) | ||||
| { | { | ||||
| NlaEvalData echannels; | NlaEvalData echannels; | ||||
| nlaeval_init(&echannels); | nlaeval_init(&echannels); | ||||
| /* evaluate the NLA stack, obtaining a set of values to flush */ | /* evaluate the NLA stack, obtaining a set of values to flush */ | ||||
| if (animsys_evaluate_nla(&echannels, ptr, adt, ctime, flush_to_original, NULL)) { | if (animsys_evaluate_nla(&echannels, ptr, adt, anim_eval_context, flush_to_original, NULL)) { | ||||
| /* reset any channels touched by currently inactive actions to default value */ | /* reset any channels touched by currently inactive actions to default value */ | ||||
| animsys_evaluate_nla_domain(ptr, &echannels, adt); | animsys_evaluate_nla_domain(ptr, &echannels, adt); | ||||
| /* flush effects of accumulating channels in NLA to the actual data they affect */ | /* flush effects of accumulating channels in NLA to the actual data they affect */ | ||||
| nladata_flush_channels(ptr, &echannels, &echannels.eval_snapshot, flush_to_original); | nladata_flush_channels(ptr, &echannels, &echannels.eval_snapshot, flush_to_original); | ||||
| } | } | ||||
| else { | else { | ||||
| /* special case - evaluate as if there isn't any NLA data */ | /* special case - evaluate as if there isn't any NLA data */ | ||||
| /* TODO: this is really just a stop-gap measure... */ | /* TODO: this is really just a stop-gap measure... */ | ||||
| if (G.debug & G_DEBUG) { | if (G.debug & G_DEBUG) { | ||||
| CLOG_WARN(&LOG, "NLA Eval: Stopgap for active action on NLA Stack - no strips case"); | CLOG_WARN(&LOG, "NLA Eval: Stopgap for active action on NLA Stack - no strips case"); | ||||
| } | } | ||||
| animsys_evaluate_action(ptr, adt->action, ctime, flush_to_original); | animsys_evaluate_action(ptr, adt->action, anim_eval_context, flush_to_original); | ||||
| } | } | ||||
| /* free temp data */ | /* free temp data */ | ||||
| nlaeval_free(&echannels); | nlaeval_free(&echannels); | ||||
| } | } | ||||
| /* ---------------------- */ | /* ---------------------- */ | ||||
| /** | /** | ||||
| * Prepare data necessary to compute correct keyframe values for NLA strips | * Prepare data necessary to compute correct keyframe values for NLA strips | ||||
| * with non-Replace mode or influence different from 1. | * with non-Replace mode or influence different from 1. | ||||
| * | * | ||||
| * \param cache: List used to cache contexts for reuse when keying | * \param cache: List used to cache contexts for reuse when keying | ||||
| * multiple channels in one operation. | * multiple channels in one operation. | ||||
| * \param ptr: RNA pointer to the Object with the animation. | * \param ptr: RNA pointer to the Object with the animation. | ||||
| * \return Keyframing context, or NULL if not necessary. | * \return Keyframing context, or NULL if not necessary. | ||||
| */ | */ | ||||
| NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(struct ListBase *cache, | NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context( | ||||
| struct ListBase *cache, | |||||
| struct PointerRNA *ptr, | struct PointerRNA *ptr, | ||||
| struct AnimData *adt, | struct AnimData *adt, | ||||
| float ctime, | const AnimationEvalContext *anim_eval_context, | ||||
| const bool flush_to_original) | const bool flush_to_original) | ||||
| { | { | ||||
| /* No remapping needed if NLA is off or no action. */ | /* No remapping needed if NLA is off or no action. */ | ||||
| if ((adt == NULL) || (adt->action == NULL) || (adt->nla_tracks.first == NULL) || | if ((adt == NULL) || (adt->action == NULL) || (adt->nla_tracks.first == NULL) || | ||||
| (adt->flag & ADT_NLA_EVAL_OFF)) { | (adt->flag & ADT_NLA_EVAL_OFF)) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* No remapping if editing an ordinary Replace action with full influence. */ | /* No remapping if editing an ordinary Replace action with full influence. */ | ||||
| if (!(adt->flag & ADT_NLA_EDIT_ON) && | 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)) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* Try to find a cached context. */ | /* Try to find a cached context. */ | ||||
| NlaKeyframingContext *ctx = BLI_findptr(cache, adt, offsetof(NlaKeyframingContext, adt)); | NlaKeyframingContext *ctx = BLI_findptr(cache, adt, offsetof(NlaKeyframingContext, adt)); | ||||
| if (ctx == NULL) { | if (ctx == NULL) { | ||||
| /* Allocate and evaluate a new context. */ | /* Allocate and evaluate a new context. */ | ||||
| ctx = MEM_callocN(sizeof(*ctx), "NlaKeyframingContext"); | ctx = MEM_callocN(sizeof(*ctx), "NlaKeyframingContext"); | ||||
| ctx->adt = adt; | ctx->adt = adt; | ||||
| nlaeval_init(&ctx->nla_channels); | nlaeval_init(&ctx->nla_channels); | ||||
| animsys_evaluate_nla(&ctx->nla_channels, ptr, adt, ctime, flush_to_original, ctx); | animsys_evaluate_nla(&ctx->nla_channels, ptr, adt, anim_eval_context, flush_to_original, ctx); | ||||
| BLI_assert(ELEM(ctx->strip.act, NULL, adt->action)); | BLI_assert(ELEM(ctx->strip.act, NULL, adt->action)); | ||||
| BLI_addtail(cache, ctx); | BLI_addtail(cache, ctx); | ||||
| } | } | ||||
| return ctx; | return ctx; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 173 Lines • ▼ Show 20 Lines | |||||
| */ | */ | ||||
| /* Evaluation loop for evaluation animation data | /* Evaluation loop for evaluation animation data | ||||
| * | * | ||||
| * This assumes that the animation-data provided belongs to the ID block in question, | * This assumes that the animation-data provided belongs to the ID block in question, | ||||
| * and that the flags for which parts of the anim-data settings need to be recalculated | * and that the flags for which parts of the anim-data settings need to be recalculated | ||||
| * have been set already by the depsgraph. Now, we use the recalc | * have been set already by the depsgraph. Now, we use the recalc | ||||
| */ | */ | ||||
| void BKE_animsys_evaluate_animdata( | void BKE_animsys_evaluate_animdata(ID *id, | ||||
| ID *id, AnimData *adt, float ctime, eAnimData_Recalc recalc, const bool flush_to_original) | AnimData *adt, | ||||
| const AnimationEvalContext *anim_eval_context, | |||||
| eAnimData_Recalc recalc, | |||||
| const bool flush_to_original) | |||||
| { | { | ||||
| PointerRNA id_ptr; | PointerRNA id_ptr; | ||||
| /* sanity checks */ | /* sanity checks */ | ||||
| if (ELEM(NULL, id, adt)) { | if (ELEM(NULL, id, adt)) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* get pointer to ID-block for RNA to use */ | /* get pointer to ID-block for RNA to use */ | ||||
| RNA_id_pointer_create(id, &id_ptr); | RNA_id_pointer_create(id, &id_ptr); | ||||
| /* recalculate keyframe data: | /* recalculate keyframe data: | ||||
| * - NLA before Active Action, as Active Action behaves as 'tweaking track' | * - NLA before Active Action, as Active Action behaves as 'tweaking track' | ||||
| * that overrides 'rough' work in NLA | * that overrides 'rough' work in NLA | ||||
| */ | */ | ||||
| /* TODO: need to double check that this all works correctly */ | /* TODO: need to double check that this all works correctly */ | ||||
| if (recalc & ADT_RECALC_ANIM) { | if (recalc & ADT_RECALC_ANIM) { | ||||
| /* evaluate NLA data */ | /* evaluate NLA data */ | ||||
| if ((adt->nla_tracks.first) && !(adt->flag & ADT_NLA_EVAL_OFF)) { | if ((adt->nla_tracks.first) && !(adt->flag & ADT_NLA_EVAL_OFF)) { | ||||
| /* evaluate NLA-stack | /* evaluate NLA-stack | ||||
| * - active action is evaluated as part of the NLA stack as the last item | * - active action is evaluated as part of the NLA stack as the last item | ||||
| */ | */ | ||||
| animsys_calculate_nla(&id_ptr, adt, ctime, flush_to_original); | animsys_calculate_nla(&id_ptr, adt, anim_eval_context, flush_to_original); | ||||
| } | } | ||||
| /* evaluate Active Action only */ | /* evaluate Active Action only */ | ||||
| else if (adt->action) { | else if (adt->action) { | ||||
| animsys_evaluate_action_ex(&id_ptr, adt->action, ctime, flush_to_original); | animsys_evaluate_action_ex(&id_ptr, adt->action, anim_eval_context, flush_to_original); | ||||
| } | } | ||||
| } | } | ||||
| /* recalculate drivers | /* recalculate drivers | ||||
| * - Drivers need to be evaluated afterwards, as they can either override | * - Drivers need to be evaluated afterwards, as they can either override | ||||
| * or be layered on top of existing animation data. | * or be layered on top of existing animation data. | ||||
| * - Drivers should be in the appropriate order to be evaluated without problems... | * - Drivers should be in the appropriate order to be evaluated without problems... | ||||
| */ | */ | ||||
| if (recalc & ADT_RECALC_DRIVERS) { | if (recalc & ADT_RECALC_DRIVERS) { | ||||
| animsys_evaluate_drivers(&id_ptr, adt, ctime); | animsys_evaluate_drivers(&id_ptr, adt, anim_eval_context); | ||||
| } | } | ||||
| /* always execute 'overrides' | /* always execute 'overrides' | ||||
| * - Overrides allow editing, by overwriting the value(s) set from animation-data, with the | * - Overrides allow editing, by overwriting the value(s) set from animation-data, with the | ||||
| * value last set by the user (and not keyframed yet). | * value last set by the user (and not keyframed yet). | ||||
| * - Overrides are cleared upon frame change and/or keyframing | * - Overrides are cleared upon frame change and/or keyframing | ||||
| * - It is best that we execute this every time, so that no errors are likely to occur. | * - It is best that we execute this every time, so that no errors are likely to occur. | ||||
| */ | */ | ||||
| Show All 11 Lines | |||||
| { | { | ||||
| ID *id; | ID *id; | ||||
| if (G.debug & G_DEBUG) { | if (G.debug & G_DEBUG) { | ||||
| printf("Evaluate all animation - %f\n", ctime); | printf("Evaluate all animation - %f\n", ctime); | ||||
| } | } | ||||
| const bool flush_to_original = DEG_is_active(depsgraph); | const bool flush_to_original = DEG_is_active(depsgraph); | ||||
| const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph, | |||||
| ctime); | |||||
| /* macros for less typing | /* macros for less typing | ||||
| * - only evaluate animation data for id if it has users (and not just fake ones) | * - only evaluate animation data for id if it has users (and not just fake ones) | ||||
| * - whether animdata exists is checked for by the evaluation function, though taking | * - whether animdata exists is checked for by the evaluation function, though taking | ||||
| * this outside of the function may make things slightly faster? | * this outside of the function may make things slightly faster? | ||||
| */ | */ | ||||
| #define EVAL_ANIM_IDS(first, aflag) \ | #define EVAL_ANIM_IDS(first, aflag) \ | ||||
| for (id = first; id; id = id->next) { \ | for (id = first; id; id = id->next) { \ | ||||
| if (ID_REAL_USERS(id) > 0) { \ | if (ID_REAL_USERS(id) > 0) { \ | ||||
| AnimData *adt = BKE_animdata_from_id(id); \ | AnimData *adt = BKE_animdata_from_id(id); \ | ||||
| BKE_animsys_evaluate_animdata(id, adt, ctime, aflag, flush_to_original); \ | BKE_animsys_evaluate_animdata(id, adt, &anim_eval_context, aflag, flush_to_original); \ | ||||
| } \ | } \ | ||||
| } \ | } \ | ||||
| (void)0 | (void)0 | ||||
| /* another macro for the "embedded" nodetree cases | /* another macro for the "embedded" nodetree cases | ||||
| * - this is like EVAL_ANIM_IDS, but this handles the case "embedded nodetrees" | * - this is like EVAL_ANIM_IDS, but this handles the case "embedded nodetrees" | ||||
| * (i.e. scene/material/texture->nodetree) which we need a special exception | * (i.e. scene/material/texture->nodetree) which we need a special exception | ||||
| * for, otherwise they'd get skipped | * for, otherwise they'd get skipped | ||||
| * - 'ntp' stands for "node tree parent" = data-block where node tree stuff resides | * - 'ntp' stands for "node tree parent" = data-block where node tree stuff resides | ||||
| */ | */ | ||||
| #define EVAL_ANIM_NODETREE_IDS(first, NtId_Type, aflag) \ | #define EVAL_ANIM_NODETREE_IDS(first, NtId_Type, aflag) \ | ||||
| for (id = first; id; id = id->next) { \ | for (id = first; id; id = id->next) { \ | ||||
| if (ID_REAL_USERS(id) > 0) { \ | if (ID_REAL_USERS(id) > 0) { \ | ||||
| AnimData *adt = BKE_animdata_from_id(id); \ | AnimData *adt = BKE_animdata_from_id(id); \ | ||||
| NtId_Type *ntp = (NtId_Type *)id; \ | NtId_Type *ntp = (NtId_Type *)id; \ | ||||
| if (ntp->nodetree) { \ | if (ntp->nodetree) { \ | ||||
| AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \ | AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \ | ||||
| BKE_animsys_evaluate_animdata( \ | BKE_animsys_evaluate_animdata( \ | ||||
| &ntp->nodetree->id, adt2, ctime, ADT_RECALC_ANIM, flush_to_original); \ | &ntp->nodetree->id, adt2, &anim_eval_context, ADT_RECALC_ANIM, flush_to_original); \ | ||||
| } \ | } \ | ||||
| BKE_animsys_evaluate_animdata(id, adt, ctime, aflag, flush_to_original); \ | BKE_animsys_evaluate_animdata(id, adt, &anim_eval_context, aflag, flush_to_original); \ | ||||
| } \ | } \ | ||||
| } \ | } \ | ||||
| (void)0 | (void)0 | ||||
| /* optimization: | /* optimization: | ||||
| * when there are no actions, don't go over database and loop over heaps of data-blocks, | * when there are no actions, don't go over database and loop over heaps of data-blocks, | ||||
| * which should ultimately be empty, since it is not possible for now to have any animation | * which should ultimately be empty, since it is not possible for now to have any animation | ||||
| * without some actions, and drivers wouldn't get affected by any state changes | * without some actions, and drivers wouldn't get affected by any state changes | ||||
| ▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | |||||
| void BKE_animsys_eval_animdata(Depsgraph *depsgraph, ID *id) | void BKE_animsys_eval_animdata(Depsgraph *depsgraph, ID *id) | ||||
| { | { | ||||
| float ctime = DEG_get_ctime(depsgraph); | float ctime = DEG_get_ctime(depsgraph); | ||||
| AnimData *adt = BKE_animdata_from_id(id); | AnimData *adt = BKE_animdata_from_id(id); | ||||
| /* XXX: this is only needed for flushing RNA updates, | /* XXX: this is only needed for flushing RNA updates, | ||||
| * which should get handled as part of the dependency graph instead. */ | * which should get handled as part of the dependency graph instead. */ | ||||
| DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime); | DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime); | ||||
| const bool flush_to_original = DEG_is_active(depsgraph); | const bool flush_to_original = DEG_is_active(depsgraph); | ||||
| BKE_animsys_evaluate_animdata(id, adt, ctime, ADT_RECALC_ANIM, flush_to_original); | |||||
| const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph, | |||||
| ctime); | |||||
| BKE_animsys_evaluate_animdata(id, adt, &anim_eval_context, ADT_RECALC_ANIM, flush_to_original); | |||||
| } | } | ||||
| void BKE_animsys_update_driver_array(ID *id) | void BKE_animsys_update_driver_array(ID *id) | ||||
| { | { | ||||
| AnimData *adt = BKE_animdata_from_id(id); | AnimData *adt = BKE_animdata_from_id(id); | ||||
| /* Runtime driver map to avoid O(n^2) lookups in BKE_animsys_eval_driver. | /* Runtime driver map to avoid O(n^2) lookups in BKE_animsys_eval_driver. | ||||
| * Ideally the depsgraph could pass a pointer to the COW driver directly, | * Ideally the depsgraph could pass a pointer to the COW driver directly, | ||||
| ▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID)) { | ||||
| * NOTE: for 'layering' option later on, we should check if we should remove old value before | * NOTE: for 'layering' option later on, we should check if we should remove old value before | ||||
| * adding new to only be done when drivers only changed */ | * adding new to only be done when drivers only changed */ | ||||
| // printf("\told val = %f\n", fcu->curval); | // printf("\told val = %f\n", fcu->curval); | ||||
| PathResolvedRNA anim_rna; | PathResolvedRNA anim_rna; | ||||
| if (BKE_animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { | if (BKE_animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { | ||||
| /* Evaluate driver, and write results to COW-domain destination */ | /* Evaluate driver, and write results to COW-domain destination */ | ||||
| const float ctime = DEG_get_ctime(depsgraph); | const float ctime = DEG_get_ctime(depsgraph); | ||||
| const float curval = calculate_fcurve(&anim_rna, fcu, ctime); | const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct( | ||||
| depsgraph, ctime); | |||||
| const float curval = calculate_fcurve(&anim_rna, fcu, &anim_eval_context); | |||||
| ok = BKE_animsys_write_rna_setting(&anim_rna, curval); | ok = BKE_animsys_write_rna_setting(&anim_rna, curval); | ||||
| /* Flush results & status codes to original data for UI (T59984) */ | /* Flush results & status codes to original data for UI (T59984) */ | ||||
| if (ok && DEG_is_active(depsgraph)) { | if (ok && DEG_is_active(depsgraph)) { | ||||
| animsys_write_orig_anim_rna(&id_ptr, fcu->rna_path, fcu->array_index, curval); | animsys_write_orig_anim_rna(&id_ptr, fcu->rna_path, fcu->array_index, curval); | ||||
| /* curval is displayed in the UI, and flag contains error-status codes */ | /* curval is displayed in the UI, and flag contains error-status codes */ | ||||
| fcu_orig->curval = fcu->curval; | fcu_orig->curval = fcu->curval; | ||||
| Show All 26 Lines | |||||