Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/anim_sys.c
| Show First 20 Lines • Show All 615 Lines • ▼ Show 20 Lines | if (BKE_animsys_rna_path_resolve(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { | ||||
| BKE_animsys_write_to_rna_path(&anim_rna, curval); | BKE_animsys_write_to_rna_path(&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); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* This function assumes that the quaternion is fully keyed, and is stored in array index order. */ | |||||
| static void animsys_quaternion_evaluate_fcurves(PathResolvedRNA quat_rna, | |||||
| FCurve *first_fcurve, | |||||
| const AnimationEvalContext *anim_eval_context, | |||||
| float r_quaternion[4]) | |||||
| { | |||||
| FCurve *quat_curve_fcu = first_fcurve; | |||||
| for (int prop_index = 0; prop_index < 4; ++prop_index, quat_curve_fcu = quat_curve_fcu->next) { | |||||
| /* Big fat assumption that the quaternion is fully keyed, and stored in order. */ | |||||
| BLI_assert(STREQ(quat_curve_fcu->rna_path, first_fcurve->rna_path) && | |||||
| quat_curve_fcu->array_index == prop_index); | |||||
| quat_rna.prop_index = prop_index; | |||||
| r_quaternion[prop_index] = calculate_fcurve(&quat_rna, quat_curve_fcu, anim_eval_context); | |||||
| } | |||||
| } | |||||
| /* This function assumes that the quaternion is fully keyed, and is stored in array index order. */ | |||||
| static void animsys_blend_fcurves_quaternion(PathResolvedRNA *anim_rna, | |||||
| FCurve *first_fcurve, | |||||
| const AnimationEvalContext *anim_eval_context, | |||||
| const float blend_factor) | |||||
| { | |||||
| float current_quat[4]; | |||||
| RNA_property_float_get_array(&anim_rna->ptr, anim_rna->prop, current_quat); | |||||
| float target_quat[4]; | |||||
| animsys_quaternion_evaluate_fcurves(*anim_rna, first_fcurve, anim_eval_context, target_quat); | |||||
| float blended_quat[4]; | |||||
| interp_qt_qtqt(blended_quat, current_quat, target_quat, blend_factor); | |||||
| RNA_property_float_set_array(&anim_rna->ptr, anim_rna->prop, blended_quat); | |||||
| } | |||||
| /* LERP between current value (blend_factor=0.0) and the value from the FCurve (blend_factor=1.0) | |||||
| */ | |||||
| static void animsys_blend_in_fcurves(PointerRNA *ptr, | |||||
| ListBase *fcurves, | |||||
| const AnimationEvalContext *anim_eval_context, | |||||
| const float blend_factor) | |||||
| { | |||||
| char *channel_to_skip = NULL; | |||||
| int num_channels_to_skip = 0; | |||||
| LISTBASE_FOREACH (FCurve *, fcu, fcurves) { | |||||
| if (num_channels_to_skip) { | |||||
| /* For skipping already-handled rotation channels. Rotation channels are handled per group, | |||||
| * and not per individual channel. */ | |||||
| BLI_assert(channel_to_skip != NULL); | |||||
| if (STREQ(channel_to_skip, fcu->rna_path)) { | |||||
| /* This is indeed the channel we want to skip. */ | |||||
| num_channels_to_skip--; | |||||
| continue; | |||||
| } | |||||
| } | |||||
| if (!is_fcurve_evaluatable(fcu)) { | |||||
| continue; | |||||
| } | |||||
| PathResolvedRNA anim_rna; | |||||
| if (!BKE_animsys_rna_path_resolve(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { | |||||
| continue; | |||||
| } | |||||
| if (STREQ(RNA_property_identifier(anim_rna.prop), "rotation_quaternion")) { | |||||
| animsys_blend_fcurves_quaternion(&anim_rna, fcu, anim_eval_context, blend_factor); | |||||
| /* Skip the next three channels, because those have already been handled here. */ | |||||
| MEM_SAFE_FREE(channel_to_skip); | |||||
| channel_to_skip = BLI_strdup(fcu->rna_path); | |||||
| num_channels_to_skip = 3; | |||||
| continue; | |||||
| } | |||||
| /* TODO(Sybren): do something similar as above for Euler and Axis/Angle representations. */ | |||||
| const float fcurve_value = calculate_fcurve(&anim_rna, fcu, anim_eval_context); | |||||
| float current_value; | |||||
| float value_to_write; | |||||
| if (BKE_animsys_read_from_rna_path(&anim_rna, ¤t_value)) { | |||||
| value_to_write = (1 - blend_factor) * current_value + blend_factor * fcurve_value; | |||||
| switch (RNA_property_type(anim_rna.prop)) { | |||||
| case PROP_BOOLEAN: | |||||
| /* Without this, anything less than 1.0 is converted to 'False' by | |||||
| * ANIMSYS_FLOAT_AS_BOOL(). This is probably not desirable for blends, where anything | |||||
| * above a 50% blend should act more like the FCurve than like the current value. */ | |||||
| case PROP_INT: | |||||
| case PROP_ENUM: | |||||
| value_to_write = roundf(value_to_write); | |||||
| break; | |||||
| default: | |||||
| /* All other types are just handled as float, and value_to_write is already correct. */ | |||||
| break; | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* Unable to read the current value for blending, so just apply the FCurve value instead. */ | |||||
| value_to_write = fcurve_value; | |||||
| } | |||||
| BKE_animsys_write_to_rna_path(&anim_rna, value_to_write); | |||||
| } | |||||
| MEM_SAFE_FREE(channel_to_skip); | |||||
| } | |||||
| /* ***************************************** */ | /* ***************************************** */ | ||||
| /* Driver Evaluation */ | /* Driver Evaluation */ | ||||
| AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, | AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, | ||||
| float eval_time) | float eval_time) | ||||
| { | { | ||||
| AnimationEvalContext ctx = { | AnimationEvalContext ctx = { | ||||
| .depsgraph = depsgraph, | .depsgraph = depsgraph, | ||||
| ▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Lines | void animsys_evaluate_action(PointerRNA *ptr, | ||||
| } | } | ||||
| 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, anim_eval_context, flush_to_original); | animsys_evaluate_fcurves(ptr, &act->curves, anim_eval_context, flush_to_original); | ||||
| } | } | ||||
| /* Evaluate Action and blend it into the current values of the animated properties. */ | |||||
| void animsys_blend_in_action(PointerRNA *ptr, | |||||
| bAction *act, | |||||
| const AnimationEvalContext *anim_eval_context, | |||||
| const float blend_factor) | |||||
| { | |||||
| action_idcode_patch_check(ptr->owner_id, act); | |||||
| animsys_blend_in_fcurves(ptr, &act->curves, anim_eval_context, blend_factor); | |||||
| } | |||||
| /* ***************************************** */ | /* ***************************************** */ | ||||
| /* 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) | ||||
| { | { | ||||
| /* sanity checks - normalize the blendin/out values? */ | /* sanity checks - normalize the blendin/out values? */ | ||||
| strip->blendin = fabsf(strip->blendin); | strip->blendin = fabsf(strip->blendin); | ||||
| ▲ Show 20 Lines • Show All 672 Lines • ▼ Show 20 Lines | case NLASTRIP_MODE_SUBTRACT: | ||||
| /* Simply subtract the scaled value from the stack. */ | /* Simply subtract the scaled value from the stack. */ | ||||
| return lower_value - (strip_value * influence); | return lower_value - (strip_value * influence); | ||||
| case NLASTRIP_MODE_MULTIPLY: | case NLASTRIP_MODE_MULTIPLY: | ||||
| /* Multiply the scaled value with the stack. */ | /* Multiply the scaled value with the stack. */ | ||||
| return influence * (lower_value * strip_value) + (1 - influence) * lower_value; | return influence * (lower_value * strip_value) + (1 - influence) * lower_value; | ||||
| case NLASTRIP_MODE_COMBINE: | case NLASTRIP_MODE_COMBINE: | ||||
| BLI_assert(!"combine mode"); | BLI_assert_msg(0, "combine mode"); | ||||
| ATTR_FALLTHROUGH; | ATTR_FALLTHROUGH; | ||||
| default: | default: | ||||
| /* TODO: Do we really want to blend by default? it seems more uses might prefer add... */ | /* TODO: Do we really want to blend by default? it seems more uses might prefer add... */ | ||||
| /* Do linear interpolation. The influence of the accumulated data (elsewhere, that is called | /* Do linear interpolation. The influence of the accumulated data (elsewhere, that is called | ||||
| * dstweight) is 1 - influence, since the strip's influence is srcweight. | * dstweight) is 1 - influence, since the strip's influence is srcweight. | ||||
| */ | */ | ||||
| return lower_value * (1.0f - influence) + (strip_value * influence); | return lower_value * (1.0f - influence) + (strip_value * influence); | ||||
| Show All 21 Lines | switch (mix_mode) { | ||||
| case NEC_MIX_MULTIPLY: | case NEC_MIX_MULTIPLY: | ||||
| if (IS_EQF(base_value, 0.0f)) { | if (IS_EQF(base_value, 0.0f)) { | ||||
| base_value = 1.0f; | base_value = 1.0f; | ||||
| } | } | ||||
| return lower_value * powf(strip_value / base_value, influence); | return lower_value * powf(strip_value / base_value, influence); | ||||
| default: | default: | ||||
| BLI_assert(!"invalid mix mode"); | BLI_assert_msg(0, "invalid mix mode"); | ||||
| return lower_value; | return lower_value; | ||||
| } | } | ||||
| } | } | ||||
| /** \returns true if solution exists and output is written to. */ | /** \returns true if solution exists and output is written to. */ | ||||
| static bool nla_blend_get_inverted_strip_value(const int blendmode, | static bool nla_blend_get_inverted_strip_value(const int blendmode, | ||||
| const float lower_value, | const float lower_value, | ||||
| const float blended_value, | const float blended_value, | ||||
| Show All 34 Lines | case NLASTRIP_MODE_MULTIPLY: | ||||
| * ((blended_value - lower_value) / (inf * lower_value)) + 1 = strip_value | * ((blended_value - lower_value) / (inf * lower_value)) + 1 = strip_value | ||||
| * | * | ||||
| * strip_value = ((blended_value - lower_value) / (inf * lower_value)) + 1 | * strip_value = ((blended_value - lower_value) / (inf * lower_value)) + 1 | ||||
| */ | */ | ||||
| *r_strip_value = ((blended_value - lower_value) / (influence * lower_value)) + 1.0f; | *r_strip_value = ((blended_value - lower_value) / (influence * lower_value)) + 1.0f; | ||||
| return true; | return true; | ||||
| case NLASTRIP_MODE_COMBINE: | case NLASTRIP_MODE_COMBINE: | ||||
| BLI_assert(!"combine mode"); | BLI_assert_msg(0, "combine mode"); | ||||
| ATTR_FALLTHROUGH; | ATTR_FALLTHROUGH; | ||||
| default: | default: | ||||
| /** Math: | /** Math: | ||||
| * | * | ||||
| * blended_value = lower_value * (1.0f - inf) + (strip_value * inf) | * blended_value = lower_value * (1.0f - inf) + (strip_value * inf) | ||||
| * blended_value - lower_value * (1.0f - inf) = (strip_value * inf) | * blended_value - lower_value * (1.0f - inf) = (strip_value * inf) | ||||
| Show All 39 Lines | case NEC_MIX_MULTIPLY: | ||||
| /* Division by zero. */ | /* Division by zero. */ | ||||
| return false; | return false; | ||||
| } | } | ||||
| *r_strip_value = base_value * powf(blended_value / lower_value, 1.0f / influence); | *r_strip_value = base_value * powf(blended_value / lower_value, 1.0f / influence); | ||||
| return true; | return true; | ||||
| default: | default: | ||||
| BLI_assert(!"invalid mix mode"); | BLI_assert_msg(0, "invalid mix mode"); | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Accumulate quaternion channels for Combine mode according to influence. | * Accumulate quaternion channels for Combine mode according to influence. | ||||
| * \returns `blended_value = lower_values @ strip_values^infl` | * \returns `blended_value = lower_values @ strip_values^infl` | ||||
| */ | */ | ||||
| ▲ Show 20 Lines • Show All 209 Lines • ▼ Show 20 Lines | case NLASTRIP_MODE_COMBINE: { | ||||
| } | } | ||||
| case NEC_MIX_ADD: | case NEC_MIX_ADD: | ||||
| case NEC_MIX_AXIS_ANGLE: | case NEC_MIX_AXIS_ANGLE: | ||||
| case NEC_MIX_MULTIPLY: { | case NEC_MIX_MULTIPLY: { | ||||
| nlaevalchan_combine_value(lower_necs, upper_necs, upper_influence, r_blended_necs); | nlaevalchan_combine_value(lower_necs, upper_necs, upper_influence, r_blended_necs); | ||||
| return; | return; | ||||
| } | } | ||||
| default: | default: | ||||
| BLI_assert("Mix mode should've been handled"); | BLI_assert_msg(0, "Mix mode should've been handled"); | ||||
| } | } | ||||
| return; | return; | ||||
| } | } | ||||
| case NLASTRIP_MODE_ADD: | case NLASTRIP_MODE_ADD: | ||||
| case NLASTRIP_MODE_SUBTRACT: | case NLASTRIP_MODE_SUBTRACT: | ||||
| case NLASTRIP_MODE_MULTIPLY: | case NLASTRIP_MODE_MULTIPLY: | ||||
| case NLASTRIP_MODE_REPLACE: { | case NLASTRIP_MODE_REPLACE: { | ||||
| nlaevalchan_blend_value( | nlaevalchan_blend_value( | ||||
| lower_necs, upper_necs, upper_blendmode, upper_influence, r_blended_necs); | lower_necs, upper_necs, upper_blendmode, upper_influence, r_blended_necs); | ||||
| return; | return; | ||||
| } | } | ||||
| default: | default: | ||||
| BLI_assert("Blend mode should've been handled"); | BLI_assert_msg(0, "Blend mode should've been handled"); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Based on blend-mode, solve for the upper values such that when lower blended with upper then we | * Based on blend-mode, solve for the upper values such that when lower blended with upper then we | ||||
| * get blended values as a result. | * get blended values as a result. | ||||
| * | * | ||||
| * Only processes blended values in the remap domain. Successfully remapped upper values are placed | * Only processes blended values in the remap domain. Successfully remapped upper values are placed | ||||
| ▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | case NLASTRIP_MODE_COMBINE: { | ||||
| case NEC_MIX_ADD: | case NEC_MIX_ADD: | ||||
| case NEC_MIX_AXIS_ANGLE: | case NEC_MIX_AXIS_ANGLE: | ||||
| case NEC_MIX_MULTIPLY: { | case NEC_MIX_MULTIPLY: { | ||||
| nlaevalchan_combine_value_get_inverted_upper_evalchan( | nlaevalchan_combine_value_get_inverted_upper_evalchan( | ||||
| lower_necs, blended_necs, upper_influence, r_upper_necs); | lower_necs, blended_necs, upper_influence, r_upper_necs); | ||||
| return; | return; | ||||
| } | } | ||||
| default: | default: | ||||
| BLI_assert("Mix mode should've been handled"); | BLI_assert_msg(0, "Mix mode should've been handled"); | ||||
| } | } | ||||
| return; | return; | ||||
| } | } | ||||
| case NLASTRIP_MODE_ADD: | case NLASTRIP_MODE_ADD: | ||||
| case NLASTRIP_MODE_SUBTRACT: | case NLASTRIP_MODE_SUBTRACT: | ||||
| case NLASTRIP_MODE_MULTIPLY: | case NLASTRIP_MODE_MULTIPLY: | ||||
| case NLASTRIP_MODE_REPLACE: { | case NLASTRIP_MODE_REPLACE: { | ||||
| nlaevalchan_blend_value_get_inverted_upper_evalchan( | nlaevalchan_blend_value_get_inverted_upper_evalchan( | ||||
| lower_necs, blended_necs, upper_blendmode, upper_influence, r_upper_necs); | lower_necs, blended_necs, upper_blendmode, upper_influence, r_upper_necs); | ||||
| return; | return; | ||||
| } | } | ||||
| default: | default: | ||||
| BLI_assert("Blend mode should've been handled"); | BLI_assert_msg(0, "Blend mode should've been handled"); | ||||
| } | } | ||||
| } | } | ||||
| /* ---------------------- */ | /* ---------------------- */ | ||||
| /* F-Modifier stack joining/separation utilities - | /* F-Modifier stack joining/separation utilities - | ||||
| * should we generalize these for BLI_listbase.h interface? */ | * should we generalize these for BLI_listbase.h interface? */ | ||||
| /* Temporarily join two lists of modifiers together, storing the result in a third list */ | /* Temporarily join two lists of modifiers together, storing the result in a third list */ | ||||
| ▲ Show 20 Lines • Show All 1,012 Lines • ▼ Show 20 Lines | bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, | ||||
| NlaEvalChannelKey key = { | NlaEvalChannelKey key = { | ||||
| .ptr = *prop_ptr, | .ptr = *prop_ptr, | ||||
| .prop = prop, | .prop = prop, | ||||
| }; | }; | ||||
| NlaEvalChannel *nec = nlaevalchan_verify_key(eval_data, NULL, &key); | NlaEvalChannel *nec = nlaevalchan_verify_key(eval_data, NULL, &key); | ||||
| BLI_assert(nec); | BLI_assert(nec); | ||||
| if (nec->base_snapshot.length != count) { | if (nec->base_snapshot.length != count) { | ||||
| BLI_assert(!"invalid value count"); | BLI_assert_msg(0, "invalid value count"); | ||||
| nlaeval_snapshot_free_data(&blended_snapshot); | nlaeval_snapshot_free_data(&blended_snapshot); | ||||
| return false; | return false; | ||||
| } | } | ||||
| NlaEvalChannelSnapshot *blended_necs = nlaeval_snapshot_ensure_channel(&blended_snapshot, nec); | NlaEvalChannelSnapshot *blended_necs = nlaeval_snapshot_ensure_channel(&blended_snapshot, nec); | ||||
| memcpy(blended_necs->values, values, sizeof(float) * count); | memcpy(blended_necs->values, values, sizeof(float) * count); | ||||
| BLI_bitmap_set_all(blended_necs->remap_domain.ptr, true, count); | BLI_bitmap_set_all(blended_necs->remap_domain.ptr, true, count); | ||||
| ▲ Show 20 Lines • Show All 433 Lines • Show Last 20 Lines | |||||