added rudimentary shake effect
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
#include "effects/effects.h"
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QtMath>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QDebug>
|
||||
|
||||
#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;i<attr.size();i++) {
|
||||
const QXmlStreamAttribute& a = attr.at(i);
|
||||
if (a.name() == "intensity") {
|
||||
intensity_val->set_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++;
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -150,6 +150,8 @@ private slots:
|
||||
|
||||
void load_recent_project();
|
||||
|
||||
void on_actionScroll_Wheel_Zooms_triggered();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
void setup_layout();
|
||||
|
||||
@@ -139,6 +139,7 @@
|
||||
<addaction name="actionEdit_Tool_Also_Seeks"/>
|
||||
<addaction name="actionEdit_Tool_Selects_Links"/>
|
||||
<addaction name="actionSeek_to_the_End_of_Pastes"/>
|
||||
<addaction name="actionScroll_Wheel_Zooms"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionPreferences"/>
|
||||
<addaction name="separator"/>
|
||||
@@ -600,6 +601,14 @@
|
||||
<string>Clear Recent List</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionScroll_Wheel_Zooms">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Scroll Wheel Zooms</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
|
||||
@@ -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 \
|
||||
|
||||
+4
-3
@@ -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;
|
||||
|
||||
@@ -16,6 +16,8 @@ struct Clip;
|
||||
struct Media;
|
||||
struct MediaStream;
|
||||
|
||||
int lerp(int a, int b, double t);
|
||||
|
||||
struct Ghost {
|
||||
int clip;
|
||||
long in;
|
||||
|
||||
+7
-1
@@ -346,7 +346,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="timeline_area">
|
||||
<widget class="ScrollArea" name="timeline_area">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
@@ -459,6 +459,12 @@
|
||||
<header>ui/audiomonitor.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ScrollArea</class>
|
||||
<extends>QScrollArea</extends>
|
||||
<header>ui/scrollarea.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../icons/icons.qrc"/>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "scrollarea.h"
|
||||
|
||||
#include <QWheelEvent>
|
||||
#include <QDebug>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef SCROLLAREA_H
|
||||
#define SCROLLAREA_H
|
||||
|
||||
#include <QScrollArea>
|
||||
|
||||
class ScrollArea : public QScrollArea
|
||||
{
|
||||
public:
|
||||
ScrollArea(QWidget* parent = 0);
|
||||
void wheelEvent(QWheelEvent *);
|
||||
};
|
||||
|
||||
#endif // SCROLLAREA_H
|
||||
Reference in New Issue
Block a user