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.
This commit is contained in:
Alexander Gavrilov 2019-01-08 18:49:38 +03:00
parent 1665278c14
commit 9c1a961dc4
Notes: blender-bot 2023-11-22 13:52:19 +01:00
Referenced by issue #115259, Property state colors do not respond to changes from keyframed values
4 changed files with 323 additions and 172 deletions

View File

@ -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);
/* ************************************* */

View File

@ -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;
return nla_invert_blend_value(blend_mode, old_value, *r_value, influence, r_value);
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 true;
}
/**

View File

@ -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(buffer, tmat);
mat4_to_size(scale, 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;
if (values != value_buffer) {
MEM_freeN(values);
}
/* check whether this curve really needs a new keyframe */
insert_mode = new_key_needed(fcu, cfra, curval);
return insert_keyframe_value(reports, &ptr, prop, fcu, cfra, curval, keytype, flag);
}
/* insert new keyframe at current frame */
if (insert_mode)
insert_vert_fcurve(fcu, cfra, curval, keytype, flag);
/* 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);
/* 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;
/* 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);
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;
/* 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;
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;
}
}
else if (ELEM(prop_subtype, PROP_QUATERNION)) {
fcu->color_mode = FCURVE_COLOR_AUTO_YRGB;
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);
}
}
}
}
/* 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);
}

View File

@ -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;