merged fxrestructure

This commit is contained in:
itsmattkc
2019-03-16 20:14:36 +11:00
289 changed files with 8975 additions and 6556 deletions
+11 -10
View File
@@ -1,4 +1,4 @@
/*
/*
* Olive. Olive is a free non-linear video editor for Windows, macOS, and Linux.
* Copyright (C) 2018 {{ organization }}
*
@@ -21,14 +21,15 @@
#include <QtMath>
AudioNoiseEffect::AudioNoiseEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
amount_val = add_row(tr("Amount"))->add_field(EFFECT_FIELD_DOUBLE, "amount");
amount_val->set_double_minimum_value(0);
amount_val->set_double_maximum_value(100);
amount_val->set_double_default_value(20);
mix_val = add_row(tr("Mix"))->add_field(EFFECT_FIELD_BOOL, "mix");
mix_val->set_bool_value(true);
EffectRow* amount_row = new EffectRow(this, tr("Amount"));
amount_val = new DoubleField(amount_row, "amount");
amount_val->SetMinimum(0);
amount_val->SetDefault(20);
amount_val->SetMaximum(100);
EffectRow* mix_row = new EffectRow(this, tr("Mix"));
mix_val = new BoolField(mix_row, "mix");
mix_val->SetValueAt(0, true);
}
void AudioNoiseEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int) {
@@ -40,12 +41,12 @@ void AudioNoiseEffect::process_audio(double timecode_start, double timecode_end,
qint16 right_noise_sample = this->randomNumber<qint16>();
// set noise volume
double vol = log_volume( amount_val->get_double_value(timecode, true)*0.01 );
double vol = log_volume( amount_val->GetDoubleAt(timecode)*0.01 );
left_noise_sample *= vol;
right_noise_sample *= vol;
// mix with source audio
if (mix_val->get_bool_value(timecode, true)) {
if (mix_val->GetBoolAt(timecode)) {
qint16 left_sample = static_cast<qint16> (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
qint16 right_sample = static_cast<qint16> (((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF));
left_noise_sample = mix_audio_sample(left_noise_sample, left_sample);
+6 -6
View File
@@ -21,16 +21,16 @@
#ifndef AUDIONOISEEFFECT_H
#define AUDIONOISEEFFECT_H
#include "project/effect.h"
#include "effects/effect.h"
class AudioNoiseEffect : public Effect {
Q_OBJECT
Q_OBJECT
public:
AudioNoiseEffect(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
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;
EffectField* mix_val;
DoubleField* amount_val;
BoolField* mix_val;
};
#endif // AUDIONOISEEFFECT_H
+50 -50
View File
@@ -20,78 +20,78 @@
#include "cornerpineffect.h"
#include "io/path.h"
#include "project/clip.h"
#include "debug.h"
#include "global/path.h"
#include "timeline/clip.h"
#include "global/debug.h"
CornerPinEffect::CornerPinEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
enable_coords = true;
enable_shader = true;
SetFlags(Effect::CoordsFlag | Effect::ShaderFlag);
EffectRow* top_left = add_row(tr("Top Left"));
top_left_x = top_left->add_field(EFFECT_FIELD_DOUBLE, "topleftx");
top_left_y = top_left->add_field(EFFECT_FIELD_DOUBLE, "toplefty");
EffectRow* top_left = new EffectRow(this, tr("Top Left"));
top_left_x = new DoubleField(top_left, "topleftx");
top_left_y = new DoubleField(top_left, "toplefty");
EffectRow* top_right = add_row(tr("Top Right"));
top_right_x = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprightx");
top_right_y = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprighty");
EffectRow* top_right = new EffectRow(this, tr("Top Right"));
top_right_x = new DoubleField(top_right, "toprightx");
top_right_y = new DoubleField(top_right, "toprighty");
EffectRow* bottom_left = add_row(tr("Bottom Left"));
bottom_left_x = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomleftx");
bottom_left_y = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomlefty");
EffectRow* bottom_left = new EffectRow(this, tr("Bottom Left"));
bottom_left_x = new DoubleField(bottom_left, "bottomleftx");
bottom_left_y = new DoubleField(bottom_left, "bottomlefty");
EffectRow* bottom_right = add_row(tr("Bottom Right"));
bottom_right_x = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrightx");
bottom_right_y = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrighty");
EffectRow* bottom_right = new EffectRow(this, tr("Bottom Right"));
bottom_right_x = new DoubleField(bottom_right, "bottomrightx");
bottom_right_y = new DoubleField(bottom_right, "bottomrighty");
perspective = add_row(tr("Perspective"))->add_field(EFFECT_FIELD_BOOL, "perspective");
perspective->set_bool_value(true);
EffectRow* perspective_row = new EffectRow(this, tr("Perspective"));
perspective = new BoolField(perspective_row, "perspective");
perspective->SetValueAt(0, true);
top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
top_left_gizmo->x_field1 = top_left_x;
top_left_gizmo->y_field1 = top_left_y;
top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
top_left_gizmo->x_field1 = top_left_x;
top_left_gizmo->y_field1 = top_left_y;
top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
top_right_gizmo->x_field1 = top_right_x;
top_right_gizmo->y_field1 = top_right_y;
top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
top_right_gizmo->x_field1 = top_right_x;
top_right_gizmo->y_field1 = top_right_y;
bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
bottom_left_gizmo->x_field1 = bottom_left_x;
bottom_left_gizmo->y_field1 = bottom_left_y;
bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
bottom_left_gizmo->x_field1 = bottom_left_x;
bottom_left_gizmo->y_field1 = bottom_left_y;
bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
bottom_right_gizmo->x_field1 = bottom_right_x;
bottom_right_gizmo->y_field1 = bottom_right_y;
bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
bottom_right_gizmo->x_field1 = bottom_right_x;
bottom_right_gizmo->y_field1 = bottom_right_y;
vertPath = "cornerpin.vert";
fragPath = "cornerpin.frag";
vertPath = "cornerpin.vert";
fragPath = "cornerpin.frag";
}
void CornerPinEffect::process_coords(double timecode, GLTextureCoords &coords, int) {
coords.vertexTopLeftX += top_left_x->get_double_value(timecode);
coords.vertexTopLeftY += top_left_y->get_double_value(timecode);
coords.vertexTopLeftX += top_left_x->GetDoubleAt(timecode);
coords.vertexTopLeftY += top_left_y->GetDoubleAt(timecode);
coords.vertexTopRightX += top_right_x->get_double_value(timecode);
coords.vertexTopRightY += top_right_y->get_double_value(timecode);
coords.vertexTopRightX += top_right_x->GetDoubleAt(timecode);
coords.vertexTopRightY += top_right_y->GetDoubleAt(timecode);
coords.vertexBottomLeftX += bottom_left_x->get_double_value(timecode);
coords.vertexBottomLeftY += bottom_left_y->get_double_value(timecode);
coords.vertexBottomLeftX += bottom_left_x->GetDoubleAt(timecode);
coords.vertexBottomLeftY += bottom_left_y->GetDoubleAt(timecode);
coords.vertexBottomRightX += bottom_right_x->get_double_value(timecode);
coords.vertexBottomRightY += bottom_right_y->get_double_value(timecode);
coords.vertexBottomRightX += bottom_right_x->GetDoubleAt(timecode);
coords.vertexBottomRightY += bottom_right_y->GetDoubleAt(timecode);
}
void CornerPinEffect::process_shader(double timecode, GLTextureCoords &coords, int) {
glslProgram->setUniformValue("p0", GLfloat(coords.vertexBottomLeftX), GLfloat(coords.vertexBottomLeftY));
glslProgram->setUniformValue("p1", GLfloat(coords.vertexBottomRightX), GLfloat(coords.vertexBottomRightY));
glslProgram->setUniformValue("p2", GLfloat(coords.vertexTopLeftX), GLfloat(coords.vertexTopLeftY));
glslProgram->setUniformValue("p3", GLfloat(coords.vertexTopRightX), GLfloat(coords.vertexTopRightY));
glslProgram->setUniformValue("perspective", perspective->get_bool_value(timecode));
glslProgram->setUniformValue("p0", GLfloat(coords.vertexBottomLeftX), GLfloat(coords.vertexBottomLeftY));
glslProgram->setUniformValue("p1", GLfloat(coords.vertexBottomRightX), GLfloat(coords.vertexBottomRightY));
glslProgram->setUniformValue("p2", GLfloat(coords.vertexTopLeftX), GLfloat(coords.vertexTopLeftY));
glslProgram->setUniformValue("p3", GLfloat(coords.vertexTopRightX), GLfloat(coords.vertexTopRightY));
glslProgram->setUniformValue("perspective", perspective->GetBoolAt(timecode));
}
void CornerPinEffect::gizmo_draw(double, GLTextureCoords &coords) {
top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY);
top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY);
bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY);
bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY);
top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY);
top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY);
bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY);
bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY);
}
+18 -18
View File
@@ -21,30 +21,30 @@
#ifndef CORNERPINEFFECT_H
#define CORNERPINEFFECT_H
#include "project/effect.h"
#include "effects/effect.h"
class CornerPinEffect : public Effect {
Q_OBJECT
Q_OBJECT
public:
CornerPinEffect(Clip* c, const EffectMeta* em);
void process_coords(double timecode, GLTextureCoords& coords, int data);
void process_shader(double timecode, GLTextureCoords& coords, int iterations);
void gizmo_draw(double timecode, GLTextureCoords& coords);
void process_coords(double timecode, GLTextureCoords& coords, int data);
void process_shader(double timecode, GLTextureCoords& coords, int iterations);
void gizmo_draw(double timecode, GLTextureCoords& coords);
private:
EffectField* top_left_x;
EffectField* top_left_y;
EffectField* top_right_x;
EffectField* top_right_y;
EffectField* bottom_left_x;
EffectField* bottom_left_y;
EffectField* bottom_right_x;
EffectField* bottom_right_y;
EffectField* perspective;
DoubleField* top_left_x;
DoubleField* top_left_y;
DoubleField* top_right_x;
DoubleField* top_right_y;
DoubleField* bottom_left_x;
DoubleField* bottom_left_y;
DoubleField* bottom_right_x;
DoubleField* bottom_right_y;
BoolField* perspective;
EffectGizmo* top_left_gizmo;
EffectGizmo* top_right_gizmo;
EffectGizmo* bottom_left_gizmo;
EffectGizmo* bottom_right_gizmo;
EffectGizmo* top_left_gizmo;
EffectGizmo* top_right_gizmo;
EffectGizmo* bottom_left_gizmo;
EffectGizmo* bottom_right_gizmo;
};
#endif // CORNERPINEFFECT_H
+5 -7
View File
@@ -23,14 +23,12 @@
#include <QOpenGLFunctions>
CrossDissolveTransition::CrossDissolveTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) {
enable_coords = true;
// add_row("Smooth")->add_field(EFFECT_FIELD_BOOL, "smooth");
SetFlags(Effect::CoordsFlag);
}
void CrossDissolveTransition::process_coords(double progress, GLTextureCoords& coords, int data) {
if (!(data == kTransitionClosing && secondary_clip != nullptr)) {
if (data == kTransitionClosing) progress = 1.0 - progress;
coords.opacity *= progress;
}
if (!(data == kTransitionClosing && secondary_clip != nullptr)) {
if (data == kTransitionClosing) progress = 1.0 - progress;
coords.opacity *= progress;
}
}
+1 -1
View File
@@ -21,7 +21,7 @@
#ifndef CROSSDISSOLVETRANSITION_H
#define CROSSDISSOLVETRANSITION_H
#include "project/transition.h"
#include "effects/transition.h"
class CrossDissolveTransition : public Transition {
public:
-33
View File
@@ -1,33 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "cubetransition.h"
#include "debug.h"
CubeTransition::CubeTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) {
enable_coords = true;
}
void CubeTransition::process_coords(double, GLTextureCoords& coords, int) {
coords.vertexTopLeftZ = 1;
coords.vertexBottomLeftZ = 1;
}
+1 -1
View File
@@ -21,7 +21,7 @@
#ifndef CUBETRANSITION_H
#define CUBETRANSITION_H
#include "project/transition.h"
#include "effects/transition.h"
class CubeTransition : public Transition {
public:
+2 -2
View File
@@ -21,12 +21,12 @@
#ifndef EXPONENTIALFADETRANSITION_H
#define EXPONENTIALFADETRANSITION_H
#include "project/transition.h"
#include "effects/transition.h"
class ExponentialFadeTransition : public Transition {
public:
ExponentialFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
};
#endif // LINEARFADETRANSITION_H
+14 -14
View File
@@ -24,21 +24,21 @@
#define FILL_TYPE_RIGHT 1
FillLeftRightEffect::FillLeftRightEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
EffectRow* type_row = add_row(tr("Type"));
fill_type = type_row->add_field(EFFECT_FIELD_COMBO, "type");
fill_type->add_combo_item(tr("Fill Left with Right"), FILL_TYPE_LEFT);
fill_type->add_combo_item(tr("Fill Right with Left"), FILL_TYPE_RIGHT);
EffectRow* type_row = new EffectRow(this, tr("Type"));
fill_type = new ComboField(type_row, "type");
fill_type->AddItem(tr("Fill Left with Right"), FILL_TYPE_LEFT);
fill_type->AddItem(tr("Fill Right with Left"), FILL_TYPE_RIGHT);
}
void FillLeftRightEffect::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;i<nb_bytes;i+=4) {
if (fill_type->get_combo_data(timecode_start+(interval*i)) == FILL_TYPE_LEFT) {
samples[i+1] = samples[i+3];
samples[i] = samples[i+2];
} else {
samples[i+3] = samples[i+1];
samples[i+2] = samples[i];
}
}
double interval = (timecode_end-timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=4) {
if (fill_type->GetValueAt(timecode_start+(interval*i)) == FILL_TYPE_LEFT) {
samples[i+1] = samples[i+3];
samples[i] = samples[i+2];
} else {
samples[i+3] = samples[i+1];
samples[i+2] = samples[i];
}
}
}
+5 -5
View File
@@ -21,15 +21,15 @@
#ifndef FILLLEFTRIGHTEFFECT_H
#define FILLLEFTRIGHTEFFECT_H
#include "project/effect.h"
#include "effects/effect.h"
class FillLeftRightEffect : public Effect {
Q_OBJECT
Q_OBJECT
public:
FillLeftRightEffect(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
FillLeftRightEffect(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
private:
EffectField* fill_type;
ComboField* fill_type;
};
#endif // FILLLEFTRIGHTEFFECT_H
+26 -21
View File
@@ -25,7 +25,7 @@
#include <QMessageBox>
#include <QDir>
#include "project/clip.h"
#include "timeline/clip.h"
typedef f0r_instance_t (*f0rConstructFunc)(unsigned int width, unsigned int height);
typedef int (*f0rInitFunc) ();
@@ -41,7 +41,7 @@ Frei0rEffect::Frei0rEffect(Clip* c, const EffectMeta *em) :
Effect(c, em),
open(false)
{
enable_image = true;
SetFlags(ImageFlag);
// Windows DLL loading routine
QString dll_fn = QDir(em->path).filePath(em->filename);
@@ -92,33 +92,33 @@ Frei0rEffect::Frei0rEffect(Clip* c, const EffectMeta *em) :
get_param_info(&param_info, i);
if (param_info.type >= 0 && param_info.type <= F0R_PARAM_STRING) {
EffectRow* row = add_row(param_info.name);
EffectRow* row = new EffectRow(this, param_info.name);
switch (param_info.type) {
case F0R_PARAM_BOOL:
row->add_field(EFFECT_FIELD_BOOL, QString::number(i));
new BoolField(row, QString::number(i));
break;
case F0R_PARAM_DOUBLE:
{
EffectField* f = row->add_field(EFFECT_FIELD_DOUBLE, QString::number(i));
f->set_double_minimum_value(0);
f->set_double_maximum_value(100);
DoubleField* f = new DoubleField(row, QString::number(i));
f->SetMinimum(0);
f->SetMaximum(100);
}
break;
case F0R_PARAM_COLOR:
row->add_field(EFFECT_FIELD_COLOR, QString::number(i));
new ColorField(row, QString::number(i));
break;
case F0R_PARAM_POSITION:
{
EffectField* fx = row->add_field(EFFECT_FIELD_DOUBLE, QString("%1X").arg(QString::number(i)));
fx->set_double_minimum_value(0);
fx->set_double_maximum_value(100);
EffectField* fy = row->add_field(EFFECT_FIELD_DOUBLE, QString("%1Y").arg(QString::number(i)));
fy->set_double_minimum_value(0);
fy->set_double_maximum_value(100);
DoubleField* fx = new DoubleField(row, QString("%1X").arg(QString::number(i)));
fx->SetMinimum(0);
fx->SetMaximum(100);
DoubleField* fy = new DoubleField(row, QString("%1Y").arg(QString::number(i)));
fy->SetMinimum(0);
fy->SetMaximum(100);
}
break;
case F0R_PARAM_STRING:
row->add_field(EFFECT_FIELD_STRING, QString::number(i));
new StringField(row, QString::number(i));
break;
}
}
@@ -147,19 +147,21 @@ void Frei0rEffect::process_image(double timecode, uint8_t *input, uint8_t *outpu
switch (param_info.type) {
case F0R_PARAM_BOOL:
{
double b = param_row->field(0)->get_bool_value(timecode);
double b = param_row->Field(0)->GetValueAt(timecode).toBool();
set_param(instance, &b, i);
}
break;
case F0R_PARAM_DOUBLE:
{
double d = param_row->field(0)->get_double_value(timecode)*0.01;
double d = param_row->Field(0)->GetValueAt(timecode).toDouble()*0.01;
set_param(instance, &d, i);
}
break;
case F0R_PARAM_COLOR:
{
QColor qcolor = param_row->field(0)->get_color_value(timecode);;
QColor qcolor = param_row->Field(0)->GetValueAt(timecode).value<QColor>();
f0r_param_color fcolor;
fcolor.r = float(qcolor.redF());
@@ -172,14 +174,17 @@ void Frei0rEffect::process_image(double timecode, uint8_t *input, uint8_t *outpu
case F0R_PARAM_POSITION:
{
f0r_param_position pos;
pos.x = param_row->field(0)->get_double_value(timecode);
pos.y = param_row->field(1)->get_double_value(timecode);
pos.x = param_row->Field(0)->GetValueAt(timecode).toDouble();
pos.y = param_row->Field(1)->GetValueAt(timecode).toDouble();
set_param(instance, &pos, i);
}
break;
case F0R_PARAM_STRING:
{
QByteArray bytes = param_row->field(0)->get_string_value(timecode).toUtf8();
QByteArray bytes = param_row->Field(0)->GetValueAt(timecode).toString().toUtf8();
char* byte_data = bytes.data();
set_param(instance, &byte_data, i);
}
+2 -3
View File
@@ -23,11 +23,10 @@
#ifndef NO_FREI0R
#include "project/effect.h"
#include <frei0r.h>
#include "io/crossplatformlib.h"
#include "effects/effect.h"
#include "global/crossplatformlib.h"
typedef void (*f0rGetParamInfo)(f0r_param_info_t * info,
int param_index );
+2 -2
View File
@@ -21,12 +21,12 @@
#ifndef LINEARFADETRANSITION_H
#define LINEARFADETRANSITION_H
#include "project/transition.h"
#include "effects/transition.h"
class LinearFadeTransition : public Transition {
public:
LinearFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
};
#endif // LINEARFADETRANSITION_H
+2 -2
View File
@@ -21,12 +21,12 @@
#ifndef LOGARITHMICFADETRANSITION_H
#define LOGARITHMICFADETRANSITION_H
#include "project/transition.h"
#include "effects/transition.h"
class LogarithmicFadeTransition : public Transition {
public:
LogarithmicFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
};
#endif // LOGARITHMICFADETRANSITION_H
+23 -25
View File
@@ -29,35 +29,33 @@
#include "ui/collapsiblewidget.h"
PanEffect::PanEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
EffectRow* pan_row = add_row(tr("Pan"));
pan_val = pan_row->add_field(EFFECT_FIELD_DOUBLE, "pan");
pan_val->set_double_minimum_value(-100);
pan_val->set_double_maximum_value(100);
// set defaults
pan_val->set_double_default_value(0);
EffectRow* pan_row = new EffectRow(this, tr("Pan"));
pan_val = new DoubleField(pan_row, "pan");
pan_val->SetMinimum(-100);
pan_val->SetDefault(0);
pan_val->SetMaximum(100);
}
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;i<nb_bytes;i+=4) {
double pan_field_val = pan_val->get_double_value(timecode_start+(interval*i), true);
double pval = log_volume(qAbs(pan_field_val)*0.01);
double interval = (timecode_end - timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=4) {
double pan_field_val = pan_val->GetDoubleAt(timecode_start+(interval*i));
double pval = log_volume(qAbs(pan_field_val)*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));
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));
if (pan_field_val < 0) {
// affect right channel
right_sample *= (1.0-pval);
} else {
// affect left channel
left_sample *= (1.0-pval);
}
if (pan_field_val < 0) {
// affect right channel
right_sample *= (1.0-pval);
} else {
// affect left channel
left_sample *= (1.0-pval);
}
samples[i+3] = quint8(right_sample >> 8);
samples[i+2] = quint8(right_sample);
samples[i+1] = quint8(left_sample >> 8);
samples[i] = quint8(left_sample);
}
samples[i+3] = quint8(right_sample >> 8);
samples[i+2] = quint8(right_sample);
samples[i+1] = quint8(left_sample >> 8);
samples[i] = quint8(left_sample);
}
}
+5 -5
View File
@@ -21,15 +21,15 @@
#ifndef PANEFFECT_H
#define PANEFFECT_H
#include "project/effect.h"
#include "effects/effect.h"
class PanEffect : public Effect {
Q_OBJECT
Q_OBJECT
public:
PanEffect(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
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;
DoubleField* pan_val;
};
#endif // PANEFFECT_H
+192
View File
@@ -0,0 +1,192 @@
#include "richtexteffect.h"
#include <QTextDocument>
#include <QtMath>
#include "timeline/clip.h"
#include "ui/blur.h"
enum AutoscrollDirection {
SCROLL_OFF,
SCROLL_UP,
SCROLL_DOWN,
SCROLL_LEFT,
SCROLL_RIGHT,
};
RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) :
Effect(c, em)
{
SetFlags(Effect::SuperimposeFlag);
EffectRow* text_row = new EffectRow(this, tr("Text"));
text_val = new StringField(text_row, "text");
text_val->SetColumnSpan(2);
EffectRow* padding_row = new EffectRow(this, tr("Padding"));
padding_field = new DoubleField(padding_row, "padding");
padding_field->SetColumnSpan(2);
EffectRow* position_row = new EffectRow(this, tr("Position"));
position_x = new DoubleField(position_row, "posx");
position_y = new DoubleField(position_row, "posy");
EffectRow* vertical_align_row = new EffectRow(this, tr("Vertical Align:"));
vertical_align = new ComboField(vertical_align_row, "valign");
vertical_align->AddItem(tr("Top"), Qt::AlignTop);
vertical_align->AddItem(tr("Center"), Qt::AlignCenter);
vertical_align->AddItem(tr("Bottom"), Qt::AlignBottom);
vertical_align->SetValueAt(0, Qt::AlignCenter);
vertical_align->SetColumnSpan(2);
EffectRow* autoscroll_row = new EffectRow(this, tr("Auto-Scroll"));
autoscroll = new ComboField(autoscroll_row, "autoscroll");
autoscroll->AddItem(tr("Off"), SCROLL_OFF);
autoscroll->AddItem(tr("Up"), SCROLL_UP);
autoscroll->AddItem(tr("Down"), SCROLL_DOWN);
autoscroll->AddItem(tr("Left"), SCROLL_LEFT);
autoscroll->AddItem(tr("Right"), SCROLL_RIGHT);
autoscroll->SetColumnSpan(2);
EffectRow* shadow_row = new EffectRow(this, tr("Shadow"));
shadow_bool = new BoolField(shadow_row, "shadow");
shadow_bool->SetColumnSpan(2);
EffectRow* shadow_color_row = new EffectRow(this, tr("Shadow Color"));
shadow_color = new ColorField(shadow_color_row, "shadowcolor");
shadow_color->SetColumnSpan(2);
EffectRow* shadow_angle_row = new EffectRow(this, tr("Shadow Angle"));
shadow_angle = new DoubleField(shadow_angle_row, "shadowangle");
shadow_angle->SetColumnSpan(2);
EffectRow* shadow_distance_row = new EffectRow(this, tr("Shadow Distance"));
shadow_distance = new DoubleField(shadow_distance_row, "shadowdistance");
shadow_distance->SetColumnSpan(2);
shadow_distance->SetMinimum(0);
EffectRow* shadow_softness_row = new EffectRow(this, tr("Shadow Softness"));
shadow_softness = new DoubleField(shadow_softness_row, "shadowsoftness");
shadow_softness->SetColumnSpan(2);
shadow_softness->SetMinimum(0);
EffectRow* shadow_opacity_row = new EffectRow(this, tr("Shadow Opacity"));
shadow_opacity = new DoubleField(shadow_opacity_row, "shadowopacity");
shadow_opacity->SetColumnSpan(2);
shadow_opacity->SetMinimum(0);
shadow_opacity->SetMaximum(100);
// Create default text
text_val->SetValueAt(0, "<html>"
"<body style=\"color: #ffffff; font-size: 36pt;\">"
"<center>Sample Text</center>"
"</body>"
"</html>");
}
void RichTextEffect::redraw(double timecode)
{
QPainter p(&img);
p.setRenderHint(QPainter::Antialiasing);
int width = img.width();
int height = img.height();
int padding = qRound(padding_field->GetDoubleAt(timecode));
width -= 2 * padding;
height -= 2 * padding;
QTextDocument td;
td.setHtml(text_val->GetStringAt(timecode));
td.setTextWidth(width);
int translate_x = qRound(position_x->GetDoubleAt(timecode) + padding);
int translate_y = qRound(position_y->GetDoubleAt(timecode) + padding);
int doc_height = qRound(td.size().height());
AutoscrollDirection auto_scroll_dir = static_cast<AutoscrollDirection>(autoscroll->GetValueAt(timecode).toInt());
double scroll_progress = 0;
if (auto_scroll_dir != SCROLL_OFF) {
double clip_length_secs = double(parent_clip->length()) / parent_clip->media_frame_rate();
scroll_progress = (timecode - double(parent_clip->clip_in()) / parent_clip->media_frame_rate()) / clip_length_secs;
}
if (auto_scroll_dir == SCROLL_OFF || auto_scroll_dir == SCROLL_LEFT || auto_scroll_dir == SCROLL_RIGHT) {
// If we're not auto-scrolling the vertical direction, respect the vertical alignment
if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignCenter) {
translate_y += height / 2 - doc_height / 2;
} else if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignBottom) {
translate_y += height - doc_height;
}
// Check if we are autoscrolling
if (auto_scroll_dir != SCROLL_OFF) {
if (auto_scroll_dir == SCROLL_LEFT) {
scroll_progress = 1.0 - scroll_progress;
}
int doc_width = qRound(td.size().width());
translate_x += qRound(-doc_width + (img.width() + doc_width) * scroll_progress);
}
} else if (auto_scroll_dir == SCROLL_UP || auto_scroll_dir == SCROLL_DOWN) {
// Auto-scroll bottom to top or top to bottom
if (auto_scroll_dir == SCROLL_UP) {
scroll_progress = 1.0 - scroll_progress;
}
translate_y += qRound(-doc_height + (img.height() + doc_height)*scroll_progress);
}
QRect clip_rect = img.rect();
clip_rect.translate(-translate_x, -translate_y);
p.translate(translate_x, translate_y);
img.fill(Qt::transparent);
// draw software shadow
if (shadow_bool->GetBoolAt(timecode)) {
// calculate offset using distance and angle
double angle = shadow_angle->GetDoubleAt(timecode) * M_PI / 180.0;
double distance = qFloor(shadow_distance->GetDoubleAt(timecode));
int shadow_x_offset = qRound(qCos(angle) * distance);
int shadow_y_offset = qRound(qSin(angle) * distance);
p.translate(shadow_x_offset, shadow_y_offset);
clip_rect.translate(-shadow_x_offset, -shadow_y_offset);
td.drawContents(&p, clip_rect);
int blurSoftness = qFloor(shadow_softness->GetDoubleAt(timecode));
if (blurSoftness > 0) {
olive::ui::blur(img, img.rect(), blurSoftness, true);
}
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
p.fillRect(img.rect(), shadow_color->GetColorAt(timecode));
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
p.translate(-shadow_x_offset, -shadow_y_offset);
clip_rect.translate(shadow_x_offset, shadow_y_offset);
}
td.drawContents(&p, clip_rect);
p.end();
}
bool RichTextEffect::AlwaysUpdate()
{
return autoscroll->GetValueAt(autoscroll->Now()).toInt() != SCROLL_OFF;
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef RICHTEXTEFFECT_H
#define RICHTEXTEFFECT_H
#include "effects/effect.h"
class RichTextEffect : public Effect {
Q_OBJECT
public:
RichTextEffect(Clip* c, const EffectMeta *em);
void redraw(double timecode);
protected:
virtual bool AlwaysUpdate() override;
private:
StringField* text_val;
DoubleField* padding_field;
DoubleField* position_x;
DoubleField* position_y;
ComboField* vertical_align;
ComboField* autoscroll;
BoolField* shadow_bool;
DoubleField* shadow_angle;
DoubleField* shadow_distance;
ColorField* shadow_color;
DoubleField* shadow_softness;
DoubleField* shadow_opacity;
};
#endif // RICHTEXTEFFECT_H
+45 -48
View File
@@ -27,69 +27,66 @@
#include "ui/labelslider.h"
#include "ui/collapsiblewidget.h"
#include "project/clip.h"
#include "project/sequence.h"
#include "timeline/clip.h"
#include "timeline/sequence.h"
#include "panels/timeline.h"
#include "debug.h"
#include "global/debug.h"
ShakeEffect::ShakeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
enable_coords = true;
SetFlags(Effect::CoordsFlag);
EffectRow* intensity_row = add_row(tr("Intensity"));
intensity_val = intensity_row->add_field(EFFECT_FIELD_DOUBLE, "intensity");
intensity_val->set_double_minimum_value(0);
EffectRow* intensity_row = new EffectRow(this, tr("Intensity"));
intensity_val = new DoubleField(intensity_row, "intensity");
intensity_val->SetMinimum(0);
intensity_val->SetDefault(25);
EffectRow* rotation_row = add_row(tr("Rotation"));
rotation_val = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation");
rotation_val->set_double_minimum_value(0);
EffectRow* rotation_row = new EffectRow(this, tr("Rotation"));
rotation_val = new DoubleField(rotation_row, "rotation");
rotation_val->SetMinimum(0);
rotation_val->SetDefault(10);
EffectRow* frequency_row = add_row(tr("Frequency"));
frequency_val = frequency_row->add_field(EFFECT_FIELD_DOUBLE, "frequency");
frequency_val->set_double_minimum_value(0);
EffectRow* frequency_row = new EffectRow(this, tr("Frequency"));
frequency_val = new DoubleField(frequency_row, "frequency");
frequency_val->SetMinimum(0);
frequency_val->SetDefault(5);
// set defaults
intensity_val->set_double_default_value(25);
rotation_val->set_double_default_value(10);
frequency_val->set_double_default_value(5);
const auto limit = std::numeric_limits<int32_t>::max();
for (int i=0;i<RANDOM_VAL_SIZE;i++) {
random_vals[i] = static_cast<double>(this->randomNumber<int32_t>()) / limit;
}
const auto limit = std::numeric_limits<int32_t>::max();
for (int i=0;i<RANDOM_VAL_SIZE;i++) {
random_vals[i] = static_cast<double>(this->randomNumber<int32_t>()) / limit;
}
}
void ShakeEffect::process_coords(double timecode, GLTextureCoords& coords, int) {
int lim = RANDOM_VAL_SIZE/6;
int lim = RANDOM_VAL_SIZE/6;
double multiplier = intensity_val->get_double_value(timecode)/lim;
double rotmult = rotation_val->get_double_value(timecode)/lim/10;
double x = timecode * frequency_val->get_double_value(timecode);
double multiplier = intensity_val->GetDoubleAt(timecode)/lim;
double rotmult = rotation_val->GetDoubleAt(timecode)/lim/10;
double x = timecode * frequency_val->GetDoubleAt(timecode);
double xoff = 0;
double yoff = 0;
double rotoff = 0;
double xoff = 0;
double yoff = 0;
double rotoff = 0;
for (int i=0;i<lim;i++) {
int offset = 6*i;
xoff += qSin((x+random_vals[offset])*random_vals[offset+1]);
yoff += qSin((x+random_vals[offset+2])*random_vals[offset+3]);
rotoff += qSin((x+random_vals[offset+4])*random_vals[offset+5]);
}
for (int i=0;i<lim;i++) {
int offset = 6*i;
xoff += qSin((x+random_vals[offset])*random_vals[offset+1]);
yoff += qSin((x+random_vals[offset+2])*random_vals[offset+3]);
rotoff += qSin((x+random_vals[offset+4])*random_vals[offset+5]);
}
xoff *= multiplier;
yoff *= multiplier;
rotoff *= rotmult;
xoff *= multiplier;
yoff *= multiplier;
rotoff *= rotmult;
coords.vertexTopLeftX += xoff;
coords.vertexTopRightX += xoff;
coords.vertexBottomLeftX += xoff;
coords.vertexBottomRightX += xoff;
coords.vertexTopLeftX += xoff;
coords.vertexTopRightX += xoff;
coords.vertexBottomLeftX += xoff;
coords.vertexBottomRightX += xoff;
coords.vertexTopLeftY += yoff;
coords.vertexTopRightY += yoff;
coords.vertexBottomLeftY += yoff;
coords.vertexBottomRightY += yoff;
coords.vertexTopLeftY += yoff;
coords.vertexTopRightY += yoff;
coords.vertexBottomLeftY += yoff;
coords.vertexBottomRightY += yoff;
glRotatef(rotoff, 0, 0, 1);
glRotatef(rotoff, 0, 0, 1);
}
+6 -6
View File
@@ -21,21 +21,21 @@
#ifndef SHAKEEFFECT_H
#define SHAKEEFFECT_H
#include "project/effect.h"
#include "effects/effect.h"
#define RANDOM_VAL_SIZE 30
class ShakeEffect : public Effect {
Q_OBJECT
Q_OBJECT
public:
ShakeEffect(Clip* c, const EffectMeta* em);
void process_coords(double timecode, GLTextureCoords& coords, int data);
EffectField* intensity_val;
EffectField* rotation_val;
EffectField* frequency_val;
DoubleField* intensity_val;
DoubleField* rotation_val;
DoubleField* frequency_val;
private:
double random_vals[RANDOM_VAL_SIZE];
double random_vals[RANDOM_VAL_SIZE];
};
#endif // SHAKEEFFECT_H
+161 -148
View File
@@ -27,171 +27,184 @@
#include <QImage>
#include <QComboBox>
#include "project/clip.h"
#include "project/sequence.h"
#include "timeline/clip.h"
#include "timeline/sequence.h"
#define SOLID_TYPE_COLOR 0
#define SOLID_TYPE_BARS 1
#define SOLID_TYPE_CHECKERBOARD 2
const int SMPTE_BARS = 7;
const int SMPTE_STRIP_COUNT = 3;
const int SMPTE_LOWER_BARS = 4;
#define SMPTE_BARS 7
#define SMPTE_STRIP_COUNT 3
#define SMPTE_LOWER_BARS 4
SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) :
Effect(c, em)
{
SetFlags(Effect::SuperimposeFlag);
SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) : Effect(c, em) {
enable_superimpose = true;
// Field for solid type
EffectRow* type_row = new EffectRow(this, tr("Type"));
solid_type = new ComboField(type_row, "type");
solid_type->AddItem(tr("Solid Color"), SOLID_TYPE_COLOR);
solid_type->AddItem(tr("SMPTE Bars"), SOLID_TYPE_BARS);
solid_type->AddItem(tr("Checkerboard"), SOLID_TYPE_CHECKERBOARD);
solid_type = add_row(tr("Type"))->add_field(EFFECT_FIELD_COMBO, "type");
solid_type->add_combo_item(tr("Solid Color"), SOLID_TYPE_COLOR);
solid_type->add_combo_item(tr("SMPTE Bars"), SOLID_TYPE_BARS);
solid_type->add_combo_item(tr("Checkerboard"), SOLID_TYPE_CHECKERBOARD);
EffectRow* opacity_row = new EffectRow(this, tr("Opacity"));
opacity_field = new DoubleField(opacity_row, "opacity");
opacity_field->SetMinimum(0);
opacity_field->SetDefault(100);
opacity_field->SetMaximum(100);
opacity_field = add_row(tr("Opacity"))->add_field(EFFECT_FIELD_DOUBLE, "opacity");
opacity_field->set_double_minimum_value(0);
opacity_field->set_double_maximum_value(100);
opacity_field->set_double_default_value(100);
EffectRow* solid_color_row = new EffectRow(this, tr("Color"));
solid_color_field = new ColorField(solid_color_row, "color");
solid_color_field->SetValueAt(0, QColor(Qt::red));
solid_color_field = add_row(tr("Color"))->add_field(EFFECT_FIELD_COLOR, "color");
solid_color_field->set_color_value(Qt::red);
EffectRow* checkerboard_size = new EffectRow(this, tr("Checkerboard Size"));
checkerboard_size_field = new DoubleField(checkerboard_size, "checker_size");
checkerboard_size_field->SetMinimum(1);
checkerboard_size_field->SetDefault(10);
checkerboard_size_field = add_row(tr("Checkerboard Size"))->add_field(EFFECT_FIELD_DOUBLE, "checker_size");
checkerboard_size_field->set_double_minimum_value(1);
checkerboard_size_field->set_double_default_value(10);
connect(solid_type, SIGNAL(DataChanged(const QVariant&)), this, SLOT(ui_update(const QVariant&)));
// hacky but eh
QComboBox* solid_type_combo = static_cast<QComboBox*>(solid_type->get_ui_element());
connect(solid_type_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(ui_update(int)));
ui_update(solid_type_combo->currentIndex());
// Set default UI
solid_type->SetValueAt(0, SOLID_TYPE_COLOR);
/*vertPath = ":/shaders/common.vert";
fragPath = ":/shaders/solideffect.frag";*/
// TODO necessary? Isn't this called from the connect() above?
ui_update(SOLID_TYPE_COLOR);
/*vertPath = ":/shaders/common.vert";
fragPath = ":/shaders/solideffect.frag";*/
}
void SolidEffect::redraw(double timecode) {
int w = img.width();
int h = img.height();
int alpha = qRound(opacity_field->get_double_value(timecode)*2.55);
switch (solid_type->get_combo_data(timecode).toInt()) {
case SOLID_TYPE_COLOR:
{
QColor solidColor = solid_color_field->get_color_value(timecode);
solidColor.setAlpha(alpha);
img.fill(solidColor);
}
break;
case SOLID_TYPE_BARS:
{
// draw smpte bars
QPainter p(&img);
img.fill(Qt::transparent);
int bar_width = qCeil((double) w / 7.0);
int first_bar_height = qCeil((double) h / 3.0 * 2.0);
int second_bar_height = qCeil((double) h / 12.5);
int third_bar_y = first_bar_height + second_bar_height;
int third_bar_height = h - third_bar_y;
int third_bar_width = 0;
int bar_x, strip_width;
QColor first_color, second_color, third_color;
for (int i=0;i<SMPTE_BARS;i++) {
bar_x = bar_width*i;
switch (i) {
case 0:
first_color = QColor(192, 192, 192);
second_color = QColor(0, 0, 192);
break;
case 1:
first_color = QColor(192, 192, 0);
second_color = QColor(19, 19, 19);
break;
case 2:
first_color = QColor(0, 192, 192);
second_color = QColor(192, 0, 192);
break;
case 3:
first_color = QColor(0, 192, 0);
second_color = QColor(19, 19, 19);
break;
case 4:
first_color = QColor(192, 0, 192);
second_color = QColor(0, 192, 192);
break;
case 5:
third_bar_width = qRound((double) bar_x / (double) SMPTE_LOWER_BARS);
int w = img.width();
int h = img.height();
int alpha = qRound(opacity_field->GetDoubleAt(timecode)*2.55);
switch (solid_type->GetValueAt(timecode).toInt()) {
case SOLID_TYPE_COLOR:
{
QColor solidColor = solid_color_field->GetColorAt(timecode);
solidColor.setAlpha(alpha);
img.fill(solidColor);
}
break;
case SOLID_TYPE_BARS:
{
// draw smpte bars
QPainter p(&img);
img.fill(Qt::transparent);
int bar_width = qCeil(double(w) / 7.0);
int first_bar_height = qCeil(double(h) / 3.0 * 2.0);
int second_bar_height = qCeil(double(h) / 12.5);
int third_bar_y = first_bar_height + second_bar_height;
int third_bar_height = h - third_bar_y;
int third_bar_width = 0;
int bar_x, strip_width;
QColor first_color, second_color, third_color;
for (int i=0;i<SMPTE_BARS;i++) {
bar_x = bar_width*i;
switch (i) {
case 0:
first_color = QColor(192, 192, 192);
second_color = QColor(0, 0, 192);
break;
case 1:
first_color = QColor(192, 192, 0);
second_color = QColor(19, 19, 19);
break;
case 2:
first_color = QColor(0, 192, 192);
second_color = QColor(192, 0, 192);
break;
case 3:
first_color = QColor(0, 192, 0);
second_color = QColor(19, 19, 19);
break;
case 4:
first_color = QColor(192, 0, 192);
second_color = QColor(0, 192, 192);
break;
case 5:
third_bar_width = qRound(double(bar_x) / double(SMPTE_LOWER_BARS));
first_color = QColor(192, 0, 0);
second_color = QColor(19, 19, 19);
first_color = QColor(192, 0, 0);
second_color = QColor(19, 19, 19);
strip_width = qCeil(bar_width/SMPTE_STRIP_COUNT);
for (int j=0;j<SMPTE_STRIP_COUNT;j++) {
switch (j) {
case 0:
third_color = QColor(29, 29, 29, alpha);
p.fillRect(QRect(bar_x, third_bar_y, bar_width, third_bar_height), third_color);
break;
case 1:
third_color = QColor(19, 19, 19, alpha);
p.fillRect(QRect(bar_x + strip_width, third_bar_y, strip_width, third_bar_height), third_color);
break;
case 2:
third_color = QColor(9, 9, 9, alpha);
p.fillRect(QRect(bar_x, third_bar_y, strip_width, third_bar_height), third_color);
break;
}
}
break;
case 6:
first_color = QColor(0, 0, 192);
second_color = QColor(192, 192, 192);
p.fillRect(QRect(bar_x, third_bar_y, bar_width, third_bar_height), QColor(19, 19, 19, alpha));
break;
}
first_color.setAlpha(alpha);
second_color.setAlpha(alpha);
p.fillRect(QRect(bar_x, 0, bar_width, first_bar_height), first_color);
p.fillRect(QRect(bar_x, first_bar_height, bar_width, second_bar_height), second_color);
}
for (int i=0;i<SMPTE_LOWER_BARS;i++) {
bar_x = third_bar_width*i;
switch (i) {
case 0: third_color = QColor(0, 33, 76); break;
case 1: third_color = QColor(255, 255, 255); break;
case 2: third_color = QColor(50, 0, 106); break;
case 3: third_color = QColor(19, 19, 19); break;
}
third_color.setAlpha(alpha);
p.fillRect(QRect(bar_x, third_bar_y, third_bar_width, third_bar_height), third_color);
}
}
break;
case SOLID_TYPE_CHECKERBOARD:
{
// draw checkboard
QPainter p(&img);
img.fill(Qt::transparent);
strip_width = qCeil(bar_width/SMPTE_STRIP_COUNT);
for (int j=0;j<SMPTE_STRIP_COUNT;j++) {
switch (j) {
case 0:
third_color = QColor(29, 29, 29, alpha);
p.fillRect(QRect(bar_x, third_bar_y, bar_width, third_bar_height), third_color);
break;
case 1:
third_color = QColor(19, 19, 19, alpha);
p.fillRect(QRect(bar_x + strip_width, third_bar_y, strip_width, third_bar_height), third_color);
break;
case 2:
third_color = QColor(9, 9, 9, alpha);
p.fillRect(QRect(bar_x, third_bar_y, strip_width, third_bar_height), third_color);
break;
}
}
break;
case 6:
first_color = QColor(0, 0, 192);
second_color = QColor(192, 192, 192);
p.fillRect(QRect(bar_x, third_bar_y, bar_width, third_bar_height), QColor(19, 19, 19, alpha));
break;
}
first_color.setAlpha(alpha);
second_color.setAlpha(alpha);
p.fillRect(QRect(bar_x, 0, bar_width, first_bar_height), first_color);
p.fillRect(QRect(bar_x, first_bar_height, bar_width, second_bar_height), second_color);
}
for (int i=0;i<SMPTE_LOWER_BARS;i++) {
bar_x = third_bar_width*i;
switch (i) {
case 0: third_color = QColor(0, 33, 76); break;
case 1: third_color = QColor(255, 255, 255); break;
case 2: third_color = QColor(50, 0, 106); break;
case 3: third_color = QColor(19, 19, 19); break;
}
third_color.setAlpha(alpha);
p.fillRect(QRect(bar_x, third_bar_y, third_bar_width, third_bar_height), third_color);
}
}
break;
case SOLID_TYPE_CHECKERBOARD:
{
// draw checkboard
QPainter p(&img);
img.fill(Qt::transparent);
int checker_width = qCeil(checkerboard_size_field->get_double_value(timecode));
int checker_x, checker_y;
int checkerboard_size_w = qCeil(double(w)/checker_width);
int checkerboard_size_h = qCeil(double(h)/checker_width);
int checker_width = qCeil(checkerboard_size_field->GetDoubleAt(timecode));
int checker_x, checker_y;
int checkerboard_size_w = qCeil(double(w)/checker_width);
int checkerboard_size_h = qCeil(double(h)/checker_width);
QColor checker_odd(QColor(0, 0, 0, alpha));
QColor checker_even(solid_color_field->get_color_value(timecode));
checker_even.setAlpha(alpha);
QVector<QColor> checker_color{checker_odd, checker_even};
QColor checker_odd(QColor(0, 0, 0, alpha));
QColor checker_even(solid_color_field->GetColorAt(timecode));
checker_even.setAlpha(alpha);
QVector<QColor> checker_color{checker_odd, checker_even};
for(int i = 0; i < checkerboard_size_w; i++){
checker_x = checker_width*i;
for(int j = 0; j < checkerboard_size_h; j++){
checker_y = checker_width*j;
p.fillRect(QRect(checker_x, checker_y, checker_width, checker_width), checker_color[(i + j)%2]);
}
}
}
break;
}
for(int i = 0; i < checkerboard_size_w; i++){
checker_x = checker_width*i;
for(int j = 0; j < checkerboard_size_h; j++){
checker_y = checker_width*j;
p.fillRect(QRect(checker_x, checker_y, checker_width, checker_width), checker_color[(i + j)%2]);
}
}
}
break;
}
}
void SolidEffect::ui_update(int i) {
solid_color_field->set_enabled(i == SOLID_TYPE_COLOR || i == SOLID_TYPE_CHECKERBOARD);
checkerboard_size_field->set_enabled(i == SOLID_TYPE_CHECKERBOARD);
void SolidEffect::SetType(SolidEffect::SolidType type)
{
solid_type->SetValueAt(0, type);
}
void SolidEffect::ui_update(const QVariant& d) {
int i = d.toInt();
solid_color_field->SetEnabled(i == SOLID_TYPE_COLOR || i == SOLID_TYPE_CHECKERBOARD);
checkerboard_size_field->SetEnabled(i == SOLID_TYPE_CHECKERBOARD);
}
+17 -9
View File
@@ -21,22 +21,30 @@
#ifndef SOLIDEFFECT_H
#define SOLIDEFFECT_H
#include "project/effect.h"
#include "effects/effect.h"
#include <QImage>
class SolidEffect : public Effect {
Q_OBJECT
Q_OBJECT
public:
SolidEffect(Clip* c, const EffectMeta *em);
void redraw(double timecode);
enum SolidType {
SOLID_TYPE_COLOR,
SOLID_TYPE_BARS,
SOLID_TYPE_CHECKERBOARD
};
SolidEffect(Clip* c, const EffectMeta *em);
virtual void redraw(double timecode);
void SetType(SolidType type);
private slots:
void ui_update(int);
void ui_update(const QVariant &d);
private:
EffectField* solid_type;
EffectField* solid_color_field;
EffectField* opacity_field;
EffectField* checkerboard_size_field;
ComboField* solid_type;
ColorField* solid_color_field;
DoubleField* opacity_field;
DoubleField* checkerboard_size_field;
};
#endif // SOLIDEFFECT_H
+214 -253
View File
@@ -35,319 +35,280 @@
#include "ui/labelslider.h"
#include "ui/collapsiblewidget.h"
#include "project/clip.h"
#include "project/sequence.h"
#include "timeline/clip.h"
#include "timeline/sequence.h"
#include "ui/comboboxex.h"
#include "ui/colorbutton.h"
#include "ui/fontcombobox.h"
#include "dialogs/texteditdialog.h"
#include "io/config.h"
#include "mainwindow.h"
#include "ui/blur.h"
#include "global/config.h"
TextEffect::TextEffect(Clip* c, const EffectMeta* em) :
Effect(c, em)
Effect(c, em)
{
enable_superimpose = true;
SetFlags(Effect::SuperimposeFlag);
text_val = add_row(tr("Text"))->add_field(EFFECT_FIELD_STRING, "text", 2);
QTextEdit* text_widget = static_cast<QTextEdit*>(text_val->ui_element);
text_widget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(text_widget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(text_edit_menu()));
EffectRow* text_field = new EffectRow(this, tr("Text"));
text_val = new StringField(text_field, "text", false);
text_val->SetColumnSpan(2);
set_font_combobox = add_row(tr("Font"))->add_field(EFFECT_FIELD_FONT, "font", 2);
EffectRow* font_row = new EffectRow(this, tr("Font"));
set_font_combobox = new FontField(font_row, "font");
set_font_combobox->SetColumnSpan(2);
size_val = add_row(tr("Size"))->add_field(EFFECT_FIELD_DOUBLE, "size", 2);
size_val->set_double_minimum_value(0);
EffectRow* size_row = new EffectRow(this, tr("Size"));
size_val = new DoubleField(size_row, "size");
size_val->SetMinimum(0);
size_val->SetColumnSpan(2);
set_color_button = add_row(tr("Color"))->add_field(EFFECT_FIELD_COLOR, "color", 2);
EffectRow* color_row = new EffectRow(this, tr("Color"));
set_color_button = new ColorField(color_row, "color");
set_color_button->SetColumnSpan(2);
EffectRow* alignment_row = add_row(tr("Alignment"));
halign_field = alignment_row->add_field(EFFECT_FIELD_COMBO, "halign");
halign_field->add_combo_item(tr("Left"), Qt::AlignLeft);
halign_field->add_combo_item(tr("Center"), Qt::AlignHCenter);
halign_field->add_combo_item(tr("Right"), Qt::AlignRight);
halign_field->add_combo_item(tr("Justify"), Qt::AlignJustify);
EffectRow* alignment_row = new EffectRow(this, tr("Alignment"));
halign_field = new ComboField(alignment_row, "halign");
halign_field->AddItem(tr("Left"), Qt::AlignLeft);
halign_field->AddItem(tr("Center"), Qt::AlignHCenter);
halign_field->AddItem(tr("Right"), Qt::AlignRight);
halign_field->AddItem(tr("Justify"), Qt::AlignJustify);
valign_field = alignment_row->add_field(EFFECT_FIELD_COMBO, "valign");
valign_field->add_combo_item(tr("Top"), Qt::AlignTop);
valign_field->add_combo_item(tr("Center"), Qt::AlignVCenter);
valign_field->add_combo_item(tr("Bottom"), Qt::AlignBottom);
valign_field = new ComboField(alignment_row, "valign");
valign_field->AddItem(tr("Top"), Qt::AlignTop);
valign_field->AddItem(tr("Center"), Qt::AlignVCenter);
valign_field->AddItem(tr("Bottom"), Qt::AlignBottom);
word_wrap_field = add_row(tr("Word Wrap"))->add_field(EFFECT_FIELD_BOOL, "wordwrap", 2);
EffectRow* word_wrap_row = new EffectRow(this, tr("Word Wrap"));
word_wrap_field = new BoolField(word_wrap_row, "wordwrap");
word_wrap_field->SetColumnSpan(2);
outline_bool = add_row(tr("Outline"))->add_field(EFFECT_FIELD_BOOL, "outline", 2);
outline_color = add_row(tr("Outline Color"))->add_field(EFFECT_FIELD_COLOR, "outlinecolor", 2);
outline_width = add_row(tr("Outline Width"))->add_field(EFFECT_FIELD_DOUBLE, "outlinewidth", 2);
outline_width->set_double_minimum_value(0);
EffectRow* padding_row = new EffectRow(this, tr("Padding"));
padding_field = new DoubleField(padding_row, "padding");
padding_field->SetColumnSpan(2);
shadow_bool = add_row(tr("Shadow"))->add_field(EFFECT_FIELD_BOOL, "shadow", 2);
shadow_color = add_row(tr("Shadow Color"))->add_field(EFFECT_FIELD_COLOR, "shadowcolor", 2);
shadow_angle = add_row(tr("Shadow Angle"))->add_field(EFFECT_FIELD_DOUBLE, "shadowangle", 2);
shadow_distance = add_row(tr("Shadow Distance"))->add_field(EFFECT_FIELD_DOUBLE, "shadowdistance", 2);
shadow_distance->set_double_minimum_value(0);
shadow_softness = add_row(tr("Shadow Softness"))->add_field(EFFECT_FIELD_DOUBLE, "shadowsoftness", 2);
shadow_softness->set_double_minimum_value(0);
shadow_opacity = add_row(tr("Shadow Opacity"))->add_field(EFFECT_FIELD_DOUBLE, "shadowopacity", 2);
shadow_opacity->set_double_minimum_value(0);
shadow_opacity->set_double_maximum_value(100);
EffectRow* position_row = new EffectRow(this, tr("Position"));
position_x = new DoubleField(position_row, "posx");
position_y = new DoubleField(position_row, "posy");
size_val->set_double_default_value(48);
text_val->set_string_value(tr("Sample Text"));
halign_field->set_combo_index(1);
valign_field->set_combo_index(1);
word_wrap_field->set_bool_value(true);
outline_color->set_color_value(Qt::black);
shadow_color->set_color_value(Qt::black);
shadow_angle->set_double_default_value(45);
shadow_opacity->set_double_default_value(100);
shadow_softness->set_double_default_value(5);
shadow_distance->set_double_default_value(5);
shadow_opacity->set_double_default_value(80);
outline_width->set_double_default_value(20);
EffectRow* outline_row = new EffectRow(this, tr("Outline"));
outline_bool = new BoolField(outline_row, "outline");
outline_bool->SetColumnSpan(2);
outline_enable(false);
shadow_enable(false);
EffectRow* outline_color_row = new EffectRow(this, tr("Outline Color"));
outline_color = new ColorField(outline_color_row, "outlinecolor");
outline_color->SetColumnSpan(2);
connect(shadow_bool, SIGNAL(toggled(bool)), this, SLOT(shadow_enable(bool)));
connect(outline_bool, SIGNAL(toggled(bool)), this, SLOT(outline_enable(bool)));
EffectRow* outline_width_row = new EffectRow(this, tr("Outline Width"));
outline_width = new DoubleField(outline_width_row, "outlinewidth");
outline_width->SetColumnSpan(2);
outline_width->SetMinimum(0);
vertPath = "common.vert";
fragPath = "dropshadow.frag";
}
EffectRow* shadow_row = new EffectRow(this, tr("Shadow"));
shadow_bool = new BoolField(shadow_row, "shadow");
shadow_bool->SetColumnSpan(2);
void blurred2(QImage& result, const QRect& rect, int radius, bool alphaOnly = false) {
int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1];
EffectRow* shadow_color_row = new EffectRow(this, tr("Shadow Color"));
shadow_color = new ColorField(shadow_color_row, "shadowcolor");
shadow_color->SetColumnSpan(2);
int r1 = rect.top();
int r2 = rect.bottom();
int c1 = rect.left();
int c2 = rect.right();
EffectRow* shadow_angle_row = new EffectRow(this, tr("Shadow Angle"));
shadow_angle = new DoubleField(shadow_angle_row, "shadowangle");
shadow_angle->SetColumnSpan(2);
int bpl = result.bytesPerLine();
int rgba[4];
unsigned char* p;
EffectRow* shadow_distance_row = new EffectRow(this, tr("Shadow Distance"));
shadow_distance = new DoubleField(shadow_distance_row, "shadowdistance");
shadow_distance->SetColumnSpan(2);
shadow_distance->SetMinimum(0);
int i1 = 0;
int i2 = 3;
EffectRow* shadow_softness_row = new EffectRow(this, tr("Shadow Softness"));
shadow_softness = new DoubleField(shadow_softness_row, "shadowsoftness");
shadow_softness->SetColumnSpan(2);
shadow_softness->SetMinimum(0);
if (alphaOnly)
i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
EffectRow* shadow_opacity_row = new EffectRow(this, tr("Shadow Opacity"));
shadow_opacity = new DoubleField(shadow_opacity_row, "shadowopacity");
shadow_opacity->SetColumnSpan(2);
shadow_opacity->SetMinimum(0);
shadow_opacity->SetMaximum(100);
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r1) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
size_val->SetDefault(48);
text_val->SetValueAt(0, tr("Sample Text"));
set_color_button->SetValueAt(0, QColor(Qt::white));
halign_field->SetValueAt(0, Qt::AlignHCenter);
valign_field->SetValueAt(0, Qt::AlignVCenter);
word_wrap_field->SetValueAt(0, true);
outline_color->SetValueAt(0, QColor(Qt::black));
shadow_color->SetValueAt(0, QColor(Qt::black));
shadow_angle->SetDefault(45);
shadow_opacity->SetDefault(100);
shadow_softness->SetDefault(5);
shadow_distance->SetDefault(5);
shadow_opacity->SetDefault(80);
outline_width->SetDefault(20);
p += bpl;
for (int j = r1; j < r2; j++, p += bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
outline_enable(false);
shadow_enable(false);
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c1 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
connect(shadow_bool, SIGNAL(Toggled(bool)), this, SLOT(shadow_enable(bool)));
connect(outline_bool, SIGNAL(Toggled(bool)), this, SLOT(outline_enable(bool)));
p += 4;
for (int j = c1; j < c2; j++, p += 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r2) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= bpl;
for (int j = r1; j < r2; j++, p -= bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c2 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= 4;
for (int j = c1; j < c2; j++, p -= 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
vertPath = "common.vert";
fragPath = "dropshadow.frag";
}
void TextEffect::redraw(double timecode) {
QColor bkg = set_color_button->get_color_value(timecode);
bkg.setAlpha(0);
img.fill(bkg);
QColor bkg = set_color_button->GetColorAt(timecode);
bkg.setAlpha(0);
img.fill(bkg);
QPainter p(&img);
p.setRenderHint(QPainter::Antialiasing);
int width = img.width();
int height = img.height();
QPainter p(&img);
p.setRenderHint(QPainter::Antialiasing);
int padding = qRound(padding_field->GetDoubleAt(timecode));
int width = img.width() - padding * 2;
int height = img.height() - padding * 2;
// set font
font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
font.setFamily(set_font_combobox->get_font_name(timecode));
font.setPointSize(size_val->get_double_value(timecode));
p.setFont(font);
QFontMetrics fm(font);
// set font
font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
font.setFamily(set_font_combobox->GetFontAt(timecode));
font.setPointSize(qRound(size_val->GetDoubleAt(timecode)));
p.setFont(font);
QFontMetrics fm(font);
QStringList lines = text_val->get_string_value(timecode).split('\n');
QStringList lines = text_val->GetStringAt(timecode).split('\n');
// word wrap function
if (word_wrap_field->get_bool_value(timecode)) {
for (int i=0;i<lines.size();i++) {
QString s(lines.at(i));
if (fm.width(s) > width) {
int last_space_index = 0;
for (int j=0;j<s.length();j++) {
if (s.at(j) == ' ') {
if (fm.width(s.left(j)) > width) {
break;
} else {
last_space_index = j;
}
}
}
if (last_space_index > 0) {
lines.insert(i+1, s.mid(last_space_index + 1));
lines[i] = s.left(last_space_index);
}
}
}
}
// word wrap function
if (word_wrap_field->GetBoolAt(timecode)) {
for (int i=0;i<lines.size();i++) {
QString s(lines.at(i));
if (fm.width(s) > width) {
int last_space_index = 0;
for (int j=0;j<s.length();j++) {
if (s.at(j) == ' ') {
if (fm.width(s.left(j)) > width) {
break;
} else {
last_space_index = j;
}
}
}
if (last_space_index > 0) {
lines.insert(i+1, s.mid(last_space_index + 1));
lines[i] = s.left(last_space_index);
}
}
}
}
QPainterPath path;
QPainterPath path;
int text_height = fm.height()*lines.size();
int text_height = fm.height()*lines.size();
for (int i=0;i<lines.size();i++) {
int text_x, text_y;
for (int i=0;i<lines.size();i++) {
int text_x, text_y;
switch (halign_field->get_combo_data(timecode).toInt()) {
case Qt::AlignLeft: text_x = 0; break;
case Qt::AlignRight: text_x = width - fm.width(lines.at(i)); break;
case Qt::AlignJustify:
// add spaces until the string is too big
text_x = 0;
while (fm.width(lines.at(i)) < width) {
bool space = false;
QString spaced(lines.at(i));
for (int i=0;i<spaced.length();i++) {
if (spaced.at(i) == ' ') {
// insert a space
spaced.insert(i, ' ');
space = true;
switch (halign_field->GetValueAt(timecode).toInt()) {
case Qt::AlignLeft: text_x = 0; break;
case Qt::AlignRight: text_x = width - fm.width(lines.at(i)); break;
case Qt::AlignJustify:
// add spaces until the string is too big
text_x = 0;
while (fm.width(lines.at(i)) < width) {
bool space = false;
QString spaced(lines.at(i));
for (int i=0;i<spaced.length();i++) {
if (spaced.at(i) == ' ') {
// insert a space
spaced.insert(i, ' ');
space = true;
// scan to next non-space
while (i < spaced.length() && spaced.at(i) == ' ') i++;
}
}
if (fm.width(spaced) > width || !space) {
break;
} else {
lines[i] = spaced;
}
}
break;
case Qt::AlignHCenter:
default:
text_x = (width/2) - (fm.width(lines.at(i))/2);
break;
}
// scan to next non-space
while (i < spaced.length() && spaced.at(i) == ' ') i++;
}
}
if (fm.width(spaced) > width || !space) {
break;
} else {
lines[i] = spaced;
}
}
break;
case Qt::AlignHCenter:
default:
text_x = (width/2) - (fm.width(lines.at(i))/2);
break;
}
switch (valign_field->get_combo_data(timecode).toInt()) {
case Qt::AlignTop:
text_y = (fm.height()*i)+fm.ascent();
break;
case Qt::AlignBottom:
text_y = (height - text_height - fm.descent()) + (fm.height()*(i+1));
break;
case Qt::AlignVCenter:
default:
text_y = ((height/2) - (text_height/2) - fm.descent()) + (fm.height()*(i+1));
break;
}
switch (valign_field->GetValueAt(timecode).toInt()) {
case Qt::AlignTop:
text_y = (fm.height()*i)+fm.ascent();
break;
case Qt::AlignBottom:
text_y = (height - text_height - fm.descent()) + (fm.height()*(i+1));
break;
case Qt::AlignVCenter:
default:
text_y = ((height/2) - (text_height/2) - fm.descent()) + (fm.height()*(i+1));
break;
}
path.addText(text_x, text_y, font, lines.at(i));
}
path.addText(text_x, text_y, font, lines.at(i));
}
// draw software shadow
if (shadow_bool->get_bool_value(timecode)) {
p.setPen(Qt::NoPen);
path.translate(position_x->GetDoubleAt(timecode) + padding, position_y->GetDoubleAt(timecode) + padding);
// draw software shadow
if (shadow_bool->GetBoolAt(timecode)) {
p.setPen(Qt::NoPen);
// calculate offset using distance and angle
double angle = shadow_angle->get_double_value(timecode) * M_PI / 180.0;
double distance = qFloor(shadow_distance->get_double_value(timecode));
double angle = shadow_angle->GetDoubleAt(timecode) * M_PI / 180.0;
double distance = qFloor(shadow_distance->GetDoubleAt(timecode));
int shadow_x_offset = qRound(qCos(angle) * distance);
int shadow_y_offset = qRound(qSin(angle) * distance);
QPainterPath shadow_path(path);
QPainterPath shadow_path(path);
shadow_path.translate(shadow_x_offset, shadow_y_offset);
QColor col = shadow_color->get_color_value(timecode);
col.setAlpha(0);
img.fill(col);
QColor col = shadow_color->GetColorAt(timecode);
col.setAlpha(0);
img.fill(col);
col.setAlphaF(shadow_opacity->get_double_value(timecode)*0.01);
p.setBrush(col);
p.drawPath(shadow_path);
col.setAlphaF(shadow_opacity->GetDoubleAt(timecode)*0.01);
p.setBrush(col);
p.drawPath(shadow_path);
int blurSoftness = qFloor(shadow_softness->get_double_value(timecode));
if (blurSoftness > 0) blurred2(img, img.rect(), blurSoftness, true);
}
int blurSoftness = qFloor(shadow_softness->GetDoubleAt(timecode));
if (blurSoftness > 0) olive::ui::blur(img, img.rect(), blurSoftness, true);
}
// draw outline
int outline_width_val = outline_width->get_double_value(timecode);
if (outline_bool->get_bool_value(timecode) && outline_width_val > 0) {
QPen outline(outline_color->get_color_value(timecode));
outline.setWidth(outline_width_val);
p.setPen(outline);
p.setBrush(Qt::NoBrush);
p.drawPath(path);
}
// draw outline
int outline_width_val = qCeil(outline_width->GetDoubleAt(timecode));
if (outline_bool->GetBoolAt(timecode) && outline_width_val > 0) {
QPen outline(outline_color->GetColorAt(timecode));
outline.setWidth(outline_width_val);
p.setPen(outline);
p.setBrush(Qt::NoBrush);
p.drawPath(path);
}
// draw "master" text
p.setPen(Qt::NoPen);
p.setBrush(set_color_button->get_color_value(timecode));
p.drawPath(path);
// draw "master" text
p.setPen(Qt::NoPen);
p.setBrush(set_color_button->GetColorAt(timecode));
p.drawPath(path);
p.end();
p.end();
}
void TextEffect::shadow_enable(bool e) {
close();
close();
shadow_color->set_enabled(e);
shadow_angle->set_enabled(e);
shadow_distance->set_enabled(e);
shadow_softness->set_enabled(e);
shadow_opacity->set_enabled(e);
}
void TextEffect::text_edit_menu() {
QMenu menu;
menu.addAction(tr("&Edit Text"), this, SLOT(open_text_edit()));
menu.exec(QCursor::pos());
}
void TextEffect::open_text_edit() {
TextEditDialog ted(olive::MainWindow, text_val->get_current_data().toString());
ted.exec();
QString result = ted.get_string();
if (!result.isEmpty()) {
text_val->set_current_data(result);
text_val->ui_element_change();
}
shadow_color->SetEnabled(e);
shadow_angle->SetEnabled(e);
shadow_distance->SetEnabled(e);
shadow_softness->SetEnabled(e);
shadow_opacity->SetEnabled(e);
}
void TextEffect::outline_enable(bool e) {
outline_color->set_enabled(e);
outline_width->set_enabled(e);
outline_color->SetEnabled(e);
outline_width->SetEnabled(e);
}
+30 -28
View File
@@ -21,42 +21,44 @@
#ifndef TEXTEFFECT_H
#define TEXTEFFECT_H
#include "project/effect.h"
#include "effects/effect.h"
#include <QFont>
#include <QImage>
class TextEffect : public Effect {
Q_OBJECT
Q_OBJECT
public:
TextEffect(Clip* c, const EffectMeta *em);
void redraw(double timecode);
EffectField* text_val;
EffectField* size_val;
EffectField* set_color_button;
EffectField* set_font_combobox;
EffectField* halign_field;
EffectField* valign_field;
EffectField* word_wrap_field;
EffectField* outline_bool;
EffectField* outline_width;
EffectField* outline_color;
EffectField* shadow_bool;
EffectField* shadow_angle;
EffectField* shadow_distance;
EffectField* shadow_color;
EffectField* shadow_softness;
EffectField* shadow_opacity;
TextEffect(Clip* c, const EffectMeta *em);
void redraw(double timecode);
private slots:
void outline_enable(bool);
void shadow_enable(bool);
void text_edit_menu();
void open_text_edit();
void outline_enable(bool);
void shadow_enable(bool);
private:
QFont font;
QFont font;
StringField* text_val;
DoubleField* size_val;
ColorField* set_color_button;
FontField* set_font_combobox;
ComboField* halign_field;
ComboField* valign_field;
BoolField* word_wrap_field;
DoubleField* padding_field;
DoubleField* position_x;
DoubleField* position_y;
BoolField* outline_bool;
DoubleField* outline_width;
ColorField* outline_color;
BoolField* shadow_bool;
DoubleField* shadow_angle;
DoubleField* shadow_distance;
ColorField* shadow_color;
DoubleField* shadow_softness;
DoubleField* shadow_opacity;
};
#endif // TEXTEFFECT_H
+55 -36
View File
@@ -35,56 +35,70 @@
#include "ui/labelslider.h"
#include "ui/collapsiblewidget.h"
#include "project/clip.h"
#include "project/sequence.h"
#include "timeline/clip.h"
#include "timeline/sequence.h"
#include "panels/viewer.h"
#include "ui/comboboxex.h"
#include "ui/colorbutton.h"
#include "ui/fontcombobox.h"
#include "io/config.h"
#include "global/config.h"
TimecodeEffect::TimecodeEffect(Clip* c, const EffectMeta* em) :
Effect(c, em)
{
enable_always_update = true;
enable_superimpose = true;
SetFlags(Effect::SuperimposeFlag);
EffectRow* tc_row = add_row(tr("Timecode"));
tc_select = tc_row->add_field(EFFECT_FIELD_COMBO, "tc_selector");
tc_select->add_combo_item(tr("Sequence"), true);
tc_select->add_combo_item(tr("Media"), false);
tc_select->set_combo_index(0);
EffectRow* tc_row = new EffectRow(this, tr("Timecode"));
tc_select = new ComboField(tc_row, "tc_selector");
tc_select->AddItem(tr("Sequence"), true);
tc_select->AddItem(tr("Media"), false);
tc_select->SetValueAt(0, true);
scale_val = add_row(tr("Scale"))->add_field(EFFECT_FIELD_DOUBLE, "scale", 2);
scale_val->set_double_minimum_value(1);
scale_val->set_double_default_value(100);
scale_val->set_double_maximum_value(1000);
EffectRow* scale_row = new EffectRow(this, tr("Scale"));
scale_val = new DoubleField(scale_row, "scale");
scale_val->SetColumnSpan(2);
scale_val->SetMinimum(1);
scale_val->SetDefault(100);
scale_val->SetMaximum(1000);
color_val = add_row(tr("Color"))->add_field(EFFECT_FIELD_COLOR, "color", 2);
color_val->set_color_value(Qt::white);
EffectRow* color_row = new EffectRow(this, tr("Color"));
color_val = new ColorField(color_row, "color");
color_val->SetColumnSpan(2);
color_val->SetValueAt(0, QColor(Qt::white));
color_bg_val = add_row(tr("Background Color"))->add_field(EFFECT_FIELD_COLOR, "bgcolor", 2);
color_bg_val->set_color_value(Qt::black);
EffectRow* color_bg_row = new EffectRow(this, tr("Background Color"));
color_bg_val = new ColorField(color_bg_row, "bgcolor");
color_bg_val->SetColumnSpan(2);
color_bg_val->SetValueAt(0, QColor(Qt::black));
bg_alpha = add_row(tr("Background Opacity"))->add_field(EFFECT_FIELD_DOUBLE, "bgalpha", 2);
bg_alpha->set_double_minimum_value(0);
bg_alpha->set_double_maximum_value(100);
bg_alpha->set_double_default_value(50);
EffectRow* bg_alpha_row = new EffectRow(this, tr("Background Opacity"));
bg_alpha = new DoubleField(bg_alpha_row, "bgalpha");
bg_alpha->SetColumnSpan(2);
bg_alpha->SetMinimum(0);
bg_alpha->SetDefault(50);
bg_alpha->SetMaximum(100);
EffectRow* offset = add_row(tr("Offset"));
offset_x_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsetx");
offset_y_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsety");
EffectRow* offset_row = new EffectRow(this, tr("Offset"));
offset_x_val = new DoubleField(offset_row, "offsetx");
offset_y_val = new DoubleField(offset_row, "offsety");
prepend_text = add_row(tr("Prepend"))->add_field(EFFECT_FIELD_STRING, "prepend", 2);
EffectRow* prepent_text_row = new EffectRow(this, tr("Prepend"));
prepend_text = new StringField(prepent_text_row, "prepend");
prepend_text->SetColumnSpan(2);
}
void TimecodeEffect::redraw(double timecode) {
if (tc_select->get_combo_data(timecode).toBool()){
display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(olive::ActiveSequence->playhead, olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate);}
else {
if (tc_select->GetValueAt(timecode).toBool()) {
display_timecode = prepend_text->GetStringAt(timecode) + frame_to_timecode(olive::ActiveSequence->playhead,
olive::CurrentConfig.timecode_view,
olive::ActiveSequence->frame_rate);
} else {
double media_rate = parent_clip->media_frame_rate();
display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(timecode * media_rate, olive::CurrentConfig.timecode_view, media_rate);}
display_timecode = prepend_text->GetStringAt(timecode) + frame_to_timecode(qRound(timecode * media_rate),
olive::CurrentConfig.timecode_view,
media_rate);
}
img.fill(Qt::transparent);
QPainter p(&img);
@@ -95,7 +109,7 @@ void TimecodeEffect::redraw(double timecode) {
// set font
font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
font.setFamily("Helvetica");
font.setPixelSize(qCeil(scale_val->get_double_value(timecode)*.01*(height/10)));
font.setPixelSize(qCeil(scale_val->GetDoubleAt(timecode)*.01*(height/10)));
p.setFont(font);
QFontMetrics fm(font);
@@ -104,12 +118,12 @@ void TimecodeEffect::redraw(double timecode) {
int text_x, text_y, rect_y, offset_x, offset_y;
int text_height = fm.height();
int text_width = fm.width(display_timecode);
QColor background_color = color_bg_val->get_color_value(timecode);
int alpha_val = bg_alpha->get_double_value(timecode)*2.55;
QColor background_color = color_bg_val->GetColorAt(timecode);
int alpha_val = qCeil(bg_alpha->GetDoubleAt(timecode)*2.55);
background_color.setAlpha(alpha_val);
offset_x = int(offset_x_val->get_double_value(timecode));
offset_y = int(offset_y_val->get_double_value(timecode));
offset_x = int(offset_x_val->GetDoubleAt(timecode));
offset_y = int(offset_y_val->GetDoubleAt(timecode));
text_x = offset_x + (width/2) - (text_width/2);
text_y = offset_y + height - height/10;
@@ -120,6 +134,11 @@ void TimecodeEffect::redraw(double timecode) {
p.setPen(Qt::NoPen);
p.setBrush(background_color);
p.drawRect(QRect(text_x-fm.descent(), rect_y, text_width+fm.descent()*2, text_height));
p.setBrush(color_val->get_color_value(timecode));
p.setBrush(color_val->GetColorAt(timecode));
p.drawPath(path);
}
bool TimecodeEffect::AlwaysUpdate()
{
return true;
}
+17 -14
View File
@@ -21,28 +21,31 @@
#ifndef TIMECODEEFFECT_H
#define TIMECODEEFFECT_H
#include "project/effect.h"
#include "effects/effect.h"
#include <QFont>
#include <QImage>
class TimecodeEffect : public Effect {
Q_OBJECT
Q_OBJECT
public:
TimecodeEffect(Clip* c, const EffectMeta *em);
void redraw(double timecode);
EffectField * scale_val;
EffectField * color_val;
EffectField * color_bg_val;
EffectField * bg_alpha;
EffectField * offset_x_val;
EffectField * offset_y_val;
EffectField * prepend_text;
EffectField * tc_select;
TimecodeEffect(Clip* c, const EffectMeta *em);
void redraw(double timecode);
DoubleField* scale_val;
ColorField* color_val;
ColorField* color_bg_val;
DoubleField* bg_alpha;
DoubleField* offset_x_val;
DoubleField* offset_y_val;
StringField* prepend_text;
ComboField* tc_select;
protected:
virtual bool AlwaysUpdate() override;
private:
QFont font;
QString display_timecode;
QFont font;
QString display_timecode;
};
#endif // TIMECODEEFFECT_H
+38 -33
View File
@@ -24,49 +24,54 @@
#define TONE_TYPE_SINE 0
#include "project/clip.h"
#include "project/sequence.h"
#include "debug.h"
#include "timeline/clip.h"
#include "timeline/sequence.h"
ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_MIN) {
type_val = add_row(tr("Type"))->add_field(EFFECT_FIELD_COMBO, "type");
type_val->add_combo_item("Sine", TONE_TYPE_SINE);
EffectRow* type_row = new EffectRow(this, tr("Type"));
type_val = new ComboField(type_row, "type");
type_val->AddItem(tr("Sine"), TONE_TYPE_SINE);
freq_val = add_row(tr("Frequency"))->add_field(EFFECT_FIELD_DOUBLE, "frequency");
freq_val->set_double_minimum_value(20);
freq_val->set_double_maximum_value(20000);
freq_val->set_double_default_value(1000);
EffectRow* frequency_row = new EffectRow(this, tr("Frequency"));
freq_val = new DoubleField(frequency_row, "frequency");
freq_val->SetMinimum(20);
freq_val->SetMaximum(20000);
freq_val->SetDefault(1000);
amount_val = add_row(tr("Amount"))->add_field(EFFECT_FIELD_DOUBLE, "amount");
amount_val->set_double_minimum_value(0);
amount_val->set_double_maximum_value(100);
amount_val->set_double_default_value(25);
EffectRow* amount_row = new EffectRow(this, tr("Amount"));
amount_val = new DoubleField(amount_row, "amount");
amount_val->SetMinimum(0);
amount_val->SetMaximum(100);
amount_val->SetDefault(25);
mix_val = add_row(tr("Mix"))->add_field(EFFECT_FIELD_BOOL, "mix");
mix_val->set_bool_value(true);
EffectRow* mix_row = new EffectRow(this, tr("Mix"));
mix_val = new BoolField(mix_row, "mix");
mix_val->SetValueAt(0, true);
}
void ToneEffect::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;i<nb_bytes;i+=4) {
double timecode = timecode_start+(interval*i);
double interval = (timecode_end - timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=4) {
double timecode = timecode_start+(interval*i);
qint16 left_tone_sample = qint16(qRound(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;
qint16 left_tone_sample = qint16(qRound(qSin((2*M_PI*sinX*freq_val->GetDoubleAt(timecode))
/parent_clip->sequence->audio_frequency)
*log_volume(amount_val->GetDoubleAt(timecode)*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));
qint16 right_sample = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF));
left_tone_sample = mix_audio_sample(left_tone_sample, left_sample);
right_tone_sample = mix_audio_sample(right_tone_sample, right_sample);
}
// mix with source audio
if (mix_val->GetBoolAt(timecode)) {
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));
left_tone_sample = mix_audio_sample(left_tone_sample, left_sample);
right_tone_sample = mix_audio_sample(right_tone_sample, right_sample);
}
samples[i+3] = quint8(right_tone_sample >> 8);
samples[i+2] = quint8(right_tone_sample);
samples[i+1] = quint8(left_tone_sample >> 8);
samples[i] = quint8(left_tone_sample);
samples[i+3] = quint8(right_tone_sample >> 8);
samples[i+2] = quint8(right_tone_sample);
samples[i+1] = quint8(left_tone_sample >> 8);
samples[i] = quint8(left_tone_sample);
sinX++;
}
sinX++;
}
}
+9 -9
View File
@@ -21,20 +21,20 @@
#ifndef TONEEFFECT_H
#define TONEEFFECT_H
#include "project/effect.h"
#include "effects/effect.h"
class ToneEffect : public Effect {
Q_OBJECT
Q_OBJECT
public:
ToneEffect(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
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;
EffectField* freq_val;
EffectField* amount_val;
EffectField* mix_val;
ComboField* type_val;
DoubleField* freq_val;
DoubleField* amount_val;
BoolField* mix_val;
private:
int sinX;
int sinX;
};
#endif // TONEEFFECT_H
+63 -78
View File
@@ -30,60 +30,63 @@
#include <QMouseEvent>
#include "ui/collapsiblewidget.h"
#include "project/clip.h"
#include "project/sequence.h"
#include "timeline/clip.h"
#include "timeline/sequence.h"
#include "project/footage.h"
#include "io/math.h"
#include "global/math.h"
#include "ui/labelslider.h"
#include "ui/comboboxex.h"
#include "project/effectloaders.h"
#include "panels/project.h"
#include "debug.h"
#include "global/debug.h"
#include "panels/panels.h"
#include "panels/viewer.h"
#include "ui/viewerwidget.h"
TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) {
enable_coords = true;
SetFlags(Effect::CoordsFlag);
EffectRow* position_row = add_row(tr("Position"));
position_x = position_row->add_field(EFFECT_FIELD_DOUBLE, "posx"); // position X
position_y = position_row->add_field(EFFECT_FIELD_DOUBLE, "posy"); // position Y
EffectRow* position_row = new EffectRow(this, tr("Position"));
EffectRow* scale_row = add_row(tr("Scale"));
scale_x = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scalex"); // scale X (and Y is uniform scale is selected)
scale_x->set_double_minimum_value(0);
scale_x->set_double_maximum_value(3000);
scale_y = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scaley"); // scale Y (disabled if uniform scale is selected)
scale_y->set_double_minimum_value(0);
scale_y->set_double_maximum_value(3000);
position_x = new DoubleField(position_row, "posx"); // position X
position_y = new DoubleField(position_row, "posy"); // position Y
EffectRow* uniform_scale_row = add_row(tr("Uniform Scale"));
uniform_scale_field = uniform_scale_row->add_field(EFFECT_FIELD_BOOL, "uniformscale"); // uniform scale option
EffectRow* scale_row = new EffectRow(this, tr("Scale"));
EffectRow* rotation_row = add_row(tr("Rotation"));
rotation = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation");
// scale X (and Y is uniform scale is selected)
scale_x = new DoubleField(scale_row, "scalex");
scale_x->SetMinimum(0);
EffectRow* anchor_point_row = add_row(tr("Anchor Point"));
anchor_x_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE, "anchorx"); // anchor point X
anchor_y_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE, "anchory"); // anchor point Y
// scale Y (disabled if uniform scale is selected)
scale_y = new DoubleField(scale_row, "scaley");
scale_y->SetMinimum(0);
EffectRow* opacity_row = add_row(tr("Opacity"));
opacity = opacity_row->add_field(EFFECT_FIELD_DOUBLE, "opacity"); // opacity
opacity->set_double_minimum_value(0);
opacity->set_double_maximum_value(100);
EffectRow* uniform_scale_row = new EffectRow(this, tr("Uniform Scale"));
EffectRow* blend_mode_row = add_row(tr("Blend Mode"));
blend_mode_box = blend_mode_row->add_field(EFFECT_FIELD_COMBO, "blendmode", 2); // blend mode
blend_mode_box->add_combo_item(tr("Normal"), -1);
uniform_scale_field = new BoolField(uniform_scale_row, "uniformscale"); // uniform scale option
// add loaded blending modes
olive::effects_loaded.lock();
for (int i=0;i<olive::blend_modes.size();i++) {
blend_mode_box->add_combo_item(olive::blend_modes.at(i).name, i);
}
olive::effects_loaded.unlock();
EffectRow* rotation_row = new EffectRow(this, tr("Rotation"));
rotation = new DoubleField(rotation_row, "rotation");
EffectRow* anchor_point_row = new EffectRow(this, tr("Anchor Point"));
anchor_x_box = new DoubleField(anchor_point_row, "anchorx"); // anchor point X
anchor_y_box = new DoubleField(anchor_point_row, "anchory"); // anchor point Y
EffectRow* opacity_row = new EffectRow(this, tr("Opacity"));
// opacity
opacity = new DoubleField(opacity_row, "opacity");
opacity->SetMinimum(0);
opacity->SetMaximum(100);
EffectRow* blend_mode_row = new EffectRow(this, tr("Blend Mode"));
// blend mode
blend_mode_box = new ComboField(blend_mode_row, "blendmode");
blend_mode_box->SetColumnSpan(2);
blend_mode_box->AddItem(tr("Normal"), -1);
// set up gizmos
top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
@@ -134,49 +137,29 @@ TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em)
rect_gizmo->x_field1 = position_x;
rect_gizmo->y_field1 = position_y;
connect(uniform_scale_field, SIGNAL(toggled(bool)), this, SLOT(toggle_uniform_scale(bool)));
connect(uniform_scale_field, SIGNAL(Toggled(bool)), this, SLOT(toggle_uniform_scale(bool)));
// set defaults
uniform_scale_field->set_bool_value(true);
blend_mode_box->set_combo_index(0);
set = false;
refresh();
}
uniform_scale_field->SetValueAt(0, true);
blend_mode_box->SetValueAt(0, -1);
anchor_x_box->SetDefault(0);
anchor_y_box->SetDefault(0);
opacity->SetDefault(100);
scale_x->SetDefault(100);
scale_y->SetDefault(100);
void adjust_field(EffectField* field, double old_offset, double new_offset) {
if (field->keyframes.size() > 0) {
for (int i=0;i<field->keyframes.size();i++) {
field->keyframes[i].data = field->keyframes.at(i).data.toDouble() - old_offset + new_offset;
}
} else {
field->set_current_data(field->get_current_data().toDouble() - old_offset + new_offset);
}
refresh();
}
void TransformEffect::refresh() {
if (parent_clip != nullptr && parent_clip->sequence != nullptr) {
double new_default_pos_x = parent_clip->sequence->width/2;
double new_default_pos_y = parent_clip->sequence->height/2;
/*if (set) {
adjust_field(position_x, default_pos_x, new_default_pos_x);
adjust_field(position_y, default_pos_y, new_default_pos_y);
}*/
double default_pos_x = new_default_pos_x;
double default_pos_y = new_default_pos_y;
position_x->set_double_default_value(default_pos_x);
position_y->set_double_default_value(default_pos_y);
scale_x->set_double_default_value(100);
scale_y->set_double_default_value(100);
anchor_x_box->set_double_default_value(0);
anchor_y_box->set_double_default_value(0);
opacity->set_double_default_value(100);
position_x->SetDefault(parent_clip->sequence->width/2);
position_y->SetDefault(parent_clip->sequence->height/2);
double x_percent_multipler = 200.0 / parent_clip->sequence->width;
double y_percent_multipler = 200.0 / parent_clip->sequence->height;
top_left_gizmo->x_field_multi1 = -x_percent_multipler;
top_left_gizmo->y_field_multi1 = -y_percent_multipler;
top_center_gizmo->y_field_multi1 = -y_percent_multipler;
@@ -191,12 +174,11 @@ void TransformEffect::refresh() {
right_center_gizmo->x_field_multi1 = x_percent_multipler;
rotate_gizmo->x_field_multi1 = x_percent_multipler;
set = true;
}
}
void TransformEffect::toggle_uniform_scale(bool enabled) {
scale_y->set_enabled(!enabled);
scale_y->SetEnabled(!enabled);
top_center_gizmo->y_field1 = enabled ? scale_x : scale_y;
bottom_center_gizmo->y_field1 = enabled ? scale_x : scale_y;
@@ -208,11 +190,14 @@ void TransformEffect::toggle_uniform_scale(bool enabled) {
void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, int) {
// position
glTranslated(position_x->get_double_value(timecode)-(parent_clip->sequence->width/2), position_y->get_double_value(timecode)-(parent_clip->sequence->height/2), 0);
glTranslated(position_x->GetDoubleAt(timecode)-(parent_clip->sequence->width/2),
position_y->GetDoubleAt(timecode)-(parent_clip->sequence->height/2),
0);
// anchor point
int anchor_x_offset = qRound(anchor_x_box->get_double_value(timecode));
int anchor_y_offset = qRound(anchor_y_box->get_double_value(timecode));
int anchor_x_offset = qRound(anchor_x_box->GetDoubleAt(timecode));
int anchor_y_offset = qRound(anchor_y_box->GetDoubleAt(timecode));
coords.vertexTopLeftX -= anchor_x_offset;
coords.vertexTopRightX -= anchor_x_offset;
coords.vertexBottomLeftX -= anchor_x_offset;
@@ -223,18 +208,18 @@ void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, i
coords.vertexBottomRightY -= anchor_y_offset;
// rotation
glRotated(rotation->get_double_value(timecode), 0, 0, 1);
glRotated(rotation->GetDoubleAt(timecode), 0, 0, 1);
// scale
double sx = scale_x->get_double_value(timecode)*0.01;
double sy = (uniform_scale_field->get_bool_value(timecode)) ? sx : scale_y->get_double_value(timecode)*0.01;
double sx = scale_x->GetDoubleAt(timecode)*0.01;
double sy = (uniform_scale_field->GetBoolAt(timecode)) ? sx : scale_y->GetDoubleAt(timecode)*0.01;
glScaled(sx, sy, 1);
// blend mode
coords.blendmode = blend_mode_box->get_combo_data(timecode).toInt();
coords.blendmode = blend_mode_box->GetValueAt(timecode).toInt();
// opacity
coords.opacity *= float(opacity->get_double_value(timecode)*0.01);
coords.opacity *= float(opacity->GetDoubleAt(timecode)*0.01);
}
void TransformEffect::gizmo_draw(double, GLTextureCoords& coords) {
+28 -30
View File
@@ -21,43 +21,41 @@
#ifndef TRANSFORMEFFECT_H
#define TRANSFORMEFFECT_H
#include "project/effect.h"
#include "effects/effect.h"
class TransformEffect : public Effect {
Q_OBJECT
Q_OBJECT
public:
TransformEffect(Clip* c, const EffectMeta* em);
void refresh();
void process_coords(double timecode, GLTextureCoords& coords, int data);
TransformEffect(Clip* c, const EffectMeta* em);
void refresh();
void process_coords(double timecode, GLTextureCoords& coords, int data);
void gizmo_draw(double timecode, GLTextureCoords& coords);
void gizmo_draw(double timecode, GLTextureCoords& coords);
public slots:
void toggle_uniform_scale(bool enabled);
void toggle_uniform_scale(bool enabled);
private:
EffectField* position_x;
EffectField* position_y;
EffectField* scale_x;
EffectField* scale_y;
EffectField* uniform_scale_field;
EffectField* rotation;
EffectField* anchor_x_box;
EffectField* anchor_y_box;
EffectField* opacity;
EffectField* blend_mode_box;
DoubleField* position_x;
DoubleField* position_y;
DoubleField* scale_x;
DoubleField* scale_y;
BoolField* uniform_scale_field;
DoubleField* rotation;
DoubleField* anchor_x_box;
DoubleField* anchor_y_box;
DoubleField* opacity;
ComboField* blend_mode_box;
EffectGizmo* top_left_gizmo;
EffectGizmo* top_center_gizmo;
EffectGizmo* top_right_gizmo;
EffectGizmo* bottom_left_gizmo;
EffectGizmo* bottom_center_gizmo;
EffectGizmo* bottom_right_gizmo;
EffectGizmo* left_center_gizmo;
EffectGizmo* right_center_gizmo;
EffectGizmo* anchor_gizmo;
EffectGizmo* rotate_gizmo;
EffectGizmo* rect_gizmo;
bool set;
EffectGizmo* top_left_gizmo;
EffectGizmo* top_center_gizmo;
EffectGizmo* top_right_gizmo;
EffectGizmo* bottom_left_gizmo;
EffectGizmo* bottom_center_gizmo;
EffectGizmo* bottom_right_gizmo;
EffectGizmo* left_center_gizmo;
EffectGizmo* right_center_gizmo;
EffectGizmo* anchor_gizmo;
EffectGizmo* rotate_gizmo;
EffectGizmo* rect_gizmo;
};
#endif // TRANSFORMEFFECT_H
+47 -46
View File
@@ -25,68 +25,69 @@
#include <QFile>
#include "ui/collapsiblewidget.h"
#include "debug.h"
#include "global/debug.h"
VoidEffect::VoidEffect(Clip* c, const QString& n) : Effect(c, nullptr) {
name = n;
QString display_name;
if (n.isEmpty()) {
display_name = tr("(unknown)");
} else {
display_name = n;
}
EffectRow* row = add_row(tr("Missing Effect"), false, false);
row->add_widget(new QLabel(display_name));
container->setText(display_name);
QString display_name;
if (n.isEmpty()) {
display_name = tr("(unknown)");
} else {
display_name = n;
}
EffectRow* row = new EffectRow(this, tr("Missing Effect"), false, false);
void_meta.type = EFFECT_TYPE_EFFECT;
meta = &void_meta;
new LabelField(row, display_name);
name = display_name;
void_meta.type = EFFECT_TYPE_EFFECT;
meta = &void_meta;
}
EffectPtr VoidEffect::copy(Clip* c) {
EffectPtr copy(new VoidEffect(c, name));
copy->set_enabled(is_enabled());
copy_field_keyframes(copy);
return copy;
EffectPtr copy = std::make_shared<VoidEffect>(c, name);
copy->SetEnabled(IsEnabled());
copy_field_keyframes(copy);
return copy;
}
void VoidEffect::load(QXmlStreamReader &stream) {
QString tag = stream.name().toString();
QString tag = stream.name().toString();
QXmlStreamWriter writer(&bytes);
QXmlStreamWriter writer(&bytes);
// copy XML from reader to writer
while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) {
stream.readNext();
// copy XML from reader to writer
while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) {
stream.readNext();
if (stream.isStartElement()) {
writer.writeStartElement(stream.name().toString());
}
if (stream.isEndElement()) {
writer.writeEndElement();
}
if (stream.isCharacters()) {
writer.writeCharacters(stream.text().toString());
}
for (int i=0;i<stream.attributes().size();i++) {
writer.writeAttribute(stream.attributes().at(i));
}
if (stream.isStartElement()) {
writer.writeStartElement(stream.name().toString());
}
if (stream.isEndElement()) {
writer.writeEndElement();
}
if (stream.isCharacters()) {
writer.writeCharacters(stream.text().toString());
}
for (int i=0;i<stream.attributes().size();i++) {
writer.writeAttribute(stream.attributes().at(i));
}
}
}
void VoidEffect::save(QXmlStreamWriter &stream) {
if (!name.isEmpty()) {
stream.writeAttribute("name", name);
stream.writeAttribute("enabled", QString::number(is_enabled()));
if (!name.isEmpty()) {
stream.writeAttribute("name", name);
stream.writeAttribute("enabled", QString::number(IsEnabled()));
// force xml writer to expand <effect> tag, ignored when loading
stream.writeStartElement("void");
stream.writeEndElement();
// force xml writer to expand <effect> tag, ignored when loading
stream.writeStartElement("void");
stream.writeEndElement();
if (!bytes.isEmpty()) {
// write stored data
QIODevice* device = stream.device();
device->write(bytes);
}
}
if (!bytes.isEmpty()) {
// write stored data
QIODevice* device = stream.device();
device->write(bytes);
}
}
}
+8 -8
View File
@@ -27,19 +27,19 @@
* isn't lost if the user saves over the project.
*/
#include "project/effect.h"
#include "effects/effect.h"
class VoidEffect : public Effect {
Q_OBJECT
Q_OBJECT
public:
VoidEffect(Clip* c, const QString& n);
VoidEffect(Clip* c, const QString& n);
virtual EffectPtr copy(Clip* c) override;
virtual void load(QXmlStreamReader &stream) override;
virtual void save(QXmlStreamWriter &stream) override;
virtual EffectPtr copy(Clip* c) override;
virtual void load(QXmlStreamReader &stream) override;
virtual void save(QXmlStreamWriter &stream) override;
private:
QByteArray bytes;
EffectMeta void_meta;
QByteArray bytes;
EffectMeta void_meta;
};
#endif // VOIDEFFECT_H
+27 -28
View File
@@ -29,41 +29,40 @@
#include "ui/collapsiblewidget.h"
VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
EffectRow* volume_row = add_row(tr("Volume"));
volume_val = volume_row->add_field(EFFECT_FIELD_DOUBLE, "volume");
EffectRow* volume_row = new EffectRow(this, tr("Volume"));
volume_val = new DoubleField(volume_row, "volume");
// set defaults
volume_val->set_double_default_value(1);
static_cast<LabelSlider*>(volume_val->get_ui_element())->set_display_type(LABELSLIDER_DECIBEL);
// set defaults
volume_val->SetDefault(1);
volume_val->SetDisplayType(LabelSlider::Decibel);
}
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;i<nb_bytes;i+=4) {
// double vol_val = log_volume(volume_val->get_double_value(timecode_start+(interval*i), true));
double vol_val = volume_val->get_double_value(timecode_start+(interval*i), true);
double interval = (timecode_end-timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=4) {
double vol_val = volume_val->GetDoubleAt(timecode_start+(interval*i));
qint32 right_samp = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF));
qint32 left_samp = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
qint32 right_samp = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF));
qint32 left_samp = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
left_samp *= vol_val;
right_samp *= vol_val;
left_samp *= vol_val;
right_samp *= vol_val;
if (left_samp > INT16_MAX) {
left_samp = INT16_MAX;
} else if (left_samp < INT16_MIN) {
left_samp = INT16_MIN;
}
if (left_samp > INT16_MAX) {
left_samp = INT16_MAX;
} else if (left_samp < INT16_MIN) {
left_samp = INT16_MIN;
}
if (right_samp > INT16_MAX) {
right_samp = INT16_MAX;
} else if (right_samp < INT16_MIN) {
right_samp = INT16_MIN;
}
if (right_samp > INT16_MAX) {
right_samp = INT16_MAX;
} else if (right_samp < INT16_MIN) {
right_samp = INT16_MIN;
}
samples[i+3] = (quint8) (right_samp >> 8);
samples[i+2] = (quint8) right_samp;
samples[i+1] = (quint8) (left_samp >> 8);
samples[i] = (quint8) left_samp;
}
samples[i+3] = (quint8) (right_samp >> 8);
samples[i+2] = (quint8) right_samp;
samples[i+1] = (quint8) (left_samp >> 8);
samples[i] = (quint8) left_samp;
}
}
+5 -5
View File
@@ -21,15 +21,15 @@
#ifndef VOLUMEEFFECT_H
#define VOLUMEEFFECT_H
#include "project/effect.h"
#include "effects/effect.h"
class VolumeEffect : public Effect {
Q_OBJECT
Q_OBJECT
public:
VolumeEffect(Clip* c, const EffectMeta* em);
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
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;
DoubleField* volume_val;
};
#endif // VOLUMEEFFECT_H
+34 -22
View File
@@ -30,8 +30,8 @@
#include <QWindow>
#include "rendering/audio.h"
#include "mainwindow.h"
#include "debug.h"
#include "ui/mainwindow.h"
#include "global/debug.h"
#ifdef __linux__
#include <X11/X.h>
@@ -104,7 +104,7 @@ typedef int32_t (*processEventsFuncPtr)(VstEvents *events);
typedef void (*processFuncPtr)(AEffect *effect, float **inputs, float **outputs, int32_t sampleFrames);
void VSTHost::loadPlugin() {
QString dll_fn = file_field->get_filename(0, true);
QString dll_fn = file_field->GetFileAt(0);
if (dll_fn.isEmpty()) {
return;
@@ -254,7 +254,22 @@ void VSTHost::processAudio(long numFrames) {
plugin->processReplacing(plugin, inputs, outputs, numFrames);
}
VSTHost::VSTHost(Clip* c, const EffectMeta *em) : Effect(c, em) {
void VSTHost::CreateDialogIfNull()
{
if (dialog == nullptr) {
dialog = new QDialog(olive::MainWindow);
dialog->setWindowTitle(tr("VST Plugin"));
dialog->setAttribute(Qt::WA_NativeWindow, true);
dialog->setWindowFlags(dialog->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
connect(dialog, SIGNAL(finished(int)), this, SLOT(uncheck_show_button()));
}
}
VSTHost::VSTHost(Clip* c, const EffectMeta *em) :
Effect(c, em),
plugin(nullptr),
dialog(nullptr)
{
plugin = nullptr;
inputs = new float* [CHANNEL_COUNT];
@@ -264,21 +279,16 @@ VSTHost::VSTHost(Clip* c, const EffectMeta *em) : Effect(c, em) {
outputs[channel] = new float[BLOCK_SIZE];
}
file_field = add_row(tr("Plugin"), true, false)->add_field(EFFECT_FIELD_FILE, "filename");
connect(file_field, SIGNAL(changed()), this, SLOT(change_plugin()));
EffectRow* file_row = new EffectRow(this, tr("Plugin"), true, false);
file_field = new FileField(file_row, "filename");
connect(file_field, SIGNAL(Changed()), this, SLOT(change_plugin()));
EffectRow* interface_row = add_row(tr("Interface"), false, false);
show_interface_btn = new QPushButton(tr("Show"));
show_interface_btn->setCheckable(true);
show_interface_btn->setEnabled(false);
connect(show_interface_btn, SIGNAL(toggled(bool)), this, SLOT(show_interface(bool)));
interface_row->add_widget(show_interface_btn);
EffectRow* interface_row = new EffectRow(this, tr("Interface"), false, false);
dialog = new QDialog(olive::MainWindow);
dialog->setWindowTitle(tr("VST Plugin"));
dialog->setAttribute(Qt::WA_NativeWindow, true);
dialog->setWindowFlags(dialog->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
connect(dialog, SIGNAL(finished(int)), this, SLOT(uncheck_show_button()));
show_interface_btn = new ButtonField(interface_row, tr("Show"));
show_interface_btn->SetCheckable(true);
show_interface_btn->SetEnabled(false);
connect(show_interface_btn, SIGNAL(Toggled(bool)), this, SLOT(show_interface(bool)));
}
VSTHost::~VSTHost() {
@@ -290,9 +300,6 @@ VSTHost::~VSTHost() {
delete [] inputs;
freePlugin();
delete show_interface_btn;
delete dialog;
}
void VSTHost::process_audio(double, double, quint8* samples, int nb_bytes, int) {
@@ -354,6 +361,7 @@ void VSTHost::save(QXmlStreamWriter &stream) {
}
void VSTHost::show_interface(bool show) {
CreateDialogIfNull();
dialog->setVisible(show);
if (show) {
@@ -370,7 +378,7 @@ void VSTHost::show_interface(bool show) {
}
void VSTHost::uncheck_show_button() {
show_interface_btn->setChecked(false);
show_interface_btn->SetChecked(false);
}
void VSTHost::change_plugin() {
@@ -379,9 +387,13 @@ void VSTHost::change_plugin() {
if (plugin != nullptr) {
if (configurePluginCallbacks()) {
startPlugin();
VSTRect* eRect = nullptr;
plugin->dispatcher(plugin, effEditGetRect, 0, 0, &eRect, 0);
CreateDialogIfNull();
dialog->setFixedSize(eRect->right - eRect->left, eRect->bottom - eRect->top);
} else {
#ifdef __APPLE__
CFBundleUnloadExecutable(bundle);
@@ -392,5 +404,5 @@ void VSTHost::change_plugin() {
plugin = nullptr;
}
}
show_interface_btn->setEnabled(plugin != nullptr);
show_interface_btn->SetEnabled(plugin != nullptr);
}
+31 -30
View File
@@ -23,9 +23,9 @@
#ifndef NOVST
#include "project/effect.h"
#include "effects/effect.h"
#include "io/crossplatformlib.h"
#include "global/crossplatformlib.h"
#include "include/vestige.h"
@@ -35,42 +35,43 @@ typedef intptr_t (*dispatcherFuncPtr)(AEffect *effect, int32_t opCode, int32_t i
#include <QDialog>
class VSTHost : public Effect {
Q_OBJECT
Q_OBJECT
public:
VSTHost(Clip* c, const EffectMeta* em);
~VSTHost();
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
VSTHost(Clip* c, const EffectMeta* em);
~VSTHost();
void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
void custom_load(QXmlStreamReader& stream);
void save(QXmlStreamWriter& stream);
void custom_load(QXmlStreamReader& stream);
void save(QXmlStreamWriter& stream);
private slots:
void show_interface(bool show);
void uncheck_show_button();
void change_plugin();
void show_interface(bool show);
void uncheck_show_button();
void change_plugin();
private:
EffectField* file_field;
FileField* file_field;
ButtonField* show_interface_btn;
void loadPlugin();
void freePlugin();
dispatcherFuncPtr dispatcher;
AEffect* plugin;
bool configurePluginCallbacks();
void startPlugin();
void stopPlugin();
void resumePlugin();
void suspendPlugin();
bool canPluginDo(char *canDoString);
void processAudio(long numFrames);
float** inputs;
float** outputs;
QDialog* dialog;
QPushButton* show_interface_btn;
QByteArray data_cache;
void loadPlugin();
void freePlugin();
dispatcherFuncPtr dispatcher;
AEffect* plugin;
bool configurePluginCallbacks();
void startPlugin();
void stopPlugin();
void resumePlugin();
void suspendPlugin();
bool canPluginDo(char *canDoString);
void processAudio(long numFrames);
void CreateDialogIfNull();
float** inputs;
float** outputs;
QDialog* dialog;
QByteArray data_cache;
#if defined(__APPLE__)
CFBundleRef bundle;
CFBundleRef bundle;
#else
ModulePtr modulePtr;
ModulePtr modulePtr;
#endif
};