Fix #126140: Cycle aware keying not working

The issue was that the code path for layered actions never hit the
function `remap_cyclic_keyframe_location`.

The solution is to move that logic into `insert_vert_fcurve`.
My reason for why this is the correct solution is that
the remapping happens on a per FCurve basis, so it should be within `fcurve.cc`.
Doing so ensures that the layered actions also hit that code.

Pull Request: https://projects.blender.org/blender/blender/pulls/126399
This commit is contained in:
Christoph Lendenfeld
2024-08-16 16:43:17 +02:00
committed by Christoph Lendenfeld
parent 5e88a1466c
commit ff0c097fa1
2 changed files with 56 additions and 52 deletions

View File

@@ -365,6 +365,48 @@ static bool new_key_needed(const FCurve &fcu, const float frame, const float val
return true;
}
/**
* Move the point where a key is about to be inserted to be inside the main cycle range.
* Returns the type of the cycle if it is enabled and valid.
*/
static float2 remap_cyclic_keyframe_location(const FCurve &fcu,
const eFCU_Cycle_Type type,
float2 position)
{
if (fcu.totvert < 2 || !fcu.bezt) {
return position;
}
if (type == FCU_CYCLE_NONE) {
return position;
}
BezTriple *first = &fcu.bezt[0], *last = &fcu.bezt[fcu.totvert - 1];
const float start = first->vec[1][0], end = last->vec[1][0];
if (start >= end) {
return position;
}
if (position.x < start || position.x > end) {
const float period = end - start;
const float step = floorf((position.x - start) / period);
position.x -= step * period;
if (type == FCU_CYCLE_OFFSET) {
/* Nasty check to handle the case when the modes are different better. */
FMod_Cycles *data = static_cast<FMod_Cycles *>(((FModifier *)fcu.modifiers.first)->data);
short mode = (step >= 0) ? data->after_mode : data->before_mode;
if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
position.y -= step * (last->vec[1][1] - first->vec[1][1]);
}
}
}
return position;
}
SingleKeyingResult insert_vert_fcurve(FCurve *fcu,
const float2 position,
const KeyframeSettings &settings,
@@ -372,12 +414,24 @@ SingleKeyingResult insert_vert_fcurve(FCurve *fcu,
{
BLI_assert(fcu != nullptr);
if ((flag & INSERTKEY_NEEDED) && !new_key_needed(*fcu, position[0], position[1])) {
float2 remapped_position = position;
/* Adjust coordinates for cycle aware insertion. */
if (flag & INSERTKEY_CYCLE_AWARE) {
eFCU_Cycle_Type type = BKE_fcurve_get_cycle_type(fcu);
remapped_position = remap_cyclic_keyframe_location(*fcu, type, position);
if (type != FCU_CYCLE_PERFECT) {
/* Inhibit action from insert_bezt_fcurve unless it's a perfect cycle. */
flag &= ~INSERTKEY_CYCLE_AWARE;
}
}
if ((flag & INSERTKEY_NEEDED) && !new_key_needed(*fcu, remapped_position.x, remapped_position.y))
{
return SingleKeyingResult::NO_KEY_NEEDED;
}
BezTriple beztr = {{{0}}};
initialize_bezt(&beztr, position, settings, eFCurve_Flags(fcu->flag));
initialize_bezt(&beztr, remapped_position, settings, eFCurve_Flags(fcu->flag));
uint oldTot = fcu->totvert;
int a;

View File

@@ -386,48 +386,6 @@ static BitVector<> nla_map_keyframe_values_and_generate_reports(
return successful_remaps;
}
/**
* Move the point where a key is about to be inserted to be inside the main cycle range.
* Returns the type of the cycle if it is enabled and valid.
*/
static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, float *py)
{
if (fcu->totvert < 2 || !fcu->bezt) {
return FCU_CYCLE_NONE;
}
eFCU_Cycle_Type type = BKE_fcurve_get_cycle_type(fcu);
if (type == FCU_CYCLE_NONE) {
return FCU_CYCLE_NONE;
}
BezTriple *first = &fcu->bezt[0], *last = &fcu->bezt[fcu->totvert - 1];
const float start = first->vec[1][0], end = last->vec[1][0];
if (start >= end) {
return FCU_CYCLE_NONE;
}
if (*px < start || *px > end) {
float period = end - start;
float step = floorf((*px - start) / period);
*px -= step * period;
if (type == FCU_CYCLE_OFFSET) {
/* Nasty check to handle the case when the modes are different better. */
FMod_Cycles *data = static_cast<FMod_Cycles *>(((FModifier *)fcu->modifiers.first)->data);
short mode = (step >= 0) ? data->after_mode : data->before_mode;
if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
*py -= step * (last->vec[1][1] - first->vec[1][1]);
}
}
}
return type;
}
static float nla_time_remap(float time,
const AnimationEvalContext *anim_eval_context,
PointerRNA *id_ptr,
@@ -456,14 +414,6 @@ static SingleKeyingResult insert_keyframe_value(
return SingleKeyingResult::FCURVE_NOT_KEYFRAMEABLE;
}
/* 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;
}
}
KeyframeSettings settings = get_keyframe_settings((flag & INSERTKEY_NO_USERPREF) == 0);
settings.keyframe_type = keytype;