Refactor: centralize responsibility for "Only Insert Needed" #121525

Merged
Nathan Vegdahl merged 13 commits from nathanvegdahl/blender:centralize_only_insert_needed into main 2024-05-10 17:11:31 +02:00
3 changed files with 51 additions and 44 deletions

View File

@ -6,12 +6,14 @@
* \ingroup animrig
*/
#include <cfloat>
#include <cmath>
#include <cstring>
#include "ANIM_animdata.hh"
#include "ANIM_fcurve.hh"
#include "BKE_fcurve.hh"
#include "BLI_math_base.h"
#include "BLI_math_vector_types.hh"
#include "BLI_string.h"
#include "DNA_anim_types.h"
@ -271,11 +273,57 @@ void initialize_bezt(BezTriple *beztr,
beztr->period = 4.1f;
}
/**
* Return whether the given fcurve already evaluates to the same value as the
* proposed keyframe at the keyframe's time.
*
* This is a helper function for determining whether to insert a keyframe or not
* when "only insert needed" is enabled.
*
* Note: this does *not* determine whether inserting the keyframe would change
* the fcurve at points other than the keyframe itself. For example, even if
* inserting the key wouldn't change the fcurve's value at the time of the
* keyframe, the resulting changes to bezier interpolation could change the
* fcurve on either side of it. This function intentionally does not account for
* that, since that's not how the "only insert needed" feature is supposed to
* work.
*/
static bool new_key_needed(FCurve &fcu, const float frame, const float value)
{
if (fcu.totvert == 0) {
return true;
}
bool replace;
const int bezt_index = BKE_fcurve_bezt_binarysearch_index(
fcu.bezt, frame, fcu.totvert, &replace);
if (replace) {
/* If there is already a key, we only need to modify it if the proposed value is different. */
return fcu.bezt[bezt_index].vec[1][1] != value;
}
const int diff_ulp = 32;
const float fcu_eval = evaluate_fcurve(&fcu, frame);
/* No need to insert a key if the same value is already the value of the FCurve at that point. */
if (compare_ff_relative(fcu_eval, value, FLT_EPSILON, diff_ulp)) {
return false;
}
return true;
}
SingleKeyingResult insert_vert_fcurve(FCurve *fcu,
const float2 position,
const KeyframeSettings &settings,
eInsertKeyFlags flag)
{
BLI_assert(fcu != nullptr);
if ((flag & INSERTKEY_NEEDED) && !new_key_needed(*fcu, position[0], position[1])) {
nathanvegdahl marked this conversation as resolved Outdated

Add parentheses around (flag & INSERTKEY_NEEDED)

Add parentheses around `(flag & INSERTKEY_NEEDED)`

Gah! Thanks.

Gah! Thanks.
return SingleKeyingResult::NO_KEY_NEEDED;
}
BezTriple beztr = {{{0}}};
initialize_bezt(&beztr, position, settings, eFCurve_Flags(fcu->flag));
@ -494,7 +542,7 @@ void bake_fcurve_segments(FCurve *fcu)
/* Add keyframes with these, tagging as 'breakdowns'. */
for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
blender::animrig::insert_vert_fcurve(
fcu, {fp->frame, fp->val}, settings, eInsertKeyFlags(1));
fcu, {fp->frame, fp->val}, settings, INSERTKEY_NOFLAGS);
}

Note to reviewers: this is changed to INSERTKEY_NOFLAGS because the flag previously passed was actually not used by insert_vert_fcurve(), but now is. So this actually preserves the previous behavior.

This same change is elsewhere in this PR as well, for the same reason.

Note to reviewers: this is changed to `INSERTKEY_NOFLAGS` because the flag previously passed was actually not used by `insert_vert_fcurve()`, but now is. So this actually preserves the previous behavior. This same change is elsewhere in this PR as well, for the same reason.
MEM_freeN(value_cache);

View File

