From 859a17dfda62753ee9dadc52070bb9b161d8f43e Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 19 Aug 2018 15:53:35 +1000 Subject: [PATCH] half way through keyframes data --- effects/audio/paneffect.cpp | 4 +- effects/audio/volumeeffect.cpp | 4 +- effects/effect.cpp | 132 +++++++++++++----- effects/effect.h | 44 +++--- effects/video/inverteffect.cpp | 19 +-- effects/video/inverteffect.h | 4 +- effects/video/shakeeffect.cpp | 12 +- effects/video/shakeeffect.h | 2 +- effects/video/solideffect.cpp | 10 +- effects/video/solideffect.h | 2 +- effects/video/texteffect.cpp | 39 +++--- effects/video/texteffect.h | 2 +- effects/video/transformeffect.cpp | 29 ++-- effects/video/transformeffect.h | 2 +- panels/effectcontrols.cpp | 26 +++- panels/effectcontrols.h | 11 ++ panels/effectcontrols.ui | 214 +++++++++++++++++------------- panels/timeline.cpp | 2 +- playback/playback.cpp | 5 +- ui/keyframeview.cpp | 19 ++- ui/keyframeview.h | 6 +- ui/viewerwidget.cpp | 2 +- 22 files changed, 352 insertions(+), 238 deletions(-) diff --git a/effects/audio/paneffect.cpp b/effects/audio/paneffect.cpp index 1066795da..df34eedb6 100644 --- a/effects/audio/paneffect.cpp +++ b/effects/audio/paneffect.cpp @@ -24,12 +24,12 @@ void PanEffect::refresh() {} Effect* PanEffect::copy(Clip* c) { PanEffect* p = new PanEffect(c); - p->pan_val->set_double_value(pan_val->get_double_value()); + copy_field_keyframes(p); return p; } void PanEffect::process_audio(quint8 *samples, int nb_bytes) { - double pval = pan_val->get_double_value(); + double pval = pan_val->get_double_value(-1); if (pval != 0) { for (int i=0;ivolume_val->set_double_value(volume_val->get_double_value()); + copy_field_keyframes(v); return v; } void VolumeEffect::process_audio(quint8* samples, int nb_bytes) { - double vol_val = volume_val->get_double_value(); + double vol_val = volume_val->get_double_value(-1); if (vol_val != 100) { for (int i=0;ifieldCount();j++) { + EffectField* field = row->field(j); + e->rows.at(i)->field(j)->keyframes = field->keyframes; + } + } +} + EffectRow* Effect::add_row(const QString& name) { EffectRow* row = new EffectRow(this, ui_layout, name, rows.size()); rows.append(row); @@ -165,34 +176,31 @@ void Effect::save(QXmlStreamWriter* stream) { stream->writeStartElement("row"); for (int j=0;jfieldCount();j++) { EffectField* field = row->field(j); - switch (field->type) { - case EFFECT_FIELD_DOUBLE: - stream->writeTextElement("field", QString::number(field->get_double_value())); - break; - case EFFECT_FIELD_COLOR: - stream->writeTextElement("field", field->get_color_value().name()); - break; - case EFFECT_FIELD_STRING: - stream->writeTextElement("field", field->get_string_value()); - break; - case EFFECT_FIELD_BOOL: - stream->writeTextElement("field", QString::number(field->get_bool_value())); - break; - case EFFECT_FIELD_COMBO: - stream->writeTextElement("field", field->get_combo_string()); - break; - case EFFECT_FIELD_FONT: - stream->writeTextElement("field", field->get_font_name()); - break; + stream->writeStartElement("field"); + for (int k=0;kkeyframes.size();k++) { + const EffectKeyframe& key = field->keyframes.at(i); + stream->writeStartElement("key"); + stream->writeAttribute("frame", QString::number(key.frame)); + stream->writeAttribute("type", QString::number(key.type)); + switch (field->type) { + case EFFECT_FIELD_DOUBLE: stream->writeAttribute("value", QString::number(key.data.toDouble())); break; + case EFFECT_FIELD_COLOR: stream->writeAttribute("value", key.data.value().name()); break; + case EFFECT_FIELD_STRING: stream->writeAttribute("value", key.data.toString()); break; + case EFFECT_FIELD_BOOL: stream->writeAttribute("value", QString::number(key.data.toBool())); break; + case EFFECT_FIELD_COMBO: stream->writeAttribute("value", key.data.toString()); break; + case EFFECT_FIELD_FONT: stream->writeAttribute("value", key.data.toString()); break; + } + stream->writeEndElement(); } + stream->writeEndElement(); // field } stream->writeEndElement(); // row } } Effect* Effect::copy(Clip*) {return NULL;} -void Effect::process_image(QImage&) {} -void Effect::process_gl(QOpenGLShaderProgram&, int*, int*) {} +void Effect::process_image(long, QImage&) {} +void Effect::process_gl(long, QOpenGLShaderProgram&, int*, int*) {} void Effect::process_audio(uint8_t*, int) {} /* Effect Row Definitions */ @@ -231,6 +239,11 @@ int EffectRow::fieldCount() { /* Effect Field Definitions */ EffectField::EffectField(int t) : type(t) { + // DEFAULT KEYFRAME + EffectKeyframe key; + key.frame = -1; + keyframes.append(key); + switch (t) { case EFFECT_FIELD_DOUBLE: { @@ -279,6 +292,62 @@ EffectField::EffectField(int t) : type(t) { } } +bool EffectField::is_keyframed(long p) { + return keyframes.size() == 0 || p < 0; +} + +QVariant EffectField::get_keyframe_data(long p) { + if (keyframes.size() == 1) { + return keyframes.at(0).data; + } + + EffectKeyframe* before = NULL; + EffectKeyframe* after = NULL; + for (int i=1;iframe)) { + before = &keyframes[i]; + } else if (keyframes.at(i).frame > p && !(after != NULL && keyframes.at(i).frame >= after->frame)) { + after = &keyframes[i]; + } + } + + // interpolate data + if (before != NULL && after != NULL) { + double progress = (p - before->frame)/(after->frame - before->frame); + switch (type) { + case EFFECT_FIELD_DOUBLE: + { + return lerp(before->data.toDouble(), after->data.toDouble(), progress); + } + break; + case EFFECT_FIELD_COLOR: + { + QColor before_color = before->data.value(); + QColor after_color = after->data.value(); + QColor interval_color = QColor( + lerp(before_color.red(), after_color.red(), progress), + lerp(before_color.green(), after_color.green(), progress), + lerp(before_color.blue(), after_color.blue(), progress) + ); + return QVariant(interval_color); + } + break; + case EFFECT_FIELD_STRING: + case EFFECT_FIELD_BOOL: + case EFFECT_FIELD_COMBO: + case EFFECT_FIELD_FONT: + return before->data; + break; + } + } + + // return pre or post data + if (before != NULL) return before->data; + if (after != NULL) return after->data; +} + QWidget* EffectField::get_ui_element() { return ui_element; } @@ -287,11 +356,12 @@ void EffectField::set_enabled(bool e) { ui_element->setEnabled(e); } -double EffectField::get_double_value() { - return static_cast(ui_element)->value(); +double EffectField::get_double_value(long p) { + return get_keyframe_data(p).toDouble(); } void EffectField::set_double_value(double v) { + static_cast(ui_element)->set_value(v, false); } @@ -311,16 +381,16 @@ void EffectField::add_combo_item(const QString& name, const QVariant& data) { static_cast(ui_element)->addItem(name, data); } -int EffectField::get_combo_index() { +int EffectField::get_combo_index(long p) { return static_cast(ui_element)->currentIndex(); } -const QVariant EffectField::get_combo_data() { +const QVariant EffectField::get_combo_data(long p) { return static_cast(ui_element)->currentData(); } -const QString EffectField::get_combo_string() { - return static_cast(ui_element)->currentText(); +const QString EffectField::get_combo_string(long p) { + return static_cast(ui_element)->itemText(get_keyframe_data(p).toInt()); } void EffectField::set_combo_index(int index) { @@ -331,7 +401,7 @@ void EffectField::set_combo_string(const QString& s) { static_cast(ui_element)->setCurrentTextEx(s); } -bool EffectField::get_bool_value() { +bool EffectField::get_bool_value(long p) { return static_cast(ui_element)->isChecked(); } @@ -339,7 +409,7 @@ void EffectField::set_bool_value(bool b) { return static_cast(ui_element)->setChecked(b); } -const QString EffectField::get_string_value() { +const QString EffectField::get_string_value(long p) { return static_cast(ui_element)->toPlainText(); } @@ -347,7 +417,7 @@ void EffectField::set_string_value(const QString& s) { static_cast(ui_element)->setText(s); } -const QString EffectField::get_font_name() { +const QString EffectField::get_font_name(long p) { return static_cast(ui_element)->currentText(); } @@ -355,7 +425,7 @@ void EffectField::set_font_name(const QString& s) { static_cast(ui_element)->setCurrentText(s); } -QColor EffectField::get_color_value() { +QColor EffectField::get_color_value(long p) { return static_cast(ui_element)->get_color(); } diff --git a/effects/effect.h b/effects/effect.h index 726107db1..d8d007372 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -52,17 +52,10 @@ Effect* create_effect(int effect_id, Clip* c); #define EFFECT_KEYFRAME_HOLD 1 #define EFFECT_KEYFRAME_BEZIER 2 -union KeyframeValue { - double d; - QColor c; - bool b; -}; - -class EffectKeyframe { -public: +struct EffectKeyframe { long frame; int type; - KeyframeValue value; + QVariant data; }; class EffectField : public QObject { @@ -71,33 +64,37 @@ public: EffectField(int t); int type; - double get_double_value(); + QVariant get_keyframe_data(long p); + bool is_keyframed(long p); + + double get_double_value(long p); void set_double_value(double v); void set_double_default_value(double v); void set_double_minimum_value(double v); void set_double_maximum_value(double v); - const QString get_string_value(); + const QString get_string_value(long p); void set_string_value(const QString &s); void add_combo_item(const QString& name, const QVariant &data); - int get_combo_index(); - const QVariant get_combo_data(); - const QString get_combo_string(); + int get_combo_index(long p); + const QVariant get_combo_data(long p); + const QString get_combo_string(long p); void set_combo_index(int index); void set_combo_string(const QString& s); - bool get_bool_value(); + bool get_bool_value(long p); void set_bool_value(bool b); - const QString get_font_name(); + const QString get_font_name(long p); void set_font_name(const QString& s); - QColor get_color_value(); + QColor get_color_value(long p); void set_color_value(QColor color); QWidget* get_ui_element(); void set_enabled(bool e); + QVector keyframes; signals: void changed(); void toggled(bool); @@ -112,12 +109,12 @@ public: EffectField* add_field(int type, int colspan = 1); EffectField* field(int i); int fieldCount(); - void set_keyframe(int field, long time); - void move_keyframe(int field, long from, long to); - void delete_keyframe(int field, long time); + void set_keyframe(long time); + void move_keyframe(long from, long to); + void delete_keyframe(long time); QLabel* label; -private: Effect* parent_effect; +private: QGridLayout* ui; QString name; int ui_row; @@ -146,6 +143,7 @@ public: virtual void refresh(); virtual Effect* copy(Clip* c); + void copy_field_keyframes(Effect *e); void load(QXmlStreamReader* stream); void save(QXmlStreamWriter* stream); @@ -155,8 +153,8 @@ public: const char* ffmpeg_filter; - virtual void process_image(QImage& img); - virtual void process_gl(QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y); + virtual void process_image(long frame, QImage& img); + virtual void process_gl(long frame, QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y); virtual void process_audio(quint8* samples, int nb_bytes); public slots: void field_changed(); diff --git a/effects/video/inverteffect.cpp b/effects/video/inverteffect.cpp index 28562f073..3a2aefd8f 100644 --- a/effects/video/inverteffect.cpp +++ b/effects/video/inverteffect.cpp @@ -19,25 +19,20 @@ InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_ // set defaults amount_val->set_double_default_value(100); - connect(amount_val, SIGNAL(changed()), this, SLOT(compile())); - - compile(); -} - -void InvertEffect::compile() { - double value = amount_val->get_double_value()*0.01; - vert_shader.compileSourceCode("varying vec2 vTexCoord; void main() { vTexCoord = gl_MultiTexCoord0; gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; }"); - frag_shader.compileSourceCode("uniform sampler2D myTexture; varying vec2 vTexCoord; void main(void) { vec4 textureColor = texture2D(myTexture, vTexCoord); gl_FragColor = vec4(textureColor.r+((1.0-textureColor.r-textureColor.r)*" + QString::number(value) + "), textureColor.g+((1.0-textureColor.g-textureColor.g)*" + QString::number(value) + "), textureColor.b+((1.0-textureColor.b-textureColor.b)*" + QString::number(value) + "), 1); }"); - field_changed(); + connect(amount_val, SIGNAL(changed()), this, SLOT(field_changed())); } Effect* InvertEffect::copy(Clip* c) { InvertEffect* i = new InvertEffect(c); - i->amount_val->set_double_value(amount_val->get_double_value()); + copy_field_keyframes(i); return i; } -void InvertEffect::process_gl(QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y) { +void InvertEffect::process_gl(long p, QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y) { + double value = amount_val->get_double_value(p)*0.01; + vert_shader.compileSourceCode("varying vec2 vTexCoord; void main() { vTexCoord = gl_MultiTexCoord0; gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; }"); + frag_shader.compileSourceCode("uniform sampler2D myTexture; varying vec2 vTexCoord; void main(void) { vec4 textureColor = texture2D(myTexture, vTexCoord); gl_FragColor = vec4(textureColor.r+((1.0-textureColor.r-textureColor.r)*" + QString::number(value) + "), textureColor.g+((1.0-textureColor.g-textureColor.g)*" + QString::number(value) + "), textureColor.b+((1.0-textureColor.b-textureColor.b)*" + QString::number(value) + "), 1); }"); + shader_prog.addShader(&vert_shader); shader_prog.addShader(&frag_shader); } diff --git a/effects/video/inverteffect.h b/effects/video/inverteffect.h index 924506545..05565637c 100644 --- a/effects/video/inverteffect.h +++ b/effects/video/inverteffect.h @@ -9,12 +9,10 @@ class InvertEffect : public Effect { Q_OBJECT public: InvertEffect(Clip* c); - void process_gl(QOpenGLShaderProgram& shader_prog, int *anchor_x, int *anchor_y); + void process_gl(long p, QOpenGLShaderProgram& shader_prog, int *anchor_x, int *anchor_y); Effect* copy(Clip *c); EffectField* amount_val; -private slots: - void compile(); private: QOpenGLShader vert_shader; QOpenGLShader frag_shader; diff --git a/effects/video/shakeeffect.cpp b/effects/video/shakeeffect.cpp index 7c03c10c8..77ca62da0 100644 --- a/effects/video/shakeeffect.cpp +++ b/effects/video/shakeeffect.cpp @@ -41,7 +41,7 @@ ShakeEffect::ShakeEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_SHAKE_EFF void ShakeEffect::refresh() { if (parent_clip->sequence != NULL) { - shake_limit = qRound(parent_clip->sequence->frame_rate / frequency_val->get_double_value()); + shake_limit = qRound(parent_clip->sequence->frame_rate / frequency_val->get_double_value(-1)); shake_progress = shake_limit; next_x = 0; next_y = 0; @@ -51,15 +51,13 @@ void ShakeEffect::refresh() { Effect* ShakeEffect::copy(Clip* c) { ShakeEffect* e = new ShakeEffect(c); - e->intensity_val->set_double_value(intensity_val->get_double_value()); - e->rotation_val->set_double_value(rotation_val->get_double_value()); - e->frequency_val->set_double_value(frequency_val->get_double_value()); + copy_field_keyframes(e); return e; } -void ShakeEffect::process_gl(QOpenGLShaderProgram&, int*, int*) { +void ShakeEffect::process_gl(long p, QOpenGLShaderProgram&, int*, int*) { if (shake_progress > shake_limit) { - double ival = intensity_val->get_double_value(); + double ival = intensity_val->get_double_value(p); if ((int)ival > 0) { prev_x = next_x; prev_y = next_y; @@ -89,7 +87,7 @@ void ShakeEffect::process_gl(QOpenGLShaderProgram&, int*, int*) { offset_x = 0; offset_y = 0; } - double rot_val = rotation_val->get_double_value(); + double rot_val = rotation_val->get_double_value(p); if ((int)rot_val > 0) { prev_rot = next_rot; next_rot = (qrand() % (int) (rot_val * 2)) - rot_val; diff --git a/effects/video/shakeeffect.h b/effects/video/shakeeffect.h index 738923ace..e18f704cb 100644 --- a/effects/video/shakeeffect.h +++ b/effects/video/shakeeffect.h @@ -7,7 +7,7 @@ class ShakeEffect : public Effect { Q_OBJECT public: ShakeEffect(Clip* c); - void process_gl(QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y); + void process_gl(long p, QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y); Effect* copy(Clip *c); EffectField* intensity_val; diff --git a/effects/video/solideffect.cpp b/effects/video/solideffect.cpp index 5e9005a05..0b2d2bbdc 100644 --- a/effects/video/solideffect.cpp +++ b/effects/video/solideffect.cpp @@ -37,19 +37,19 @@ SolidEffect::SolidEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_SOLID_EFF } void SolidEffect::enable_color() { - solid_color_field->set_enabled(solid_type->get_combo_data() == SOLID_TYPE_COLOR); + solid_color_field->set_enabled(solid_type->get_combo_data(-1) == SOLID_TYPE_COLOR); } -void SolidEffect::process_image(QImage& img) { +void SolidEffect::process_image(long frame, QImage& img) { QPainter p(&img); int width = img.width(); int height = img.height(); - switch (solid_type->get_combo_data().toInt()) { + switch (solid_type->get_combo_data(frame).toInt()) { case SOLID_TYPE_COLOR: { - QColor brush = solid_color_field->get_color_value(); - p.fillRect(0, 0, width, height, QColor(brush.red(), brush.green(), brush.blue(), opacity_field->get_double_value()*2.55)); + QColor brush = solid_color_field->get_color_value(frame); + p.fillRect(0, 0, width, height, QColor(brush.red(), brush.green(), brush.blue(), opacity_field->get_double_value(frame)*2.55)); } break; case SOLID_TYPE_BARS: diff --git a/effects/video/solideffect.h b/effects/video/solideffect.h index a08a8a814..3892e66be 100644 --- a/effects/video/solideffect.h +++ b/effects/video/solideffect.h @@ -10,7 +10,7 @@ public: EffectField* solid_type; EffectField* solid_color_field; EffectField* opacity_field; - void process_image(QImage &img); + void process_image(long p, QImage &img); private slots: void enable_color(); }; diff --git a/effects/video/texteffect.cpp b/effects/video/texteffect.cpp index d4d398d5d..acec66314 100644 --- a/effects/video/texteffect.cpp +++ b/effects/video/texteffect.cpp @@ -242,7 +242,7 @@ void blurred2(QImage& result, const QRect& rect, int radius, bool alphaOnly = fa } } -void TextEffect::process_image(QImage& img) { +void TextEffect::process_image(long frame, QImage& img) { QPainter p(&img); p.setRenderHint(QPainter::Antialiasing); int width = img.width(); @@ -250,15 +250,15 @@ void TextEffect::process_image(QImage& img) { // set font font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias); - font.setFamily(set_font_combobox->get_font_name()); - font.setPointSize(size_val->get_double_value()); + font.setFamily(set_font_combobox->get_font_name(frame)); + font.setPointSize(size_val->get_double_value(frame)); p.setFont(font); QFontMetrics fm(font); - QStringList lines = text_val->get_string_value().split('\n'); + QStringList lines = text_val->get_string_value(frame).split('\n'); // word wrap function - if (word_wrap_field->get_bool_value()) { + if (word_wrap_field->get_bool_value(frame)) { for (int i=0;i width) { @@ -287,7 +287,7 @@ void TextEffect::process_image(QImage& img) { for (int i=0;iget_combo_data().toInt()) { + switch (halign_field->get_combo_data(frame).toInt()) { case Qt::AlignLeft: text_x = 0; break; case Qt::AlignHCenter: text_x = (width/2) - (fm.width(lines.at(i))/2); break; case Qt::AlignRight: text_x = width - fm.width(lines.at(i)); break; @@ -316,7 +316,7 @@ void TextEffect::process_image(QImage& img) { break; } - switch (valign_field->get_combo_data().toInt()) { + switch (valign_field->get_combo_data(frame).toInt()) { case Qt::AlignTop: text_y = (fm.height()*i)+fm.ascent(); break; case Qt::AlignVCenter: text_y = ((height/2) - (text_height/2) - fm.descent()) + (fm.height()*(i+1)); break; case Qt::AlignBottom: text_y = (height - text_height - fm.descent()) + (fm.height()*(i+1)); break; @@ -328,43 +328,38 @@ void TextEffect::process_image(QImage& img) { p.setPen(Qt::NoPen); // draw shadow - if (shadow_bool->get_bool_value()) { + if (shadow_bool->get_bool_value(frame)) { QImage shadow(width, height, QImage::Format_ARGB32_Premultiplied); shadow.fill(Qt::transparent); QPainter spaint(&shadow); - int shadow_offset = shadow_distance->get_double_value(); - QColor col = shadow_color->get_color_value(); - col.setAlphaF(shadow_opacity->get_double_value()*0.01); + int shadow_offset = shadow_distance->get_double_value(frame); + QColor col = shadow_color->get_color_value(frame); + col.setAlphaF(shadow_opacity->get_double_value(frame)*0.01); spaint.setBrush(col); spaint.drawPath(path); - blurred2(shadow, shadow.rect(), shadow_softness->get_double_value(), false); + blurred2(shadow, shadow.rect(), shadow_softness->get_double_value(frame), false); p.drawImage(shadow_offset, shadow_offset, shadow); spaint.end(); } // draw outline - int outline_width_val = outline_width->get_double_value(); - if (outline_bool->get_bool_value() && outline_width_val > 0) { - QPen outline(outline_color->get_color_value()); + int outline_width_val = outline_width->get_double_value(frame); + if (outline_bool->get_bool_value(frame) && outline_width_val > 0) { + QPen outline(outline_color->get_color_value(frame)); outline.setWidth(outline_width_val); p.setPen(outline); } // draw "master" text - p.setBrush(set_color_button->get_color_value()); + p.setBrush(set_color_button->get_color_value(frame)); p.drawPath(path); } Effect* TextEffect::copy(Clip* c) { TextEffect* e = new TextEffect(c); - e->text_val->set_string_value(text_val->get_string_value()); - e->size_val->set_double_value(size_val->get_double_value()); - e->set_color_button->set_color_value(set_color_button->get_color_value()); - e->set_font_combobox->set_font_name(set_font_combobox->get_font_name()); - e->halign_field->set_combo_index(halign_field->get_combo_index()); - e->valign_field->set_combo_index(valign_field->get_combo_index()); + copy_field_keyframes(e); return e; } diff --git a/effects/video/texteffect.h b/effects/video/texteffect.h index 0574f2e8d..919d72bf9 100644 --- a/effects/video/texteffect.h +++ b/effects/video/texteffect.h @@ -9,7 +9,7 @@ class TextEffect : public Effect { Q_OBJECT public: TextEffect(Clip* c); - void process_image(QImage& img); + void process_image(long frame, QImage& img); Effect* copy(Clip* c); EffectField* text_val; diff --git a/effects/video/transformeffect.cpp b/effects/video/transformeffect.cpp index 1e4b50342..4a413e647 100644 --- a/effects/video/transformeffect.cpp +++ b/effects/video/transformeffect.cpp @@ -80,16 +80,7 @@ TransformEffect::TransformEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_T Effect* TransformEffect::copy(Clip* c) { TransformEffect* t = new TransformEffect(c); - t->position_x->set_double_value(position_x->get_double_value()); - t->position_y->set_double_value(position_y->get_double_value()); - t->scale_x->set_double_value(scale_x->get_double_value()); - t->scale_y->set_double_value(scale_y->get_double_value()); - t->uniform_scale_field->set_bool_value(uniform_scale_field->get_bool_value()); - t->rotation->set_double_value(rotation->get_double_value()); - t->anchor_x_box->set_double_value(anchor_x_box->get_double_value()); - t->anchor_y_box->set_double_value(anchor_y_box->get_double_value()); - t->opacity->set_double_value(opacity->get_double_value()); - t->blend_mode_box->set_combo_index(blend_mode_box->get_combo_index()); + copy_field_keyframes(t); return t; } @@ -136,24 +127,24 @@ void TransformEffect::toggle_uniform_scale(bool enabled) { scale_y->set_enabled(!enabled); } -void TransformEffect::process_gl(QOpenGLShaderProgram&, int* anchor_x, int* anchor_y) { +void TransformEffect::process_gl(long frame, QOpenGLShaderProgram&, int* anchor_x, int* anchor_y) { // position - glTranslatef(position_x->get_double_value()-(parent_clip->sequence->width/2), position_y->get_double_value()-(parent_clip->sequence->height/2), 0); + glTranslatef(position_x->get_double_value(frame)-(parent_clip->sequence->width/2), position_y->get_double_value(frame)-(parent_clip->sequence->height/2), 0); // anchor point - *anchor_x += (anchor_x_box->get_double_value()-default_anchor_x); - *anchor_y += (anchor_y_box->get_double_value()-default_anchor_y); + *anchor_x += (anchor_x_box->get_double_value(frame)-default_anchor_x); + *anchor_y += (anchor_y_box->get_double_value(frame)-default_anchor_y); // rotation - glRotatef(rotation->get_double_value(), 0, 0, 1); + glRotatef(rotation->get_double_value(frame), 0, 0, 1); // scale - float sx = scale_x->get_double_value()*0.01; - float sy = (uniform_scale_field->get_bool_value()) ? sx : scale_y->get_double_value()*0.01; + float sx = scale_x->get_double_value(frame)*0.01; + float sy = (uniform_scale_field->get_bool_value(frame)) ? sx : scale_y->get_double_value(frame)*0.01; glScalef(sx, sy, 1); // blend mode - switch (blend_mode_box->get_combo_data().toInt()) { + switch (blend_mode_box->get_combo_data(frame).toInt()) { case BLEND_MODE_NORMAL: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; @@ -173,5 +164,5 @@ void TransformEffect::process_gl(QOpenGLShaderProgram&, int* anchor_x, int* anch // opacity float color[4]; glGetFloatv(GL_CURRENT_COLOR, color); - glColor4f(1.0, 1.0, 1.0, color[3]*(opacity->get_double_value()*0.01)); + glColor4f(1.0, 1.0, 1.0, color[3]*(opacity->get_double_value(frame)*0.01)); } diff --git a/effects/video/transformeffect.h b/effects/video/transformeffect.h index 7f8df6550..7eaf485b4 100644 --- a/effects/video/transformeffect.h +++ b/effects/video/transformeffect.h @@ -8,7 +8,7 @@ class TransformEffect : public Effect { public: TransformEffect(Clip* c); void refresh(); - void process_gl(QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y); + void process_gl(long p, QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y); Effect* copy(Clip *c); EffectField* position_x; diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 72264ddce..c6788d424 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "panels/panels.h" #include "effects/effect.h" @@ -28,6 +30,12 @@ EffectControls::EffectControls(QWidget *parent) : init_transitions(); clear_effects(false); ui->headers->snapping = false; + + ui->effects_area->parent_widget = ui->scrollArea; + ui->effects_area->keyframe_area = ui->keyframeView; + ui->effects_area->header = ui->headers; + + connect(ui->keyframeScroller->verticalScrollBar(), SIGNAL(valueChanged(int)), ui->scrollArea->verticalScrollBar(), SLOT(setValue(int))); } EffectControls::~EffectControls() { @@ -182,9 +190,18 @@ void EffectControls::load_effects() { } connect(container, SIGNAL(deselect_others(QWidget*)), this, SLOT(deselect_all_effects(QWidget*))); connect(container, SIGNAL(visibleChanged()), ui->keyframeView, SLOT(reload())); - } + } } if (selected_clips.size() > 0) { +// ui->scrollArea->setMinimumWidth(ui->effects_area->width()); + + /*ui->effects_area->layout()->update(); + ui->effects_area->layout()->activate(); + qDebug() << ui->effects_area->height(); + + ui->keyframeView->resize(ui->keyframeView->width(), ui->effects_area->height());*/ + + ui->keyframeView->setMinimumHeight(ui->effects_area->height()); ui->keyframeView->setEnabled(true); ui->keyframeView->visible_in = effects_in; ui->keyframeView->visible_out = effects_out; @@ -266,3 +283,10 @@ bool EffectControls::is_focused() { } return false; } + +EffectsArea::EffectsArea(QWidget* parent) : QWidget(parent) {} + +void EffectsArea::resizeEvent(QResizeEvent *event) { + parent_widget->setMinimumWidth(sizeHint().width()); + keyframe_area->setMinimumHeight(height() - header->height()); +} diff --git a/panels/effectcontrols.h b/panels/effectcontrols.h index ccb94d15d..49accdd75 100644 --- a/panels/effectcontrols.h +++ b/panels/effectcontrols.h @@ -8,6 +8,17 @@ struct Clip; class QMenu; class Effect; class TimelineHeader; +class QScrollArea; +class KeyframeView; + +class EffectsArea : public QWidget { +public: + EffectsArea(QWidget* parent = 0); + void resizeEvent(QResizeEvent *event); + QScrollArea* parent_widget; + KeyframeView* keyframe_area; + TimelineHeader* header; +}; namespace Ui { class EffectControls; diff --git a/panels/effectcontrols.ui b/panels/effectcontrols.ui index f18fdbbbf..401449ca6 100644 --- a/panels/effectcontrols.ui +++ b/panels/effectcontrols.ui @@ -40,44 +40,62 @@ 0 - - - true + + + Qt::Horizontal - - - - 0 - 0 - 619 - 489 - + + false + + + + + 0 + 0 + - - - 0 + + QFrame::NoFrame + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOn + + + true + + + + + 0 + 0 + 225 + 477 + - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - false - - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 @@ -399,69 +417,75 @@ - + + + + + + + + 1 + 0 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOn + + + true + + + + + 0 + 0 + 376 + 475 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + - - 1 + + 0 0 - - true + + + 0 + 15 + + + + Qt::ClickFocus - - - - 0 - 0 - 388 - 487 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 0 - 15 - - - - Qt::ClickFocus - - - - - - - - - - - + + + + + + @@ -481,6 +505,12 @@
ui/timelineheader.h
1 + + EffectsArea + QWidget +
panels/effectcontrols.h
+ 1 +
diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 8d78f2f4c..027c97da4 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -394,7 +394,7 @@ void Timeline::delete_selection(bool ripple_delete) { } int lerp(int a, int b, double t) { - return ((1.0 - t) * a) + (t * b); + return ((1.0 - t) * a) + (t * b); } void Timeline::set_zoom(bool in) { diff --git a/playback/playback.cpp b/playback/playback.cpp index ef08e1bb9..53f587de1 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -76,7 +76,8 @@ void cache_clip(Clip* clip, long playhead, bool write_A, bool write_B, bool rese void get_clip_frame(Clip* c, long playhead) { if (c->open) { - long clip_time = refactor_frame_number(playhead - c->timeline_in + c->clip_in, c->sequence->frame_rate, av_q2d(av_guess_frame_rate(c->formatCtx, c->stream, c->frame))); + long sequence_clip_time = playhead - c->timeline_in + c->clip_in; + long clip_time = refactor_frame_number(sequence_clip_time, c->sequence->frame_rate, av_q2d(av_guess_frame_rate(c->formatCtx, c->stream, c->frame))); // do we need to update the texture? MediaStream* ms = static_cast(c->media)->get_stream_from_file_index(c->media_stream); @@ -169,7 +170,7 @@ void get_clip_frame(Clip* c, long playhead) { QImage img(c->comp_frame, current_frame->width, current_frame->height, QImage::Format_RGBA8888); for (int i=0;ieffects.size();i++) { if (c->effects.at(i)->enable_image) { - c->effects.at(i)->process_image(img); + c->effects.at(i)->process_image(sequence_clip_time, img); } } diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index 11b7131ce..c7c605a1b 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -16,12 +16,6 @@ KeyframeView::KeyframeView(QWidget *parent) : QWidget(parent), mouseover(false), visible_in(0), visible_out(0) { setFocusPolicy(Qt::ClickFocus); setMouseTracking(true); - reload(); -} - -void KeyframeView::reload() { - enable_reload = true; - update(); } void KeyframeView::paintEvent(QPaintEvent*) { @@ -30,6 +24,7 @@ void KeyframeView::paintEvent(QPaintEvent*) { setMinimumWidth(getScreenPointFromFrame(panel_effect_controls->zoom, visible_out - visible_in)); rowY.clear(); + rows.clear(); for (int i=0;icontainer->is_expanded()) { @@ -39,6 +34,8 @@ void KeyframeView::paintEvent(QPaintEvent*) { long frame = 20; int keyframe_y = label->y() + (label->height()>>1) + mapFrom(panel_effect_controls, contents->mapTo(panel_effect_controls, contents->pos())).y() - e->container->title_bar->height(); draw_keyframe(p, getScreenPointFromFrame(panel_effect_controls->zoom, frame), keyframe_y, false); + + rows.append(e->row(j)); rowY.append(keyframe_y); } } @@ -51,7 +48,7 @@ void KeyframeView::paintEvent(QPaintEvent*) { } if (mouseover && mouseover_row < rowY.size()) { - draw_keyframe(p, getScreenPointFromFrame(panel_effect_controls->zoom, mouseover_frame) - visible_in, rowY.at(mouseover_row), true); + draw_keyframe(p, getScreenPointFromFrame(panel_effect_controls->zoom, mouseover_frame - visible_in), rowY.at(mouseover_row), true); } } @@ -63,6 +60,10 @@ void KeyframeView::draw_keyframe(QPainter &p, int x, int y, bool semiTransparent p.drawPolygon(points, KEYFRAME_POINT_COUNT); } +void KeyframeView::mousePressEvent(QMouseEvent *event) { + qDebug() << "create keyframe @ clip frame" << mouseover_frame - visible_in + (rows.at(mouseover_row)->parent_effect->parent_clip->clip_in) << "effect row" << mouseover_row; +} + void KeyframeView::mouseMoveEvent(QMouseEvent* event) { unsetCursor(); bool new_mo = false; @@ -80,3 +81,7 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) { } mouseover = new_mo; } + +void KeyframeView::mouseReleaseEvent(QMouseEvent* event) { + +} diff --git a/ui/keyframeview.h b/ui/keyframeview.h index 986b5faf4..8382ce015 100644 --- a/ui/keyframeview.h +++ b/ui/keyframeview.h @@ -16,14 +16,12 @@ public: long visible_in; long visible_out; -public slots: - void reload(); private: QVector rowY; QVector rows; + void mousePressEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event); - /*void mousePressEvent(QMouseEvent* event); - void mouseReleaseEvent(QMouseEvent *event);*/ + void mouseReleaseEvent(QMouseEvent *event); void paintEvent(QPaintEvent *event); void draw_keyframe(QPainter& p, int x, int y, bool semiTransparent); bool enable_reload; diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 567f48290..6aa7508d4 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -177,7 +177,7 @@ void ViewerWidget::compose_sequence(QVector& nests, bool render_audio) { QOpenGLShaderProgram shader; for (int j=0;jeffects.size();j++) { - if (c->effects.at(j)->enable_opengl && c->effects.at(j)->is_enabled()) c->effects.at(j)->process_gl(shader, &anchor_x, &anchor_y); + if (c->effects.at(j)->enable_opengl && c->effects.at(j)->is_enabled()) c->effects.at(j)->process_gl(panel_timeline->playhead-c->timeline_in+c->clip_in, shader, &anchor_x, &anchor_y); } if (c->opening_transition != NULL) {