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
path: root/source
diff options
context:
space:
mode:
authorRichard Antalik <richardantalik@gmail.com>2022-04-08 20:21:47 +0300
committerRichard Antalik <richardantalik@gmail.com>2022-04-09 17:29:40 +0300
commit32da64c17e9d509bc8ce534b1fdf03d748ca13c8 (patch)
tree4d3ab1032ec36f714f5a60d983e2659a85cc8253 /source
parenta3827d4b2925a5c6bd0eb2dac9aa44e7982e482c (diff)
Fix T95276: Effect strip animation not updated when moving strips
Since effect strips can't be transformed directly, their selection had to be forced in order to process them. This often failed in more complicated scenarios, because there was no attempt to parse hierarchy completely. In worst case only one effect in chain would be selected. This code was marked by `XXX_DURIAN_ANIM_TX_HACK`. Instead solution described above, a collection of strips that depend on non effect strip position is built by function `query_time_dependent_strips_strips` and it is stored in `TransSeq`. In `flushTransSeq` this collection is iterated and transformation offset is applied to effect strip animation. Strips in collection should be consistent with true state of dependency and should be complete. Functional changes: - When 2-input effect strip changes position, animation is offset even if only handles are moved. This only applies to 2-input effect however. - Selection is not extended to include effect strips anymore. If effects are to be moved, they must be selected manually. This is because previously it was very hard to reorganize effects in chain, since moving first strip in chain would always select anywhere from 1 to n effects. So creating or filling gap in channel would almos always result in collision especially if their order in timeline doesn't perfectly represent their order in chain.
Diffstat (limited to 'source')
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c176
1 files changed, 146 insertions, 30 deletions
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 990d3680057..417cfc8cb75 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -66,6 +66,9 @@ typedef struct TransSeq {
/* Initial rect of the view2d, used for computing offset during edge panning */
rctf initial_v2d_cur;
View2DEdgePanData edge_pan;
+
+ /* Strips that aren't selected, but their position entirely depends on transformed strips. */
+ SeqCollection *time_dependent_strips;
} TransSeq;
/* -------------------------------------------------------------------- */
@@ -256,6 +259,7 @@ static void free_transform_custom_data(TransCustomData *custom_data)
{
if ((custom_data->data != NULL) && custom_data->use_free) {
TransSeq *ts = custom_data->data;
+ SEQ_collection_free(ts->time_dependent_strips);
MEM_freeN(ts->tdseq);
MEM_freeN(custom_data->data);
custom_data->data = NULL;
@@ -630,10 +634,114 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
free_transform_custom_data(custom_data);
}
-void createTransSeqData(TransInfo *t)
+SeqCollection *query_selected_strips_no_handles(ListBase *seqbase)
{
-#define XXX_DURIAN_ANIM_TX_HACK
+ SeqCollection *strips = SEQ_collection_create(__func__);
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if ((seq->flag & SELECT) != 0 && ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == 0)) {
+ SEQ_collection_append_strip(seq, strips);
+ }
+ }
+ return strips;
+}
+
+typedef enum SeqInputSide {
+ SEQ_INPUT_LEFT = -1,
+ SEQ_INPUT_RIGHT = 1,
+} SeqInputSide;
+static Sequence *effect_input_get(Sequence *effect, SeqInputSide side)
+{
+ Sequence *input = effect->seq1;
+ if (effect->seq2 && (effect->seq2->startdisp - effect->seq1->startdisp) * side > 0) {
+ input = effect->seq2;
+ }
+ return input;
+}
+
+static Sequence *effect_base_input_get(Sequence *effect, SeqInputSide side)
+{
+ Sequence *input = effect, *seq_iter = effect;
+ while (seq_iter != NULL) {
+ input = seq_iter;
+ seq_iter = effect_input_get(seq_iter, side);
+ }
+ return input;
+}
+
+/* Strips that aren't selected, but their position entirely depends on transformed strips.
+ * This collection is used to offset animation.*/
+static SeqCollection *query_time_dependent_strips_strips(TransInfo *t)
+{
+ ListBase *seqbase = seqbase_active_get(t);
+
+ /* Query dependent strips where used strips do not have handles selected.
+ * If all inputs of any effect even indirectly(through another effect) points to selected strip,
+ * it's position will change. */
+
+ SeqCollection *strips_no_handles = query_selected_strips_no_handles(seqbase);
+ /* Selection is needed as reference for related strips. */
+ SeqCollection *dependent = SEQ_collection_duplicate(strips_no_handles);
+ SEQ_collection_expand(seqbase, strips_no_handles, SEQ_query_strip_effect_chain);
+ bool strip_added = true;
+
+ while (strip_added) {
+ strip_added = false;
+
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips_no_handles) {
+ if (SEQ_collection_has_strip(seq, dependent)) {
+ continue; /* Strip is already in collection, skip it. */
+ }
+
+ /* If both seq1 and seq2 exist, both must be selected. */
+ if (seq->seq1 && SEQ_collection_has_strip(seq->seq1, dependent)) {
+ if (seq->seq2 && !SEQ_collection_has_strip(seq->seq2, dependent)) {
+ continue;
+ }
+ strip_added = true;
+ SEQ_collection_append_strip(seq, dependent);
+ }
+ }
+ }
+
+ SEQ_collection_free(strips_no_handles);
+
+ /* Query dependent strips where used strips do have handles selected.
+ * If any 2-input effect changes position because handles were moved, animation should be offset.
+ * With single input effect, it is less likely desirable to move animation. */
+
+ SeqCollection *selected_strips = SEQ_query_selected_strips(seqbase);
+ SEQ_collection_expand(seqbase, selected_strips, SEQ_query_strip_effect_chain);
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, selected_strips) {
+ /* Check only 2 input effects. */
+ if (seq->seq1 == NULL || seq->seq2 == NULL) {
+ continue;
+ }
+
+ /* Find immediate base inputs(left and right side). */
+ Sequence *input_left = effect_base_input_get(seq, SEQ_INPUT_LEFT);
+ Sequence *input_right = effect_base_input_get(seq, SEQ_INPUT_RIGHT);
+
+ if ((input_left->flag & SEQ_RIGHTSEL) != 0 && (input_right->flag & SEQ_LEFTSEL) != 0) {
+ SEQ_collection_append_strip(seq, dependent);
+ }
+ }
+ SEQ_collection_free(selected_strips);
+
+ /* Remove all non-effects. */
+ SEQ_ITERATOR_FOREACH (seq, dependent) {
+ if (SEQ_transform_sequence_can_be_translated(seq)) {
+ SEQ_collection_remove_strip(seq, dependent);
+ }
+ }
+
+ return dependent;
+}
+
+void createTransSeqData(TransInfo *t)
+{
Scene *scene = t->scene;
Editing *ed = SEQ_editing_get(t->scene);
TransData *td = NULL;
@@ -653,26 +761,6 @@ void createTransSeqData(TransInfo *t)
tc->custom.type.free_cb = freeSeqData;
t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
-#ifdef XXX_DURIAN_ANIM_TX_HACK
- {
- Sequence *seq;
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- /* hack */
- if ((seq->flag & SELECT) == 0 && seq->type & SEQ_TYPE_EFFECT) {
- Sequence *seq_user;
- int i;
- for (i = 0; i < 3; i++) {
- seq_user = *((&seq->seq1) + i);
- if (seq_user && (seq_user->flag & SELECT) && !(seq_user->flag & SEQ_LOCK) &&
- !(seq_user->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL))) {
- seq->flag |= SELECT;
- }
- }
- }
- }
- }
-#endif
-
count = SeqTransCount(t, ed->seqbasep);
/* allocate memory for data */
@@ -712,7 +800,7 @@ void createTransSeqData(TransInfo *t)
}
}
-#undef XXX_DURIAN_ANIM_TX_HACK
+ ts->time_dependent_strips = query_time_dependent_strips_strips(t);
}
/** \} */
@@ -771,7 +859,8 @@ static void flushTransSeq(TransInfo *t)
/* Editing null check already done */
ListBase *seqbasep = seqbase_active_get(t);
- int a, new_frame;
+ int a, new_frame, offset;
+
TransData *td = NULL;
TransData2D *td2d = NULL;
TransDataSeq *tdsq = NULL;
@@ -779,6 +868,15 @@ static void flushTransSeq(TransInfo *t)
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ /* This is calculated for offsetting animation of effects that change position with inputs.
+ * Maximum(positive or negative) value is used, because individual strips can be clamped. This
+ * works fairly well in most scenarios, but there can be some edge cases.
+ *
+ * Better solution would be to store effect position and calculate real offset. However with many
+ * (>5) effects in chain, there is visible lag in strip position update, because during
+ * recalculation, hierarchy is not taken into account. */
+ int max_offset = 0;
+
/* Flush to 2D vector from internally used 3D vector. */
for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
tdsq = (TransDataSeq *)td->extra;
@@ -788,31 +886,49 @@ static void flushTransSeq(TransInfo *t)
new_frame = round_fl_to_int(loc[0]);
switch (tdsq->sel_flag) {
- case SELECT:
+ case SELECT: {
if (SEQ_transform_sequence_can_be_translated(seq)) {
- const int offset = new_frame - tdsq->start_offset - seq->start;
+ offset = new_frame - tdsq->start_offset - seq->start;
SEQ_transform_translate_sequence(t->scene, seq, offset);
+ if (abs(offset) > abs(max_offset)) {
+ max_offset = offset;
+ }
}
seq->machine = round_fl_to_int(loc[1]);
CLAMP(seq->machine, 1, MAXSEQ);
break;
-
- case SEQ_LEFTSEL: /* No vertical transform. */
+ }
+ case SEQ_LEFTSEL: { /* No vertical transform. */
+ int old_startdisp = seq->startdisp;
SEQ_transform_set_left_handle_frame(seq, new_frame);
SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
SEQ_transform_fix_single_image_seq_offsets(seq);
SEQ_time_update_sequence(t->scene, seqbasep, seq);
+ if (abs(seq->startdisp - old_startdisp) > abs(max_offset)) {
+ max_offset = seq->startdisp - old_startdisp;
+ }
break;
- case SEQ_RIGHTSEL: /* No vertical transform. */
+ }
+ case SEQ_RIGHTSEL: { /* No vertical transform. */
+ int old_enddisp = seq->enddisp;
SEQ_transform_set_right_handle_frame(seq, new_frame);
SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL);
SEQ_transform_fix_single_image_seq_offsets(seq);
SEQ_time_update_sequence(t->scene, seqbasep, seq);
+ if (abs(seq->enddisp - old_enddisp) > abs(max_offset)) {
+ max_offset = seq->enddisp - old_enddisp;
+ }
break;
+ }
}
}
- /* Update all effects. */
+ /* Update animation for effects. */
+ SEQ_ITERATOR_FOREACH (seq, ts->time_dependent_strips) {
+ SEQ_offset_animdata(t->scene, seq, max_offset);
+ }
+
+ /* Update effect length and position. */
if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) {
for (seq = seqbasep->first; seq; seq = seq->next) {
if (seq->seq1 || seq->seq2 || seq->seq3) {