From 10347f94187ce3b82fc45a7cedb2306a97007991 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 30 Oct 2018 11:23:14 +1100 Subject: [PATCH] effects system rewrite --- effects/effect.cpp | 303 ++++++++++++++++++++++++++++---------- effects/effect.h | 22 ++- io/config.h | 2 +- io/media.cpp | 4 +- io/media.h | 1 + io/path.cpp | 18 ++- io/path.h | 2 + io/previewgenerator.cpp | 1 + mainwindow.cpp | 2 + olive.pro | 32 ---- panels/effectcontrols.cpp | 48 +++++- panels/project.cpp | 3 +- project/undo.cpp | 6 +- project/undo.h | 5 +- ui/timelinewidget.cpp | 4 +- ui/viewerwidget.cpp | 18 +-- 16 files changed, 327 insertions(+), 144 deletions(-) diff --git a/effects/effect.cpp b/effects/effect.cpp index a168fbb32..18cf85430 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -17,24 +17,7 @@ #include "panels/timeline.h" #include "panels/effectcontrols.h" #include "debug.h" - -#include "effects/video/transformeffect.h" -#include "effects/video/inverteffect.h" -#include "effects/video/shakeeffect.h" -#include "effects/video/solideffect.h" -#include "effects/video/texteffect.h" -#include "effects/video/chromakeyeffect.h" -#include "effects/video/gaussianblureffect.h" -#include "effects/video/cropeffect.h" -#include "effects/video/flipeffect.h" -#include "effects/video/boxblureffect.h" -#include "effects/video/waveeffect.h" -#include "effects/video/temperatureeffect.h" - -#include "effects/audio/paneffect.h" -#include "effects/audio/volumeeffect.h" -#include "effects/audio/audionoiseeffect.h" -#include "effects/audio/toneeffect.h" +#include "io/path.h" #include #include @@ -42,58 +25,92 @@ #include #include #include +#include + +QVector video_effects; +QVector audio_effects; QVector video_effect_names; QVector audio_effect_names; void init_effects() { - video_effect_names.resize(VIDEO_EFFECT_COUNT); - audio_effect_names.resize(AUDIO_EFFECT_COUNT); + video_effect_names.resize(VIDEO_EFFECT_COUNT); + audio_effect_names.resize(AUDIO_EFFECT_COUNT); - video_effect_names[VIDEO_TRANSFORM_EFFECT] = "Transform"; - video_effect_names[VIDEO_SHAKE_EFFECT] = "Shake"; - video_effect_names[VIDEO_TEXT_EFFECT] = "Text"; - video_effect_names[VIDEO_SOLID_EFFECT] = "Solid"; - video_effect_names[VIDEO_INVERT_EFFECT] = "Invert"; - video_effect_names[VIDEO_CHROMAKEY_EFFECT] = "Chroma Key"; - video_effect_names[VIDEO_GAUSSIANBLUR_EFFECT] = "Gaussian Blur"; - video_effect_names[VIDEO_CROP_EFFECT] = "Crop"; - video_effect_names[VIDEO_FLIP_EFFECT] = "Flip"; + video_effect_names[VIDEO_TRANSFORM_EFFECT] = "Transform"; + video_effect_names[VIDEO_SHAKE_EFFECT] = "Shake"; + video_effect_names[VIDEO_TEXT_EFFECT] = "Text"; + video_effect_names[VIDEO_SOLID_EFFECT] = "Solid"; + video_effect_names[VIDEO_INVERT_EFFECT] = "Invert"; + video_effect_names[VIDEO_CHROMAKEY_EFFECT] = "Chroma Key"; + video_effect_names[VIDEO_GAUSSIANBLUR_EFFECT] = "Gaussian Blur"; + video_effect_names[VIDEO_CROP_EFFECT] = "Crop"; + video_effect_names[VIDEO_FLIP_EFFECT] = "Flip"; video_effect_names[VIDEO_BOXBLUR_EFFECT] = "Box Blur"; - video_effect_names[VIDEO_WAVE_EFFECT] = "Wave"; + video_effect_names[VIDEO_WAVE_EFFECT] = "Wave"; video_effect_names[VIDEO_TEMPERATURE_EFFECT] = "Temperature"; - audio_effect_names[AUDIO_VOLUME_EFFECT] = "Volume"; - audio_effect_names[AUDIO_PAN_EFFECT] = "Pan"; - audio_effect_names[AUDIO_NOISE_EFFECT] = "Noise"; - audio_effect_names[AUDIO_TONE_EFFECT] = "Tone"; + audio_effect_names[AUDIO_VOLUME_EFFECT] = "Volume"; + audio_effect_names[AUDIO_PAN_EFFECT] = "Pan"; + audio_effect_names[AUDIO_NOISE_EFFECT] = "Noise"; + audio_effect_names[AUDIO_TONE_EFFECT] = "Tone"; + + dout << "Starting init effect (TODO: multithread this)"; + QString effects_path = get_effects_dir(); + QDir effects_dir(effects_path); + if (effects_dir.exists()) { + QList entries = effects_dir.entryList(QStringList("*.xml"), QDir::Files); + for (int i=0;itrack < 0) { - switch (effect_id) { - case VIDEO_TRANSFORM_EFFECT: return new TransformEffect(c); break; - case VIDEO_SHAKE_EFFECT: return new ShakeEffect(c); break; - case VIDEO_TEXT_EFFECT: return new TextEffect(c); break; - case VIDEO_SOLID_EFFECT: return new SolidEffect(c); break; - case VIDEO_INVERT_EFFECT: return new InvertEffect(c); break; - case VIDEO_CHROMAKEY_EFFECT: return new ChromaKeyEffect(c); break; - case VIDEO_GAUSSIANBLUR_EFFECT: return new GaussianBlurEffect(c); break; - case VIDEO_CROP_EFFECT: return new CropEffect(c); - case VIDEO_FLIP_EFFECT: return new FlipEffect(c); - case VIDEO_BOXBLUR_EFFECT: return new BoxBlurEffect(c); - case VIDEO_WAVE_EFFECT: return new WaveEffect(c); - case VIDEO_TEMPERATURE_EFFECT: return new TemperatureEffect(c); - } - } else { - switch (effect_id) { - case AUDIO_VOLUME_EFFECT: return new VolumeEffect(c); break; - case AUDIO_PAN_EFFECT: return new PanEffect(c); break; - case AUDIO_NOISE_EFFECT: return new AudioNoiseEffect(c); break; - case AUDIO_TONE_EFFECT: return new ToneEffect(c); break; - } - } - dout << "[ERROR] Invalid effect ID"; return NULL; } @@ -101,31 +118,167 @@ double double_lerp(double a, double b, double t) { return ((1.0 - t) * a) + (t * b); } -Effect::Effect(Clip* c, int t, int i) : +Effect::Effect(Clip* c, const EffectMeta &em) : parent_clip(c), - type(t), - id(i), + meta(em), enable_shader(false), enable_coords(false), - enable_superimpose(false), - iterations(1), + enable_superimpose(false), isOpen(false), glslProgram(NULL), bound(false) { - container = new CollapsibleWidget(); - if (type == EFFECT_TYPE_VIDEO) { - container->setText(video_effect_names[i]); - } else if (type == EFFECT_TYPE_AUDIO) { - container->setText(audio_effect_names[i]); - } + // set up base UI + container = new CollapsibleWidget(); connect(container->enabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed())); ui = new QWidget(); - ui_layout = new QGridLayout(); ui_layout->setSpacing(4); ui->setLayout(ui_layout); container->setContents(ui); + + // set up UI from effect file + container->setText(em.name); + QFile effect_file(get_effects_dir() + "/" + em.filename); + + if (effect_file.open(QFile::ReadOnly)) { + QXmlStreamReader reader(&effect_file); + + while (!reader.atEnd()) { + if (reader.name() == "row" && reader.isStartElement()) { + QString row_name; + const QXmlStreamAttributes& attributes = reader.attributes(); + for (int i=0;i -1) { + EffectField* field = row->add_field(type); + switch (type) { + case EFFECT_FIELD_DOUBLE: + for (int i=0;iset_double_default_value(attr.value().toDouble()); + } else if (attr.name() == "min") { + field->set_double_minimum_value(attr.value().toDouble()); + } else if (attr.name() == "max") { + field->set_double_maximum_value(attr.value().toDouble()); + } + } + break; + case EFFECT_FIELD_COLOR: + { + QColor color; + for (int i=0;iset_string_value(attr.value().toString()); + } + } + break; + case EFFECT_FIELD_BOOL: + for (int i=0;iset_bool_value(attr.value() == "1"); + } + } + break; + case EFFECT_FIELD_COMBO: + { + int combo_index = 0; + for (int i=0;iadd_combo_item(reader.text().toString(), 0); + } + } + field->set_combo_index(combo_index); + } + break; + case EFFECT_FIELD_FONT: + for (int i=0;iset_font_name(attr.value().toString()); + } + } + break; + } + } + } + } + } + } + reader.readNext(); + } + + effect_file.close(); + } else { + dout << "[ERROR] Failed to open effect file" << em.filename; + } } Effect::~Effect() { @@ -351,14 +504,6 @@ void Effect::endEffect() { bound = false; } -int Effect::getIterations() { - return iterations; -} - -void Effect::setIterations(int i) { - iterations = qMax(i, 1); -} - Effect* Effect::copy(Clip* c) { Effect* copy = create_effect(id, c); copy->set_enabled(is_enabled()); @@ -371,7 +516,7 @@ void Effect::process_coords(double, GLTextureCoords&) {} GLuint Effect::process_superimpose(double) {return 0;} void Effect::process_audio(double, double, quint8*, int, int) {} -SuperimposeEffect::SuperimposeEffect(Clip* c, int t, int i) : Effect(c, t, i), texture(NULL) { +SuperimposeEffect::SuperimposeEffect(Clip* c, const EffectMeta& e) : Effect(c, e), texture(NULL) { enable_superimpose = true; } diff --git a/effects/effect.h b/effects/effect.h index 950d3ad52..db63969aa 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -46,8 +46,17 @@ enum AudioEffects { AUDIO_EFFECT_COUNT }; -extern QVector video_effect_names; -extern QVector audio_effect_names; +struct EffectMeta { + QString name; + QString category; + QString filename; +}; + +extern QVector video_effects; +extern QVector audio_effects; + +extern QVector video_effect_names; // deprecated +extern QVector audio_effect_names; // deprecated void init_effects(); Effect* create_effect(int effect_id, Clip* c); @@ -184,10 +193,10 @@ private: class Effect : public QObject { Q_OBJECT public: - Effect(Clip* c, int t, int i); + Effect(Clip* c, const EffectMeta& em); ~Effect(); Clip* parent_clip; - int type; + const EffectMeta& meta; int id; QString name; CollapsibleWidget* container; @@ -236,14 +245,13 @@ protected: private: QVector rows; QGridLayout* ui_layout; - QWidget* ui; - int iterations; + QWidget* ui; bool bound; }; class SuperimposeEffect : public Effect { public: - SuperimposeEffect(Clip* c, int t, int i); + SuperimposeEffect(Clip* c, const EffectMeta& e); virtual void open(); virtual void close(); virtual GLuint process_superimpose(double timecode); diff --git a/io/config.h b/io/config.h index 5531f9672..dbd7fcd40 100644 --- a/io/config.h +++ b/io/config.h @@ -3,7 +3,7 @@ #include -#define SAVE_VERSION "180820" // YYMMDD +#define SAVE_VERSION "181030" // YYMMDD #define TIMECODE_DROP 0 #define TIMECODE_NONDROP 1 diff --git a/io/media.cpp b/io/media.cpp index 7947c5667..f2b3f55de 100644 --- a/io/media.cpp +++ b/io/media.cpp @@ -10,7 +10,9 @@ extern "C" { #include "project/clip.h" -Media::Media() : ready(false), preview_gen(NULL) {} +Media::Media() : ready(false), preview_gen(NULL) { + ready_lock.lock(); +} Media::~Media() { reset(); diff --git a/io/media.h b/io/media.h index 39a937507..8c4e50e05 100644 --- a/io/media.h +++ b/io/media.h @@ -53,6 +53,7 @@ struct Media { bool ready; PreviewGenerator* preview_gen; + QMutex ready_lock; bool using_inout; long in; diff --git a/io/path.cpp b/io/path.cpp index 26f76127d..21442a27f 100644 --- a/io/path.cpp +++ b/io/path.cpp @@ -4,10 +4,22 @@ #include #include -QString get_data_path() { - QString app_path = QCoreApplication::applicationFilePath(); - QString app_dir = app_path.left(app_path.lastIndexOf('/')); +QString real_app_dir; +QString get_effects_dir() { + return get_app_dir() + "/effects"; +} + +QString get_app_dir() { + if (real_app_dir.isEmpty()) { + QString app_path = QCoreApplication::applicationFilePath(); + real_app_dir = app_path.left(app_path.lastIndexOf('/')); + } + return real_app_dir; +} + +QString get_data_path() { + QString app_dir = get_app_dir(); if (QFileInfo::exists(app_dir + "/portable")) { return app_dir; } else { diff --git a/io/path.h b/io/path.h index f11fc206f..b53476693 100644 --- a/io/path.h +++ b/io/path.h @@ -3,6 +3,8 @@ #include +QString get_app_dir(); QString get_data_path(); +QString get_effects_dir(); #endif // PATH_H diff --git a/io/previewgenerator.cpp b/io/previewgenerator.cpp index 5be60b80a..49e69596a 100644 --- a/io/previewgenerator.cpp +++ b/io/previewgenerator.cpp @@ -168,6 +168,7 @@ bool PreviewGenerator::retrieve_preview(const QString& hash) { } void PreviewGenerator::finalize_media() { + media->ready_lock.unlock(); media->ready = true; if (media->video_tracks.size() == 0) { diff --git a/mainwindow.cpp b/mainwindow.cpp index a813f2c6c..9dd0aa214 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -128,6 +128,8 @@ MainWindow::MainWindow(QWidget *parent) : qint64 a_month_ago = QDateTime::currentMSecsSinceEpoch() - 2592000000; qint64 a_week_ago = QDateTime::currentMSecsSinceEpoch() - 604800000; + // TODO put delete functions in another thread? + // delete auto-recoveries older than 7 days QStringList old_autorecoveries = dir.entryList(QStringList("autorecovery.ove.*"), QDir::Files); int deleted_ars = 0; diff --git a/olive.pro b/olive.pro index dd4495482..79f7c9aba 100644 --- a/olive.pro +++ b/olive.pro @@ -63,28 +63,12 @@ SOURCES += \ ui/fontcombobox.cpp \ ui/checkboxex.cpp \ effects/effect.cpp \ - effects/video/transformeffect.cpp \ - effects/audio/volumeeffect.cpp \ - effects/audio/paneffect.cpp \ - effects/video/texteffect.cpp \ - effects/video/solideffect.cpp \ - effects/video/shakeeffect.cpp \ - effects/video/inverteffect.cpp \ ui/keyframeview.cpp \ ui/texteditex.cpp \ - effects/video/chromakeyeffect.cpp \ - effects/video/gaussianblureffect.cpp \ - effects/video/cropeffect.cpp \ - effects/video/flipeffect.cpp \ - effects/audio/audionoiseeffect.cpp \ - effects/video/boxblureffect.cpp \ dialogs/demonotice.cpp \ - effects/audio/toneeffect.cpp \ project/marker.cpp \ dialogs/speeddialog.cpp \ dialogs/mediapropertiesdialog.cpp \ - effects/video/waveeffect.cpp \ - effects/video/temperatureeffect.cpp \ io/crc32.cpp \ dialogs/loaddialog.cpp \ debug.cpp \ @@ -128,30 +112,14 @@ HEADERS += \ ui/fontcombobox.h \ ui/checkboxex.h \ effects/effect.h \ - effects/video/transformeffect.h \ - effects/video/solideffect.h \ - effects/video/shakeeffect.h \ - effects/video/texteffect.h \ - effects/video/inverteffect.h \ - effects/audio/volumeeffect.h \ - effects/audio/paneffect.h \ ui/keyframeview.h \ ui/texteditex.h \ - effects/video/chromakeyeffect.h \ - effects/video/gaussianblureffect.h \ - effects/video/cropeffect.h \ - effects/video/flipeffect.h \ - effects/audio/audionoiseeffect.h \ - effects/video/boxblureffect.h \ dialogs/demonotice.h \ - effects/audio/toneeffect.h \ project/marker.h \ project/selection.h \ dialogs/speeddialog.h \ dialogs/speeddialog.h \ dialogs/mediapropertiesdialog.h \ - effects/video/waveeffect.h \ - effects/video/temperatureeffect.h \ io/crc32.h \ dialogs/loaddialog.h \ debug.h \ diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index fc944f1fa..d73da0ae1 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -74,7 +74,7 @@ void EffectControls::menu_select(QAction* q) { ca->append(new AddTransitionCommand(c, q->data().toInt(), TA_CLOSING_TRANSITION)); } } else { - ca->append(new AddEffectCommand(c, q->data().toInt())); + ca->append(new AddEffectCommand(c, reinterpret_cast(q->data().value()))); } } } @@ -84,7 +84,7 @@ void EffectControls::menu_select(QAction* q) { } else { reload_clips(); panel_sequence_viewer->viewer_widget->update(); - } + } } void EffectControls::update_keyframes() { @@ -97,7 +97,7 @@ void EffectControls::delete_selected_keyframes() { } void EffectControls::show_effect_menu(bool video, bool transitions) { - video_menu = video; + /*video_menu = video; transition_menu = transitions; int lim; @@ -142,6 +142,48 @@ 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());*/ + video_menu = video; + transition_menu = transitions; + + QVector& effect_list = (video) ? video_effects : audio_effects; + QMenu effects_menu(this); + for (int i=0;isetText(em.name); + action->setData(reinterpret_cast(&em)); + + // TODO alphabetical ordering + 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); + effects_menu.addMenu(parent); + } + } + + parent->addAction(action); + } + + QMenu test_menu(this); + test_menu.setTitle("HEY NOW"); + test_menu.addAction("YOU'RE AN ALL STAR"); + effects_menu.addMenu(&test_menu); + + connect(&effects_menu, SIGNAL(triggered(QAction*)), this, SLOT(menu_select(QAction*))); effects_menu.exec(QCursor::pos()); } diff --git a/panels/project.cpp b/panels/project.cpp index 01dc75d64..4c2f1ab72 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -56,8 +56,7 @@ Project::Project(QWidget *parent) : connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(rename_media(QTreeWidgetItem*,int))); } -Project::~Project() -{ +Project::~Project() { delete ui; } diff --git a/project/undo.cpp b/project/undo.cpp index 7235745eb..191e8a57a 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -193,9 +193,9 @@ void SetTimelineInOutCommand::redo() { mainWindow->setWindowModified(true); } -AddEffectCommand::AddEffectCommand(Clip* c, int ieffect) : +AddEffectCommand::AddEffectCommand(Clip* c, EffectMeta *e) : clip(c), - effect(ieffect), + meta(e), ref(NULL), done(false), old_project_changed(mainWindow->isWindowModified()) @@ -213,7 +213,7 @@ void AddEffectCommand::undo() { void AddEffectCommand::redo() { if (ref == NULL) { - ref = create_effect(effect, clip); + ref = new Effect(clip, *meta); } clip->effects.append(ref); done = true; diff --git a/project/undo.h b/project/undo.h index 138cf964a..f00fe0e43 100644 --- a/project/undo.h +++ b/project/undo.h @@ -12,6 +12,7 @@ class Transition; struct Clip; struct Sequence; struct Media; +struct EffectMeta; #include "project/marker.h" #include "project/selection.h" @@ -90,13 +91,13 @@ private: class AddEffectCommand : public QUndoCommand { public: - AddEffectCommand(Clip* c, int ieffect); + AddEffectCommand(Clip* c, EffectMeta* e); ~AddEffectCommand(); void undo(); void redo(); private: Clip* clip; - int effect; + EffectMeta* meta; Effect* ref; bool done; bool old_project_changed; diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 0d949b0db..8c9ae11e5 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -623,14 +623,14 @@ void TimelineWidget::dropEvent(QDropEvent* event) { } } - if (c->track < 0) { + /*if (c->track < 0) { // add default video effects c->effects.append(create_effect(VIDEO_TRANSFORM_EFFECT, c)); } else { // add default audio effects c->effects.append(create_effect(AUDIO_VOLUME_EFFECT, c)); c->effects.append(create_effect(AUDIO_PAN_EFFECT, c)); - } + }*/ } panel_timeline->ghosts.clear(); diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index bd681128b..819f655e8 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -365,15 +365,15 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { } if (e->enable_shader || e->enable_superimpose) { e->startEffect(); - for (int k=0;kgetIterations();k++) { - 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; - } + //for (int k=0;kgetIterations();k++) { + 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; + //} } } }