VSE: Handle drivers when duplicating strips

Most operations where strips are duplicated use `SEQ_animation` API,
which handles keyframe animation. Now drivers are handled as well.

When group of strips is duplicated and driver references other strip,
it will still reference original strip. However, this is much better,
than previous behavior, when strip duplication results in "transfer" of
driver from original strip to duplicated one.

Fixes T104141
This commit is contained in:
Richard Antalik 2023-01-28 03:24:44 +01:00
parent 3a9e589142
commit 4e9c6929c1
Notes: blender-bot 2023-02-13 13:30:18 +01:00
Referenced by issue #104141, Driver is reassigned from source VSE strip to its copy after duplicating
6 changed files with 95 additions and 54 deletions

View File

@ -1606,8 +1606,8 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
* This way, when pasted strips are renamed, curves are renamed with them. Finally, restore
* original curves from backup.
*/
ListBase fcurves_original_backup = {NULL, NULL};
SEQ_animation_backup_original(scene, &fcurves_original_backup);
SeqAnimationBackup animation_backup = {0};
SEQ_animation_backup_original(scene, &animation_backup);
Sequence *seq = duplicated_strips.first;
@ -1623,12 +1623,15 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
}
seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK);
seq->flag |= SEQ_IGNORE_CHANNEL_LOCK;
SEQ_animation_duplicate(scene, seq, &fcurves_original_backup);
SEQ_animation_duplicate_backup_to_scene(scene, seq, &animation_backup);
SEQ_ensure_unique_name(seq, scene);
}
SEQ_animation_restore_original(scene, &fcurves_original_backup);
SEQ_animation_restore_original(scene, &animation_backup);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
}
@ -2393,33 +2396,41 @@ static void seq_copy_del_sound(Scene *scene, Sequence *seq)
}
}
static void sequencer_copy_animation(Scene *scene, Sequence *seq)
static void sequencer_copy_animation_listbase(Scene *scene,
Sequence *seq,
ListBase *clipboard,
ListBase *fcurve_base)
{
if (scene->adt == NULL || scene->adt->action == NULL ||
BLI_listbase_is_empty(&scene->adt->action->curves)) {
return;
}
/* Add curves for strips inside meta strip. */
if (seq->type == SEQ_TYPE_META) {
LISTBASE_FOREACH (Sequence *, meta_child, &seq->seqbase) {
sequencer_copy_animation(scene, meta_child);
sequencer_copy_animation_listbase(scene, meta_child, clipboard, fcurve_base);
}
}
GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
GSet *fcurves = SEQ_fcurves_by_strip_get(seq, fcurve_base);
if (fcurves == NULL) {
return;
}
GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) {
BLI_addtail(&fcurves_clipboard, BKE_fcurve_copy(fcu));
BLI_addtail(clipboard, BKE_fcurve_copy(fcu));
}
GSET_FOREACH_END();
BLI_gset_free(fcurves, NULL);
}
static void sequencer_copy_animation(Scene *scene, Sequence *seq)
{
if (SEQ_animation_curves_exist(scene)) {
sequencer_copy_animation_listbase(scene, seq, &fcurves_clipboard, &scene->adt->action->curves);
}
if (SEQ_animation_drivers_exist(scene)) {
sequencer_copy_animation_listbase(scene, seq, &drivers_clipboard, &scene->adt->drivers);
}
}
static int sequencer_copy_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@ -2496,7 +2507,7 @@ void ED_sequencer_deselect_all(Scene *scene)
static void sequencer_paste_animation(bContext *C)
{
if (BLI_listbase_is_empty(&fcurves_clipboard)) {
if (BLI_listbase_is_empty(&fcurves_clipboard) && BLI_listbase_is_empty(&drivers_clipboard)) {
return;
}
@ -2515,6 +2526,9 @@ static void sequencer_paste_animation(bContext *C)
LISTBASE_FOREACH (FCurve *, fcu, &fcurves_clipboard) {
BLI_addtail(&act->curves, BKE_fcurve_copy(fcu));
}
LISTBASE_FOREACH (FCurve *, fcu, &drivers_clipboard) {
BLI_addtail(&scene->adt->drivers, BKE_fcurve_copy(fcu));
}
}
static int sequencer_paste_exec(bContext *C, wmOperator *op)
@ -2553,8 +2567,8 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
* curves from backup.
*/
ListBase fcurves_original_backup = {NULL, NULL};
SEQ_animation_backup_original(scene, &fcurves_original_backup);
SeqAnimationBackup animation_backup = {0};
SEQ_animation_backup_original(scene, &animation_backup);
sequencer_paste_animation(C);
/* Copy strips, temporarily restoring pointers to actual data-blocks. This
@ -2589,7 +2603,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
}
}
SEQ_animation_restore_original(scene, &fcurves_original_backup);
SEQ_animation_restore_original(scene, &animation_backup);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
DEG_relations_tag_update(bmain);

View File

@ -15,22 +15,31 @@ struct GSet;
struct ListBase;
struct Scene;
struct Sequence;
struct SeqAnimationBackup;
bool SEQ_animation_curves_exist(struct Scene *scene);
bool SEQ_animation_drivers_exist(struct Scene *scene);
void SEQ_free_animdata(struct Scene *scene, struct Sequence *seq);
void SEQ_offset_animdata(struct Scene *scene, struct Sequence *seq, int ofs);
struct GSet *SEQ_fcurves_by_strip_get(const struct Sequence *seq, struct ListBase *fcurve_base);
typedef struct SeqAnimationBackup {
ListBase curves;
ListBase drivers;
} SeqAnimationBackup;
/**
* Move all `F-Curves` from `scene` to `list`.
* Move all F-Curves and drivers from `scene` to `backup`.
*/
void SEQ_animation_backup_original(struct Scene *scene, struct ListBase *list);
void SEQ_animation_backup_original(struct Scene *scene, struct SeqAnimationBackup *backup);
/**
* Move all `F-Curves` from `list` to `scene`.
* Move all F-Curves and drivers from `backup` to `scene`.
*/
void SEQ_animation_restore_original(struct Scene *scene, struct ListBase *list);
void SEQ_animation_restore_original(struct Scene *scene, struct SeqAnimationBackup *backup);
/**
* Duplicate `F-Curves` used by `seq` from `list` to `scene`.
* Duplicate F-Curves and drivers used by `seq` from `backup` to `scene`.
*/
void SEQ_animation_duplicate(struct Scene *scene, struct Sequence *seq, struct ListBase *list);
void SEQ_animation_duplicate_backup_to_scene(struct Scene *scene,
struct Sequence *seq,
struct SeqAnimationBackup *backup);
#ifdef __cplusplus
}

