From bd305c8d18442ec056b84b889f604e0abeef8ea6 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Fri, 15 Sep 2023 09:52:40 +0200 Subject: [PATCH] Fix #110108: NLA absolute snapping Before this patch the following snapping options were broken * snap to markers * snap to seconds with "Absolute Time Snap" turned on * technically also snap to Frames with "Absolute Time Snap" turned on (but made no real difference) The issue was that each end of the strip would snap individually. Potentially collapsing the strip. This would happen e.g. when snapping to markers but with only 1 marker present. This PR fixes the issue by finding out the closest snap offset and shifting the strip as a whole by that amount. That means either the start or the end of the strip will snap to the target. By doing it that way the length of the strip is never changed by snapping. This means when snapping to Seconds with "Absolute Time Snap" turned on, the start of the strip might not be on a full second when the end is. Pull Request: https://projects.blender.org/blender/blender/pulls/111984 --- .../transform/transform_convert_nla.cc | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/transform/transform_convert_nla.cc b/source/blender/editors/transform/transform_convert_nla.cc index b7ffc637021..3a35e84cebf 100644 --- a/source/blender/editors/transform/transform_convert_nla.cc +++ b/source/blender/editors/transform/transform_convert_nla.cc @@ -660,9 +660,28 @@ static void snap_transform_data(TransInfo *t, TransDataContainer *tc) if (t->modifiers & MOD_SNAP_INVERT) { invert_snap(snap_mode); } - TransData *td = tc->data; - for (int i = 0; i < tc->data_len; i++, td++) { - transform_snap_anim_flush_data(t, td, snap_mode, td->loc); + + float offset = 0; + float smallest_snap_delta = FLT_MAX; + + /* In order to move the strip in a block and not each end individually, + * find the minimal snap offset first and then shift the whole strip by that amount. */ + for (int i = 0; i < tc->data_len; i++) { + TransData td = tc->data[i]; + float snap_value; + transform_snap_anim_flush_data(t, &td, snap_mode, &snap_value); + + /* The snap_delta measures how far from the unsnapped position the value has moved. */ + const float snap_delta = *td.loc - snap_value; + if (fabs(snap_delta) < fabs(smallest_snap_delta)) { + offset = snap_value - td.iloc[0]; + smallest_snap_delta = snap_delta; + } + } + + for (int i = 0; i < tc->data_len; i++) { + TransData td = tc->data[i]; + *td.loc = td.iloc[0] + offset; } }