diff options
author | Alexander Gavrilov <angavrilov@gmail.com> | 2019-01-08 18:49:38 +0300 |
---|---|---|
committer | Alexander Gavrilov <angavrilov@gmail.com> | 2019-01-14 19:14:28 +0300 |
commit | 9c1a961dc423d2eb19b875564bb4bb3c0b297ca5 (patch) | |
tree | 4abdc2ad84252ce4f0535386e4447d1e494c6096 | |
parent | 1665278c14faa2a51ff2f0e33947b73aada25b12 (diff) |
Keyframing: refactor insertion code to allow property-global NLA tweaks.
Supporting a strip blending type that treats quaternions as a unit
also means being able to adjust all sub-channels as a unit when
inserting keyframes. This requires refactoring keyframe insertion
code to retrieve array property values for all channels at once,
before iterating over the indices being inserted.
-rw-r--r-- | source/blender/blenkernel/BKE_animsys.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/anim_sys.c | 36 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframing.c | 454 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_anim.c | 7 |
4 files changed, 325 insertions, 174 deletions
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 7cdb62712e8..b49eb182981 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -177,7 +177,7 @@ void BKE_fcurves_main_cb(struct Main *bmain, ID_FCurve_Edit_Callback func, void 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); +bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, struct PointerRNA *prop_ptr, struct PropertyRNA *prop, float *values, int count, int index, bool *r_force_all); void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache); /* ************************************* */ diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 5ec3b931f09..8928ecbb5e2 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -3106,16 +3106,22 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context( } /** - * Apply correction from the NLA context to the value about to be keyframed. + * Apply correction from the NLA context to the values 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. + * @param[in,out] values Array of property values to adjust. + * @param count Number of values in the array. + * @param index Index of the element about to be updated, or -1. + * @param[out] r_force_all Set to true if all channels must be inserted. May be NULL. + * @return False if correction fails due to a division by zero, or null r_force_all when all channels are required. */ -bool BKE_animsys_nla_remap_keyframe_value(struct NlaKeyframingContext *context, struct PointerRNA *prop_ptr, struct PropertyRNA *prop, int index, float *r_value) +bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, struct PointerRNA *prop_ptr, struct PropertyRNA *prop, float *values, int count, int index, bool *r_force_all) { + if (r_force_all != NULL) { + *r_force_all = false; + } + /* No context means no correction. */ if (context == NULL || context->strip.act == NULL) { return true; @@ -3143,18 +3149,26 @@ bool BKE_animsys_nla_remap_keyframe_value(struct NlaKeyframingContext *context, NlaEvalChannelKey key = { .ptr = *prop_ptr, .prop = prop, }; NlaEvalData *nlaeval = &context->nla_channels; NlaEvalChannel *nec = nlaevalchan_verify_key(nlaeval, NULL, &key); - int real_index = nlaevalchan_validate_index(nec, index); - if (real_index < 0) { - return true; + if (nec->base_snapshot.length != count) { + BLI_assert(!"invalid value count"); + return false; } - /* Invert the blending operation to compute the desired key value. */ + /* Invert the blending operation to compute the desired key values. */ NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(&nlaeval->eval_snapshot, nec); - float old_value = nec_snapshot->values[real_index]; + float *old_values = nec_snapshot->values; + + for (int i = 0; i < count; i++) { + if (ELEM(index, i, -1)) { + if (!nla_invert_blend_value(blend_mode, old_values[i], values[i], influence, &values[i])) { + return false; + } + } + } - return nla_invert_blend_value(blend_mode, old_value, *r_value, influence, r_value); + return true; } /** diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 02d5e2cb28a..84d911681b3 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -425,6 +425,9 @@ int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag) fcu->totvert++; } + else { + return -1; + } } /* no keyframes already, but can only add if... * 1) keyframing modes say that keyframes can only be replaced, so adding new ones won't know @@ -678,42 +681,73 @@ static short new_key_needed(FCurve *fcu, float cFrame, float nValue) /* ------------------ RNA Data-Access Functions ------------------ */ /* Try to read value using RNA-properties obtained already */ -static float setting_get_rna_value(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, int index, const bool get_evaluated) +static float *setting_get_rna_values(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, const bool get_evaluated, float *buffer, int buffer_size, int *r_count) { - PointerRNA ptr_eval = *ptr; - float value = 0.0f; + BLI_assert(buffer_size >= 1); + + float *values = buffer; + PointerRNA ptr_eval; if (get_evaluated) { DEG_get_evaluated_rna_pointer(depsgraph, ptr, &ptr_eval); + ptr = &ptr_eval; } - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - if (RNA_property_array_check(prop)) - value = (float)RNA_property_boolean_get_index(&ptr_eval, prop, index); - else - value = (float)RNA_property_boolean_get(&ptr_eval, prop); - break; - case PROP_INT: - if (RNA_property_array_check(prop)) - value = (float)RNA_property_int_get_index(&ptr_eval, prop, index); - else - value = (float)RNA_property_int_get(&ptr_eval, prop); - break; - case PROP_FLOAT: - if (RNA_property_array_check(prop)) - value = RNA_property_float_get_index(&ptr_eval, prop, index); - else - value = RNA_property_float_get(&ptr_eval, prop); - break; - case PROP_ENUM: - value = (float)RNA_property_enum_get(&ptr_eval, prop); - break; - default: - break; + if (RNA_property_array_check(prop)) { + int length = *r_count = RNA_property_array_length(ptr, prop); + bool *tmp_bool; + int *tmp_int; + + if (length > buffer_size) { + values = MEM_malloc_arrayN(sizeof(float), length, __func__); + } + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + tmp_bool = MEM_malloc_arrayN(sizeof(*tmp_bool), length, __func__); + RNA_property_boolean_get_array(ptr, prop, tmp_bool); + for (int i = 0; i < length; i++) { + values[i] = (float)tmp_bool[i]; + } + MEM_freeN(tmp_bool); + break; + case PROP_INT: + tmp_int = MEM_malloc_arrayN(sizeof(*tmp_int), length, __func__); + RNA_property_int_get_array(ptr, prop, tmp_int); + for (int i = 0; i < length; i++) { + values[i] = (float)tmp_int[i]; + } + MEM_freeN(tmp_int); + break; + case PROP_FLOAT: + RNA_property_float_get_array(ptr, prop, values); + break; + default: + memset(values, 0, sizeof(float) * length); + } + } + else { + *r_count = 1; + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + *values = (float)RNA_property_boolean_get(ptr, prop); + break; + case PROP_INT: + *values = (float)RNA_property_int_get(ptr, prop); + break; + case PROP_FLOAT: + *values = RNA_property_float_get(ptr, prop); + break; + case PROP_ENUM: + *values = (float)RNA_property_enum_get(ptr, prop); + break; + default: + *values = 0.0f; + } } - return value; + return values; } /* ------------------ 'Visual' Keyframing Functions ------------------ */ @@ -869,8 +903,10 @@ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) * In the event that it is not possible to perform visual keying, try to fall-back * to using the default method. Assumes that all data it has been passed is valid. */ -static float visualkey_get_value(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, int array_index) +static float *visualkey_get_values(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, float *buffer, int buffer_size, int *r_count) { + BLI_assert(buffer_size >= 4); + const char *identifier = RNA_property_identifier(prop); float tmat[4][4]; int rotmode; @@ -888,7 +924,9 @@ static float visualkey_get_value(Depsgraph *depsgraph, PointerRNA *ptr, Property /* Loc code is specific... */ if (strstr(identifier, "location")) { - return ob_eval->obmat[3][array_index]; + copy_v3_v3(buffer, ob_eval->obmat[3]); + *r_count = 3; + return buffer; } copy_m4_m4(tmat, ob_eval->obmat); @@ -907,58 +945,162 @@ static float visualkey_get_value(Depsgraph *depsgraph, PointerRNA *ptr, Property /* Loc code is specific... */ if (strstr(identifier, "location")) { /* only use for non-connected bones */ - if ((pchan->bone->parent == NULL) || !(pchan->bone->flag & BONE_CONNECTED)) - return tmat[3][array_index]; + if ((pchan->bone->parent == NULL) || !(pchan->bone->flag & BONE_CONNECTED)) { + copy_v3_v3(buffer, tmat[3]); + *r_count = 3; + return buffer; + } } } else { - return setting_get_rna_value(depsgraph, ptr, prop, array_index, true); + return setting_get_rna_values(depsgraph, ptr, prop, true, buffer, buffer_size, r_count); } /* Rot/Scale code are common! */ if (strstr(identifier, "rotation_euler")) { - float eul[3]; + mat4_to_eulO(buffer, rotmode, tmat); - mat4_to_eulO(eul, rotmode, tmat); - return eul[array_index]; + *r_count = 3; + return buffer; } else if (strstr(identifier, "rotation_quaternion")) { - float mat3[3][3], quat[4]; + float mat3[3][3]; copy_m3_m4(mat3, tmat); - mat3_to_quat_is_ok(quat, mat3); + mat3_to_quat_is_ok(buffer, mat3); - return quat[array_index]; + *r_count = 4; + return buffer; } else if (strstr(identifier, "rotation_axis_angle")) { - float axis[3], angle; - - mat4_to_axis_angle(axis, &angle, tmat); - /* w = 0, x,y,z = 1,2,3 */ - if (array_index == 0) - return angle; - else - return axis[array_index - 1]; + mat4_to_axis_angle(buffer + 1, buffer, tmat); + + *r_count = 4; + return buffer; } else if (strstr(identifier, "scale")) { - float scale[3]; - - mat4_to_size(scale, tmat); + mat4_to_size(buffer, tmat); - return scale[array_index]; + *r_count = 3; + return buffer; } /* as the function hasn't returned yet, read value from system in the default way */ - return setting_get_rna_value(depsgraph, ptr, prop, array_index, true); + return setting_get_rna_values(depsgraph, ptr, prop, true, buffer, buffer_size, r_count); } /* ------------------------- Insert Key API ------------------------- */ +/* Retrieve current property values to keyframe, possibly applying NLA correction when necessary. */ +static float *get_keyframe_values( + Depsgraph *depsgraph, ReportList *reports, PointerRNA ptr, PropertyRNA *prop, int index, + struct NlaKeyframingContext *nla_context, eInsertKeyFlags flag, + float *buffer, int buffer_size, int *r_count, bool *r_force_all) +{ + float *values; + + if ( (flag & INSERTKEY_MATRIX) && + (visualkey_can_use(&ptr, prop)) ) + { + /* visual-keying is only available for object and pchan datablocks, as + * it works by keyframing using a value extracted from the final matrix + * instead of using the kt system to extract a value. + */ + values = visualkey_get_values(depsgraph, &ptr, prop, buffer, buffer_size, r_count); + } + else { + /* read value from system */ + values = setting_get_rna_values(depsgraph, &ptr, prop, false, buffer, buffer_size, r_count); + } + + /* adjust the value for NLA factors */ + if (!BKE_animsys_nla_remap_keyframe_values(nla_context, &ptr, prop, values, *r_count, index, r_force_all)) { + BKE_report(reports, RPT_ERROR, "Could not insert keyframe due to zero NLA influence or base value"); + + if (values != buffer) { + MEM_freeN(values); + } + return NULL; + } + + return values; +} + +/* Insert the specified keyframe value into a single F-Curve. */ +static bool insert_keyframe_value(ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, FCurve *fcu, float cfra, float curval, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag) +{ + /* F-Curve not editable? */ + if (fcurve_is_keyframable(fcu) == 0) { + BKE_reportf(reports, RPT_ERROR, + "F-Curve with path '%s[%d]' cannot be keyframed, ensure that it is not locked or sampled, " + "and try removing F-Modifiers", + fcu->rna_path, fcu->array_index); + return false; + } + + /* adjust frame on which to add keyframe */ + if ((flag & INSERTKEY_DRIVER) && (fcu->driver)) { + PathResolvedRNA anim_rna; + + if (RNA_path_resolved_create(ptr, prop, fcu->array_index, &anim_rna)) { + /* for making it easier to add corrective drivers... */ + cfra = evaluate_driver(&anim_rna, fcu->driver, fcu->driver, cfra); + } + else { + cfra = 0.0f; + } + } + + /* adjust coordinates for cycle aware insertion */ + if (flag & INSERTKEY_CYCLE_AWARE) { + if (remap_cyclic_keyframe_location(fcu, &cfra, &curval) != FCU_CYCLE_PERFECT) { + /* inhibit action from insert_vert_fcurve unless it's a perfect cycle */ + flag &= ~INSERTKEY_CYCLE_AWARE; + } + } + + /* only insert keyframes where they are needed */ + if (flag & INSERTKEY_NEEDED) { + short insert_mode; + + /* check whether this curve really needs a new keyframe */ + insert_mode = new_key_needed(fcu, cfra, curval); + + /* only return success if keyframe added */ + if (insert_mode == KEYNEEDED_DONTADD) { + return false; + } + + /* insert new keyframe at current frame */ + if (insert_vert_fcurve(fcu, cfra, curval, keytype, flag) < 0) { + return false; + } + + /* delete keyframe immediately before/after newly added */ + switch (insert_mode) { + case KEYNEEDED_DELPREV: + delete_fcurve_key(fcu, fcu->totvert - 2, 1); + break; + case KEYNEEDED_DELNEXT: + delete_fcurve_key(fcu, 1, 1); + break; + } + + return true; + } + else { + /* just insert keyframe */ + return insert_vert_fcurve(fcu, cfra, curval, keytype, flag) >= 0; + } +} + /* Secondary Keyframing API call: * Use this when validation of necessary animation data is not necessary, since an RNA-pointer to the necessary * data being keyframed, and a pointer to the F-Curve to use have both been provided. * + * This function can't keyframe quaternion channels on some NLA strip types. + * * keytype is the "keyframe type" (eBezTriple_KeyframeType), as shown in the Dope Sheet. * * The flag argument is used for special settings that alter the behavior of @@ -974,14 +1116,6 @@ bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRN BKE_report(reports, RPT_ERROR, "No F-Curve to add keyframes to"); return false; } - /* F-Curve not editable? */ - if (fcurve_is_keyframable(fcu) == 0) { - BKE_reportf(reports, RPT_ERROR, - "F-Curve with path '%s[%d]' cannot be keyframed, ensure that it is not locked or sampled, " - "and try removing F-Modifiers", - fcu->rna_path, fcu->array_index); - return false; - } /* if no property given yet, try to validate from F-Curve info */ if ((ptr.id.data == NULL) && (ptr.data == NULL)) { @@ -1010,83 +1144,67 @@ bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRN /* update F-Curve flags to ensure proper behavior for property type */ update_autoflags_fcurve_direct(fcu, prop); - /* adjust frame on which to add keyframe */ - if ((flag & INSERTKEY_DRIVER) && (fcu->driver)) { - PathResolvedRNA anim_rna; + /* Obtain the value to insert. */ + float value_buffer[RNA_MAX_ARRAY_LENGTH]; + int value_count; + int index = fcu->array_index; - if (RNA_path_resolved_create(&ptr, prop, fcu->array_index, &anim_rna)) { - /* for making it easier to add corrective drivers... */ - cfra = evaluate_driver(&anim_rna, fcu->driver, fcu->driver, cfra); - } - else { - cfra = 0.0f; - } - } + float *values = get_keyframe_values(depsgraph, reports, ptr, prop, index, nla_context, flag, + value_buffer, RNA_MAX_ARRAY_LENGTH, &value_count, NULL); - /* obtain value to give keyframe */ - if ( (flag & INSERTKEY_MATRIX) && - (visualkey_can_use(&ptr, prop)) ) - { - /* visual-keying is only available for object and pchan datablocks, as - * it works by keyframing using a value extracted from the final matrix - * instead of using the kt system to extract a value. - */ - curval = visualkey_get_value(depsgraph, &ptr, prop, fcu->array_index); - } - else { - /* read value from system */ - 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"); + if (values == NULL) { + /* This happens if NLA rejects this insertion. */ return false; } - /* adjust coordinates for cycle aware insertion */ - if (flag & INSERTKEY_CYCLE_AWARE) { - if (remap_cyclic_keyframe_location(fcu, &cfra, &curval) != FCU_CYCLE_PERFECT) { - /* inhibit action from insert_vert_fcurve unless it's a perfect cycle */ - flag &= ~INSERTKEY_CYCLE_AWARE; - } + if (index >= 0 && index < value_count) { + curval = values[index]; } - /* only insert keyframes where they are needed */ - if (flag & INSERTKEY_NEEDED) { - short insert_mode; - - /* check whether this curve really needs a new keyframe */ - insert_mode = new_key_needed(fcu, cfra, curval); + if (values != value_buffer) { + MEM_freeN(values); + } - /* insert new keyframe at current frame */ - if (insert_mode) - insert_vert_fcurve(fcu, cfra, curval, keytype, flag); + return insert_keyframe_value(reports, &ptr, prop, fcu, cfra, curval, keytype, flag); +} - /* delete keyframe immediately before/after newly added */ - switch (insert_mode) { - case KEYNEEDED_DELPREV: - delete_fcurve_key(fcu, fcu->totvert - 2, 1); - break; - case KEYNEEDED_DELNEXT: - delete_fcurve_key(fcu, 1, 1); - break; +/* Find or create the FCurve based on the given path, and insert the specified value into it. */ +static bool insert_keyframe_fcurve_value( + Main *bmain, ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, + bAction *act, const char group[], const char rna_path[], int array_index, + float cfra, float curval, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag) +{ + /* make sure the F-Curve exists + * - if we're replacing keyframes only, DO NOT create new F-Curves if they do not exist yet + * but still try to get the F-Curve if it exists... + */ + FCurve *fcu = verify_fcurve(bmain, act, group, ptr, rna_path, array_index, (flag & INSERTKEY_REPLACE) == 0); + + /* we may not have a F-Curve when we're replacing only... */ + if (fcu) { + /* set color mode if the F-Curve is new (i.e. without any keyframes) */ + if ((fcu->totvert == 0) && (flag & INSERTKEY_XYZ2RGB)) { + /* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor, + * is determined by the array index for the F-Curve + */ + PropertySubType prop_subtype = RNA_property_subtype(prop); + if (ELEM(prop_subtype, PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { + fcu->color_mode = FCURVE_COLOR_AUTO_RGB; + } + else if (ELEM(prop_subtype, PROP_QUATERNION)) { + fcu->color_mode = FCURVE_COLOR_AUTO_YRGB; + } } - /* only return success if keyframe added */ - if (insert_mode) - return true; + /* update F-Curve flags to ensure proper behavior for property type */ + update_autoflags_fcurve_direct(fcu, prop); + + /* insert keyframe */ + return insert_keyframe_value(reports, ptr, prop, fcu, cfra, curval, keytype, flag); } else { - /* just insert keyframe */ - insert_vert_fcurve(fcu, cfra, curval, keytype, flag); - - /* return success */ - return true; + return false; } - - /* failed */ - return false; } /* Main Keyframing API call: @@ -1105,10 +1223,8 @@ short insert_keyframe( 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; /* validate pointer first - exit if failure */ @@ -1149,46 +1265,56 @@ short insert_keyframe( cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); } - /* key entire array convenience method */ - if (array_index == -1) { - array_index = 0; - array_index_max = RNA_property_array_length(&ptr, prop); + /* Obtain values to insert. */ + float value_buffer[RNA_MAX_ARRAY_LENGTH]; + int value_count; + bool force_all; - /* for single properties, increase max_index so that the property itself gets included, - * but don't do this for standard arrays since that can cause corruption issues - * (extra unused curves) - */ - if (array_index_max == array_index) - array_index_max++; - } + float *values = get_keyframe_values(depsgraph, reports, ptr, prop, array_index, nla_context, flag, + value_buffer, RNA_MAX_ARRAY_LENGTH, &value_count, &force_all); - /* will only loop once unless the array index was -1 */ - for (; array_index < array_index_max; array_index++) { - /* make sure the F-Curve exists - * - if we're replacing keyframes only, DO NOT create new F-Curves if they do not exist yet - * but still try to get the F-Curve if it exists... - */ - fcu = verify_fcurve(bmain, act, group, &ptr, rna_path, array_index, (flag & INSERTKEY_REPLACE) == 0); - - /* we may not have a F-Curve when we're replacing only... */ - if (fcu) { - /* set color mode if the F-Curve is new (i.e. without any keyframes) */ - if ((fcu->totvert == 0) && (flag & INSERTKEY_XYZ2RGB)) { - /* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor, - * is determined by the array index for the F-Curve - */ - PropertySubType prop_subtype = RNA_property_subtype(prop); - if (ELEM(prop_subtype, PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { - fcu->color_mode = FCURVE_COLOR_AUTO_RGB; + if (values != NULL) { + /* Key the entire array. */ + if (array_index == -1 || force_all) { + /* In force mode, if any of the curves succeeds, drop the replace mode and restart. */ + if (force_all && (flag & INSERTKEY_REPLACE) != 0) { + int exclude = -1; + + for (array_index = 0; array_index < value_count; array_index++) { + if (insert_keyframe_fcurve_value(bmain, reports, &ptr, prop, act, group, rna_path, array_index, cfra, values[array_index], keytype, flag)) { + ret++; + exclude = array_index; + break; + } + } + + if (exclude != -1) { + flag &= ~INSERTKEY_REPLACE; + + for (array_index = 0; array_index < value_count; array_index++) { + if (array_index != exclude) { + ret += insert_keyframe_fcurve_value(bmain, reports, &ptr, prop, act, group, rna_path, array_index, cfra, values[array_index], keytype, flag); + } + } } - else if (ELEM(prop_subtype, PROP_QUATERNION)) { - fcu->color_mode = FCURVE_COLOR_AUTO_YRGB; + } + /* Simply insert all channels. */ + else { + for (array_index = 0; array_index < value_count; array_index++) { + ret += insert_keyframe_fcurve_value(bmain, reports, &ptr, prop, act, group, rna_path, array_index, cfra, values[array_index], keytype, flag); } } - - /* insert keyframe */ - ret += insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, keytype, nla_context, flag); } + /* Key a single index. */ + else { + if (array_index >= 0 && array_index < value_count) { + ret += insert_keyframe_fcurve_value(bmain, reports, &ptr, prop, act, group, rna_path, array_index, cfra, values[array_index], keytype, flag); + } + } + } + + if (values != value_buffer) { + MEM_freeN(values); } BKE_animsys_free_nla_keyframing_context_cache(&tmp_nla_cache); @@ -2267,8 +2393,16 @@ bool fcurve_is_changed(PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float fra anim_rna.prop = prop; anim_rna.prop_index = fcu->array_index; + float buffer[RNA_MAX_ARRAY_LENGTH]; + int count, index = fcu->array_index; + float *values = setting_get_rna_values(NULL, &ptr, prop, false, buffer, RNA_MAX_ARRAY_LENGTH, &count); + float fcurve_val = calculate_fcurve(&anim_rna, fcu, frame); - float cur_val = setting_get_rna_value(NULL, &ptr, prop, fcu->array_index, false); + float cur_val = (index >= 0 && index < count) ? values[index] : 0.0f; + + if (values != buffer) { + MEM_freeN(values); + } return !compare_ff_relative(fcurve_val, cur_val, FLT_EPSILON, 64); } diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 9ec238d7b5e..4cd3acc7474 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -98,8 +98,11 @@ void ui_but_anim_flag(uiBut *but, float cfra) if (fcurve_frame_has_keyframe(fcu, cfra, 0)) but->flag |= UI_BUT_ANIMATED_KEY; - if (fcurve_is_changed(but->rnapoin, but->rnaprop, fcu, cfra)) - but->drawflag |= UI_BUT_ANIMATED_CHANGED; + /* XXX: this feature is totally broken and useless with NLA */ + if (adt == NULL || adt->nla_tracks.first == NULL) { + if (fcurve_is_changed(but->rnapoin, but->rnaprop, fcu, cfra)) + but->drawflag |= UI_BUT_ANIMATED_CHANGED; + } } else { but->flag |= UI_BUT_DRIVEN; |