Cleanup: Refactor VSE retiming code
Move functions, so the file is ordered: - Generic retiming logic - Sound animation logic - Selection code Also try to keep get/set function close. Pull Request: https://projects.blender.org/blender/blender/pulls/131660
This commit is contained in:
committed by
Richard Antalik
parent
b33a7ca6e8
commit
21534a705b
@@ -601,6 +601,179 @@ SeqRetimingKey *SEQ_retiming_add_transition(Sequence *seq, SeqRetimingKey *key,
|
||||
return seq->retiming_keys + orig_key_index + 1;
|
||||
}
|
||||
|
||||
static int seq_retiming_clamp_transition_offset(SeqRetimingKey *start_key, int offset)
|
||||
{
|
||||
SeqRetimingKey *end_key = start_key + 1;
|
||||
SeqRetimingKey *prev_key = start_key - 1;
|
||||
SeqRetimingKey *next_key = start_key + 2;
|
||||
const int prev_dist = start_key->strip_frame_index - prev_key->strip_frame_index;
|
||||
const int next_dist = next_key->strip_frame_index - end_key->strip_frame_index;
|
||||
|
||||
if (offset >= 0) {
|
||||
return min_ii(offset, next_dist - 1);
|
||||
}
|
||||
else {
|
||||
return max_ii(offset, -(prev_dist - 1));
|
||||
}
|
||||
}
|
||||
|
||||
static void seq_retiming_transition_offset(const Scene *scene,
|
||||
Sequence *seq,
|
||||
SeqRetimingKey *key,
|
||||
const int offset)
|
||||
{
|
||||
int clamped_offset = seq_retiming_clamp_transition_offset(key, offset);
|
||||
const float duration = (key->original_strip_frame_index - key->strip_frame_index);
|
||||
const bool was_selected = SEQ_retiming_selection_contains(SEQ_editing_get(scene), key);
|
||||
|
||||
SeqRetimingKey *original_key = seq_retiming_remove_transition(seq, key);
|
||||
original_key->strip_frame_index += clamped_offset *
|
||||
SEQ_time_media_playback_rate_factor_get(scene, seq);
|
||||
|
||||
SeqRetimingKey *transition_out = SEQ_retiming_add_transition(seq, original_key, duration);
|
||||
|
||||
if (was_selected) {
|
||||
SEQ_retiming_selection_append(transition_out);
|
||||
SEQ_retiming_selection_append(transition_out - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int seq_retiming_clamp_timeline_frame(const Scene *scene,
|
||||
Sequence *seq,
|
||||
SeqRetimingKey *key,
|
||||
const int timeline_frame)
|
||||
{
|
||||
int prev_key_timeline_frame = -MAXFRAME;
|
||||
int next_key_timeline_frame = MAXFRAME;
|
||||
|
||||
if (key->strip_frame_index > 0) {
|
||||
SeqRetimingKey *prev_key = key - 1;
|
||||
prev_key_timeline_frame = SEQ_retiming_key_timeline_frame_get(scene, seq, prev_key);
|
||||
}
|
||||
|
||||
if (!SEQ_retiming_is_last_key(seq, key)) {
|
||||
SeqRetimingKey *next_key = key + 1;
|
||||
next_key_timeline_frame = SEQ_retiming_key_timeline_frame_get(scene, seq, next_key);
|
||||
}
|
||||
|
||||
const int orig_timeline_frame = SEQ_retiming_key_timeline_frame_get(scene, seq, key);
|
||||
int clamped_timeline_frame = timeline_frame;
|
||||
|
||||
if (timeline_frame < orig_timeline_frame) {
|
||||
clamped_timeline_frame = max_ii(timeline_frame, prev_key_timeline_frame + 1);
|
||||
}
|
||||
else if (timeline_frame > orig_timeline_frame) {
|
||||
clamped_timeline_frame = min_ii(timeline_frame, next_key_timeline_frame - 1);
|
||||
}
|
||||
return clamped_timeline_frame;
|
||||
}
|
||||
|
||||
/* Remove and re-create transition. This way transition won't change length.
|
||||
* Alternative solution is to find where in arc segment the `y` value is closest to key
|
||||
* retiming factor, then trim transition to that point. This would change transition length. */
|
||||
|
||||
static void seq_retiming_fix_transition(Sequence *seq, SeqRetimingKey *key)
|
||||
{
|
||||
const int keys_num = seq->retiming_keys_num;
|
||||
|
||||
const float transition_duration = (key->original_strip_frame_index - key->strip_frame_index);
|
||||
SeqRetimingKey *orig_key = seq_retiming_remove_transition(seq, key);
|
||||
SEQ_retiming_add_transition(seq, orig_key, transition_duration);
|
||||
BLI_assert(keys_num == seq->retiming_keys_num);
|
||||
UNUSED_VARS_NDEBUG(keys_num);
|
||||
}
|
||||
|
||||
static void seq_retiming_fix_transitions(Sequence *seq, SeqRetimingKey *key)
|
||||
{
|
||||
if (SEQ_retiming_key_index_get(seq, key) <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int key_index = SEQ_retiming_key_index_get(seq, key);
|
||||
|
||||
/* Store value, since handles array will be reallocated. */
|
||||
bool is_last_key = SEQ_retiming_is_last_key(seq, key);
|
||||
|
||||
SeqRetimingKey *prev_key = key - 2;
|
||||
if (SEQ_retiming_key_is_transition_start(prev_key)) {
|
||||
seq_retiming_fix_transition(seq, prev_key);
|
||||
}
|
||||
|
||||
if (is_last_key) {
|
||||
return;
|
||||
}
|
||||
|
||||
SeqRetimingKey *next_key = &SEQ_retiming_keys_get(seq)[key_index + 1];
|
||||
if (SEQ_retiming_key_is_transition_start(next_key)) {
|
||||
seq_retiming_fix_transition(seq, next_key);
|
||||
}
|
||||
}
|
||||
|
||||
static void seq_retiming_key_offset(const Scene *scene,
|
||||
Sequence *seq,
|
||||
SeqRetimingKey *key,
|
||||
const int offset)
|
||||
{
|
||||
if ((key->flag & SEQ_SPEED_TRANSITION_IN) != 0) {
|
||||
seq_retiming_transition_offset(scene, seq, key, offset);
|
||||
}
|
||||
else {
|
||||
key->strip_frame_index += offset * SEQ_time_media_playback_rate_factor_get(scene, seq);
|
||||
seq_retiming_fix_transitions(seq, key);
|
||||
}
|
||||
}
|
||||
|
||||
int SEQ_retiming_key_timeline_frame_get(const Scene *scene,
|
||||
const Sequence *seq,
|
||||
const SeqRetimingKey *key)
|
||||
{
|
||||
int sound_offset = SEQ_time_get_rounded_sound_offset(scene, seq);
|
||||
return round_fl_to_int(SEQ_time_start_frame_get(seq) + sound_offset +
|
||||
key->strip_frame_index /
|
||||
SEQ_time_media_playback_rate_factor_get(scene, seq));
|
||||
}
|
||||
|
||||
void SEQ_retiming_key_timeline_frame_set(const Scene *scene,
|
||||
Sequence *seq,
|
||||
SeqRetimingKey *key,
|
||||
const int timeline_frame)
|
||||
{
|
||||
if ((key->flag & SEQ_SPEED_TRANSITION_OUT) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int orig_timeline_frame = SEQ_retiming_key_timeline_frame_get(scene, seq, key);
|
||||
const int clamped_timeline_frame = seq_retiming_clamp_timeline_frame(
|
||||
scene, seq, key, timeline_frame);
|
||||
const int offset = clamped_timeline_frame - orig_timeline_frame;
|
||||
|
||||
const int key_count = SEQ_retiming_keys_get(seq).size();
|
||||
const int key_index = SEQ_retiming_key_index_get(seq, key);
|
||||
|
||||
if (orig_timeline_frame == SEQ_time_right_handle_frame_get(scene, seq)) {
|
||||
for (int i = key_index; i < key_count; i++) {
|
||||
SeqRetimingKey *key_iter = &SEQ_retiming_keys_get(seq)[i];
|
||||
seq_retiming_key_offset(scene, seq, key_iter, offset);
|
||||
}
|
||||
}
|
||||
else if (orig_timeline_frame == SEQ_time_left_handle_frame_get(scene, seq) ||
|
||||
key->strip_frame_index == 0)
|
||||
{
|
||||
seq->start += offset;
|
||||
for (int i = key_index + 1; i < key_count; i++) {
|
||||
SeqRetimingKey *key_iter = &SEQ_retiming_keys_get(seq)[i];
|
||||
seq_retiming_key_offset(scene, seq, key_iter, -offset);
|
||||
}
|
||||
}
|
||||
else {
|
||||
seq_retiming_key_offset(scene, seq, key, offset);
|
||||
}
|
||||
|
||||
blender::Span effects = seq_sequence_lookup_effects_by_seq(scene, seq);
|
||||
seq_time_update_effects_strip_range(scene, effects);
|
||||
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
|
||||
}
|
||||
|
||||
float SEQ_retiming_key_speed_get(const Sequence *seq, const SeqRetimingKey *key)
|
||||
{
|
||||
if (key->strip_frame_index == 0) {
|
||||
@@ -622,6 +795,40 @@ float SEQ_retiming_key_speed_get(const Sequence *seq, const SeqRetimingKey *key)
|
||||
return speed;
|
||||
}
|
||||
|
||||
void SEQ_retiming_key_speed_set(
|
||||
const Scene *scene, Sequence *seq, SeqRetimingKey *key, const float speed, bool keep_retiming)
|
||||
{
|
||||
if (key->strip_frame_index == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const SeqRetimingKey *key_prev = key - 1;
|
||||
const float speed_fac = 100.0f / speed;
|
||||
|
||||
const int frame_index_max = seq->len;
|
||||
const int frame_retimed_prev = round_fl_to_int(key_prev->retiming_factor * frame_index_max);
|
||||
const int frame_retimed = round_fl_to_int(key->retiming_factor * frame_index_max);
|
||||
|
||||
const int segment_duration = (frame_retimed - frame_retimed_prev) /
|
||||
SEQ_time_media_playback_rate_factor_get(scene, seq);
|
||||
const int new_duration = segment_duration * speed_fac;
|
||||
|
||||
const int orig_timeline_frame = SEQ_retiming_key_timeline_frame_get(scene, seq, key);
|
||||
const int new_timeline_frame = SEQ_retiming_key_timeline_frame_get(scene, seq, key_prev) +
|
||||
new_duration;
|
||||
|
||||
SEQ_retiming_key_timeline_frame_set(scene, seq, key, new_timeline_frame);
|
||||
|
||||
if (keep_retiming) {
|
||||
const int key_index = SEQ_retiming_key_index_get(seq, key);
|
||||
const int offset = new_timeline_frame - orig_timeline_frame;
|
||||
for (int i = key_index + 1; i < SEQ_retiming_keys_count(seq); i++) {
|
||||
SeqRetimingKey *key_iter = &SEQ_retiming_keys_get(seq)[i];
|
||||
seq_retiming_key_offset(scene, seq, key_iter, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum eRangeType {
|
||||
LINEAR = 0,
|
||||
TRANSITION = 1,
|
||||
@@ -870,213 +1077,6 @@ void SEQ_retiming_sound_animation_data_set(const Scene *scene, const Sequence *s
|
||||
}
|
||||
}
|
||||
|
||||
int SEQ_retiming_key_timeline_frame_get(const Scene *scene,
|
||||
const Sequence *seq,
|
||||
const SeqRetimingKey *key)
|
||||
{
|
||||
int sound_offset = SEQ_time_get_rounded_sound_offset(scene, seq);
|
||||
return round_fl_to_int(SEQ_time_start_frame_get(seq) + sound_offset +
|
||||
key->strip_frame_index /
|
||||
SEQ_time_media_playback_rate_factor_get(scene, seq));
|
||||
}
|
||||
|
||||
static int seq_retiming_clamp_transition_offset(SeqRetimingKey *start_key, int offset)
|
||||
{
|
||||
SeqRetimingKey *end_key = start_key + 1;
|
||||
SeqRetimingKey *prev_key = start_key - 1;
|
||||
SeqRetimingKey *next_key = start_key + 2;
|
||||
const int prev_dist = start_key->strip_frame_index - prev_key->strip_frame_index;
|
||||
const int next_dist = next_key->strip_frame_index - end_key->strip_frame_index;
|
||||
|
||||
if (offset >= 0) {
|
||||
return min_ii(offset, next_dist - 1);
|
||||
}
|
||||
else {
|
||||
return max_ii(offset, -(prev_dist - 1));
|
||||
}
|
||||
}
|
||||
|
||||
static void seq_retiming_transition_offset(const Scene *scene,
|
||||
Sequence *seq,
|
||||
SeqRetimingKey *key,
|
||||
const int offset)
|
||||
{
|
||||
int clamped_offset = seq_retiming_clamp_transition_offset(key, offset);
|
||||
const float duration = (key->original_strip_frame_index - key->strip_frame_index);
|
||||
const bool was_selected = SEQ_retiming_selection_contains(SEQ_editing_get(scene), key);
|
||||
|
||||
SeqRetimingKey *original_key = seq_retiming_remove_transition(seq, key);
|
||||
original_key->strip_frame_index += clamped_offset *
|
||||
SEQ_time_media_playback_rate_factor_get(scene, seq);
|
||||
|
||||
SeqRetimingKey *transition_out = SEQ_retiming_add_transition(seq, original_key, duration);
|
||||
|
||||
if (was_selected) {
|
||||
SEQ_retiming_selection_append(transition_out);
|
||||
SEQ_retiming_selection_append(transition_out - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int seq_retiming_clamp_timeline_frame(const Scene *scene,
|
||||
Sequence *seq,
|
||||
SeqRetimingKey *key,
|
||||
const int timeline_frame)
|
||||
{
|
||||
int prev_key_timeline_frame = -MAXFRAME;
|
||||
int next_key_timeline_frame = MAXFRAME;
|
||||
|
||||
if (key->strip_frame_index > 0) {
|
||||
SeqRetimingKey *prev_key = key - 1;
|
||||
prev_key_timeline_frame = SEQ_retiming_key_timeline_frame_get(scene, seq, prev_key);
|
||||
}
|
||||
|
||||
if (!SEQ_retiming_is_last_key(seq, key)) {
|
||||
SeqRetimingKey *next_key = key + 1;
|
||||
next_key_timeline_frame = SEQ_retiming_key_timeline_frame_get(scene, seq, next_key);
|
||||
}
|
||||
|
||||
const int orig_timeline_frame = SEQ_retiming_key_timeline_frame_get(scene, seq, key);
|
||||
int clamped_timeline_frame = timeline_frame;
|
||||
|
||||
if (timeline_frame < orig_timeline_frame) {
|
||||
clamped_timeline_frame = max_ii(timeline_frame, prev_key_timeline_frame + 1);
|
||||
}
|
||||
else if (timeline_frame > orig_timeline_frame) {
|
||||
clamped_timeline_frame = min_ii(timeline_frame, next_key_timeline_frame - 1);
|
||||
}
|
||||
return clamped_timeline_frame;
|
||||
}
|
||||
|
||||
/* Remove and re-create transition. This way transition won't change length.
|
||||
* Alternative solution is to find where in arc segment the `y` value is closest to key
|
||||
* retiming factor, then trim transition to that point. This would change transition length. */
|
||||
|
||||
static void seq_retiming_fix_transition(Sequence *seq, SeqRetimingKey *key)
|
||||
{
|
||||
const int keys_num = seq->retiming_keys_num;
|
||||
|
||||
const float transition_duration = (key->original_strip_frame_index - key->strip_frame_index);
|
||||
SeqRetimingKey *orig_key = seq_retiming_remove_transition(seq, key);
|
||||
SEQ_retiming_add_transition(seq, orig_key, transition_duration);
|
||||
BLI_assert(keys_num == seq->retiming_keys_num);
|
||||
UNUSED_VARS_NDEBUG(keys_num);
|
||||
}
|
||||
|
||||
static void seq_retiming_fix_transitions(Sequence *seq, SeqRetimingKey *key)
|
||||
{
|
||||
if (SEQ_retiming_key_index_get(seq, key) <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int key_index = SEQ_retiming_key_index_get(seq, key);
|
||||
|
||||
/* Store value, since handles array will be reallocated. */
|
||||
bool is_last_key = SEQ_retiming_is_last_key(seq, key);
|
||||
|
||||
SeqRetimingKey *prev_key = key - 2;
|
||||
if (SEQ_retiming_key_is_transition_start(prev_key)) {
|
||||
seq_retiming_fix_transition(seq, prev_key);
|
||||
}
|
||||
|
||||
if (is_last_key) {
|
||||
return;
|
||||
}
|
||||
|
||||
SeqRetimingKey *next_key = &SEQ_retiming_keys_get(seq)[key_index + 1];
|
||||
if (SEQ_retiming_key_is_transition_start(next_key)) {
|
||||
seq_retiming_fix_transition(seq, next_key);
|
||||
}
|
||||
}
|
||||
|
||||
static void seq_retiming_key_offset(const Scene *scene,
|
||||
Sequence *seq,
|
||||
SeqRetimingKey *key,
|
||||
const int offset)
|
||||
{
|
||||
if ((key->flag & SEQ_SPEED_TRANSITION_IN) != 0) {
|
||||
seq_retiming_transition_offset(scene, seq, key, offset);
|
||||
}
|
||||
else {
|
||||
key->strip_frame_index += offset * SEQ_time_media_playback_rate_factor_get(scene, seq);
|
||||
seq_retiming_fix_transitions(seq, key);
|
||||
}
|
||||
}
|
||||
|
||||
void SEQ_retiming_key_timeline_frame_set(const Scene *scene,
|
||||
Sequence *seq,
|
||||
SeqRetimingKey *key,
|
||||
const int timeline_frame)
|
||||
{
|
||||
if ((key->flag & SEQ_SPEED_TRANSITION_OUT) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int orig_timeline_frame = SEQ_retiming_key_timeline_frame_get(scene, seq, key);
|
||||
const int clamped_timeline_frame = seq_retiming_clamp_timeline_frame(
|
||||
scene, seq, key, timeline_frame);
|
||||
const int offset = clamped_timeline_frame - orig_timeline_frame;
|
||||
|
||||
const int key_count = SEQ_retiming_keys_get(seq).size();
|
||||
const int key_index = SEQ_retiming_key_index_get(seq, key);
|
||||
|
||||
if (orig_timeline_frame == SEQ_time_right_handle_frame_get(scene, seq)) {
|
||||
for (int i = key_index; i < key_count; i++) {
|
||||
SeqRetimingKey *key_iter = &SEQ_retiming_keys_get(seq)[i];
|
||||
seq_retiming_key_offset(scene, seq, key_iter, offset);
|
||||
}
|
||||
}
|
||||
else if (orig_timeline_frame == SEQ_time_left_handle_frame_get(scene, seq) ||
|
||||
key->strip_frame_index == 0)
|
||||
{
|
||||
seq->start += offset;
|
||||
for (int i = key_index + 1; i < key_count; i++) {
|
||||
SeqRetimingKey *key_iter = &SEQ_retiming_keys_get(seq)[i];
|
||||
seq_retiming_key_offset(scene, seq, key_iter, -offset);
|
||||
}
|
||||
}
|
||||
else {
|
||||
seq_retiming_key_offset(scene, seq, key, offset);
|
||||
}
|
||||
|
||||
blender::Span effects = seq_sequence_lookup_effects_by_seq(scene, seq);
|
||||
seq_time_update_effects_strip_range(scene, effects);
|
||||
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
|
||||
}
|
||||
|
||||
void SEQ_retiming_key_speed_set(
|
||||
const Scene *scene, Sequence *seq, SeqRetimingKey *key, const float speed, bool keep_retiming)
|
||||
{
|
||||
if (key->strip_frame_index == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const SeqRetimingKey *key_prev = key - 1;
|
||||
const float speed_fac = 100.0f / speed;
|
||||
|
||||
const int frame_index_max = seq->len;
|
||||
const int frame_retimed_prev = round_fl_to_int(key_prev->retiming_factor * frame_index_max);
|
||||
const int frame_retimed = round_fl_to_int(key->retiming_factor * frame_index_max);
|
||||
|
||||
const int segment_duration = (frame_retimed - frame_retimed_prev) /
|
||||
SEQ_time_media_playback_rate_factor_get(scene, seq);
|
||||
const int new_duration = segment_duration * speed_fac;
|
||||
|
||||
const int orig_timeline_frame = SEQ_retiming_key_timeline_frame_get(scene, seq, key);
|
||||
const int new_timeline_frame = SEQ_retiming_key_timeline_frame_get(scene, seq, key_prev) +
|
||||
new_duration;
|
||||
|
||||
SEQ_retiming_key_timeline_frame_set(scene, seq, key, new_timeline_frame);
|
||||
|
||||
if (keep_retiming) {
|
||||
const int key_index = SEQ_retiming_key_index_get(seq, key);
|
||||
const int offset = new_timeline_frame - orig_timeline_frame;
|
||||
for (int i = key_index + 1; i < SEQ_retiming_keys_count(seq); i++) {
|
||||
SeqRetimingKey *key_iter = &SEQ_retiming_keys_get(seq)[i];
|
||||
seq_retiming_key_offset(scene, seq, key_iter, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SEQ_retiming_selection_clear(const Editing *ed)
|
||||
{
|
||||
bool was_empty = true;
|
||||
|
||||
Reference in New Issue
Block a user