From 97343fb7524c459c446f3e246024dcdaa9ecbe02 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 16 Jul 2018 23:19:22 +0100 Subject: [PATCH] added rudimentary shake effect --- effects/effects.cpp | 2 + effects/effects.h | 30 ++++++++++ effects/shakeeffect.cpp | 122 ++++++++++++++++++++++++++++++++++++++++ io/config.cpp | 1 + io/config.h | 2 + mainwindow.cpp | 6 ++ mainwindow.h | 2 + mainwindow.ui | 9 +++ olive.pro | 7 ++- panels/timeline.cpp | 7 ++- panels/timeline.h | 2 + panels/timeline.ui | 8 ++- ui/scrollarea.cpp | 19 +++++++ ui/scrollarea.h | 13 +++++ 14 files changed, 224 insertions(+), 6 deletions(-) create mode 100644 effects/shakeeffect.cpp create mode 100644 ui/scrollarea.cpp create mode 100644 ui/scrollarea.h diff --git a/effects/effects.cpp b/effects/effects.cpp index 3d3aaa72d..6daf18d74 100644 --- a/effects/effects.cpp +++ b/effects/effects.cpp @@ -13,6 +13,7 @@ void init_effects() { audio_effect_names.resize(AUDIO_EFFECT_COUNT); video_effect_names[VIDEO_TRANSFORM_EFFECT] = "Transform"; + video_effect_names[VIDEO_SHAKE_EFFECT] = "Shake"; audio_effect_names[AUDIO_VOLUME_EFFECT] = "Volume"; audio_effect_names[AUDIO_PAN_EFFECT] = "Pan"; @@ -22,6 +23,7 @@ Effect* create_effect(int effect_id, Clip* c) { if (c->track < 0) { switch (effect_id) { case VIDEO_TRANSFORM_EFFECT: return new TransformEffect(c); + case VIDEO_SHAKE_EFFECT: return new ShakeEffect(c); } } else { switch (effect_id) { diff --git a/effects/effects.h b/effects/effects.h index 58683dc1f..700700d65 100644 --- a/effects/effects.h +++ b/effects/effects.h @@ -11,6 +11,7 @@ class LabelSlider; enum VideoEffects { VIDEO_TRANSFORM_EFFECT, + VIDEO_SHAKE_EFFECT, VIDEO_EFFECT_COUNT }; @@ -52,6 +53,35 @@ private: int default_anchor_y; }; +class ShakeEffect : public Effect { + Q_OBJECT +public: + ShakeEffect(Clip* c); + void process_gl(int* anchor_x, int* anchor_y); + Effect* copy(Clip *c); + void load(QXmlStreamReader* stream); + void save(QXmlStreamWriter* stream); + + LabelSlider* intensity_val; + LabelSlider* rotation_val; + LabelSlider* frequency_val; +private slots: + void set_values(); +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; + double t; +}; + // audio effects class VolumeEffect : public Effect { public: diff --git a/effects/shakeeffect.cpp b/effects/shakeeffect.cpp new file mode 100644 index 000000000..5c79e0c9e --- /dev/null +++ b/effects/shakeeffect.cpp @@ -0,0 +1,122 @@ +#include "effects/effects.h" + +#include +#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) { + setup_effect(EFFECT_TYPE_VIDEO, VIDEO_SHAKE_EFFECT); + + QGridLayout* ui_layout = new QGridLayout(); + + ui_layout->addWidget(new QLabel("Intensity:"), 0, 0); + intensity_val = new LabelSlider(); + intensity_val->set_minimum_value(0); + ui_layout->addWidget(intensity_val, 0, 1); + + ui_layout->addWidget(new QLabel("Rotation:"), 1, 0); + rotation_val = new LabelSlider(); + rotation_val->set_minimum_value(0); + ui_layout->addWidget(rotation_val, 1, 1); + + ui_layout->addWidget(new QLabel("Frequency:"), 2, 0); + frequency_val = new LabelSlider(); + frequency_val->set_minimum_value(0); + ui_layout->addWidget(frequency_val, 2, 1); + + ui->setLayout(ui_layout); + + container->setContents(ui); + + // set defaults + intensity_val->set_value(50); + rotation_val->set_value(0); + frequency_val->set_value(10); + + set_values(); + + connect(intensity_val, SIGNAL(valueChanged()), this, SLOT(field_changed())); + connect(rotation_val, SIGNAL(valueChanged()), this, SLOT(field_changed())); + connect(frequency_val, SIGNAL(valueChanged()), this, SLOT(field_changed())); + connect(intensity_val, SIGNAL(valueChanged()), this, SLOT(set_values())); + connect(rotation_val, SIGNAL(valueChanged()), this, SLOT(set_values())); + connect(frequency_val, SIGNAL(valueChanged()), this, SLOT(set_values())); +} + +void ShakeEffect::set_values() { + shake_limit = qRound(parent_clip->sequence->frame_rate / frequency_val->value()); + shake_progress = shake_limit; + next_x = 0; + next_y = 0; + next_rot = 0; +} + +Effect* ShakeEffect::copy(Clip* c) { + ShakeEffect* e = new ShakeEffect(c); + e->intensity_val->set_value(intensity_val->value()); + e->rotation_val->set_value(rotation_val->value()); + e->frequency_val->set_value(frequency_val->value()); + return e; +} + +void ShakeEffect::load(QXmlStreamReader* reader) { + const QXmlStreamAttributes& attr = reader->attributes(); + for (int i=0;iset_value(a.value().toFloat()); + } else if (a.name() == "rotation") { + rotation_val->set_value(a.value().toFloat()); + } else if (a.name() == "frequency") { + frequency_val->set_value(a.value().toFloat()); + } + } +} + +void ShakeEffect::save(QXmlStreamWriter* stream) { + stream->writeAttribute("intensity", QString::number(intensity_val->value())); + stream->writeAttribute("rotation", QString::number(rotation_val->value())); + stream->writeAttribute("frequency", QString::number(frequency_val->value())); +} + +void ShakeEffect::process_gl(int*, int*) { + if (shake_progress > shake_limit) { + if (intensity_val->value() > 0) { + prev_x = next_x; + prev_y = next_y; + next_x = (qrand() % (int) (intensity_val->value() * 2)) - intensity_val->value(); + next_y = (qrand() % (int) (intensity_val->value() * 2)) - intensity_val->value(); + } else { + prev_x = 0; + prev_y = 0; + next_x = 0; + next_y = 0; + offset_x = 0; + offset_y = 0; + } + if (rotation_val->value() > 0) { + prev_rot = next_rot; + next_rot = (qrand() % (int) (rotation_val->value() * 2)) - rotation_val->value(); + } else { + prev_rot = 0; + next_rot = 0; + offset_rot = 0; + } + shake_progress = 0; + } + t = 1 - qPow(((double) shake_progress / (double) shake_limit)-1, 2); + offset_x = lerp(prev_x, next_x, t); + offset_y = lerp(prev_y, next_y, t); + 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/io/config.cpp b/io/config.cpp index c655a45e4..c42235ab8 100644 --- a/io/config.cpp +++ b/io/config.cpp @@ -14,6 +14,7 @@ bool custom_scale = false; bool saved_layout = false; bool left_mouse_dominant = true; bool show_track_lines = false; +bool scroll_zooms = false; void load_config() { /*if (!custom_scale) { diff --git a/io/config.h b/io/config.h index 7a618c2ce..b46bfdad7 100644 --- a/io/config.h +++ b/io/config.h @@ -10,6 +10,8 @@ extern bool custom_scale; extern bool saved_layout; extern bool show_track_lines; +extern bool scroll_zooms; + void load_config(); void save_config(); diff --git a/mainwindow.cpp b/mainwindow.cpp index ec9682469..6fb8c3759 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -540,6 +540,7 @@ void MainWindow::toolMenu_About_To_Be_Shown() { ui->actionSelecting_Also_Seeks->setChecked(panel_timeline->select_also_seeks); ui->actionSeek_to_the_End_of_Pastes->setChecked(panel_timeline->paste_seeks); ui->actionToggle_Snapping->setChecked(panel_timeline->snapping); + ui->actionScroll_Wheel_Zooms->setChecked(scroll_zooms); } void MainWindow::on_actionEdit_Tool_Selects_Links_triggered() { @@ -609,3 +610,8 @@ void MainWindow::load_recent_project() { panel_project->load_project(); } } + +void MainWindow::on_actionScroll_Wheel_Zooms_triggered() +{ + scroll_zooms = !scroll_zooms; +} diff --git a/mainwindow.h b/mainwindow.h index 5df50b416..de836e234 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -150,6 +150,8 @@ private slots: void load_recent_project(); + void on_actionScroll_Wheel_Zooms_triggered(); + private: Ui::MainWindow *ui; void setup_layout(); diff --git a/mainwindow.ui b/mainwindow.ui index 57503bb82..dc4123a59 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -139,6 +139,7 @@ + @@ -600,6 +601,14 @@ Clear Recent List + + + true + + + Scroll Wheel Zooms + + diff --git a/olive.pro b/olive.pro index 82b37cd6f..6ce6dbcd4 100644 --- a/olive.pro +++ b/olive.pro @@ -59,7 +59,9 @@ SOURCES += \ effects/transition.cpp \ effects/crossdissolvetransition.cpp \ ui/audiomonitor.cpp \ - project/undo.cpp + project/undo.cpp \ + ui/scrollarea.cpp \ + effects/shakeeffect.cpp HEADERS += \ mainwindow.h \ @@ -93,7 +95,8 @@ HEADERS += \ dialogs/preferencesdialog.h \ effects/transition.h \ ui/audiomonitor.h \ - project/undo.h + project/undo.h \ + ui/scrollarea.h FORMS += \ mainwindow.ui \ diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 7593cf5d6..394ba119e 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -329,8 +329,8 @@ void Timeline::delete_selection(bool ripple_delete) { } } -int lerp(int a, int b, float t) { - return ((1.0f - t) * a) + (t * b); +int lerp(int a, int b, double t) { + return ((1.0 - t) * a) + (t * b); } void Timeline::set_zoom(bool in) { @@ -343,7 +343,7 @@ void Timeline::set_zoom(bool in) { lerp( ui->timeline_area->horizontalScrollBar()->value(), getScreenPointFromFrame(playhead) - (ui->timeline_area->width()/2), - 0.99f + 0.99 ) ); redraw_all_clips(false); @@ -653,6 +653,7 @@ void Timeline::paste() { // create copy of clip and offset by playhead Clip* cc = c->copy(); + cc->sequence = sequence; cc->timeline_in += playhead; cc->timeline_out += playhead; cc->track = c->track; diff --git a/panels/timeline.h b/panels/timeline.h index 55cea36e0..a617135bb 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -16,6 +16,8 @@ struct Clip; struct Media; struct MediaStream; +int lerp(int a, int b, double t); + struct Ghost { int clip; long in; diff --git a/panels/timeline.ui b/panels/timeline.ui index 2b5930077..f486cb108 100644 --- a/panels/timeline.ui +++ b/panels/timeline.ui @@ -346,7 +346,7 @@ - + Qt::ScrollBarAlwaysOn @@ -459,6 +459,12 @@
ui/audiomonitor.h
1 + + ScrollArea + QScrollArea +
ui/scrollarea.h
+ 1 +
diff --git a/ui/scrollarea.cpp b/ui/scrollarea.cpp new file mode 100644 index 000000000..fcca7b08b --- /dev/null +++ b/ui/scrollarea.cpp @@ -0,0 +1,19 @@ +#include "scrollarea.h" + +#include +#include + +#include "io/config.h" +#include "panels/panels.h" +#include "panels/timeline.h" + +ScrollArea::ScrollArea(QWidget* parent) : QScrollArea(parent) {} + +void ScrollArea::wheelEvent(QWheelEvent *e) { + if (scroll_zooms) { + e->ignore(); + if (e->angleDelta().y() != 0) panel_timeline->set_zoom(e->angleDelta().y() < 0); + } else { + QScrollArea::wheelEvent(e); + } +} diff --git a/ui/scrollarea.h b/ui/scrollarea.h new file mode 100644 index 000000000..e7facf07a --- /dev/null +++ b/ui/scrollarea.h @@ -0,0 +1,13 @@ +#ifndef SCROLLAREA_H +#define SCROLLAREA_H + +#include + +class ScrollArea : public QScrollArea +{ +public: + ScrollArea(QWidget* parent = 0); + void wheelEvent(QWheelEvent *); +}; + +#endif // SCROLLAREA_H