From 11d10ef32922c71155a0925af4618104052ac9d6 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 6 Nov 2018 18:30:38 +1100 Subject: [PATCH] added more functionality to transition tool --- effects/effect.cpp | 62 +++++-- effects/effect.h | 19 ++- effects/internal/crossdissolvetransition.cpp | 16 +- effects/internal/crossdissolvetransition.h | 12 ++ .../internal/exponentialfadetransition.cpp | 37 ++++ effects/internal/exponentialfadetransition.h | 12 ++ effects/internal/linearfadetransition.cpp | 29 ++-- effects/internal/linearfadetransition.h | 12 ++ .../internal/logarithmicfadetransition.cpp | 27 +++ effects/internal/logarithmicfadetransition.h | 12 ++ effects/transition.cpp | 42 ----- effects/transition.h | 53 ------ olive.pro | 12 +- panels/effectcontrols.cpp | 92 +++++----- panels/project.cpp | 159 +++++++++--------- panels/timeline.cpp | 47 +++++- panels/timeline.h | 9 +- playback/cacher.cpp | 10 +- project/clip.cpp | 13 +- project/clip.h | 5 +- project/sequence.cpp | 1 - project/undo.cpp | 9 +- project/undo.h | 10 +- ui/timelinewidget.cpp | 30 ++-- ui/timelinewidget.h | 5 +- ui/viewerwidget.cpp | 48 +++--- ui/viewerwidget.h | 3 + 27 files changed, 456 insertions(+), 330 deletions(-) create mode 100644 effects/internal/crossdissolvetransition.h create mode 100644 effects/internal/exponentialfadetransition.cpp create mode 100644 effects/internal/exponentialfadetransition.h create mode 100644 effects/internal/linearfadetransition.h create mode 100644 effects/internal/logarithmicfadetransition.cpp create mode 100644 effects/internal/logarithmicfadetransition.h delete mode 100644 effects/transition.cpp delete mode 100644 effects/transition.h diff --git a/effects/effect.cpp b/effects/effect.cpp index 9336ef3c8..9673c5d22 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -29,6 +29,10 @@ #include "effects/internal/volumeeffect.h" #include "effects/internal/paneffect.h" #include "effects/internal/shakeeffect.h" +#include "effects/internal/crossdissolvetransition.h" +#include "effects/internal/linearfadetransition.h" +#include "effects/internal/exponentialfadetransition.h" +#include "effects/internal/logarithmicfadetransition.h" #include #include @@ -52,14 +56,18 @@ Effect* create_effect(Clip* c, const EffectMeta* em) { } else if (em->internal >= 0 && em->internal < EFFECT_INTERNAL_COUNT) { // must be an internal effect switch (em->internal) { - case EFFECT_INTERNAL_TRANSFORM: return new TransformEffect(c, em); break; - case EFFECT_INTERNAL_TEXT: return new TextEffect(c, em); break; - case EFFECT_INTERNAL_SOLID: return new SolidEffect(c, em); break; - case EFFECT_INTERNAL_NOISE: return new AudioNoiseEffect(c, em); break; - case EFFECT_INTERNAL_VOLUME: return new VolumeEffect(c, em); break; - case EFFECT_INTERNAL_PAN: return new PanEffect(c, em); break; - case EFFECT_INTERNAL_TONE: return new ToneEffect(c, em); break; - case EFFECT_INTERNAL_SHAKE: return new ShakeEffect(c, em); break; + case EFFECT_INTERNAL_TRANSFORM: return new TransformEffect(c, em); + case EFFECT_INTERNAL_TEXT: return new TextEffect(c, em); + case EFFECT_INTERNAL_SOLID: return new SolidEffect(c, em); + case EFFECT_INTERNAL_NOISE: return new AudioNoiseEffect(c, em); + case EFFECT_INTERNAL_VOLUME: return new VolumeEffect(c, em); + case EFFECT_INTERNAL_PAN: return new PanEffect(c, em); + case EFFECT_INTERNAL_TONE: return new ToneEffect(c, em); + case EFFECT_INTERNAL_SHAKE: return new ShakeEffect(c, em); + case EFFECT_INTERNAL_CROSSDISSOLVE: return new CrossDissolveTransition(c, em); + case EFFECT_INTERNAL_LINEARFADE: return new LinearFadeTransition(c, em); + case EFFECT_INTERNAL_EXPONENTIALFADE: return new ExponentialFadeTransition(c, em); + case EFFECT_INTERNAL_LOGARITHMICFADE: return new LogarithmicFadeTransition(c, em); } } else { dout << "[ERROR] Invalid effect data"; @@ -85,6 +93,9 @@ const EffectMeta* get_internal_meta(int internal_id) { void load_internal_effects() { EffectMeta em; + // internal effects + em.type = EFFECT_TYPE_EFFECT; + em.name = "Volume"; em.internal = EFFECT_INTERNAL_VOLUME; audio_effects.append(em); @@ -120,6 +131,27 @@ void load_internal_effects() { em.category = "Distort"; em.internal = EFFECT_INTERNAL_SHAKE; video_effects.append(em); + + + // internal transitions + em.type = EFFECT_TYPE_TRANSITION; + em.category = ""; + + em.name = "Cross Dissolve"; + em.internal = EFFECT_INTERNAL_CROSSDISSOLVE; + video_effects.append(em); + + em.name = "Linear Fade"; + em.internal = EFFECT_INTERNAL_LINEARFADE; + audio_effects.append(em); + + em.name = "Exponential Fade"; + em.internal = EFFECT_INTERNAL_EXPONENTIALFADE; + audio_effects.append(em); + + em.name = "Logarithmic Fade"; + em.internal = EFFECT_INTERNAL_LOGARITHMICFADE; + audio_effects.append(em); } void load_shader_effects() { @@ -203,7 +235,9 @@ Effect::Effect(Clip* c, const EffectMeta *em) : isOpen(false), glslProgram(NULL), texture(NULL), - bound(false) + bound(false), + tlink(NULL), + length(30) { // set up base UI container = new CollapsibleWidget(); @@ -536,7 +570,9 @@ QString save_data_to_string(int type, const QVariant& data) { void Effect::load(QXmlStreamReader& stream) { int row_count = 0; - while (!stream.atEnd() && !(stream.name() == "effect" && stream.isEndElement())) { + QString tag = stream.name().toString(); + + while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) { stream.readNext(); if (stream.name() == "row" && stream.isStartElement()) { if (row_count < rows.size()) { @@ -552,7 +588,6 @@ void Effect::load(QXmlStreamReader& stream) { const QXmlStreamAttribute& attr = stream.attributes().at(k); if (attr.name() == "enabled") { row->setKeyframing(attr.value() == "1"); - break; } } if (row->isKeyframing()) { @@ -638,6 +673,10 @@ void Effect::load(QXmlStreamReader& stream) { } void Effect::save(QXmlStreamWriter& stream) { + stream.writeAttribute("name", meta->name); + stream.writeAttribute("enabled", QString::number(is_enabled())); + stream.writeAttribute("length", QString::number(length)); + for (int i=0;iset_enabled(is_enabled()); + copy->length = length; copy_field_keyframes(copy); return copy; } diff --git a/effects/effect.h b/effects/effect.h index 7c49aaffb..cd58bfea8 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -29,6 +29,7 @@ struct EffectMeta { QString category; QString filename; int internal; + int type; }; extern QVector video_effects; @@ -44,6 +45,8 @@ extern QMutex effects_loaded; #define EFFECT_TYPE_INVALID 0 #define EFFECT_TYPE_VIDEO 1 #define EFFECT_TYPE_AUDIO 2 +#define EFFECT_TYPE_EFFECT 3 +#define EFFECT_TYPE_TRANSITION 4 #define EFFECT_FIELD_DOUBLE 0 #define EFFECT_FIELD_COLOR 1 @@ -64,7 +67,16 @@ extern QMutex effects_loaded; #define EFFECT_INTERNAL_PAN 5 #define EFFECT_INTERNAL_TONE 6 #define EFFECT_INTERNAL_SHAKE 7 -#define EFFECT_INTERNAL_COUNT 8 +#define EFFECT_INTERNAL_CROSSDISSOLVE 8 +#define EFFECT_INTERNAL_LINEARFADE 9 +#define EFFECT_INTERNAL_EXPONENTIALFADE 10 +#define EFFECT_INTERNAL_LOGARITHMICFADE 11 +#define EFFECT_INTERNAL_COUNT 12 + +#define TRAN_TYPE_OPEN 1 +#define TRAN_TYPE_CLOSE 2 +#define TRAN_TYPE_OPENWLINK 3 +#define TRAN_TYPE_CLOSEWLINK 4 struct GLTextureCoords { int vertexTopLeftX; @@ -193,6 +205,9 @@ public: QString name; CollapsibleWidget* container; + long length; // only used for transitions + Effect* tlink; + EffectRow* add_row(const QString &name); EffectRow* row(int i); int row_count(); @@ -205,7 +220,7 @@ public: Effect* copy(Clip* c); void copy_field_keyframes(Effect *e); - void load(QXmlStreamReader& stream); + void load(QXmlStreamReader& stream); void save(QXmlStreamWriter& stream); // glsl handling diff --git a/effects/internal/crossdissolvetransition.cpp b/effects/internal/crossdissolvetransition.cpp index 4f88dff21..962eefc4c 100644 --- a/effects/internal/crossdissolvetransition.cpp +++ b/effects/internal/crossdissolvetransition.cpp @@ -1,19 +1,13 @@ -#include "../transition.h" +#include "crossdissolvetransition.h" #include -// TODO port to GLSL? +CrossDissolveTransition::CrossDissolveTransition(Clip* c, const EffectMeta* em) : Effect(c, em) { + enable_coords = true; +} -CrossDissolveTransition::CrossDissolveTransition() : Transition(VIDEO_DISSOLVE_TRANSITION) {} - -void CrossDissolveTransition::process_transition(double progress) { +void CrossDissolveTransition::process_coords(double progress, GLTextureCoords&) { float color[4]; glGetFloatv(GL_CURRENT_COLOR, color); glColor4f(1.0, 1.0, 1.0, color[3]*progress); } - -Transition* CrossDissolveTransition::copy() { - Transition* t = new CrossDissolveTransition(); - t->length = length; - return t; -} diff --git a/effects/internal/crossdissolvetransition.h b/effects/internal/crossdissolvetransition.h new file mode 100644 index 000000000..7792e9199 --- /dev/null +++ b/effects/internal/crossdissolvetransition.h @@ -0,0 +1,12 @@ +#ifndef CROSSDISSOLVETRANSITION_H +#define CROSSDISSOLVETRANSITION_H + +#include "../effect.h" + +class CrossDissolveTransition : public Effect { +public: + CrossDissolveTransition(Clip* c, const EffectMeta* em); + void process_coords(double timecode, GLTextureCoords &); +}; + +#endif // CROSSDISSOLVETRANSITION_H diff --git a/effects/internal/exponentialfadetransition.cpp b/effects/internal/exponentialfadetransition.cpp new file mode 100644 index 000000000..55307555f --- /dev/null +++ b/effects/internal/exponentialfadetransition.cpp @@ -0,0 +1,37 @@ +#include "exponentialfadetransition.h" + +#include + +ExponentialFadeTransition::ExponentialFadeTransition(Clip* c, const EffectMeta* em) : Effect(c, em) {} + +void ExponentialFadeTransition::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int type) { + double interval = (timecode_end-timecode_start)/nb_bytes; + + for (int i=0;i> 8); + samples[i] = (quint8) samp; + } +} diff --git a/effects/internal/exponentialfadetransition.h b/effects/internal/exponentialfadetransition.h new file mode 100644 index 000000000..a040ceb48 --- /dev/null +++ b/effects/internal/exponentialfadetransition.h @@ -0,0 +1,12 @@ +#ifndef EXPONENTIALFADETRANSITION_H +#define EXPONENTIALFADETRANSITION_H + +#include "../effect.h" + +class ExponentialFadeTransition : public Effect { +public: + ExponentialFadeTransition(Clip* c, const EffectMeta* em); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); +}; + +#endif // LINEARFADETRANSITION_H diff --git a/effects/internal/linearfadetransition.cpp b/effects/internal/linearfadetransition.cpp index 58d63d843..3b1f9cc70 100644 --- a/effects/internal/linearfadetransition.cpp +++ b/effects/internal/linearfadetransition.cpp @@ -1,26 +1,25 @@ -#include "../transition.h" +#include "linearfadetransition.h" -LinearFadeTransition::LinearFadeTransition() : Transition(AUDIO_LINEAR_FADE_TRANSITION) {} +LinearFadeTransition::LinearFadeTransition(Clip* c, const EffectMeta* em) : Effect(c, em) {} -void LinearFadeTransition::process_audio(double range_start, double range_end, quint8* samples, int nb_samples, bool reverse) { - double interval = (range_end - range_start) / nb_samples; +void LinearFadeTransition::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int type) { + double interval = (timecode_end-timecode_start)/nb_bytes; - for (int i=0;i> 8); samples[i] = (quint8) samp; } } - -Transition* LinearFadeTransition::copy() { - Transition* t = new LinearFadeTransition(); - t->length = length; - return t; -} diff --git a/effects/internal/linearfadetransition.h b/effects/internal/linearfadetransition.h new file mode 100644 index 000000000..92ec16fc8 --- /dev/null +++ b/effects/internal/linearfadetransition.h @@ -0,0 +1,12 @@ +#ifndef LINEARFADETRANSITION_H +#define LINEARFADETRANSITION_H + +#include "../effect.h" + +class LinearFadeTransition : public Effect { +public: + LinearFadeTransition(Clip* c, const EffectMeta* em); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); +}; + +#endif // LINEARFADETRANSITION_H diff --git a/effects/internal/logarithmicfadetransition.cpp b/effects/internal/logarithmicfadetransition.cpp new file mode 100644 index 000000000..a19f58c77 --- /dev/null +++ b/effects/internal/logarithmicfadetransition.cpp @@ -0,0 +1,27 @@ +#include "logarithmicfadetransition.h" + +#include + +LogarithmicFadeTransition::LogarithmicFadeTransition(Clip* c, const EffectMeta* em) : Effect(c, em) {} + +void LogarithmicFadeTransition::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int type) { + double interval = (timecode_end-timecode_start)/nb_bytes; + + for (int i=0;i> 8); + samples[i] = (quint8) samp; + } +} diff --git a/effects/internal/logarithmicfadetransition.h b/effects/internal/logarithmicfadetransition.h new file mode 100644 index 000000000..b758ce1c6 --- /dev/null +++ b/effects/internal/logarithmicfadetransition.h @@ -0,0 +1,12 @@ +#ifndef LOGARITHMICFADETRANSITION_H +#define LOGARITHMICFADETRANSITION_H + +#include "../effect.h" + +class LogarithmicFadeTransition : public Effect { +public: + LogarithmicFadeTransition(Clip* c, const EffectMeta* em); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); +}; + +#endif // LOGARITHMICFADETRANSITION_H diff --git a/effects/transition.cpp b/effects/transition.cpp deleted file mode 100644 index 2309dbd9b..000000000 --- a/effects/transition.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "transition.h" - -#include "project/clip.h" -#include "io/config.h" -#include "debug.h" - -QVector video_transition_names; -QVector audio_transition_names; - -void init_transitions() { - video_transition_names.resize(VIDEO_TRANSITION_COUNT); - audio_transition_names.resize(AUDIO_TRANSITION_COUNT); - - video_transition_names[VIDEO_DISSOLVE_TRANSITION] = "Cross Dissolve"; - - audio_transition_names[AUDIO_LINEAR_FADE_TRANSITION] = "Linear Fade"; -} - -Transition::Transition(int i) : id(i), name(video_transition_names[i]), length(config.default_transition_length), link(NULL) {} - -Transition::~Transition() {} - -Transition* Transition::copy() { - return NULL; -} - -void Transition::process_transition(double) {} -void Transition::process_audio(double, double, quint8*, int, bool) {} - -Transition* create_transition(int transition_id, Clip* c) { - if (c->track < 0) { - switch (transition_id) { - case VIDEO_DISSOLVE_TRANSITION: return new CrossDissolveTransition(); - } - } else { - switch (transition_id) { - case AUDIO_LINEAR_FADE_TRANSITION: return new LinearFadeTransition(); - } - } - dout << "[ERROR] Invalid transition ID"; - return NULL; -} diff --git a/effects/transition.h b/effects/transition.h deleted file mode 100644 index 3f9f7ec80..000000000 --- a/effects/transition.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef TRANSITION_H -#define TRANSITION_H - -#include - -struct Clip; - -enum VideoTransitions { - VIDEO_DISSOLVE_TRANSITION, - VIDEO_TRANSITION_COUNT -}; - -enum AudioTransitions { - AUDIO_LINEAR_FADE_TRANSITION, - AUDIO_TRANSITION_COUNT -}; - -class Transition -{ -public: - Transition(int); - ~Transition(); - int id; - QString name; - int length; - Transition* link; - virtual void process_transition(double); - virtual void process_audio(double, double, quint8*, int, bool); - virtual Transition* copy(); -}; - -void init_transitions(); -Transition* create_transition(int transition_id, Clip* c); -extern QVector video_transition_names; -extern QVector audio_transition_names; - -// Video Transitions -class CrossDissolveTransition : public Transition { -public: - CrossDissolveTransition(); - void process_transition(double); - Transition* copy(); -}; - -// Audio Transitions -class LinearFadeTransition : public Transition { -public: - LinearFadeTransition(); - void process_audio(double, double, quint8*, int, bool); - Transition* copy(); -}; - -#endif // TRANSITION_H diff --git a/olive.pro b/olive.pro index c35f16d72..52886806d 100644 --- a/olive.pro +++ b/olive.pro @@ -51,7 +51,6 @@ SOURCES += \ io/previewgenerator.cpp \ ui/labelslider.cpp \ dialogs/preferencesdialog.cpp \ - effects/transition.cpp \ ui/audiomonitor.cpp \ project/undo.cpp \ ui/scrollarea.cpp \ @@ -81,7 +80,9 @@ SOURCES += \ effects/internal/toneeffect.cpp \ effects/internal/volumeeffect.cpp \ effects/internal/crossdissolvetransition.cpp \ - effects/internal/shakeeffect.cpp + effects/internal/shakeeffect.cpp \ + effects/internal/exponentialfadetransition.cpp \ + effects/internal/logarithmicfadetransition.cpp HEADERS += \ mainwindow.h \ @@ -111,7 +112,6 @@ HEADERS += \ io/previewgenerator.h \ ui/labelslider.h \ dialogs/preferencesdialog.h \ - effects/transition.h \ ui/audiomonitor.h \ project/undo.h \ ui/scrollarea.h \ @@ -141,7 +141,11 @@ HEADERS += \ effects/internal/paneffect.h \ effects/internal/toneeffect.h \ effects/internal/volumeeffect.h \ - effects/internal/shakeeffect.h + effects/internal/shakeeffect.h \ + effects/internal/linearfadetransition.h \ + effects/internal/crossdissolvetransition.h \ + effects/internal/exponentialfadetransition.h \ + effects/internal/logarithmicfadetransition.h FORMS += \ mainwindow.ui \ diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 7e2826225..c0c8275fd 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -8,7 +8,6 @@ #include "panels/panels.h" #include "effects/effect.h" -#include "effects/transition.h" #include "project/clip.h" #include "effects/effect.h" #include "ui/collapsiblewidget.h" @@ -27,8 +26,7 @@ EffectControls::EffectControls(QWidget *parent) : ui(new Ui::EffectControls) { ui->setupUi(this); - init_effects(); - init_transitions(); + init_effects(); clear_effects(false); ui->headers->viewer = panel_sequence_viewer; ui->headers->snapping = false; @@ -66,15 +64,16 @@ void EffectControls::menu_select(QAction* q) { for (int i=0;iclips.at(selected_clips.at(i)); if ((c->track < 0) == video_menu) { + const EffectMeta* meta = reinterpret_cast(q->data().value()); if (transition_menu) { if (c->opening_transition == NULL) { - ca->append(new AddTransitionCommand(c, q->data().toInt(), TA_OPENING_TRANSITION)); + ca->append(new AddTransitionCommand(c, meta, TA_OPENING_TRANSITION, 30)); } if (c->closing_transition == NULL) { - ca->append(new AddTransitionCommand(c, q->data().toInt(), TA_CLOSING_TRANSITION)); + ca->append(new AddTransitionCommand(c, meta, TA_CLOSING_TRANSITION, 30)); } } else { - ca->append(new AddEffectCommand(c, reinterpret_cast(q->data().value()))); + ca->append(new AddEffectCommand(c, meta)); } } } @@ -149,7 +148,7 @@ void EffectControls::show_effect_menu(bool video, bool transitions) { video_menu = video; transition_menu = transitions; - if (transition_menu) { + /*if (transition_menu) { // TODO old effect/transition code grandfathered in, to be updated int lim; @@ -181,64 +180,67 @@ void EffectControls::show_effect_menu(bool video, bool transitions) { } connect(&effects_menu, SIGNAL(triggered(QAction*)), this, SLOT(menu_select(QAction*))); effects_menu.exec(QCursor::pos()); - } else { + } else {*/ effects_loaded.lock(); QVector& effect_list = (video) ? video_effects : audio_effects; QMenu effects_menu(this); for (int i=0;isetText(em.name); - action->setData(reinterpret_cast(&em)); - QMenu* parent = &effects_menu; - if (!em.category.isEmpty()) { - bool found = false; - for (int j=0;jmenu() != NULL) { - if (action->menu()->title() == em.category) { - parent = action->menu(); - found = true; - break; - } - } - } - if (!found) { - parent = new QMenu(&effects_menu); - parent->setTitle(em.category); + if (em.type == EFFECT_TYPE_TRANSITION == transition_menu) { + QAction* action = new QAction(&effects_menu); + action->setText(em.name); + action->setData(reinterpret_cast(&em)); + QMenu* parent = &effects_menu; + if (!em.category.isEmpty()) { bool found = false; - for (int i=0;itext() > em.category) { - effects_menu.insertMenu(comp_action, parent); - found = true; - break; + for (int j=0;jmenu() != NULL) { + if (action->menu()->title() == em.category) { + parent = action->menu(); + found = true; + break; + } } } - if (!found) effects_menu.addMenu(parent); - } - } + if (!found) { + parent = new QMenu(&effects_menu); + parent->setTitle(em.category); - bool found = false; - for (int i=0;iactions().size();i++) { - QAction* comp_action = parent->actions().at(i); - if (comp_action->text() > action->text()) { - parent->insertAction(comp_action, action); - found = true; - break; + bool found = false; + for (int i=0;itext() > em.category) { + effects_menu.insertMenu(comp_action, parent); + found = true; + break; + } + } + if (!found) effects_menu.addMenu(parent); + } } + + bool found = false; + for (int i=0;iactions().size();i++) { + QAction* comp_action = parent->actions().at(i); + if (comp_action->text() > action->text()) { + parent->insertAction(comp_action, action); + found = true; + break; + } + } + if (!found) parent->addAction(action); } - if (!found) parent->addAction(action); } effects_loaded.unlock(); connect(&effects_menu, SIGNAL(triggered(QAction*)), this, SLOT(menu_select(QAction*))); effects_menu.exec(QCursor::pos()); - } + //} } void EffectControls::clear_effects(bool clear_cache) { diff --git a/panels/project.cpp b/panels/project.cpp index 3678cf85b..c720d73dc 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -10,7 +10,6 @@ #include "panels/timeline.h" #include "project/sequence.h" #include "effects/effect.h" -#include "effects/transition.h" #include "io/previewgenerator.h" #include "project/undo.h" #include "mainwindow.h" @@ -360,7 +359,6 @@ void Project::delete_selected_media() { } for (int i=0;iappend(new DeleteMediaCommand(items.at(i))); if (get_type_from_tree(items.at(i)) == MEDIA_TYPE_SEQUENCE) { @@ -982,70 +980,78 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) { } } } - } else if (stream.name() == "effects") { - while (!(stream.name() == "effects" && stream.isEndElement()) && !stream.atEnd()) { - stream.readNext(); - if (stream.name() == "effect" && stream.isStartElement()) { - int effect_id = -1; - QString effect_name; - bool effect_enabled = true; - for (int j=0;jtrack < 0) ? "Transform" : "Volume"; break; - case 1: effect_name = (c->track < 0) ? "Shake" : "Pan"; break; - case 2: effect_name = (c->track < 0) ? "Text" : "Noise"; break; - case 3: effect_name = (c->track < 0) ? "Solid" : "Tone"; break; - case 4: effect_name = "Invert"; break; - case 5: effect_name = "Chroma Key"; break; - case 6: effect_name = "Gaussian Blur"; break; - case 7: effect_name = "Crop"; break; - case 8: effect_name = "Flip"; break; - case 9: effect_name = "Box Blur"; break; - case 10: effect_name = "Wave"; break; - case 11: effect_name = "Temperature"; break; - } + // backwards compatibility with 180820 + if (stream.name() == "effect" && effect_id != -1) { + switch (effect_id) { + case 0: effect_name = (c->track < 0) ? "Transform" : "Volume"; break; + case 1: effect_name = (c->track < 0) ? "Shake" : "Pan"; break; + case 2: effect_name = (c->track < 0) ? "Text" : "Noise"; break; + case 3: effect_name = (c->track < 0) ? "Solid" : "Tone"; break; + case 4: effect_name = "Invert"; break; + case 5: effect_name = "Chroma Key"; break; + case 6: effect_name = "Gaussian Blur"; break; + case 7: effect_name = "Crop"; break; + case 8: effect_name = "Flip"; break; + case 9: effect_name = "Box Blur"; break; + case 10: effect_name = "Wave"; break; + case 11: effect_name = "Temperature"; break; + } + } + + // wait for effects to be loaded + effects_loaded.lock(); + + const EffectMeta* meta = NULL; + + // find effect with this name + if (!effect_name.isEmpty()) { + QVector& effect_list = (c->track < 0) ? video_effects : audio_effects; + for (int j=0;j& effect_list = (c->track < 0) ? video_effects : audio_effects; - for (int j=0;j -1) e->length = effect_length; + e->set_enabled(effect_enabled); + e->load(stream); - if (meta == NULL) { - dout << "[WARNING] An effect used by this project is missing. It was not loaded."; - } else { - Effect* e = create_effect(c, meta); - e->set_enabled(effect_enabled); - e->load(stream); - c->effects.append(e); - } - - effects_loaded.unlock(); - } - } + if (tag == "opening") { + c->opening_transition = e; + } else if (tag == "closing") { + c->closing_transition = e; + } else { + c->effects.append(e); + } + } } } } @@ -1290,12 +1296,7 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int stream.writeAttribute("in", QString::number(c->timeline_in)); stream.writeAttribute("out", QString::number(c->timeline_out)); stream.writeAttribute("track", QString::number(c->track)); - if (c->opening_transition != NULL) { - stream.writeAttribute("opening", QString::number(c->opening_transition->id)); - } - if (c->closing_transition != NULL) { - stream.writeAttribute("closing", QString::number(c->closing_transition->id)); - } + stream.writeAttribute("r", QString::number(c->color_r)); stream.writeAttribute("g", QString::number(c->color_g)); stream.writeAttribute("b", QString::number(c->color_b)); @@ -1324,16 +1325,24 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int } stream.writeEndElement(); // linked - stream.writeStartElement("effects"); // effects for (int k=0;keffects.size();k++) { - stream.writeStartElement("effect"); // effect - Effect* e = c->effects.at(k); - stream.writeAttribute("name", e->meta->name); - stream.writeAttribute("enabled", QString::number(e->is_enabled())); - e->save(stream); - stream.writeEndElement(); // effect - } - stream.writeEndElement(); // effects + stream.writeStartElement("effect"); // effect + c->effects.at(k)->save(stream); + stream.writeEndElement(); // effect + } + + if (c->opening_transition != NULL) { + stream.writeStartElement("opening"); + c->opening_transition->save(stream); + stream.writeEndElement(); // opening + } + + if (c->closing_transition != NULL) { + stream.writeStartElement("closing"); // closing + c->closing_transition->save(stream); + stream.writeEndElement(); // closing + } + stream.writeEndElement(); // clip } } diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 9cea7bcf7..7190db9ec 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -12,10 +12,11 @@ #include "panels/viewer.h" #include "playback/cacher.h" #include "playback/playback.h" -#include "effects/transition.h" #include "ui_viewer.h" #include "project/undo.h" #include "io/config.h" +#include "effects/effect.h" +#include "debug.h" #include #include @@ -159,11 +160,11 @@ void Timeline::add_transition() { Clip* c = sequence->clips.at(i); if (c != NULL && is_clip_selected(c, true)) { if (c->opening_transition == NULL) { - ca->append(new AddTransitionCommand(c, 0, TA_OPENING_TRANSITION)); + ca->append(new AddTransitionCommand(c, get_internal_meta(EFFECT_INTERNAL_LINEARFADE), TA_OPENING_TRANSITION, 30)); adding = true; } if (c->closing_transition == NULL) { - ca->append(new AddTransitionCommand(c, 0, TA_OPENING_TRANSITION)); + ca->append(new AddTransitionCommand(c, get_internal_meta(EFFECT_INTERNAL_LINEARFADE), TA_OPENING_TRANSITION, 30)); adding = true; } } @@ -1192,8 +1193,44 @@ void Timeline::on_recordButton_clicked() { } void Timeline::on_toolTransitionButton_clicked() { - decheck_tool_buttons(sender()); + creating = false; + + QMenu transition_menu(this); + + for (int i=0;isetObjectName("v"); + a->setData(reinterpret_cast(&em)); + } + } + + transition_menu.addSeparator(); + + for (int i=0;isetObjectName("a"); + a->setData(reinterpret_cast(&em)); + } + } + + connect(&transition_menu, SIGNAL(triggered(QAction*)), this, SLOT(transition_menu_select(QAction*))); + transition_menu.exec(QCursor::pos()); +} + +void Timeline::transition_menu_select(QAction* a) { + transition_tool_meta = reinterpret_cast(a->data().value()); + + if (a->objectName() == "v") { + transition_tool_side = -1; + } else { + transition_tool_side = 1; + } + + decheck_tool_buttons(sender()); ui->timeline_area->setCursor(Qt::CrossCursor); tool = TIMELINE_TOOL_TRANSITION; - creating = false; } diff --git a/panels/timeline.h b/panels/timeline.h index 9e11bd2d6..006883cfb 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -21,7 +21,8 @@ class QPushButton; class SourceTable; class ViewerWidget; class ComboAction; -class Transition; +class Effect; +struct EffectMeta; struct Sequence; struct Clip; struct Media; @@ -57,7 +58,7 @@ struct Ghost { bool trimming; // transition trimming - Transition* transition; + Effect* transition; }; namespace Ui { @@ -169,6 +170,8 @@ public: bool transition_tool_proc; int transition_tool_clip; int transition_tool_type; + const EffectMeta* transition_tool_meta; + int transition_tool_side; // clipboard QVector clip_clipboard; @@ -209,6 +212,8 @@ private slots: void on_toolTransitionButton_clicked(); + void transition_menu_select(QAction*); + private: QVector tool_buttons; void decheck_tool_buttons(QObject* sender); diff --git a/playback/cacher.cpp b/playback/cacher.cpp index b5329b9ba..9a439ccbc 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -8,7 +8,6 @@ #include "effects/effect.h" #include "panels/timeline.h" #include "panels/project.h" -#include "effects/transition.h" #include "debug.h" extern "C" { @@ -47,24 +46,24 @@ void apply_audio_effects(Clip* c, double timecode_start, AVFrame* frame, int nb_ if (c->opening_transition != NULL) { if (c->media_type == MEDIA_TYPE_FOOTAGE) { double transition_start = (c->clip_in / c->sequence->frame_rate); - double transition_end = transition_start + (c->opening_transition->length / c->sequence->frame_rate); + double transition_end = ((c->clip_in + c->opening_transition->length) / c->sequence->frame_rate); if (timecode_end < transition_end) { double adjustment = transition_end - transition_start; double adjusted_range_start = (timecode_start - transition_start) / adjustment; double adjusted_range_end = (timecode_end - transition_start) / adjustment; - c->opening_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, false); + c->opening_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, TRAN_TYPE_OPEN); } } } if (c->closing_transition != NULL) { if (c->media_type == MEDIA_TYPE_FOOTAGE) { + double transition_start = (c->clip_in + c->getLength() - c->closing_transition->length) / c->sequence->frame_rate; double transition_end = (c->clip_in + c->getLength()) / c->sequence->frame_rate; - double transition_start = transition_end - (c->closing_transition->length / c->sequence->frame_rate); if (timecode_start > transition_start) { double adjustment = transition_end - transition_start; double adjusted_range_start = (timecode_start - transition_start) / adjustment; double adjusted_range_end = (timecode_end - transition_start) / adjustment; - c->closing_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, true); + c->closing_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, TRAN_TYPE_CLOSE); } } } @@ -485,7 +484,6 @@ void cache_video_worker(Clip* c, long playhead) { } void reset_cache(Clip* c, long target_frame) { - dout << "reset called"; // if we seek to a whole other place in the timeline, we'll need to reset the cache with new values switch (c->media_type) { case MEDIA_TYPE_FOOTAGE: diff --git a/project/clip.cpp b/project/clip.cpp index 6dad0aaef..66b493129 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -1,7 +1,6 @@ #include "clip.h" #include "effects/effect.h" -#include "effects/transition.h" #include "io/media.h" #include "io/config.h" #include "playback/playback.h" @@ -65,8 +64,8 @@ Clip* Clip::copy(Sequence* s) { copy->effects.append(effects.at(i)->copy(copy)); } - if (opening_transition != NULL) copy->opening_transition = opening_transition->copy(); - if (closing_transition != NULL) copy->closing_transition = closing_transition->copy(); + if (opening_transition != NULL) copy->opening_transition = opening_transition->copy(copy); + if (closing_transition != NULL) copy->closing_transition = closing_transition->copy(copy); copy->recalculateMaxLength(); @@ -164,16 +163,16 @@ Clip::~Clip() { } long Clip::get_timeline_in_with_transition() { - if (opening_transition != NULL && opening_transition->link != NULL) { - return timeline_in - opening_transition->link->length; + if (opening_transition != NULL && opening_transition->tlink != NULL) { + return timeline_in - opening_transition->tlink->length; } else { return timeline_in; } } long Clip::get_timeline_out_with_transition() { - if (closing_transition != NULL && closing_transition->link != NULL) { - return timeline_out + closing_transition->link->length; + if (closing_transition != NULL && closing_transition->tlink != NULL) { + return timeline_out + closing_transition->tlink->length; } else { return timeline_out; } diff --git a/project/clip.h b/project/clip.h index 6e43be8c2..70ab4d2b7 100644 --- a/project/clip.h +++ b/project/clip.h @@ -10,7 +10,6 @@ class Cacher; class Effect; -class Transition; class QOpenGLFramebufferObject; class ComboAction; struct Sequence; @@ -73,8 +72,8 @@ struct Clip // other variables (should be deep copied/duplicated in copy()) QList effects; QVector linked; - Transition* opening_transition; - Transition* closing_transition; + Effect* opening_transition; + Effect* closing_transition; // media handling AVFormatContext* formatCtx; diff --git a/project/sequence.cpp b/project/sequence.cpp index 86619a02c..519292280 100644 --- a/project/sequence.cpp +++ b/project/sequence.cpp @@ -1,7 +1,6 @@ #include "sequence.h" #include "project/clip.h" -#include "effects/transition.h" Sequence::Sequence() : playhead(0), diff --git a/project/undo.cpp b/project/undo.cpp index eb60dc6ea..8391f67ed 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -16,7 +16,6 @@ #include "effects/effect.h" #include "io/media.h" #include "playback/cacher.h" -#include "effects/transition.h" #include "ui/labelslider.h" #include "ui/viewerwidget.h" #include "project/marker.h" @@ -194,7 +193,7 @@ void SetTimelineInOutCommand::redo() { mainWindow->setWindowModified(true); } -AddEffectCommand::AddEffectCommand(Clip* c, EffectMeta *e) : +AddEffectCommand::AddEffectCommand(Clip* c, const EffectMeta *e) : clip(c), meta(e), ref(NULL), @@ -221,7 +220,7 @@ void AddEffectCommand::redo() { mainWindow->setWindowModified(true); } -AddTransitionCommand::AddTransitionCommand(Clip* c, int itransition, int itype, int ilength) : +AddTransitionCommand::AddTransitionCommand(Clip* c, const EffectMeta *itransition, int itype, int ilength) : clip(c), transition(itransition), type(itype), @@ -242,10 +241,10 @@ void AddTransitionCommand::undo() { void AddTransitionCommand::redo() { if (type == TA_OPENING_TRANSITION) { - clip->opening_transition = create_transition(transition, clip); + clip->opening_transition = create_effect(clip, transition); if (length > 0) clip->opening_transition->length = length; } else { - clip->closing_transition = create_transition(transition, clip); + clip->closing_transition = create_effect(clip, transition); if (length > 0) clip->closing_transition->length = length; } mainWindow->setWindowModified(true); diff --git a/project/undo.h b/project/undo.h index 9b5dac767..4ff0e0de8 100644 --- a/project/undo.h +++ b/project/undo.h @@ -91,13 +91,13 @@ private: class AddEffectCommand : public QUndoCommand { public: - AddEffectCommand(Clip* c, EffectMeta* e); + AddEffectCommand(Clip* c, const EffectMeta* e); ~AddEffectCommand(); void undo(); void redo(); private: Clip* clip; - EffectMeta* meta; + const EffectMeta* meta; Effect* ref; bool done; bool old_project_changed; @@ -105,12 +105,12 @@ private: class AddTransitionCommand : public QUndoCommand { public: - AddTransitionCommand(Clip* c, int itransition, int itype, int ilength = 0); + AddTransitionCommand(Clip* c, const EffectMeta* itransition, int itype, int ilength); void undo(); void redo(); private: Clip* clip; - int transition; + const EffectMeta* transition; int type; int length; bool old_project_changed; @@ -138,7 +138,7 @@ public: private: Clip* clip; int type; - Transition* transition; + Effect* transition; bool old_project_changed; }; diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index cb8e1b957..a7768622a 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -18,7 +18,6 @@ #include "debug.h" #include "effects/effect.h" -#include "effects/transition.h" #include "effects/internal/solideffect.h" #include "effects/internal/texteffect.h" @@ -1206,9 +1205,9 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { panel_timeline->delete_areas_and_relink(ca, areas); ca->append(new MoveClipAction(c, qMin(transition_start, c->timeline_in), qMax(transition_end, c->timeline_out), c->clip_in, c->track)); - } + } - ca->append(new AddTransitionCommand(c, 0, panel_timeline->transition_tool_type, transition_end - transition_start)); + ca->append(new AddTransitionCommand(c, panel_timeline->transition_tool_meta, panel_timeline->transition_tool_type, transition_end - transition_start)); push_undo = true; } @@ -2100,15 +2099,22 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { panel_timeline->transition_tool_proc = true; } } else { - panel_timeline->transition_tool_clip = getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track); + int mouse_clip = getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track); + if (mouse_clip > -1) { + Clip* c = sequence->clips.at(mouse_clip); + if (same_sign(c->track, panel_timeline->transition_tool_side)) { + panel_timeline->transition_tool_clip = mouse_clip; + long halfway = c->timeline_in + (c->getLength()/2); + if (panel_timeline->cursor_frame > halfway) { + panel_timeline->transition_tool_type = TA_CLOSING_TRANSITION; + } else { + panel_timeline->transition_tool_type = TA_OPENING_TRANSITION; + } + } + } + if (panel_timeline->transition_tool_clip > -1) { - Clip* c = sequence->clips.at(panel_timeline->transition_tool_clip); - long halfway = c->timeline_in + (c->getLength()/2); - if (panel_timeline->cursor_frame > halfway) { - panel_timeline->transition_tool_type = TA_CLOSING_TRANSITION; - } else { - panel_timeline->transition_tool_type = TA_OPENING_TRANSITION; - } + } } @@ -2323,7 +2329,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) { // draw clip transitions for (int i=0;i<2;i++) { - Transition* t = (i == 0) ? clip->opening_transition : clip->closing_transition; + Effect* t = (i == 0) ? clip->opening_transition : clip->closing_transition; if (t != NULL) { int transition_width = getScreenPointFromFrame(panel_timeline->zoom, t->length); int transition_height = clip_rect.height(); diff --git a/ui/timelinewidget.h b/ui/timelinewidget.h index 3b0b77e00..b995555f4 100644 --- a/ui/timelinewidget.h +++ b/ui/timelinewidget.h @@ -76,10 +76,7 @@ private: int scroll; - SetSelectionsCommand* selection_command; - - /*QVector file_import_items; - QVector file_import_media;*/ + SetSelectionsCommand* selection_command; signals: public slots: diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 7d9e43b1c..b8604ed44 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -6,7 +6,6 @@ #include "panels/project.h" #include "project/sequence.h" #include "effects/effect.h" -#include "effects/transition.h" #include "playback/playback.h" #include "playback/audio.h" #include "io/media.h" @@ -198,6 +197,26 @@ GLuint ViewerWidget::draw_clip(QOpenGLFramebufferObject* fbo, GLuint texture) { return fbo->texture(); } +void ViewerWidget::process_effect(Clip* c, Effect* e, double timecode, GLTextureCoords& coords, GLuint& composite_texture, bool& fbo_switcher) { + if (e->is_enabled()) { + if (e->enable_coords) { + e->process_coords(timecode, coords); + } + if (e->enable_shader || e->enable_superimpose) { + e->startEffect(); + if (e->enable_shader) { + e->process_shader(timecode); + } + composite_texture = draw_clip(c->fbo[fbo_switcher], composite_texture); + if (e->enable_superimpose) { + GLuint superimpose_texture = e->process_superimpose(timecode); + if (superimpose_texture != 0) draw_clip(c->fbo[fbo_switcher], superimpose_texture); + } + fbo_switcher = !fbo_switcher; + } + } +} + GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { Sequence* s = viewer->seq; long playhead = s->playhead; @@ -359,39 +378,24 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { } // EFFECT CODE START + double timecode = ((double)(playhead-c->timeline_in+c->clip_in)/(double)c->sequence->frame_rate); for (int j=0;jeffects.size();j++) { - Effect* e = c->effects.at(j); - if (e->is_enabled()) { - double timecode = ((double)(playhead-c->timeline_in+c->clip_in)/(double)c->sequence->frame_rate); - if (e->enable_coords) { - e->process_coords(timecode, coords); - } - if (e->enable_shader || e->enable_superimpose) { - e->startEffect(); - if (e->enable_shader) { - e->process_shader(timecode); - } - composite_texture = draw_clip(c->fbo[fbo_switcher], composite_texture); - if (e->enable_superimpose) { - GLuint superimpose_texture = e->process_superimpose(timecode); - if (superimpose_texture != 0) draw_clip(c->fbo[fbo_switcher], superimpose_texture); - } - fbo_switcher = !fbo_switcher; - } - } + process_effect(c, c->effects.at(j), timecode, coords, composite_texture, fbo_switcher); } if (c->opening_transition != NULL) { int transition_progress = playhead - c->timeline_in; if (transition_progress < c->opening_transition->length) { - c->opening_transition->process_transition((double)transition_progress/(double)c->opening_transition->length); + process_effect(c, c->opening_transition, (double)transition_progress/(double)c->opening_transition->length, coords, composite_texture, fbo_switcher); + //c->opening_transition->process_transition((double)transition_progress/(double)c->opening_transition->length); } } if (c->closing_transition != NULL) { int transition_progress = c->closing_transition->length - (playhead - c->timeline_in - c->getLength() + c->closing_transition->length); if (transition_progress < c->closing_transition->length) { - c->closing_transition->process_transition((double)transition_progress/(double)c->closing_transition->length); + process_effect(c, c->closing_transition, (double)transition_progress/(double)c->closing_transition->length, coords, composite_texture, fbo_switcher); + //c->closing_transition->process_transition((double)transition_progress/(double)c->closing_transition->length); } } diff --git a/ui/viewerwidget.h b/ui/viewerwidget.h index 4d0b6e1fc..cdf1c7f12 100644 --- a/ui/viewerwidget.h +++ b/ui/viewerwidget.h @@ -13,6 +13,8 @@ class Viewer; struct Clip; struct MediaStream; class QOpenGLFramebufferObject; +class Effect; +struct GLTextureCoords; class ViewerWidget : public QOpenGLWidget { @@ -42,6 +44,7 @@ private: void seek_from_click(int x); GLuint compose_sequence(Clip *nest, bool render_audio); GLuint draw_clip(QOpenGLFramebufferObject *clip, GLuint texture); + void process_effect(Clip* c, Effect* e, double timecode, GLTextureCoords& coords, GLuint& composite_texture, bool& fbo_switcher); private slots: void retry(); void deleteFunction();