Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2019-01-08 18:49:38 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2019-01-14 19:14:28 +0300
commit9c1a961dc423d2eb19b875564bb4bb3c0b297ca5 (patch)
tree4abdc2ad84252ce4f0535386e4447d1e494c6096
parent1665278c14faa2a51ff2f0e33947b73aada25b12 (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.h2
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c36
-rw-r--r--source/blender/editors/animation/keyframing.c454
-rw-r--r--source/blender/editors/interface/interface_anim.c7
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;