@ -6,7 +6,6 @@
* \ingroup animrig
*/
#include <cfloat>
#include <cmath>
#include <string>
@ -425,38 +424,6 @@ static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, fl
return type;
}
/**
* This helper function determines whether a new keyframe is needed.
* A keyframe doesn't get added when the FCurve already has the proposed value.
*/
static bool new_key_needed(FCurve *fcu, const float frame, const float value)
{
if (fcu == nullptr) {
return true;
}
if (fcu->totvert == 0) {
return true;
}
bool replace;
const int bezt_index = BKE_fcurve_bezt_binarysearch_index(
fcu->bezt, frame, fcu->totvert, &replace);
if (replace) {
/* If there is already a key, we only need to modify it if the proposed value is different. */
return fcu->bezt[bezt_index].vec[1][1] != value;
}
const int diff_ulp = 32;
const float fcu_eval = evaluate_fcurve(fcu, frame);
/* No need to insert a key if the same value is already the value of the FCurve at that point. */
if (compare_ff_relative(fcu_eval, value, FLT_EPSILON, diff_ulp)) {
return false;
}
return true;
}
static float nla_time_remap(const AnimationEvalContext *anim_eval_context,
PointerRNA *id_ptr,
AnimData *adt,
@ -496,15 +463,7 @@ static SingleKeyingResult insert_keyframe_value(
KeyframeSettings settings = get_keyframe_settings((flag & INSERTKEY_NO_USERPREF) == 0);
settings.keyframe_type = keytype;
if ((flag & INSERTKEY_NEEDED) && !new_key_needed(fcu, cfra, curval)) {
return SingleKeyingResult::NO_KEY_NEEDED;
}
if (insert_vert_fcurve(fcu, {cfra, curval}, settings, flag) != SingleKeyingResult::SUCCESS) {
return SingleKeyingResult::FCURVE_NOT_KEYFRAMEABLE;
}
return SingleKeyingResult::SUCCESS;
return insert_vert_fcurve(fcu, {cfra, curval}, settings, flag);
}
nathanvegdahl marked this conversation as resolved Outdated

Here's where I goofed. This inhibiting of the flag, and the whole note along with it, is wrong. And that's because this is the very function where "Only Insert Needed" was previously handled.

I removed the old code that handled the flag here while moving the changes over from the other PR. And then I did a separate pass after committing that code to see where the flag needed to be ignored due to the changes to insert_vert_fcurve(). Hence how I ended up here.

Here's where I goofed. This inhibiting of the flag, and the whole note along with it, is wrong. And that's because this is the very function where "Only Insert Needed" was previously handled. I removed the old code that handled the flag here while moving the changes over from the other PR. And then I did a separate pass after committing that code to see where the flag needed to be ignored due to the changes to `insert_vert_fcurve()`. Hence how I ended up here.
bool insert_keyframe_direct(ReportList *reports,

View File

@ -1714,7 +1714,7 @@ static void propagate_curve_values(ListBase /*tPChanFCurveLink*/ *pflinks,
const float current_fcu_value = evaluate_fcurve(fcu, source_frame);
LISTBASE_FOREACH (FrameLink *, target_frame, target_frames) {
insert_vert_fcurve(
fcu, {target_frame->frame, current_fcu_value}, settings, INSERTKEY_NEEDED);
nathanvegdahl marked this conversation as resolved Outdated

I expected this to change behavior but it doesn't seem to do that

I expected this to change behavior but it doesn't seem to do that

It doesn't change behavior for the same reason as the comment I left further above:

Note to reviewers: this is changed to INSERTKEY_NOFLAGS because the flag previously passed was actually not used by insert_vert_fcurve(), but now is. So this actually preserves the previous behavior.

This same change is elsewhere in this PR as well, for the same reason.

In other words, insert_vert_fcurve() previously completely ignored INSERTKEY_NEEDED, so the fact that it was passed that flag in a couple of places (including here) was meaningless before. But now it's actually used, so to preserve behavior we have to change to INSERTKEY_NOFLAGS.

It doesn't change behavior for the same reason as the comment I left further above: > Note to reviewers: this is changed to `INSERTKEY_NOFLAGS` because the flag previously passed was actually not used by `insert_vert_fcurve()`, but now is. So this actually preserves the previous behavior. > > This same change is elsewhere in this PR as well, for the same reason. In other words, `insert_vert_fcurve()` previously completely ignored `INSERTKEY_NEEDED`, so the fact that it was passed that flag in a couple of places (including here) was meaningless before. But now it's actually used, so to preserve behavior we have to change to `INSERTKEY_NOFLAGS`.
fcu, {target_frame->frame, current_fcu_value}, settings, INSERTKEY_NOFLAGS);
}
}
}