View File

@ -18,6 +18,7 @@ struct Sequence;
extern struct ListBase seqbase_clipboard;
extern struct ListBase fcurves_clipboard;
extern struct ListBase drivers_clipboard;
extern int seqbase_clipboard_frame;
void SEQ_clipboard_pointers_store(struct Main *bmain, struct ListBase *seqbase);
void SEQ_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain);

View File

@ -22,13 +22,15 @@
#include "SEQ_animation.h"
static bool seq_animation_curves_exist(Scene *scene)
bool SEQ_animation_curves_exist(Scene *scene)
{
if (scene->adt == NULL || scene->adt->action == NULL ||
BLI_listbase_is_empty(&scene->adt->action->curves)) {
return false;
}
return true;
return scene->adt != NULL && scene->adt->action != NULL &&
!BLI_listbase_is_empty(&scene->adt->action->curves);
}
bool SEQ_animation_drivers_exist(Scene *scene)
{
return scene->adt != NULL && !BLI_listbase_is_empty(&scene->adt->drivers);
}
/* r_prefix + [" + escaped_name + "] + \0 */
@ -66,7 +68,7 @@ GSet *SEQ_fcurves_by_strip_get(const Sequence *seq, ListBase *fcurve_base)
void SEQ_offset_animdata(Scene *scene, Sequence *seq, int ofs)
{
if (!seq_animation_curves_exist(scene) || ofs == 0) {
if (!SEQ_animation_curves_exist(scene) || ofs == 0) {
return;
}
GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
@ -99,7 +101,7 @@ void SEQ_offset_animdata(Scene *scene, Sequence *seq, int ofs)
void SEQ_free_animdata(Scene *scene, Sequence *seq)
{
if (!seq_animation_curves_exist(scene)) {
if (!SEQ_animation_curves_exist(scene)) {
return;
}
GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
@ -115,46 +117,55 @@ void SEQ_free_animdata(Scene *scene, Sequence *seq)
BLI_gset_free(fcurves, NULL);
}
void SEQ_animation_backup_original(Scene *scene, ListBase *list)
void SEQ_animation_backup_original(Scene *scene, SeqAnimationBackup *backup)
{
if (scene->adt == NULL || scene->adt->action == NULL ||
BLI_listbase_is_empty(&scene->adt->action->curves)) {
return;
if (SEQ_animation_curves_exist(scene)) {
BLI_movelisttolist(&backup->curves, &scene->adt->action->curves);
}
if (SEQ_animation_drivers_exist(scene)) {
BLI_movelisttolist(&backup->drivers, &scene->adt->drivers);
}
BLI_movelisttolist(list, &scene->adt->action->curves);
}
void SEQ_animation_restore_original(Scene *scene, ListBase *list)
void SEQ_animation_restore_original(Scene *scene, SeqAnimationBackup *backup)
{
if (scene->adt == NULL || scene->adt->action == NULL || BLI_listbase_is_empty(list)) {
return;
if (!BLI_listbase_is_empty(&backup->curves)) {
BLI_movelisttolist(&scene->adt->action->curves, &backup->curves);
}
if (!BLI_listbase_is_empty(&backup->drivers)) {
BLI_movelisttolist(&scene->adt->drivers, &backup->drivers);
}
BLI_movelisttolist(&scene->adt->action->curves, list);
}
void SEQ_animation_duplicate(Scene *scene, Sequence *seq, ListBase *list)
static void seq_animation_duplicate(Scene *scene, Sequence *seq, ListBase *dst, ListBase *src)
{
if (BLI_listbase_is_empty(list)) {
return;
}
if (seq->type == SEQ_TYPE_META) {
LISTBASE_FOREACH (Sequence *, meta_child, &seq->seqbase) {
SEQ_animation_duplicate(scene, meta_child, list);
seq_animation_duplicate(scene, meta_child, dst, src);
}
}
GSet *fcurves = SEQ_fcurves_by_strip_get(seq, list);
GSet *fcurves = SEQ_fcurves_by_strip_get(seq, src);
if (fcurves == NULL) {
return;
}
GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) {
FCurve *fcu_cpy = BKE_fcurve_copy(fcu);
BLI_addtail(&scene->adt->action->curves, fcu_cpy);
BLI_addtail(dst, fcu_cpy);
}
GSET_FOREACH_END();
BLI_gset_free(fcurves, NULL);
}
void SEQ_animation_duplicate_backup_to_scene(Scene *scene,
Sequence *seq,
SeqAnimationBackup *backup)
{
if (!BLI_listbase_is_empty(&backup->curves)) {
seq_animation_duplicate(scene, seq, &scene->adt->action->curves, &backup->curves);
}
if (!BLI_listbase_is_empty(&backup->drivers)) {
seq_animation_duplicate(scene, seq, &scene->adt->drivers, &backup->drivers);
}
}

View File

@ -44,6 +44,7 @@
ListBase seqbase_clipboard;
ListBase fcurves_clipboard;
ListBase drivers_clipboard;
int seqbase_clipboard_frame;
static char seq_clipboard_active_seq_name[SEQ_NAME_MAXSTR];
@ -62,6 +63,11 @@ void SEQ_clipboard_free(void)
BKE_fcurve_free(fcu);
}
BLI_listbase_clear(&fcurves_clipboard);
LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &drivers_clipboard) {
BKE_fcurve_free(fcu);
}
BLI_listbase_clear(&drivers_clipboard);
}
#define ID_PT (*id_pt)

View File

@ -436,8 +436,8 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
}
/* Store `F-Curves`, so original ones aren't renamed. */
ListBase fcurves_original_backup = {NULL, NULL};
SEQ_animation_backup_original(scene, &fcurves_original_backup);
SeqAnimationBackup animation_backup = {0};
SEQ_animation_backup_original(scene, &animation_backup);
ListBase left_strips = {NULL, NULL};
SEQ_ITERATOR_FOREACH (seq, collection) {
@ -446,7 +446,7 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
BLI_addtail(&left_strips, seq);
/* Duplicate curves from backup, so they can be renamed along with split strips. */
SEQ_animation_duplicate(scene, seq, &fcurves_original_backup);
SEQ_animation_duplicate_backup_to_scene(scene, seq, &animation_backup);
}
SEQ_collection_free(collection);
@ -489,7 +489,7 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
}
SEQ_edit_remove_flagged_sequences(scene, seqbase);
SEQ_animation_restore_original(scene, &fcurves_original_backup);
SEQ_animation_restore_original(scene, &animation_backup);
return return_seq;
}