From 01435f0d0c7b8e959d5c64af10cb6926e26a813f Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 31 Oct 2018 17:14:40 +1100 Subject: [PATCH] sweeping effects rewrite that allows external plugins --- effects/crossdissolvetransition.cpp | 2 + effects/effect.cpp | 727 +++++++++++------- effects/effect.h | 85 +- effects/effects/README | 1 + .../boxblur.frag} | 0 effects/effects/boxblur.xml | 13 + effects/{video/glsl => effects}/common.vert | 0 effects/effects/crop.frag | 36 + effects/effects/crop.xml | 19 + .../gaussianblur.frag} | 0 effects/effects/gaussianblur.xml | 16 + .../inverteffect.frag => effects/invert.frag} | 3 +- effects/effects/invert.xml | 7 + .../waveeffect.frag => effects/wave.frag} | 4 +- effects/effects/wave.xml | 16 + .../{audio => internal}/audionoiseeffect.cpp | 6 +- .../{audio => internal}/audionoiseeffect.h | 2 +- .../{ => internal}/linearfadetransition.cpp | 0 effects/{audio => internal}/paneffect.cpp | 5 +- effects/{audio => internal}/paneffect.h | 2 +- effects/{video => internal}/solideffect.cpp | 7 +- effects/{video => internal}/solideffect.h | 4 +- effects/{video => internal}/texteffect.cpp | 20 +- effects/{video => internal}/texteffect.h | 4 +- effects/{audio => internal}/toneeffect.cpp | 9 +- effects/{audio => internal}/toneeffect.h | 2 +- .../{video => internal}/transformeffect.cpp | 12 +- effects/{video => internal}/transformeffect.h | 2 +- effects/{audio => internal}/volumeeffect.cpp | 6 +- effects/{audio => internal}/volumeeffect.h | 2 +- effects/qpainterwrapper.cpp | 43 ++ effects/qpainterwrapper.h | 24 + effects/video/boxblureffect.cpp | 41 - effects/video/boxblureffect.h | 18 - effects/video/chromakeyeffect.cpp | 25 - effects/video/chromakeyeffect.h | 15 - effects/video/cropeffect.cpp | 67 -- effects/video/cropeffect.h | 18 - effects/video/flipeffect.cpp | 36 - effects/video/flipeffect.h | 16 - effects/video/gaussianblureffect.cpp | 39 - effects/video/gaussianblureffect.h | 18 - effects/video/glsl/chromakeyeffect.frag | 16 - effects/video/glsl/shaders.qrc | 12 - effects/video/glsl/solideffect.frag | 16 - effects/video/glsl/temperatureeffect.frag | 42 - effects/video/inverteffect.cpp | 27 - effects/video/inverteffect.h | 15 - effects/video/shakeeffect.cpp | 107 --- effects/video/shakeeffect.h | 35 - effects/video/temperatureeffect.cpp | 19 - effects/video/temperatureeffect.h | 15 - effects/video/waveeffect.cpp | 33 - effects/video/waveeffect.h | 19 - io/config.cpp | 2 +- io/config.h | 3 +- olive.pro | 27 +- panels/effectcontrols.cpp | 38 +- panels/project.cpp | 68 +- panels/timeline.cpp | 4 +- project/undo.cpp | 2 +- ui/timelinewidget.cpp | 44 +- ui/viewerwidget.cpp | 4 +- 63 files changed, 887 insertions(+), 1033 deletions(-) create mode 100644 effects/effects/README rename effects/{video/glsl/boxblureffect.frag => effects/boxblur.frag} (100%) create mode 100644 effects/effects/boxblur.xml rename effects/{video/glsl => effects}/common.vert (100%) create mode 100644 effects/effects/crop.frag create mode 100644 effects/effects/crop.xml rename effects/{video/glsl/gaussianblureffect.frag => effects/gaussianblur.frag} (100%) create mode 100644 effects/effects/gaussianblur.xml rename effects/{video/glsl/inverteffect.frag => effects/invert.frag} (82%) create mode 100644 effects/effects/invert.xml rename effects/{video/glsl/waveeffect.frag => effects/wave.frag} (77%) create mode 100644 effects/effects/wave.xml rename effects/{audio => internal}/audionoiseeffect.cpp (85%) rename effects/{audio => internal}/audionoiseeffect.h (83%) rename effects/{ => internal}/linearfadetransition.cpp (100%) rename effects/{audio => internal}/paneffect.cpp (83%) rename effects/{audio => internal}/paneffect.h (82%) rename effects/{video => internal}/solideffect.cpp (97%) rename effects/{video => internal}/solideffect.h (73%) rename effects/{video => internal}/texteffect.cpp (96%) rename effects/{video => internal}/texteffect.h (85%) rename effects/{audio => internal}/toneeffect.cpp (86%) rename effects/{audio => internal}/toneeffect.h (85%) rename effects/{video => internal}/transformeffect.cpp (91%) rename effects/{video => internal}/transformeffect.h (88%) rename effects/{audio => internal}/volumeeffect.cpp (77%) rename effects/{audio => internal}/volumeeffect.h (82%) create mode 100644 effects/qpainterwrapper.cpp create mode 100644 effects/qpainterwrapper.h delete mode 100644 effects/video/boxblureffect.cpp delete mode 100644 effects/video/boxblureffect.h delete mode 100644 effects/video/chromakeyeffect.cpp delete mode 100644 effects/video/chromakeyeffect.h delete mode 100644 effects/video/cropeffect.cpp delete mode 100644 effects/video/cropeffect.h delete mode 100644 effects/video/flipeffect.cpp delete mode 100644 effects/video/flipeffect.h delete mode 100644 effects/video/gaussianblureffect.cpp delete mode 100644 effects/video/gaussianblureffect.h delete mode 100644 effects/video/glsl/chromakeyeffect.frag delete mode 100644 effects/video/glsl/shaders.qrc delete mode 100644 effects/video/glsl/solideffect.frag delete mode 100644 effects/video/glsl/temperatureeffect.frag delete mode 100644 effects/video/inverteffect.cpp delete mode 100644 effects/video/inverteffect.h delete mode 100644 effects/video/shakeeffect.cpp delete mode 100644 effects/video/shakeeffect.h delete mode 100644 effects/video/temperatureeffect.cpp delete mode 100644 effects/video/temperatureeffect.h delete mode 100644 effects/video/waveeffect.cpp delete mode 100644 effects/video/waveeffect.h diff --git a/effects/crossdissolvetransition.cpp b/effects/crossdissolvetransition.cpp index b112615fe..990c2d6d8 100644 --- a/effects/crossdissolvetransition.cpp +++ b/effects/crossdissolvetransition.cpp @@ -2,6 +2,8 @@ #include +// TODO port to GLSL? + CrossDissolveTransition::CrossDissolveTransition() : Transition(VIDEO_DISSOLVE_TRANSITION) {} void CrossDissolveTransition::process_transition(double progress) { diff --git a/effects/effect.cpp b/effects/effect.cpp index 18cf85430..774eb1678 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -1,5 +1,6 @@ #include "effect.h" +#include "effects/qpainterwrapper.h" #include "panels/panels.h" #include "panels/viewer.h" #include "ui/viewerwidget.h" @@ -18,6 +19,15 @@ #include "panels/effectcontrols.h" #include "debug.h" #include "io/path.h" +#include "mainwindow.h" + +#include "effects/internal/transformeffect.h" +#include "effects/internal/texteffect.h" +#include "effects/internal/solideffect.h" +#include "effects/internal/audionoiseeffect.h" +#include "effects/internal/toneeffect.h" +#include "effects/internal/volumeeffect.h" +#include "effects/internal/paneffect.h" #include #include @@ -26,99 +36,147 @@ #include #include #include +#include +#include QVector video_effects; QVector audio_effects; +QMutex effects_loaded; -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[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_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"; - - 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;ifilename.isEmpty()) { + // load effect from file + return new Effect(c, 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; + } + } else { + dout << "[ERROR] Invalid effect data"; + QMessageBox::critical(mainWindow, "Invalid effect", "No candidate for effect '" + em->name + "'. This effect may be corrupt. Try reinstalling it or Olive."); + } + return NULL; } -Effect* create_effect(int effect_id, Clip* c) { - return NULL; +const EffectMeta* get_internal_meta(int internal_id) { + for (int i=0;i entries = effects_dir.entryList(QStringList("*.xml"), QDir::Files); + for (int i=0;isetContents(ui); // set up UI from effect file - container->setText(em.name); - QFile effect_file(get_effects_dir() + "/" + em.filename); + container->setText(em->name); - if (effect_file.open(QFile::ReadOnly)) { - QXmlStreamReader reader(&effect_file); + if (!em->filename.isEmpty()) { + 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(); - } + if (id.isEmpty()) { + dout << "[ERROR] Couldn't load field from" << em->filename << "- ID cannot be empty."; + } else if (type > -1) { + EffectField* field = row->add_field(type); + field->id = id; + connect(field, SIGNAL(changed()), this, SLOT(field_changed())); + 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_color_value(color); + } + break; + case EFFECT_FIELD_STRING: + 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; + } + } + } + } + } + } else if (reader.name() == "shader" && reader.isStartElement()) { + enable_shader = true; + const QXmlStreamAttributes& attributes = reader.attributes(); + for (int i=0;ifilename; + enable_superimpose = false; + } + break; + } + } + } + reader.readNext(); + } - effect_file.close(); - } else { - dout << "[ERROR] Failed to open effect file" << em.filename; - } + effect_file.close(); + } else { + dout << "[ERROR] Failed to open effect file" << em->filename; + } + } } Effect::~Effect() { @@ -294,13 +390,14 @@ Effect::~Effect() { void Effect::copy_field_keyframes(Effect* e) { for (int i=0;irows.at(i)->setKeyframing(rows.at(i)->isKeyframing()); - e->rows.at(i)->keyframe_times = rows.at(i)->keyframe_times; - e->rows.at(i)->keyframe_types = rows.at(i)->keyframe_types; + EffectRow* copy_row = e->rows.at(i); + copy_row->setKeyframing(row->isKeyframing()); + copy_row->keyframe_times = row->keyframe_times; + copy_row->keyframe_types = row->keyframe_types; for (int j=0;jfieldCount();j++) { EffectField* field = row->field(j); - e->rows.at(i)->field(j)->set_current_data(field->get_current_data()); - e->rows.at(i)->field(j)->keyframe_data = field->keyframe_data; + copy_row->field(j)->set_current_data(field->get_current_data()); + copy_row->field(j)->keyframe_data = field->keyframe_data; } } } @@ -405,8 +502,30 @@ void Effect::load(QXmlStreamReader& stream) { // read field if (stream.name() == "field" && stream.isStartElement()) { if (field_count < row->fieldCount()) { - EffectField* field = row->field(field_count); + // match field using ID + bool found_field_by_id = false; + int field_number = field_count; + for (int k=0;kfieldCount();l++) { + if (row->field(l)->id == attr.value()) { + field_number = l; + found_field_by_id = true; + dout << "[INFO] Found field by ID"; + break; + } + } + break; + } + } + // TODO DEPRECATED, only used for backwards compatibility with 180820 + if (!found_field_by_id) dout << "[INFO] Found field by field number"; + + EffectField* field = row->field(field_number); + + // get current field value for (int k=0;kfieldCount();j++) { EffectField* field = row->field(j); stream.writeStartElement("field"); // field + stream.writeAttribute("id", field->id); stream.writeAttribute("value", save_data_to_string(field->type, field->get_current_data())); for (int k=0;kkeyframe_data.size();k++) { stream.writeTextElement("key", save_data_to_string(field->type, field->keyframe_data.at(k))); @@ -470,24 +590,34 @@ void Effect::open() { dout << "[WARNING] Tried to open an effect that was already open"; close(); } - if (QOpenGLContext::currentContext() == NULL) { - dout << "[WARNING] No current context to create a shader program for - will retry next repaint"; + if (enable_shader) { + if (QOpenGLContext::currentContext() == NULL) { + dout << "[WARNING] No current context to create a shader program for - will retry next repaint"; + } else { + glslProgram = new QOpenGLShaderProgram(); + if (!vertPath.isEmpty()) glslProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, get_effects_dir() + "/" + vertPath); + if (!fragPath.isEmpty()) glslProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, get_effects_dir() + "/" + fragPath); + glslProgram->link(); + isOpen = true; + } } else { - glslProgram = new QOpenGLShaderProgram(); - if (!vertPath.isEmpty()) glslProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, vertPath); - if (!fragPath.isEmpty()) glslProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, fragPath); - glslProgram->link(); isOpen = true; } + + if (enable_superimpose) { + texture = new QOpenGLTexture(QOpenGLTexture::Target2D); + } } void Effect::close() { if (!isOpen) { dout << "[WARNING] Tried to close an effect that was already closed"; - } else { - delete glslProgram; } - glslProgram = NULL; + if (glslProgram != NULL) { + delete glslProgram; + glslProgram = NULL; + } + delete_texture(); isOpen = false; } @@ -496,7 +626,7 @@ void Effect::startEffect() { open(); dout << "[WARNING] Tried to start a closed effect - opening"; } - bound = glslProgram->bind(); + if (enable_shader) bound = glslProgram->bind(); } void Effect::endEffect() { @@ -505,32 +635,44 @@ void Effect::endEffect() { } Effect* Effect::copy(Clip* c) { - Effect* copy = create_effect(id, c); + Effect* copy = create_effect(c, meta); copy->set_enabled(is_enabled()); copy_field_keyframes(copy); return copy; } -void Effect::process_shader(double) {} +void Effect::process_shader(double timecode) { + glslProgram->setUniformValue("resolution", parent_clip->getWidth(), parent_clip->getHeight()); + + for (int i=0;ifieldCount();j++) { + EffectField* field = row->field(j); + if (!field->id.isEmpty()) { + switch (field->type) { + case EFFECT_FIELD_DOUBLE: + glslProgram->setUniformValue(field->id.toLatin1().constData(), (GLfloat) field->get_double_value(timecode)); + break; + case EFFECT_FIELD_COLOR: + glslProgram->setUniformValue(field->id.toLatin1().constData(), field->get_color_value(timecode)); + break; + case EFFECT_FIELD_STRING: break; // can you even send a string to a uniform value? + case EFFECT_FIELD_BOOL: + glslProgram->setUniformValue(field->id.toLatin1().constData(), field->get_bool_value(timecode)); + break; + case EFFECT_FIELD_COMBO: + glslProgram->setUniformValue(field->id.toLatin1().constData(), field->get_combo_index(timecode)); + break; + case EFFECT_FIELD_FONT: break; // can you even send a string to a uniform value? + } + } + } + } +} + 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, const EffectMeta& e) : Effect(c, e), texture(NULL) { - enable_superimpose = true; -} - -void SuperimposeEffect::open() { - Effect::open(); - texture = new QOpenGLTexture(QOpenGLTexture::Target2D); -} - -void SuperimposeEffect::close() { - Effect::close(); - deleteTexture(); -} - -GLuint SuperimposeEffect::process_superimpose(double timecode) { +GLuint Effect::process_superimpose(double timecode) { bool recreate_texture = false; int width = parent_clip->getWidth(); int height = parent_clip->getHeight(); @@ -546,7 +688,7 @@ GLuint SuperimposeEffect::process_superimpose(double timecode) { if (texture != NULL) { if (recreate_texture || texture->width() != img.width() || texture->height() != img.height()) { - deleteTexture(); + delete_texture(); texture = new QOpenGLTexture(QOpenGLTexture::Target2D); texture->setData(img); } else { @@ -555,17 +697,72 @@ GLuint SuperimposeEffect::process_superimpose(double timecode) { return texture->textureId(); } return 0; - } -void SuperimposeEffect::redraw(double) {} +void Effect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count) { + // only volume/pan, hand off to AU and VST for all other cases -void SuperimposeEffect::deleteTexture() { - delete texture; - texture = NULL; + double interval = (timecode_end-timecode_start)/nb_bytes; + + for (int i=0;ifield(0)->get_double_value(timecode_start+(interval*i), true)); + QJSValue result = eval.call(); + samp = result.toInt();*/ + /*QJSValueList args; + args << samples << nb_bytes;*/ + + + samples[i+1] = (quint8) (samp >> 8); + samples[i] = (quint8) samp; + } } -bool SuperimposeEffect::valueHasChanged(double timecode) { +void Effect::redraw(double timecode) { + // run javascript + QPainter p(&img); + painter_wrapper.img = &img; + painter_wrapper.painter = &p; + + jsEngine.globalObject().setProperty("painter", wrapper_obj); + jsEngine.globalObject().setProperty("width", parent_clip->getWidth()); + jsEngine.globalObject().setProperty("height", parent_clip->getHeight()); + + for (int i=0;ifieldCount();j++) { + EffectField* field = row->field(j); + if (!field->id.isEmpty()) { + switch (field->type) { + case EFFECT_FIELD_DOUBLE: + jsEngine.globalObject().setProperty(field->id, field->get_double_value(timecode)); + break; + case EFFECT_FIELD_COLOR: + jsEngine.globalObject().setProperty(field->id, field->get_color_value(timecode).name()); + break; + case EFFECT_FIELD_STRING: + jsEngine.globalObject().setProperty(field->id, field->get_string_value(timecode)); + break; + case EFFECT_FIELD_BOOL: + jsEngine.globalObject().setProperty(field->id, field->get_bool_value(timecode)); + break; + case EFFECT_FIELD_COMBO: + jsEngine.globalObject().setProperty(field->id, field->get_combo_index(timecode)); + break; + case EFFECT_FIELD_FONT: + jsEngine.globalObject().setProperty(field->id, field->get_font_name(timecode)); + break; + } + } + } + } + + jsEngine.evaluate(script); +} + +bool Effect::valueHasChanged(double timecode) { if (cachedValues.size() == 0) { for (int i=0;i(INT16_MAX)), static_cast(INT16_MIN)); return static_cast(mixed_sample); } + +double log_volume(double linear) { + // expects a value between 0 and 1 (or more if amplifying) + return (qExp(linear)-1)/(M_E-1); +} diff --git a/effects/effect.h b/effects/effect.h index db63969aa..f2a267847 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -8,6 +8,8 @@ #include #include #include +#include +#include class QLabel; class QWidget; class CollapsibleWidget; @@ -22,43 +24,22 @@ class EffectRow; class CheckboxEx; class KeyframeDelete; -enum VideoEffects { - VIDEO_TRANSFORM_EFFECT, - VIDEO_SHAKE_EFFECT, - VIDEO_TEXT_EFFECT, - VIDEO_SOLID_EFFECT, - VIDEO_INVERT_EFFECT, - VIDEO_CHROMAKEY_EFFECT, - VIDEO_GAUSSIANBLUR_EFFECT, - VIDEO_CROP_EFFECT, - VIDEO_FLIP_EFFECT, - VIDEO_BOXBLUR_EFFECT, - VIDEO_WAVE_EFFECT, - VIDEO_TEMPERATURE_EFFECT, - VIDEO_EFFECT_COUNT -}; - -enum AudioEffects { - AUDIO_VOLUME_EFFECT, - AUDIO_PAN_EFFECT, - AUDIO_NOISE_EFFECT, - AUDIO_TONE_EFFECT, - AUDIO_EFFECT_COUNT -}; - struct EffectMeta { QString name; QString category; QString filename; + int internal; }; extern QVector video_effects; extern QVector audio_effects; -extern QVector video_effect_names; // deprecated -extern QVector audio_effect_names; // deprecated +double log_volume(double linear); void init_effects(); -Effect* create_effect(int effect_id, Clip* c); +Effect* create_effect(Clip* c, const EffectMeta *em); +const EffectMeta* get_internal_meta(int internal_id); + +extern QMutex effects_loaded; #define EFFECT_TYPE_INVALID 0 #define EFFECT_TYPE_VIDEO 1 @@ -75,6 +56,15 @@ Effect* create_effect(int effect_id, Clip* c); #define EFFECT_KEYFRAME_HOLD 1 #define EFFECT_KEYFRAME_BEZIER 2 +#define EFFECT_INTERNAL_TRANSFORM 0 +#define EFFECT_INTERNAL_TEXT 1 +#define EFFECT_INTERNAL_SOLID 2 +#define EFFECT_INTERNAL_NOISE 3 +#define EFFECT_INTERNAL_VOLUME 4 +#define EFFECT_INTERNAL_PAN 5 +#define EFFECT_INTERNAL_TONE 6 +#define EFFECT_INTERNAL_COUNT 7 + struct GLTextureCoords { int vertexTopLeftX; int vertexTopLeftY; @@ -103,6 +93,7 @@ public: EffectField(EffectRow* parent, int t); EffectRow* parent_row; int type; + QString id; QVariant get_previous_data(); QVariant get_current_data(); @@ -193,10 +184,10 @@ private: class Effect : public QObject { Q_OBJECT public: - Effect(Clip* c, const EffectMeta& em); + Effect(Clip* c, const EffectMeta* em); ~Effect(); Clip* parent_clip; - const EffectMeta& meta; + const EffectMeta* meta; int id; QString name; CollapsibleWidget* container; @@ -210,15 +201,15 @@ public: virtual void refresh(); - Effect* copy(Clip* c); + Effect* copy(Clip* c); void copy_field_keyframes(Effect *e); void load(QXmlStreamReader& stream); void save(QXmlStreamWriter& stream); // glsl handling - virtual void open(); - virtual void close(); + void open(); + void close(); virtual void startEffect(); virtual void endEffect(); @@ -231,38 +222,38 @@ public: const char* ffmpeg_filter; - virtual void process_shader(double timecode); + void process_shader(double timecode); virtual void process_coords(double timecode, GLTextureCoords& coords); - virtual GLuint process_superimpose(double timecode); + virtual GLuint process_superimpose(double timecode); virtual void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); public slots: void field_changed(); protected: + // glsl effect QOpenGLShaderProgram* glslProgram; QString vertPath; QString fragPath; - bool isOpen; + + // superimpose effect + QImage img; + QOpenGLTexture* texture; private: + // superimpose effect + QJSEngine jsEngine; + QJSValue wrapper_obj; + QString script; + + bool isOpen; QVector rows; QGridLayout* ui_layout; QWidget* ui; bool bound; -}; -class SuperimposeEffect : public Effect { -public: - SuperimposeEffect(Clip* c, const EffectMeta& e); - virtual void open(); - virtual void close(); - virtual GLuint process_superimpose(double timecode); + // superimpose functions virtual void redraw(double timecode); -protected: - QImage img; - QOpenGLTexture* texture; - void deleteTexture(); bool valueHasChanged(double timecode); -private: QVector cachedValues; + void delete_texture(); }; #endif // EFFECT_H diff --git a/effects/effects/README b/effects/effects/README new file mode 100644 index 000000000..71a3822d3 --- /dev/null +++ b/effects/effects/README @@ -0,0 +1 @@ +Place this folder in the runtime folder of Olive. \ No newline at end of file diff --git a/effects/video/glsl/boxblureffect.frag b/effects/effects/boxblur.frag similarity index 100% rename from effects/video/glsl/boxblureffect.frag rename to effects/effects/boxblur.frag diff --git a/effects/effects/boxblur.xml b/effects/effects/boxblur.xml new file mode 100644 index 000000000..1dd4cb45e --- /dev/null +++ b/effects/effects/boxblur.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/effects/video/glsl/common.vert b/effects/effects/common.vert similarity index 100% rename from effects/video/glsl/common.vert rename to effects/effects/common.vert diff --git a/effects/effects/crop.frag b/effects/effects/crop.frag new file mode 100644 index 000000000..7dcf1b939 --- /dev/null +++ b/effects/effects/crop.frag @@ -0,0 +1,36 @@ +#version 110 + +uniform float left; +uniform float top; +uniform float right; +uniform float bottom; +uniform float feather; + +uniform mediump float amount_val; +uniform sampler2D myTexture; +varying vec2 vTexCoord; + +void main(void) { + vec4 textureColor = texture2D(myTexture, vec2(vTexCoord.x, vTexCoord.y)); + float alpha = textureColor.a; + if (feather == 0.0) { + if (vTexCoord.x < (left*0.01) || vTexCoord.y < (top*0.01) || vTexCoord.x > (1.0-(right*0.01)) || vTexCoord.y > (1.0-(bottom*0.01))) { + alpha = 0.0; + } + } else { + float f = pow(2.0, 10.0-(feather*0.1)); + if (left > 0.0) alpha = alpha * clamp(((vTexCoord.x+(0.5/f))-(left*0.01))*f, 0.0, 1.0); // left + if (top > 0.0) alpha = alpha * clamp(((vTexCoord.y+(0.5/f))-(top*0.01))*f, 0.0, 1.0); // top + if (right > 0.0) alpha = alpha * clamp((((1.0-vTexCoord.x)+(0.5/f))-(right*0.01))*f, 0.0, 1.0); // right + if (bottom > 0.0) alpha = alpha * clamp((((1.0-vTexCoord.y)+(0.5/f))-(bottom*0.01))*f, 0.0, 1.0); // bottom + } + + + + gl_FragColor = vec4( + textureColor.r, + textureColor.g, + textureColor.b, + alpha + ); +} \ No newline at end of file diff --git a/effects/effects/crop.xml b/effects/effects/crop.xml new file mode 100644 index 000000000..caa8a578c --- /dev/null +++ b/effects/effects/crop.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/effects/video/glsl/gaussianblureffect.frag b/effects/effects/gaussianblur.frag similarity index 100% rename from effects/video/glsl/gaussianblureffect.frag rename to effects/effects/gaussianblur.frag diff --git a/effects/effects/gaussianblur.xml b/effects/effects/gaussianblur.xml new file mode 100644 index 000000000..0b35d47d2 --- /dev/null +++ b/effects/effects/gaussianblur.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/effects/video/glsl/inverteffect.frag b/effects/effects/invert.frag similarity index 82% rename from effects/video/glsl/inverteffect.frag rename to effects/effects/invert.frag index f7a3184c5..4859995f1 100644 --- a/effects/video/glsl/inverteffect.frag +++ b/effects/effects/invert.frag @@ -1,11 +1,12 @@ #version 110 -uniform mediump float amount_val; +uniform mediump float amount; uniform sampler2D myTexture; varying vec2 vTexCoord; void main(void) { vec4 textureColor = texture2D(myTexture, vTexCoord); + float amount_val = amount * 0.01; gl_FragColor = vec4( textureColor.r+((1.0-textureColor.r-textureColor.r)*amount_val), textureColor.g+((1.0-textureColor.g-textureColor.g)*amount_val), diff --git a/effects/effects/invert.xml b/effects/effects/invert.xml new file mode 100644 index 000000000..bc2ee42fb --- /dev/null +++ b/effects/effects/invert.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/effects/video/glsl/waveeffect.frag b/effects/effects/wave.frag similarity index 77% rename from effects/video/glsl/waveeffect.frag rename to effects/effects/wave.frag index ec0384dad..61e698f0d 100644 --- a/effects/video/glsl/waveeffect.frag +++ b/effects/effects/wave.frag @@ -15,9 +15,9 @@ void main(void) { float y = vTexCoord.y; if (vertical) { - x -= sin((vTexCoord.y-evolution)*frequency)*intensity; + x -= sin((vTexCoord.y-(evolution*0.01))*frequency)*intensity*0.01; } else { - y -= sin((vTexCoord.x-evolution)*frequency)*intensity; + y -= sin((vTexCoord.x-(evolution*0.01))*frequency)*intensity*0.01; } if (y < 0.0 || y > 1.0 || x < 0.0 || x > 1.0) { diff --git a/effects/effects/wave.xml b/effects/effects/wave.xml new file mode 100644 index 000000000..789739616 --- /dev/null +++ b/effects/effects/wave.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/effects/audio/audionoiseeffect.cpp b/effects/internal/audionoiseeffect.cpp similarity index 85% rename from effects/audio/audionoiseeffect.cpp rename to effects/internal/audionoiseeffect.cpp index 451f1fcba..5a65763df 100644 --- a/effects/audio/audionoiseeffect.cpp +++ b/effects/internal/audionoiseeffect.cpp @@ -3,13 +3,15 @@ #include #include -AudioNoiseEffect::AudioNoiseEffect(Clip* c) : Effect(c, EFFECT_TYPE_AUDIO, AUDIO_NOISE_EFFECT) { +AudioNoiseEffect::AudioNoiseEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { amount_val = add_row("Amount:")->add_field(EFFECT_FIELD_DOUBLE); amount_val->set_double_minimum_value(0); amount_val->set_double_maximum_value(100); amount_val->set_double_default_value(20); + amount_val->id = "amount"; mix_val = add_row("Mix:")->add_field(EFFECT_FIELD_BOOL); + mix_val->id = "mix"; mix_val->set_bool_value(true); srand(QDateTime::currentMSecsSinceEpoch()); @@ -27,7 +29,7 @@ void AudioNoiseEffect::process_audio(double timecode_start, double timecode_end, qint16 right_noise_sample = rand(); // set noise volume - double vol = qSqrt(amount_val->get_double_value(timecode, true)*0.01); + double vol = log_volume( amount_val->get_double_value(timecode, true)*0.01 ); left_noise_sample *= vol; right_noise_sample *= vol; diff --git a/effects/audio/audionoiseeffect.h b/effects/internal/audionoiseeffect.h similarity index 83% rename from effects/audio/audionoiseeffect.h rename to effects/internal/audionoiseeffect.h index 0aff80a9c..23bd65425 100644 --- a/effects/audio/audionoiseeffect.h +++ b/effects/internal/audionoiseeffect.h @@ -5,7 +5,7 @@ class AudioNoiseEffect : public Effect { public: - AudioNoiseEffect(Clip* c); + AudioNoiseEffect(Clip* c, const EffectMeta* em); void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); EffectField* amount_val; diff --git a/effects/linearfadetransition.cpp b/effects/internal/linearfadetransition.cpp similarity index 100% rename from effects/linearfadetransition.cpp rename to effects/internal/linearfadetransition.cpp diff --git a/effects/audio/paneffect.cpp b/effects/internal/paneffect.cpp similarity index 83% rename from effects/audio/paneffect.cpp rename to effects/internal/paneffect.cpp index f9fb692db..159cc7136 100644 --- a/effects/audio/paneffect.cpp +++ b/effects/internal/paneffect.cpp @@ -8,11 +8,12 @@ #include "ui/labelslider.h" #include "ui/collapsiblewidget.h" -PanEffect::PanEffect(Clip* c) : Effect(c, EFFECT_TYPE_AUDIO, AUDIO_PAN_EFFECT) { +PanEffect::PanEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { EffectRow* pan_row = add_row("Pan:"); pan_val = pan_row->add_field(EFFECT_FIELD_DOUBLE); pan_val->set_double_minimum_value(-100); pan_val->set_double_maximum_value(100); + pan_val->id = "pan"; // set defaults pan_val->set_double_default_value(0); @@ -23,7 +24,7 @@ PanEffect::PanEffect(Clip* c) : Effect(c, EFFECT_TYPE_AUDIO, AUDIO_PAN_EFFECT) { void PanEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) { double interval = (timecode_end - timecode_start)/nb_bytes; for (int i=0;iget_double_value(timecode_start+(interval*i), true)*0.01); + double pval = log_volume(pan_val->get_double_value(timecode_start+(interval*i), true)*0.01); qint16 left_sample = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); qint16 right_sample = (qint16) (((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); diff --git a/effects/audio/paneffect.h b/effects/internal/paneffect.h similarity index 82% rename from effects/audio/paneffect.h rename to effects/internal/paneffect.h index d33723b62..60465a63c 100644 --- a/effects/audio/paneffect.h +++ b/effects/internal/paneffect.h @@ -5,7 +5,7 @@ class PanEffect : public Effect { public: - PanEffect(Clip* c); + PanEffect(Clip* c, const EffectMeta* em); void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); EffectField* pan_val; diff --git a/effects/video/solideffect.cpp b/effects/internal/solideffect.cpp similarity index 97% rename from effects/video/solideffect.cpp rename to effects/internal/solideffect.cpp index 98380aa23..7e87e0c1e 100644 --- a/effects/video/solideffect.cpp +++ b/effects/internal/solideffect.cpp @@ -16,18 +16,23 @@ #define SMPTE_STRIP_COUNT 3 #define SMPTE_LOWER_BARS 4 -SolidEffect::SolidEffect(Clip* c) : SuperimposeEffect(c, EFFECT_TYPE_VIDEO, VIDEO_SOLID_EFFECT) { +SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) : Effect(c, em) { + enable_superimpose = true; + solid_type = add_row("Type:")->add_field(EFFECT_FIELD_COMBO); solid_type->add_combo_item("Solid Color", SOLID_TYPE_COLOR); solid_type->add_combo_item("SMPTE Bars", SOLID_TYPE_BARS); + solid_type->id = "type"; solid_color_field = add_row("Color:")->add_field(EFFECT_FIELD_COLOR); solid_color_field->set_color_value(Qt::red); + solid_color_field->id = "color"; opacity_field = add_row("Opacity:")->add_field(EFFECT_FIELD_DOUBLE); opacity_field->set_double_minimum_value(0); opacity_field->set_double_maximum_value(100); opacity_field->set_double_default_value(100); + opacity_field->id = "opacity"; connect(solid_type, SIGNAL(changed()), this, SLOT(field_changed())); connect(solid_color_field, SIGNAL(changed()), this, SLOT(field_changed())); diff --git a/effects/video/solideffect.h b/effects/internal/solideffect.h similarity index 73% rename from effects/video/solideffect.h rename to effects/internal/solideffect.h index 54159e838..c14056470 100644 --- a/effects/video/solideffect.h +++ b/effects/internal/solideffect.h @@ -6,10 +6,10 @@ class QOpenGLTexture; #include -class SolidEffect : public SuperimposeEffect { +class SolidEffect : public Effect { Q_OBJECT public: - SolidEffect(Clip* c); + SolidEffect(Clip* c, const EffectMeta *em); EffectField* solid_type; EffectField* solid_color_field; EffectField* opacity_field; diff --git a/effects/video/texteffect.cpp b/effects/internal/texteffect.cpp similarity index 96% rename from effects/video/texteffect.cpp rename to effects/internal/texteffect.cpp index 4dba46ffd..2ec788964 100644 --- a/effects/video/texteffect.cpp +++ b/effects/internal/texteffect.cpp @@ -19,19 +19,23 @@ #include "ui/colorbutton.h" #include "ui/fontcombobox.h" -TextEffect::TextEffect(Clip *c) : - SuperimposeEffect(c, EFFECT_TYPE_VIDEO, VIDEO_TEXT_EFFECT) +TextEffect::TextEffect(Clip *c, const EffectMeta* em) : + Effect(c, em) { enable_superimpose = true; text_val = add_row("Text:")->add_field(EFFECT_FIELD_STRING, 2); + text_val->id = "text"; set_font_combobox = add_row("Font:")->add_field(EFFECT_FIELD_FONT, 2); + set_font_combobox->id = "font"; size_val = add_row("Size:")->add_field(EFFECT_FIELD_DOUBLE, 2); size_val->set_double_minimum_value(0); + size_val->id = "size"; set_color_button = add_row("Color:")->add_field(EFFECT_FIELD_COLOR, 2); + set_color_button->id = "color"; EffectRow* alignment_row = add_row("Alignment:"); halign_field = alignment_row->add_field(EFFECT_FIELD_COMBO); @@ -39,25 +43,37 @@ TextEffect::TextEffect(Clip *c) : halign_field->add_combo_item("Center", Qt::AlignHCenter); halign_field->add_combo_item("Right", Qt::AlignRight); halign_field->add_combo_item("Justify", Qt::AlignJustify); + halign_field->id = "halign"; + valign_field = alignment_row->add_field(EFFECT_FIELD_COMBO); valign_field->add_combo_item("Top", Qt::AlignTop); valign_field->add_combo_item("Center", Qt::AlignVCenter); valign_field->add_combo_item("Bottom", Qt::AlignBottom); + valign_field->id = "valign"; word_wrap_field = add_row("Word Wrap:")->add_field(EFFECT_FIELD_BOOL, 2); + word_wrap_field->id = "wordwrap"; outline_bool = add_row("Outline:")->add_field(EFFECT_FIELD_BOOL, 2); + outline_bool->id = "outline"; outline_color = add_row("Outline Color:")->add_field(EFFECT_FIELD_COLOR, 2); + outline_color->id = "outlinecolor"; outline_width = add_row("Outline Width:")->add_field(EFFECT_FIELD_DOUBLE, 2); + outline_width->id = "outlinewidth"; outline_width->set_double_minimum_value(0); shadow_bool = add_row("Shadow:")->add_field(EFFECT_FIELD_BOOL, 2); + shadow_bool->id = "shadow"; shadow_color = add_row("Shadow Color:")->add_field(EFFECT_FIELD_COLOR, 2); + shadow_color->id = "shadowcolor"; shadow_distance = add_row("Shadow Distance:")->add_field(EFFECT_FIELD_DOUBLE, 2); + shadow_distance->id = "shadowdistance"; shadow_distance->set_double_minimum_value(0); shadow_softness = add_row("Shadow Softness:")->add_field(EFFECT_FIELD_DOUBLE, 2); + shadow_softness->id = "shadowsoftness"; shadow_softness->set_double_minimum_value(0); shadow_opacity = add_row("Shadow Opacity:")->add_field(EFFECT_FIELD_DOUBLE, 2); + shadow_opacity->id = "shadowopacity"; shadow_opacity->set_double_minimum_value(0); shadow_opacity->set_double_maximum_value(100); diff --git a/effects/video/texteffect.h b/effects/internal/texteffect.h similarity index 85% rename from effects/video/texteffect.h rename to effects/internal/texteffect.h index 81e6c541c..d18d26ec8 100644 --- a/effects/video/texteffect.h +++ b/effects/internal/texteffect.h @@ -7,10 +7,10 @@ #include class QOpenGLTexture; -class TextEffect : public SuperimposeEffect { +class TextEffect : public Effect { Q_OBJECT public: - TextEffect(Clip* c); + TextEffect(Clip* c, const EffectMeta *em); void redraw(double timecode); EffectField* text_val; diff --git a/effects/audio/toneeffect.cpp b/effects/internal/toneeffect.cpp similarity index 86% rename from effects/audio/toneeffect.cpp rename to effects/internal/toneeffect.cpp index 7ca123a51..66e24ab17 100644 --- a/effects/audio/toneeffect.cpp +++ b/effects/internal/toneeffect.cpp @@ -8,21 +8,25 @@ #include "project/sequence.h" #include "debug.h" -ToneEffect::ToneEffect(Clip* c) : Effect(c, EFFECT_TYPE_AUDIO, AUDIO_TONE_EFFECT), sinX(INT_MIN) { +ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_MIN) { type_val = add_row("Type:")->add_field(EFFECT_FIELD_COMBO); + type_val->id = "type"; type_val->add_combo_item("Sine", TONE_TYPE_SINE); freq_val = add_row("Frequency:")->add_field(EFFECT_FIELD_DOUBLE); + freq_val->id = "frequency"; freq_val->set_double_minimum_value(20); freq_val->set_double_maximum_value(20000); freq_val->set_double_default_value(1000); amount_val = add_row("Amount:")->add_field(EFFECT_FIELD_DOUBLE); + amount_val->id = "amount"; amount_val->set_double_minimum_value(0); amount_val->set_double_maximum_value(100); amount_val->set_double_default_value(25); mix_val = add_row("Mix:")->add_field(EFFECT_FIELD_BOOL); + mix_val->id = "mix"; mix_val->set_bool_value(true); connect(freq_val, SIGNAL(changed()), this, SLOT(field_changed())); @@ -35,10 +39,9 @@ void ToneEffect::process_audio(double timecode_start, double timecode_end, quint for (int i=0;iget_double_value(timecode, true))/parent_clip->sequence->audio_frequency)*qSqrt((amount_val->get_double_value(timecode, true)*0.01))*INT16_MAX; + qint16 left_tone_sample = qSin((2*M_PI*sinX*freq_val->get_double_value(timecode, true))/parent_clip->sequence->audio_frequency)*log_volume(amount_val->get_double_value(timecode, true)*0.01)*INT16_MAX; qint16 right_tone_sample = left_tone_sample; - // mix with source audio if (mix_val->get_bool_value(timecode, true)) { qint16 left_sample = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); diff --git a/effects/audio/toneeffect.h b/effects/internal/toneeffect.h similarity index 85% rename from effects/audio/toneeffect.h rename to effects/internal/toneeffect.h index 28a44632e..a08155a29 100644 --- a/effects/audio/toneeffect.h +++ b/effects/internal/toneeffect.h @@ -5,7 +5,7 @@ class ToneEffect : public Effect { public: - ToneEffect(Clip *c); + ToneEffect(Clip *c, const EffectMeta* em); void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); EffectField* type_val; diff --git a/effects/video/transformeffect.cpp b/effects/internal/transformeffect.cpp similarity index 91% rename from effects/video/transformeffect.cpp rename to effects/internal/transformeffect.cpp index 4fd9a1e16..45beb3d29 100644 --- a/effects/video/transformeffect.cpp +++ b/effects/internal/transformeffect.cpp @@ -22,38 +22,48 @@ #define BLEND_MODE_MULTIPLY 2 #define BLEND_MODE_OVERLAY 3 -TransformEffect::TransformEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_TRANSFORM_EFFECT) { +TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) { enable_coords = true; EffectRow* position_row = add_row("Position:"); position_x = position_row->add_field(EFFECT_FIELD_DOUBLE); // position X + position_x->id = "posx"; position_y = position_row->add_field(EFFECT_FIELD_DOUBLE); // position Y + position_y->id = "posy"; EffectRow* scale_row = add_row("Scale:"); scale_x = scale_row->add_field(EFFECT_FIELD_DOUBLE); // scale X (and Y is uniform scale is selected) + scale_x->id = "scalex"; scale_x->set_double_minimum_value(0); scale_x->set_double_maximum_value(3000); scale_y = scale_row->add_field(EFFECT_FIELD_DOUBLE); // scale Y (disabled if uniform scale is selected) + scale_y->id = "scaley"; scale_y->set_double_minimum_value(0); scale_y->set_double_maximum_value(3000); EffectRow* uniform_scale_row = add_row("Uniform Scale:"); uniform_scale_field = uniform_scale_row->add_field(EFFECT_FIELD_BOOL); // uniform scale option + uniform_scale_field->id = "uniformscale"; EffectRow* rotation_row = add_row("Rotation:"); rotation = rotation_row->add_field(EFFECT_FIELD_DOUBLE); + rotation->id = "rotation"; EffectRow* anchor_point_row = add_row("Anchor Point:"); anchor_x_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE); // anchor point X + anchor_x_box->id = "anchorx"; anchor_y_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE); // anchor point Y + anchor_y_box->id = "anchory"; EffectRow* opacity_row = add_row("Opacity:"); opacity = opacity_row->add_field(EFFECT_FIELD_DOUBLE); // opacity + opacity->id = "opacity"; opacity->set_double_minimum_value(0); opacity->set_double_maximum_value(100); EffectRow* blend_mode_row = add_row("Blend Mode:"); blend_mode_box = blend_mode_row->add_field(EFFECT_FIELD_COMBO); // blend mode + blend_mode_box->id = "blendmode"; blend_mode_box->add_combo_item("Normal", BLEND_MODE_NORMAL); blend_mode_box->add_combo_item("Overlay", BLEND_MODE_OVERLAY); blend_mode_box->add_combo_item("Screen", BLEND_MODE_SCREEN); diff --git a/effects/video/transformeffect.h b/effects/internal/transformeffect.h similarity index 88% rename from effects/video/transformeffect.h rename to effects/internal/transformeffect.h index 9cc211b25..7111f3612 100644 --- a/effects/video/transformeffect.h +++ b/effects/internal/transformeffect.h @@ -6,7 +6,7 @@ class TransformEffect : public Effect { Q_OBJECT public: - TransformEffect(Clip* c); + TransformEffect(Clip* c, const EffectMeta* em); void refresh(); void process_coords(double timecode, GLTextureCoords& coords); diff --git a/effects/audio/volumeeffect.cpp b/effects/internal/volumeeffect.cpp similarity index 77% rename from effects/audio/volumeeffect.cpp rename to effects/internal/volumeeffect.cpp index ab74cb942..8ea84e473 100644 --- a/effects/audio/volumeeffect.cpp +++ b/effects/internal/volumeeffect.cpp @@ -8,11 +8,11 @@ #include "ui/labelslider.h" #include "ui/collapsiblewidget.h" -VolumeEffect::VolumeEffect(Clip* c) : Effect(c, EFFECT_TYPE_AUDIO, AUDIO_VOLUME_EFFECT) { +VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { EffectRow* volume_row = add_row("Volume:"); volume_val = volume_row->add_field(EFFECT_FIELD_DOUBLE); + volume_val->id = "volume"; volume_val->set_double_minimum_value(0); -// volume_val->set_double_maximum_value(1000); // set defaults volume_val->set_double_default_value(100); @@ -23,7 +23,7 @@ VolumeEffect::VolumeEffect(Clip* c) : Effect(c, EFFECT_TYPE_AUDIO, AUDIO_VOLUME_ void VolumeEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) { double interval = (timecode_end-timecode_start)/nb_bytes; for (int i=0;iget_double_value(timecode_start+(interval*i), true)*0.01); + double vol_val = log_volume(volume_val->get_double_value(timecode_start+(interval*i), true)*0.01); qint32 samp = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); samp *= vol_val; if (samp > INT16_MAX) { diff --git a/effects/audio/volumeeffect.h b/effects/internal/volumeeffect.h similarity index 82% rename from effects/audio/volumeeffect.h rename to effects/internal/volumeeffect.h index 60924d597..40b4ad4a7 100644 --- a/effects/audio/volumeeffect.h +++ b/effects/internal/volumeeffect.h @@ -5,7 +5,7 @@ class VolumeEffect : public Effect { public: - VolumeEffect(Clip* c); + VolumeEffect(Clip* c, const EffectMeta* em); void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); EffectField* volume_val; diff --git a/effects/qpainterwrapper.cpp b/effects/qpainterwrapper.cpp new file mode 100644 index 000000000..024fac1b8 --- /dev/null +++ b/effects/qpainterwrapper.cpp @@ -0,0 +1,43 @@ +#include "qpainterwrapper.h" + +#include +#include "debug.h" + +// exposes several QPainter functions to QJSEngine + +QPainterWrapper painter_wrapper; + +QPainterWrapper::QPainterWrapper() {} + +QColor get_color_from_string(const QString& s) { + dout << s; + + // workaround for alpha + if (s.at(0) == '#' && s.length() == 9) { + QColor color(s.left(7)); + color.setAlpha(s.mid(7).toInt(NULL, 16)); + return color; + } else { + return QColor(s); + } +} + +void QPainterWrapper::fill(const QString& c) { + img->fill(get_color_from_string(c)); +} + +void QPainterWrapper::fillRect(int x, int y, int width, int height, const QString& brush) { + painter->fillRect(x, y, width, height, get_color_from_string(brush)); +} + +void QPainterWrapper::drawRect(int x, int y, int width, int height) { + painter->drawRect(x, y, width, height); +} + +void QPainterWrapper::setPen(const QString& pen) { + painter->setPen(get_color_from_string(pen)); +} + +void QPainterWrapper::setBrush(const QString& brush) { + painter->setBrush(get_color_from_string(brush)); +} diff --git a/effects/qpainterwrapper.h b/effects/qpainterwrapper.h new file mode 100644 index 000000000..c8700294b --- /dev/null +++ b/effects/qpainterwrapper.h @@ -0,0 +1,24 @@ +#ifndef QPAINTERWRAPPER_H +#define QPAINTERWRAPPER_H + +#include + +class QPainter; + +class QPainterWrapper : public QObject { + Q_OBJECT +public: + QPainterWrapper(); + QImage* img; + QPainter* painter; +public slots: + void fill(const QString& color); + void fillRect(int x, int y, int width, int height, const QString& brush); + void drawRect(int x, int y, int width, int height); + void setPen(const QString& pen); + void setBrush(const QString& brush); +}; + +extern QPainterWrapper painter_wrapper; + +#endif // QPAINTERWRAPPER_H diff --git a/effects/video/boxblureffect.cpp b/effects/video/boxblureffect.cpp deleted file mode 100644 index 4f8ccbd6c..000000000 --- a/effects/video/boxblureffect.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "boxblureffect.h" - -#include "project/clip.h" - -BoxBlurEffect::BoxBlurEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_BOXBLUR_EFFECT) { - enable_shader = true; - - radius_val = add_row("Radius:")->add_field(EFFECT_FIELD_DOUBLE); -// iteration_val = add_row("Iterations:")->add_field(EFFECT_FIELD_DOUBLE); - horiz_val = add_row("Horizontal:")->add_field(EFFECT_FIELD_BOOL); - vert_val = add_row("Vertical:")->add_field(EFFECT_FIELD_BOOL); - - radius_val->set_double_default_value(9); - radius_val->set_double_minimum_value(0); - -// iteration_val->set_double_default_value(1); -// iteration_val->set_double_minimum_value(0); - - horiz_val->set_bool_value(true); - vert_val->set_bool_value(true); - - vertPath = ":/shaders/common.vert"; - fragPath = ":/shaders/boxblureffect.frag"; - /*vert.compileSourceFile(":/shaders/common.vert"); - frag.compileSourceFile(":/shaders/boxblureffect.frag"); - program.addShader(&vert); - program.addShader(&frag); - program.link();*/ - - connect(radius_val, SIGNAL(changed()), this, SLOT(field_changed())); -// connect(iteration_val, SIGNAL(changed()), this, SLOT(field_changed())); - connect(horiz_val, SIGNAL(changed()), this, SLOT(field_changed())); - connect(vert_val, SIGNAL(changed()), this, SLOT(field_changed())); -} - -void BoxBlurEffect::process_shader(double timecode) { - glslProgram->setUniformValue("resolution", parent_clip->getWidth(), parent_clip->getHeight()); - glslProgram->setUniformValue("radius", (GLfloat) radius_val->get_double_value(timecode)); - glslProgram->setUniformValue("horiz_blur", horiz_val->get_bool_value(timecode)); - glslProgram->setUniformValue("vert_blur", vert_val->get_bool_value(timecode)); -} diff --git a/effects/video/boxblureffect.h b/effects/video/boxblureffect.h deleted file mode 100644 index 008018a91..000000000 --- a/effects/video/boxblureffect.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef BOXBLUREFFECT_H -#define BOXBLUREFFECT_H - -#include "../effect.h" - -class BoxBlurEffect : public Effect -{ -public: - BoxBlurEffect(Clip* c); - void process_shader(double timecode); -private: - EffectField* radius_val; - EffectField* iteration_val; - EffectField* horiz_val; - EffectField* vert_val; -}; - -#endif // BOXBLUREFFECT_H diff --git a/effects/video/chromakeyeffect.cpp b/effects/video/chromakeyeffect.cpp deleted file mode 100644 index 029ce7397..000000000 --- a/effects/video/chromakeyeffect.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "chromakeyeffect.h" - -ChromaKeyEffect::ChromaKeyEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_CHROMAKEY_EFFECT) { - enable_shader = true; - - color_field = add_row("Color:")->add_field(EFFECT_FIELD_COLOR); - tolerance_field = add_row("Tolerance:")->add_field(EFFECT_FIELD_DOUBLE); - - color_field->set_color_value(Qt::green); - tolerance_field->set_double_default_value(10); - - tolerance_field->set_double_minimum_value(0); - tolerance_field->set_double_maximum_value(100); - - vertPath = ":/shaders/common.vert"; - fragPath = ":/shaders/chromakeyeffect.frag"; - - connect(color_field, SIGNAL(changed()), this, SLOT(field_changed())); - connect(tolerance_field, SIGNAL(changed()), this, SLOT(field_changed())); -} - -void ChromaKeyEffect::process_shader(double timecode) { - glslProgram->setUniformValue("keyColor", color_field->get_color_value(timecode)); - glslProgram->setUniformValue("threshold", (GLfloat) (tolerance_field->get_double_value(timecode)*0.01)); -} diff --git a/effects/video/chromakeyeffect.h b/effects/video/chromakeyeffect.h deleted file mode 100644 index a7498cdc1..000000000 --- a/effects/video/chromakeyeffect.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef CHROMAKEYEFFECT_H -#define CHROMAKEYEFFECT_H - -#include "effects/effect.h" - -class ChromaKeyEffect : public Effect { -public: - ChromaKeyEffect(Clip* c); - void process_shader(double timecode); -private: - EffectField* color_field; - EffectField* tolerance_field; -}; - -#endif // CHROMAKEYEFFECT_H diff --git a/effects/video/cropeffect.cpp b/effects/video/cropeffect.cpp deleted file mode 100644 index db4dbf99c..000000000 --- a/effects/video/cropeffect.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "cropeffect.h" - -CropEffect::CropEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_CROP_EFFECT) { - enable_coords = true; - - left_field = add_row("Left:")->add_field(EFFECT_FIELD_DOUBLE); - top_field = add_row("Top:")->add_field(EFFECT_FIELD_DOUBLE); - right_field = add_row("Right:")->add_field(EFFECT_FIELD_DOUBLE); - bottom_field = add_row("Bottom:")->add_field(EFFECT_FIELD_DOUBLE); - - left_field->set_double_minimum_value(0); - left_field->set_double_maximum_value(100); - top_field->set_double_minimum_value(0); - top_field->set_double_maximum_value(100); - right_field->set_double_minimum_value(0); - right_field->set_double_maximum_value(100); - bottom_field->set_double_minimum_value(0); - bottom_field->set_double_maximum_value(100); - - connect(left_field, SIGNAL(changed()), this, SLOT(field_changed())); - connect(top_field, SIGNAL(changed()), this, SLOT(field_changed())); - connect(right_field, SIGNAL(changed()), this, SLOT(field_changed())); - connect(bottom_field, SIGNAL(changed()), this, SLOT(field_changed())); -} - -void CropEffect::process_coords(double timecode, GLTextureCoords &coords) { - // store initial coord data - int left = coords.vertexTopLeftX; - int top = coords.vertexTopLeftY; - int right = coords.vertexBottomRightX; - int bottom = coords.vertexBottomRightY; - int width = right - left; - int height = bottom - top; - - double texLeft = coords.textureTopLeftX; - double texTop = coords.textureTopLeftY; - double texRight = coords.textureBottomRightX; - double texBottom = coords.textureBottomRightY; - double texWidth = texRight - texLeft; - double texHeight = texBottom - texTop; - - // retrieve values - double left_field_value = (left_field->get_double_value(timecode)*0.01); - double right_field_value = 1-(right_field->get_double_value(timecode)*0.01); - double top_field_value = (top_field->get_double_value(timecode)*0.01); - double bottom_field_value = 1-(bottom_field->get_double_value(timecode)*0.01); - - // validate values - if (left_field_value > right_field_value) right_field_value = left_field_value; - if (top_field_value > bottom_field_value) bottom_field_value = top_field_value; - - // left - coords.textureTopLeftX = coords.textureBottomLeftX = texLeft+(left_field_value*texWidth); - coords.vertexTopLeftX = coords.vertexBottomLeftX = left+(width*left_field_value); - - // right - coords.textureTopRightX = coords.textureBottomRightX = texLeft+(right_field_value*texWidth); - coords.vertexTopRightX = coords.vertexBottomRightX = left+(width*right_field_value); - - // top - coords.textureTopLeftY = coords.textureTopRightY = texTop+(top_field_value*texHeight); - coords.vertexTopLeftY = coords.vertexTopRightY = top+(height*top_field_value); - - // bottom - coords.textureBottomLeftY = coords.textureBottomRightY = texTop+(bottom_field_value*texHeight); - coords.vertexBottomLeftY = coords.vertexBottomRightY = top+(height*bottom_field_value); -} diff --git a/effects/video/cropeffect.h b/effects/video/cropeffect.h deleted file mode 100644 index 49d0ca2ff..000000000 --- a/effects/video/cropeffect.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CROPEFFECT_H -#define CROPEFFECT_H - -#include "../effect.h" - -class CropEffect : public Effect -{ -public: - CropEffect(Clip* c); - void process_coords(double timecode, GLTextureCoords &coords); -private: - EffectField* left_field; - EffectField* top_field; - EffectField* right_field; - EffectField* bottom_field; -}; - -#endif // CROPEFFECT_H diff --git a/effects/video/flipeffect.cpp b/effects/video/flipeffect.cpp deleted file mode 100644 index 143405168..000000000 --- a/effects/video/flipeffect.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "flipeffect.h" - -FlipEffect::FlipEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_FLIP_EFFECT) { - enable_coords = true; - - horizontal_field = add_row("Horizontal:")->add_field(EFFECT_FIELD_BOOL); - vertical_field = add_row("Vertical:")->add_field(EFFECT_FIELD_BOOL); - - connect(horizontal_field, SIGNAL(changed()), this, SLOT(field_changed())); - connect(vertical_field, SIGNAL(changed()), this, SLOT(field_changed())); -} - -void FlipEffect::process_coords(double timecode, GLTextureCoords &coords) { - if (horizontal_field->get_bool_value(timecode)) { - double tlX = coords.textureTopLeftX; - double blX = coords.textureBottomLeftX; - double trX = coords.textureTopRightX; - double brX = coords.textureBottomRightX; - coords.textureTopLeftX = trX; - coords.textureTopRightX = tlX; - coords.textureBottomLeftX = brX; - coords.textureBottomRightX = blX; - } - if (vertical_field->get_bool_value(timecode)) { - double tlY = coords.textureTopLeftY; - double blY = coords.textureBottomLeftY; - double trY = coords.textureTopRightY; - double brY = coords.textureBottomRightY; - coords.textureTopLeftY = blY; - coords.textureTopRightY = brY; - coords.textureBottomLeftY = tlY; - coords.textureBottomRightY = trY; - } -} - - diff --git a/effects/video/flipeffect.h b/effects/video/flipeffect.h deleted file mode 100644 index 68ae07350..000000000 --- a/effects/video/flipeffect.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef FLIPEFFECT_H -#define FLIPEFFECT_H - -#include "../effect.h" - -class FlipEffect : public Effect -{ -public: - FlipEffect(Clip* c); - void process_coords(double timecode, GLTextureCoords &coords); -private: - EffectField* horizontal_field; - EffectField* vertical_field; -}; - -#endif // FLIPEFFECT_H diff --git a/effects/video/gaussianblureffect.cpp b/effects/video/gaussianblureffect.cpp deleted file mode 100644 index 7bb4dcf9e..000000000 --- a/effects/video/gaussianblureffect.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "gaussianblureffect.h" - -#include "project/clip.h" - -#include - -GaussianBlurEffect::GaussianBlurEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_GAUSSIANBLUR_EFFECT) { - enable_shader = true; - - radius_val = add_row("Radius:")->add_field(EFFECT_FIELD_DOUBLE); - sigma_val = add_row("Sigma:")->add_field(EFFECT_FIELD_DOUBLE); - horiz_val = add_row("Horizontal:")->add_field(EFFECT_FIELD_BOOL); - vert_val = add_row("Vertical:")->add_field(EFFECT_FIELD_BOOL); - - radius_val->set_double_minimum_value(0); - sigma_val->set_double_minimum_value(0); - - radius_val->set_double_default_value(9); - sigma_val->set_double_default_value(5.5); - - horiz_val->set_bool_value(true); - vert_val->set_bool_value(true); - - vertPath = ":/shaders/common.vert"; - fragPath = ":/shaders/gaussianblureffect.frag"; - - connect(radius_val, SIGNAL(changed()), this, SLOT(field_changed())); - connect(sigma_val, SIGNAL(changed()), this, SLOT(field_changed())); - connect(horiz_val, SIGNAL(changed()), this, SLOT(field_changed())); - connect(vert_val, SIGNAL(changed()), this, SLOT(field_changed())); -} - -void GaussianBlurEffect::process_shader(double timecode) { - glslProgram->setUniformValue("resolution", parent_clip->getWidth(), parent_clip->getHeight()); - glslProgram->setUniformValue("radius", (GLfloat) radius_val->get_double_value(timecode)); - glslProgram->setUniformValue("sigma", (GLfloat) sigma_val->get_double_value(timecode)); - glslProgram->setUniformValue("horiz_blur", horiz_val->get_bool_value(timecode)); - glslProgram->setUniformValue("vert_blur", vert_val->get_bool_value(timecode)); -} diff --git a/effects/video/gaussianblureffect.h b/effects/video/gaussianblureffect.h deleted file mode 100644 index fdf5fea01..000000000 --- a/effects/video/gaussianblureffect.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef GAUSSIANBLUREFFECT_H -#define GAUSSIANBLUREFFECT_H - -#include "../effect.h" - -class GaussianBlurEffect : public Effect -{ -public: - GaussianBlurEffect(Clip* c); - void process_shader(double timecode); -private: - EffectField* radius_val; - EffectField* sigma_val; - EffectField* horiz_val; - EffectField* vert_val; -}; - -#endif // GAUSSIANBLUREFFECT_H diff --git a/effects/video/glsl/chromakeyeffect.frag b/effects/video/glsl/chromakeyeffect.frag deleted file mode 100644 index 7c44e43f4..000000000 --- a/effects/video/glsl/chromakeyeffect.frag +++ /dev/null @@ -1,16 +0,0 @@ -#version 110 - -uniform vec4 keyColor; -uniform float threshold; -uniform sampler2D myTexture; -varying vec2 vTexCoord; - -void main(void) { - vec4 textureColor = texture2D(myTexture, vTexCoord); - float diff = length(keyColor - textureColor); - if (diff < threshold) { - gl_FragColor = vec4(0, 0, 0, 0); - } else { - gl_FragColor = textureColor; - } -} \ No newline at end of file diff --git a/effects/video/glsl/shaders.qrc b/effects/video/glsl/shaders.qrc deleted file mode 100644 index b9512b59c..000000000 --- a/effects/video/glsl/shaders.qrc +++ /dev/null @@ -1,12 +0,0 @@ - - - gaussianblureffect.frag - common.vert - inverteffect.frag - chromakeyeffect.frag - solideffect.frag - boxblureffect.frag - waveeffect.frag - temperatureeffect.frag - - diff --git a/effects/video/glsl/solideffect.frag b/effects/video/glsl/solideffect.frag deleted file mode 100644 index cda8aafe0..000000000 --- a/effects/video/glsl/solideffect.frag +++ /dev/null @@ -1,16 +0,0 @@ -#version 110 - -uniform vec4 solidColor; -uniform float amount_val; -uniform sampler2D myTexture; -varying vec2 vTexCoord; - -void main(void) { - vec4 textureColor = texture2D(myTexture, vTexCoord); - gl_FragColor = vec4( - textureColor.r+((solidColor.r-textureColor.r)*amount_val), - textureColor.g+((solidColor.g-textureColor.g)*amount_val), - textureColor.b+((solidColor.b-textureColor.b)*amount_val), - textureColor.a - ); -} \ No newline at end of file diff --git a/effects/video/glsl/temperatureeffect.frag b/effects/video/glsl/temperatureeffect.frag deleted file mode 100644 index b3f12d476..000000000 --- a/effects/video/glsl/temperatureeffect.frag +++ /dev/null @@ -1,42 +0,0 @@ -#version 110 - -// adapted from Tanner Helland's temperature algorithm -// (http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/) - -uniform float temperature; - -uniform mediump float amount_val; -uniform sampler2D myTexture; -varying vec2 vTexCoord; - -void main(void) { - vec4 textureColor = texture2D(myTexture, vTexCoord); - - // red value - float red = (temperature <= 66.0) ? 1.0 : min(1.0, max(0.0, - (1.2929361861 * pow(temperature - 60.0, -0.1332047592)) - )); - - // green value - float green = min(1.0, max(0.0, - (temperature <= 66.0) ? (0.3900815788 * log(temperature) - 0.6318414438) : (1.1298908609 * pow(temperature - 60.0, -0.0755148492)) - )); - - // blue value - float blue = (temperature >= 66.0) ? 1.0 : min(1.0, max(0.0, - (0.5432067891 * log(temperature - 10.0) - 1.1962540891) - )); - - gl_FragColor = vec4( - textureColor.r*red, - textureColor.g*green, - textureColor.b*blue, - textureColor.a - ); - /*gl_FragColor = vec4( - red, - green, - blue, - 1.0 - );*/ -} \ No newline at end of file diff --git a/effects/video/inverteffect.cpp b/effects/video/inverteffect.cpp deleted file mode 100644 index 4d8d38889..000000000 --- a/effects/video/inverteffect.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "inverteffect.h" - -#include "ui/labelslider.h" - -#include -#include - -InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_EFFECT) { - enable_shader = true; - - EffectRow* amount_row = add_row("Amount:"); - amount_val = amount_row->add_field(EFFECT_FIELD_DOUBLE); - amount_val->set_double_minimum_value(0); - amount_val->set_double_maximum_value(100); - - // set defaults - amount_val->set_double_default_value(100); - - connect(amount_val, SIGNAL(changed()), this, SLOT(field_changed())); - - vertPath = ":/shaders/common.vert"; - fragPath = ":/shaders/inverteffect.frag"; -} - -void InvertEffect::process_shader(double timecode) { - glslProgram->setUniformValue("amount_val", (GLfloat) (amount_val->get_double_value(timecode)*0.01)); -} diff --git a/effects/video/inverteffect.h b/effects/video/inverteffect.h deleted file mode 100644 index 80c10a743..000000000 --- a/effects/video/inverteffect.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef INVERTEFFECT_H -#define INVERTEFFECT_H - -#include "../effect.h" - -class InvertEffect : public Effect { - Q_OBJECT -public: - InvertEffect(Clip* c); - void process_shader(double timecode); -private: - EffectField* amount_val; -}; - -#endif // INVERTEFFECT_H diff --git a/effects/video/shakeeffect.cpp b/effects/video/shakeeffect.cpp deleted file mode 100644 index cada812f7..000000000 --- a/effects/video/shakeeffect.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "shakeeffect.h" - -#include -#include -#include -#include - -#include "ui/labelslider.h" -#include "ui/collapsiblewidget.h" -#include "project/clip.h" -#include "project/sequence.h" -#include "panels/timeline.h" - -ShakeEffect::ShakeEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_SHAKE_EFFECT), inside(false) { - enable_coords = true; - - EffectRow* intensity_row = add_row("Intensity:"); - intensity_val = intensity_row->add_field(EFFECT_FIELD_DOUBLE); - intensity_val->set_double_minimum_value(0); - - EffectRow* rotation_row = add_row("Rotation:"); - rotation_val = rotation_row->add_field(EFFECT_FIELD_DOUBLE); - rotation_val->set_double_minimum_value(0); - - EffectRow* frequency_row = add_row("Frequency:"); - frequency_val = frequency_row->add_field(EFFECT_FIELD_DOUBLE); - frequency_val->set_double_minimum_value(0); - - // set defaults - intensity_val->set_double_default_value(50); - rotation_val->set_double_default_value(0); - frequency_val->set_double_default_value(10); - - refresh(); - - connect(intensity_val, SIGNAL(changed()), this, SLOT(field_changed())); - connect(rotation_val, SIGNAL(changed()), this, SLOT(field_changed())); - connect(frequency_val, SIGNAL(changed()), this, SLOT(field_changed())); -} - -void ShakeEffect::refresh() { - if (parent_clip->sequence != NULL) { - shake_limit = qRound(parent_clip->sequence->frame_rate / frequency_val->get_double_value(-1)); - shake_progress = shake_limit; - next_x = 0; - next_y = 0; - next_rot = 0; - } -} - -void ShakeEffect::process_coords(double timecode, GLTextureCoords&) { - if (shake_progress > shake_limit) { - double ival = intensity_val->get_double_value(timecode); - if ((int)ival > 0) { - prev_x = next_x; - prev_y = next_y; - next_x = (qrand() % (int) (ival * 2)) - ival; - next_y = (qrand() % (int) (ival * 2)) - ival; - - // find perpendicular slope that passes through (mid_x, mid_y) - int mid_x = (prev_x + next_x) / 2; - int mid_y = (prev_y + next_y) / 2; - int slope_num = (next_y-prev_y); - if (slope_num > 0) { - int slope_den = (next_x-prev_x); - int add = (next_x-prev_x)/4; - if (inside) add = -add; - inside = !inside; - perp_x = mid_x + add; - perp_y = (-(slope_den / slope_num)) * perp_x + mid_y; - } else { - perp_x = mid_x; - perp_y = mid_y; - } - } else { - prev_x = 0; - prev_y = 0; - next_x = 0; - next_y = 0; - offset_x = 0; - offset_y = 0; - } - double rot_val = rotation_val->get_double_value(timecode); - if ((int)rot_val > 0) { - prev_rot = next_rot; - next_rot = (qrand() % (int) (rot_val * 2)) - rot_val; - } else { - prev_rot = 0; - next_rot = 0; - offset_rot = 0; - } - shake_progress = 0; - } - - t = (double) shake_progress / (double) shake_limit; - - double oneminust = 1 - t; - - offset_x = (qPow(oneminust, 2)*prev_x) + (2*oneminust*t*perp_x) + (qPow(t, 2) * next_x); - offset_y = (qPow(oneminust, 2)*prev_y) + (2*oneminust*t*perp_y) + (qPow(t, 2) * next_y); - - offset_rot = lerp(prev_rot, next_rot, t); - - glTranslatef(offset_x, offset_y, 0); - glRotatef(offset_rot, 0, 0, 1); - shake_progress++; -} diff --git a/effects/video/shakeeffect.h b/effects/video/shakeeffect.h deleted file mode 100644 index dd9f47e5e..000000000 --- a/effects/video/shakeeffect.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef SHAKEEFFECT_H -#define SHAKEEFFECT_H - -#include "../effect.h" - -class ShakeEffect : public Effect { - Q_OBJECT -public: - ShakeEffect(Clip* c); - void process_coords(double timecode, GLTextureCoords& coords); - - EffectField* intensity_val; - EffectField* rotation_val; - EffectField* frequency_val; -public slots: - void refresh(); -private: - int shake_progress; - int shake_limit; - int next_x; - int next_y; - int next_rot; - int offset_x; - int offset_y; - int offset_rot; - int prev_x; - int prev_y; - int prev_rot; - int perp_x; - int perp_y; - double t; - bool inside; -}; - -#endif // SHAKEEFFECT_H diff --git a/effects/video/temperatureeffect.cpp b/effects/video/temperatureeffect.cpp deleted file mode 100644 index c158a6983..000000000 --- a/effects/video/temperatureeffect.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "temperatureeffect.h" - -TemperatureEffect::TemperatureEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_TEMPERATURE_EFFECT) { - enable_shader = true; - - temp_val = add_row("Temperature:")->add_field(EFFECT_FIELD_DOUBLE); - temp_val->set_double_minimum_value(2000); - temp_val->set_double_default_value(5200); - temp_val->set_double_maximum_value(40000); - - connect(temp_val, SIGNAL(changed()), this, SLOT(field_changed())); - - vertPath = ":/shaders/common.vert"; - fragPath = ":/shaders/temperatureeffect.frag"; -} - -void TemperatureEffect::process_shader(double timecode) { - glslProgram->setUniformValue("temperature", (GLfloat) (temp_val->get_double_value(timecode)*0.01)); -} diff --git a/effects/video/temperatureeffect.h b/effects/video/temperatureeffect.h deleted file mode 100644 index b367d4258..000000000 --- a/effects/video/temperatureeffect.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef TEMPERATUREEFFECT_H -#define TEMPERATUREEFFECT_H - -#include "../effect.h" - -class TemperatureEffect : public Effect { - Q_OBJECT -public: - TemperatureEffect(Clip* c); - void process_shader(double timecode); -private: - EffectField* temp_val; -}; - -#endif // TEMPERATUREEFFECT_H diff --git a/effects/video/waveeffect.cpp b/effects/video/waveeffect.cpp deleted file mode 100644 index 0e75f879f..000000000 --- a/effects/video/waveeffect.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "waveeffect.h" - -WaveEffect::WaveEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_WAVE_EFFECT) { - enable_shader = true; - - frequency_val = add_row("Frequency:")->add_field(EFFECT_FIELD_DOUBLE); - frequency_val->set_double_minimum_value(0); - frequency_val->set_double_default_value(10); - - intensity_val = add_row("Intensity:")->add_field(EFFECT_FIELD_DOUBLE); - intensity_val->set_double_default_value(10); - - evolution_val = add_row("Evolution:")->add_field(EFFECT_FIELD_DOUBLE); - evolution_val->set_double_default_value(0); - - vertical_val = add_row("Vertical:")->add_field(EFFECT_FIELD_BOOL); - vertical_val->set_bool_value(false); - - connect(frequency_val, SIGNAL(changed()), this, SLOT(field_changed())); - connect(intensity_val, SIGNAL(changed()), this, SLOT(field_changed())); - connect(evolution_val, SIGNAL(changed()), this, SLOT(field_changed())); - connect(vertical_val, SIGNAL(changed()), this, SLOT(field_changed())); - - vertPath = ":/shaders/common.vert"; - fragPath = ":/shaders/waveeffect.frag"; -} - -void WaveEffect::process_shader(double timecode) { - glslProgram->setUniformValue("frequency", (GLfloat) (frequency_val->get_double_value(timecode))); - glslProgram->setUniformValue("intensity", (GLfloat) (intensity_val->get_double_value(timecode)*0.01)); - glslProgram->setUniformValue("evolution", (GLfloat) (evolution_val->get_double_value(timecode)*0.01)); - glslProgram->setUniformValue("vertical", vertical_val->get_bool_value(timecode)); -} diff --git a/effects/video/waveeffect.h b/effects/video/waveeffect.h deleted file mode 100644 index a924be988..000000000 --- a/effects/video/waveeffect.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef WAVEEFFECT_H -#define WAVEEFFECT_H - -#include "../effect.h" - -class WaveEffect : public Effect { - Q_OBJECT -public: - WaveEffect(Clip* c); - void process_shader(double timecode); -private: - EffectField* frequency_val; - EffectField* intensity_val; - EffectField* evolution_val; - - EffectField* vertical_val; -}; - -#endif // WAVEEFFECT_H diff --git a/io/config.cpp b/io/config.cpp index e98da475a..b874698a4 100644 --- a/io/config.cpp +++ b/io/config.cpp @@ -110,7 +110,7 @@ void Config::save(QString path) { stream.writeStartDocument(); // doc stream.writeStartElement("Configuration"); // configuration - stream.writeTextElement("Version", SAVE_VERSION); + stream.writeTextElement("Version", QString::number(SAVE_VERSION)); stream.writeTextElement("SavedLayout", QString::number(saved_layout)); stream.writeTextElement("ShowTrackLines", QString::number(show_track_lines)); stream.writeTextElement("ScrollZooms", QString::number(scroll_zooms)); diff --git a/io/config.h b/io/config.h index dbd7fcd40..3d66fde5f 100644 --- a/io/config.h +++ b/io/config.h @@ -3,7 +3,8 @@ #include -#define SAVE_VERSION "181030" // YYMMDD +#define SAVE_VERSION 181030 // YYMMDD +#define MIN_SAVE_VERSION 180820 // lowest compatible project version #define TIMECODE_DROP 0 #define TIMECODE_NONDROP 1 diff --git a/olive.pro b/olive.pro index 79f7c9aba..e7f5c1184 100644 --- a/olive.pro +++ b/olive.pro @@ -4,7 +4,7 @@ # #------------------------------------------------- -QT += core gui multimedia opengl +QT += core gui multimedia opengl qml greaterThan(QT_MAJOR_VERSION, 4): QT += widgets @@ -59,7 +59,6 @@ SOURCES += \ ui/comboboxex.cpp \ ui/colorbutton.cpp \ dialogs/replaceclipmediadialog.cpp \ - effects/linearfadetransition.cpp \ ui/fontcombobox.cpp \ ui/checkboxex.cpp \ effects/effect.cpp \ @@ -72,7 +71,16 @@ SOURCES += \ io/crc32.cpp \ dialogs/loaddialog.cpp \ debug.cpp \ - io/path.cpp + io/path.cpp \ + effects/qpainterwrapper.cpp \ + effects/internal/linearfadetransition.cpp \ + effects/internal/transformeffect.cpp \ + effects/internal/solideffect.cpp \ + effects/internal/texteffect.cpp \ + effects/internal/audionoiseeffect.cpp \ + effects/internal/paneffect.cpp \ + effects/internal/toneeffect.cpp \ + effects/internal/volumeeffect.cpp HEADERS += \ mainwindow.h \ @@ -123,7 +131,15 @@ HEADERS += \ io/crc32.h \ dialogs/loaddialog.h \ debug.h \ - io/path.h + io/path.h \ + effects/qpainterwrapper.h \ + effects/internal/transformeffect.h \ + effects/internal/solideffect.h \ + effects/internal/texteffect.h \ + effects/internal/audionoiseeffect.h \ + effects/internal/paneffect.h \ + effects/internal/toneeffect.h \ + effects/internal/volumeeffect.h FORMS += \ mainwindow.ui \ @@ -153,5 +169,4 @@ linux { } RESOURCES += \ - icons/icons.qrc \ - effects/video/glsl/shaders.qrc + icons/icons.qrc diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index d73da0ae1..9d3c071c9 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -137,12 +137,15 @@ void EffectControls::show_effect_menu(bool video, bool transitions) { break; } } - if (!added) effects_menu.addAction(action); + if (!added) effects_menu.addAction(action); } connect(&effects_menu, SIGNAL(triggered(QAction*)), this, SLOT(menu_select(QAction*))); effects_menu.exec(QCursor::pos());*/ + + effects_loaded.lock(); + video_menu = video; transition_menu = transitions; @@ -152,9 +155,8 @@ void EffectControls::show_effect_menu(bool video, bool transitions) { const EffectMeta& em = effect_list.at(i); QAction* action = new QAction(&effects_menu); action->setText(em.name); - action->setData(reinterpret_cast(&em)); + action->setData(reinterpret_cast(&em)); - // TODO alphabetical ordering QMenu* parent = &effects_menu; if (!em.category.isEmpty()) { bool found = false; @@ -171,17 +173,33 @@ void EffectControls::show_effect_menu(bool video, bool transitions) { if (!found) { parent = new QMenu(&effects_menu); parent->setTitle(em.category); - effects_menu.addMenu(parent); + + 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); } } - parent->addAction(action); - } + 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); + } - QMenu test_menu(this); - test_menu.setTitle("HEY NOW"); - test_menu.addAction("YOU'RE AN ALL STAR"); - effects_menu.addMenu(&test_menu); + effects_loaded.unlock(); 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 4c2f1ab72..eafb82844 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -726,7 +726,8 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) { stream.readNextStartElement(); if (stream.name() == root_search) { if (type == LOAD_TYPE_VERSION) { - if (stream.readElementText() != SAVE_VERSION) { + int proj_version = stream.readElementText().toInt(); + if (proj_version < MIN_SAVE_VERSION && proj_version > SAVE_VERSION) { if (QMessageBox::warning(this, "Version Mismatch", "This project was saved in a different version of Olive and may not be fully compatible with this version. Would you like to attempt loading it anyway?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) { show_err = false; return false; @@ -760,7 +761,6 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) { QTreeWidgetItem* item = new_item(); Media* m = new Media(); - // TODO make save/load-able m->using_inout = false; for (int j=0;jurl = attr.value().toString(); } else if (attr.name() == "duration") { m->length = attr.value().toLongLong(); - } + } else if (attr.name() == "using_inout") { + m->using_inout = (attr.value() == "1"); + } else if (attr.name() == "in") { + m->in = attr.value().toLong(); + } else if (attr.name() == "out") { + m->out = attr.value().toLong(); + } } set_footage_of_tree(item, m); @@ -937,6 +943,7 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) { 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; + } + } + + // 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;jset_enabled(effect_enabled); -// stream.writeAttribute("enabled", QString::number(e->is_enabled())); e->load(stream); - c->effects.append(e); + c->effects.append(e); } + + effects_loaded.unlock(); } } } @@ -1125,6 +1172,9 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int stream.writeAttribute("name", m->name); stream.writeAttribute("url", m->url); stream.writeAttribute("duration", QString::number(m->length)); + stream.writeAttribute("using_inout", QString::number(m->using_inout)); + stream.writeAttribute("in", QString::number(m->in)); + stream.writeAttribute("out", QString::number(m->out)); for (int j=0;jvideo_tracks.size();j++) { MediaStream* ms = m->video_tracks.at(j); stream.writeStartElement("video"); @@ -1216,7 +1266,7 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int for (int k=0;keffects.size();k++) { stream.writeStartElement("effect"); // effect Effect* e = c->effects.at(k); - stream.writeAttribute("id", QString::number(e->id)); + stream.writeAttribute("name", e->meta->name); stream.writeAttribute("enabled", QString::number(e->is_enabled())); e->save(stream); stream.writeEndElement(); // effect @@ -1260,7 +1310,7 @@ void Project::save_project(bool autorecovery) { stream.writeStartElement("project"); // project - stream.writeTextElement("version", SAVE_VERSION); + stream.writeTextElement("version", QString::number(SAVE_VERSION)); save_folder(stream, NULL, MEDIA_TYPE_FOLDER, true); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 32221aabd..ff31cbbc3 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -27,6 +27,8 @@ #include #include +#include + long refactor_frame_number(long framenumber, double source_frame_rate, double target_frame_rate) { if (source_frame_rate == target_frame_rate) return framenumber; return qFloor(((double)framenumber/source_frame_rate)*target_frame_rate); @@ -385,7 +387,7 @@ bool Timeline::is_clip_selected(Clip* clip, bool containing) { } void Timeline::on_snappingButton_toggled(bool checked) { - snapping = checked; + //snapping = checked; } Clip* Timeline::split_clip(ComboAction* ca, int p, long frame) { diff --git a/project/undo.cpp b/project/undo.cpp index 191e8a57a..8740a452f 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -213,7 +213,7 @@ void AddEffectCommand::undo() { void AddEffectCommand::redo() { if (ref == NULL) { - ref = new Effect(clip, *meta); + ref = create_effect(clip, meta); } clip->effects.append(ref); done = true; diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 8c9ae11e5..ea221f970 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -19,7 +19,9 @@ #include "effects/effect.h" #include "effects/transition.h" -#include "effects/video/solideffect.h" + +#include "effects/internal/solideffect.h" +#include "effects/internal/texteffect.h" #include #include @@ -623,14 +625,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)); + c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_TRANSFORM))); } else { // add default audio effects - c->effects.append(create_effect(AUDIO_VOLUME_EFFECT, c)); - c->effects.append(create_effect(AUDIO_PAN_EFFECT, c)); - }*/ + c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_VOLUME))); + c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_PAN))); + } } panel_timeline->ghosts.clear(); @@ -874,41 +876,41 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { if (c->track < 0) { // default video effects (before custom effects) - c->effects.append(create_effect(VIDEO_TRANSFORM_EFFECT, c)); + c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_TRANSFORM))); c->media_type = MEDIA_TYPE_SOLID; } switch (panel_timeline->creating_object) { case ADD_OBJ_TITLE: c->name = "Title"; - c->effects.append(create_effect(VIDEO_TEXT_EFFECT, c)); + c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_TEXT))); break; case ADD_OBJ_SOLID: c->name = "Solid Color"; - c->effects.append(create_effect(VIDEO_SOLID_EFFECT, c)); + c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_SOLID))); break; case ADD_OBJ_BARS: { c->name = "Bars"; - Effect* e = create_effect(VIDEO_SOLID_EFFECT, c); + Effect* e = create_effect(c, get_internal_meta(EFFECT_INTERNAL_SOLID)); e->row(0)->field(0)->set_combo_index(1); - c->effects.append(e); + c->effects.append(e); } break; case ADD_OBJ_TONE: c->name = "Tone"; - c->effects.append(create_effect(AUDIO_TONE_EFFECT, c)); + c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_TONE))); break; case ADD_OBJ_NOISE: c->name = "Noise"; - c->effects.append(create_effect(AUDIO_NOISE_EFFECT, c)); + c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_NOISE))); break; } if (c->track >= 0) { // default audio effects (after custom effects) - c->effects.append(create_effect(AUDIO_VOLUME_EFFECT, c)); - c->effects.append(create_effect(AUDIO_PAN_EFFECT, c)); + c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_VOLUME))); + c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_PAN))); c->media_type = MEDIA_TYPE_TONE; } @@ -2333,14 +2335,12 @@ void TimelineWidget::paintEvent(QPaintEvent*) { } // Draw edit cursor - if (isLiveEditing()) { - if (is_track_visible(panel_timeline->cursor_track)) { - int cursor_x = panel_timeline->getTimelineScreenPointFromFrame(panel_timeline->cursor_frame); - int cursor_y = getScreenPointFromTrack(panel_timeline->cursor_track); + if (isLiveEditing() && is_track_visible(panel_timeline->cursor_track)) { + int cursor_x = panel_timeline->getTimelineScreenPointFromFrame(panel_timeline->cursor_frame); + int cursor_y = getScreenPointFromTrack(panel_timeline->cursor_track); - p.setPen(Qt::gray); - p.drawLine(cursor_x, cursor_y, cursor_x, cursor_y + panel_timeline->calculate_track_height(panel_timeline->cursor_track, -1)); - } + p.setPen(Qt::gray); + p.drawLine(cursor_x, cursor_y, cursor_x, cursor_y + panel_timeline->calculate_track_height(panel_timeline->cursor_track, -1)); } } } diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 819f655e8..bd7bfaf3a 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -366,7 +366,9 @@ 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); + 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);