merged effects into node structure

This commit is contained in:
itsmattkc
2019-04-12 21:50:52 +10:00
parent 4e4d2b1881
commit b21745f694
127 changed files with 1674 additions and 867 deletions
-970
View File
@@ -1,970 +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 "effect.h"
#include <QCheckBox>
#include <QGridLayout>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QMessageBox>
#include <QOpenGLContext>
#include <QDir>
#include <QPainter>
#include <QtMath>
#include <QMenu>
#include <QApplication>
#include <QFileDialog>
#include "panels/panels.h"
#include "panels/viewer.h"
#include "ui/viewerwidget.h"
#include "ui/collapsiblewidget.h"
#include "panels/project.h"
#include "undo/undo.h"
#include "timeline/sequence.h"
#include "timeline/clip.h"
#include "panels/timeline.h"
#include "panels/effectcontrols.h"
#include "panels/grapheditor.h"
#include "global/debug.h"
#include "global/path.h"
#include "ui/mainwindow.h"
#include "global/math.h"
#include "global/clipboard.h"
#include "global/config.h"
#include "transition.h"
#include "undo/undostack.h"
#include "rendering/shadergenerators.h"
#include "global/timing.h"
#include "nodes/nodes.h"
#include "effects/internal/transformeffect.h"
#include "effects/internal/texteffect.h"
#include "effects/internal/timecodeeffect.h"
#include "effects/internal/solideffect.h"
#include "effects/internal/audionoiseeffect.h"
#include "effects/internal/toneeffect.h"
#include "effects/internal/volumeeffect.h"
#include "effects/internal/paneffect.h"
#include "effects/internal/shakeeffect.h"
#include "effects/internal/cornerpineffect.h"
#include "effects/internal/vsthost.h"
#include "effects/internal/fillleftrighteffect.h"
#include "effects/internal/richtexteffect.h"
QVector<EffectMeta> olive::effects;
QVector<BlendMode> olive::blend_modes;
QString olive::generated_blending_shader;
EffectPtr Effect::Create(Clip* c, const EffectMeta* em) {
if (em->internal >= 0 && em->internal < EFFECT_INTERNAL_COUNT) {
// must be an internal effect
switch (em->internal) {
case EFFECT_INTERNAL_TRANSFORM: return std::make_shared<TransformEffect>(c, em);
case EFFECT_INTERNAL_TEXT: return std::make_shared<TextEffect>(c, em);
case EFFECT_INTERNAL_TIMECODE: return std::make_shared<TimecodeEffect>(c, em);
case EFFECT_INTERNAL_SOLID: return std::make_shared<SolidEffect>(c, em);
case EFFECT_INTERNAL_NOISE: return std::make_shared<AudioNoiseEffect>(c, em);
case EFFECT_INTERNAL_VOLUME: return std::make_shared<VolumeEffect>(c, em);
case EFFECT_INTERNAL_PAN: return std::make_shared<PanEffect>(c, em);
case EFFECT_INTERNAL_TONE: return std::make_shared<ToneEffect>(c, em);
case EFFECT_INTERNAL_SHAKE: return std::make_shared<ShakeEffect>(c, em);
case EFFECT_INTERNAL_CORNERPIN: return std::make_shared<CornerPinEffect>(c, em);
case EFFECT_INTERNAL_FILLLEFTRIGHT: return std::make_shared<FillLeftRightEffect>(c, em);
case EFFECT_INTERNAL_VST: return std::make_shared<VSTHost>(c, em);
case EFFECT_INTERNAL_RICHTEXT: return std::make_shared<RichTextEffect>(c, em);
}
} else if (!em->filename.isEmpty()) {
// load effect from file
return std::make_shared<NodeShader>(c, em);
} else {
qCritical() << "Invalid effect data";
QMessageBox::critical(olive::MainWindow,
QCoreApplication::translate("Effect", "Invalid effect"),
QCoreApplication::translate("Effect", "No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive.").arg(em->name));
}
return nullptr;
}
const EffectMeta* Effect::GetInternalMeta(int internal_id, int type) {
for (int i=0;i<olive::effects.size();i++) {
if (olive::effects.at(i).internal == internal_id && olive::effects.at(i).type == type) {
return &olive::effects.at(i);
}
}
return nullptr;
}
Effect::Effect(Clip* c, const EffectMeta *em) :
parent_clip(c),
meta(em),
flags_(0),
shader_program_(nullptr),
texture(0),
tex_width_(0),
tex_height_(0),
isOpen(false),
bound(false),
iterations(1),
enabled_(true),
expanded_(true),
texture_ctx(nullptr)
{
if (em != nullptr) {
// set up UI from effect metadata
name = em->name;
}
}
Effect::~Effect() {
if (isOpen) {
close();
}
// Clear graph editor if it's using one of these rows
if (panel_graph_editor != nullptr) {
for (int i=0;i<row_count();i++) {
if (row(i) == panel_graph_editor->get_row()) {
panel_graph_editor->set_row(nullptr);
break;
}
}
}
}
void Effect::AddRow(EffectRow *row)
{
row->setParent(this);
rows.append(row);
}
void Effect::copy_field_keyframes(EffectPtr e) {
for (int i=0;i<rows.size();i++) {
EffectRow* row = rows.at(i);
EffectRow* copy_row = e->rows.at(i);
copy_row->SetKeyframingInternal(row->IsKeyframing());
for (int j=0;j<row->FieldCount();j++) {
// Get field from this (the source) effect
EffectField* field = row->Field(j);
// Get field from the destination effect
EffectField* copy_field = copy_row->Field(j);
// Copy keyframes between effects
copy_field->keyframes = field->keyframes;
// Copy persistet data between effects
copy_field->persistent_data_ = field->persistent_data_;
}
}
}
EffectRow* Effect::row(int i) {
return rows.at(i);
}
int Effect::row_count() {
return rows.size();
}
EffectGizmo *Effect::add_gizmo(int type) {
EffectGizmo* gizmo = new EffectGizmo(this, type);
gizmos.append(gizmo);
return gizmo;
}
EffectGizmo *Effect::gizmo(int i) {
return gizmos.at(i);
}
int Effect::gizmo_count() {
return gizmos.size();
}
void Effect::refresh() {}
void Effect::FieldChanged() {
update_ui(false);
}
void Effect::delete_self() {
olive::undo_stack.push(new EffectDeleteCommand(this));
update_ui(true);
}
void Effect::move_up() {
int index_of_effect = parent_clip->IndexOfEffect(this);
if (index_of_effect == 0) {
return;
}
MoveEffectCommand* command = new MoveEffectCommand();
command->clip = parent_clip;
command->from = index_of_effect;
command->to = command->from - 1;
olive::undo_stack.push(command);
panel_effect_controls->Reload();
panel_sequence_viewer->viewer_widget()->frame_update();
}
void Effect::move_down() {
int index_of_effect = parent_clip->IndexOfEffect(this);
if (index_of_effect == parent_clip->effects.size()-1) {
return;
}
MoveEffectCommand* command = new MoveEffectCommand();
command->clip = parent_clip;
command->from = index_of_effect;
command->to = command->from + 1;
olive::undo_stack.push(command);
panel_effect_controls->Reload();
panel_sequence_viewer->viewer_widget()->frame_update();
}
void Effect::save_to_file() {
// save effect settings to file
QString file = QFileDialog::getSaveFileName(olive::MainWindow,
tr("Save Effect Settings"),
QString(),
tr("Effect XML Settings %1").arg("(*.xml)"));
// if the user picked a file
if (!file.isEmpty()) {
// ensure file ends with .xml extension
if (!file.endsWith(".xml", Qt::CaseInsensitive)) {
file.append(".xml");
}
QFile file_handle(file);
if (file_handle.open(QFile::WriteOnly)) {
file_handle.write(save_to_string());
file_handle.close();
} else {
QMessageBox::critical(olive::MainWindow,
tr("Save Settings Failed"),
tr("Failed to open \"%1\" for writing.").arg(file),
QMessageBox::Ok);
}
}
}
void Effect::load_from_file() {
// load effect settings from file
QString file = QFileDialog::getOpenFileName(olive::MainWindow,
tr("Load Effect Settings"),
QString(),
tr("Effect XML Settings %1").arg("(*.xml)"));
// if the user picked a file
if (!file.isEmpty()) {
QFile file_handle(file);
if (file_handle.open(QFile::ReadOnly)) {
olive::undo_stack.push(new SetEffectData(this, file_handle.readAll()));
file_handle.close();
update_ui(false);
} else {
QMessageBox::critical(olive::MainWindow,
tr("Load Settings Failed"),
tr("Failed to open \"%1\" for reading.").arg(file),
QMessageBox::Ok);
}
}
}
bool Effect::AlwaysUpdate()
{
return false;
}
bool Effect::IsEnabled() {
return enabled_;
}
bool Effect::IsExpanded()
{
return expanded_;
}
void Effect::SetExpanded(bool e)
{
expanded_ = e;
}
void Effect::SetEnabled(bool b) {
enabled_ = b;
emit EnabledChanged(b);
}
void Effect::load(QXmlStreamReader& stream) {
/*
int row_count = 0;
QString tag = stream.name().toString();
while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) {
stream.readNext();
if (stream.name() == "row" && stream.isStartElement()) {
if (row_count < rows.size()) {
EffectRow* row = rows.at(row_count);
while (!stream.atEnd() && !(stream.name() == "row" && stream.isEndElement())) {
stream.readNext();
// read field
if (stream.name() == "field" && stream.isStartElement()) {
int field_number = -1;
// match field using ID
for (int k=0;k<stream.attributes().size();k++) {
const QXmlStreamAttribute& attr = stream.attributes().at(k);
if (attr.name() == "id") {
for (int l=0;l<row->FieldCount();l++) {
if (row->Field(l)->id() == attr.value()) {
field_number = l;
break;
}
}
break;
}
}
if (field_number > -1) {
EffectField* field = row->Field(field_number);
// get current field value
for (int k=0;k<stream.attributes().size();k++) {
const QXmlStreamAttribute& attr = stream.attributes().at(k);
if (attr.name() == "value") {
field->persistent_data_ = field->ConvertStringToValue(attr.value().toString());
break;
}
}
while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) {
stream.readNext();
// read keyframes
if (stream.name() == "key" && stream.isStartElement()) {
row->SetKeyframingInternal(true);
EffectKeyframe key;
for (int k=0;k<stream.attributes().size();k++) {
const QXmlStreamAttribute& attr = stream.attributes().at(k);
if (attr.name() == "value") {
key.data = field->ConvertStringToValue(attr.value().toString());
} else if (attr.name() == "frame") {
key.time = attr.value().toLong();
} else if (attr.name() == "type") {
key.type = attr.value().toInt();
} else if (attr.name() == "prehx") {
key.pre_handle_x = attr.value().toDouble();
} else if (attr.name() == "prehy") {
key.pre_handle_y = attr.value().toDouble();
} else if (attr.name() == "posthx") {
key.post_handle_x = attr.value().toDouble();
} else if (attr.name() == "posthy") {
key.post_handle_y = attr.value().toDouble();
}
}
field->keyframes.append(key);
}
}
field->Changed();
}
}
}
} else {
qCritical() << "Too many rows for effect" << id << ". Project might be corrupt. (Got" << row_count << ", expected <" << rows.size()-1 << ")";
}
row_count++;
} else if (stream.isStartElement()) {
custom_load(stream);
}
}
*/
}
void Effect::custom_load(QXmlStreamReader &) {}
void Effect::save(QXmlStreamWriter& stream) {
/*
stream.writeAttribute("name", meta->category + "/" + meta->name);
stream.writeAttribute("enabled", QString::number(IsEnabled()));
for (int i=0;i<rows.size();i++) {
EffectRow* row = rows.at(i);
if (row->IsSavable()) {
stream.writeStartElement("row"); // row
for (int j=0;j<row->FieldCount();j++) {
EffectField* field = row->Field(j);
if (!field->id().isEmpty()) {
stream.writeStartElement("field"); // field
stream.writeAttribute("id", field->id());
stream.writeAttribute("value", field->ConvertValueToString(field->persistent_data_));
for (int k=0;k<field->keyframes.size();k++) {
const EffectKeyframe& key = field->keyframes.at(k);
stream.writeStartElement("key");
stream.writeAttribute("value", field->ConvertValueToString(key.data));
stream.writeAttribute("frame", QString::number(key.time));
stream.writeAttribute("type", QString::number(key.type));
stream.writeAttribute("prehx", QString::number(key.pre_handle_x));
stream.writeAttribute("prehy", QString::number(key.pre_handle_y));
stream.writeAttribute("posthx", QString::number(key.post_handle_x));
stream.writeAttribute("posthy", QString::number(key.post_handle_y));
stream.writeEndElement(); // key
}
stream.writeEndElement(); // field
}
}
stream.writeEndElement(); // row
}
}
*/
}
void Effect::load_from_string(const QByteArray &s) {
// clear existing keyframe data
for (int i=0;i<rows.size();i++) {
EffectRow* row = rows.at(i);
row->SetKeyframingInternal(false);
for (int j=0;j<row->FieldCount();j++) {
EffectField* field = row->Field(j);
field->keyframes.clear();
}
}
// write settings with xml writer
QXmlStreamReader stream(s);
while (!stream.atEnd()) {
stream.readNext();
// find the effect opening tag
if (stream.name() == "effect" && stream.isStartElement()) {
// check the name to see if it matches this effect
const QXmlStreamAttributes& attributes = stream.attributes();
for (int i=0;i<attributes.size();i++) {
const QXmlStreamAttribute& attr = attributes.at(i);
if (attr.name() == "name") {
if (Effect::GetMetaFromName(attr.value().toString()) == meta) {
// pass off to standard loading function
load(stream);
} else {
QMessageBox::critical(olive::MainWindow,
tr("Load Settings Failed"),
tr("This settings file doesn't match this effect."),
QMessageBox::Ok);
}
break;
}
}
// we've found what we're looking for
break;
}
}
}
QByteArray Effect::save_to_string() {
QByteArray save_data;
// write settings to string with xml writer
QXmlStreamWriter stream(&save_data);
stream.writeStartDocument();
stream.writeStartElement("effect");
// pass off to standard saving function
save(stream);
stream.writeEndElement(); // effect
stream.writeEndDocument();
return save_data;
}
bool Effect::is_open() {
return isOpen;
}
void Effect::validate_meta_path() {
if (!meta->path.isEmpty() || (shader_vert_path_.isEmpty() && shader_frag_path_.isEmpty())) return;
QList<QString> effects_paths = get_effects_paths();
const QString& test_fn = shader_vert_path_.isEmpty() ? shader_frag_path_ : shader_vert_path_;
for (int i=0;i<effects_paths.size();i++) {
if (QFileInfo::exists(effects_paths.at(i) + "/" + test_fn)) {
for (int j=0;j<olive::effects.size();j++) {
if (&olive::effects.at(j) == meta) {
olive::effects[j].path = effects_paths.at(i);
return;
}
}
return;
}
}
}
void Effect::open() {
if (isOpen) {
qWarning() << "Tried to open an effect that was already open";
close();
}
if (olive::runtime_config.shaders_are_enabled && (Flags() & ShaderFlag)) {
if (QOpenGLContext::currentContext() == nullptr) {
qWarning() << "No current context to create a shader program for - will retry next repaint";
} else {
validate_meta_path();
QString frag_shader_str;
QString frag_file_url = QDir(meta->path).filePath(shader_frag_path_);
QFile frag_file(frag_file_url);
if (frag_file.open(QFile::ReadOnly)) {
frag_shader_str = frag_file.readAll();
frag_file.close();
} else {
qWarning() << "Failed to open" << frag_file_url;
}
if (!frag_shader_str.isEmpty()) {
QString shader_func;
if (!shader_function_name_.isEmpty()) {
shader_func = shader_function_name_;
} else {
shader_func = "process";
}
shader_program_ = olive::shader::GetPipeline(shader_func, frag_shader_str);
}
/*
bool shader_compiled = true;
if (!shader_vert_path_.isEmpty()) {
if (shader_program_->addShaderFromSourceFile(QOpenGLShader::Vertex, meta->path + "/" + shader_vert_path_)) {
qInfo() << "Vertex shader added successfully";
} else {
shader_compiled = false;
qWarning() << "Vertex shader could not be added";
}
}
if (!shader_frag_path_.isEmpty()) {
if (shader_program_->addShaderFromSourceFile(QOpenGLShader::Fragment, meta->path + "/" + shader_frag_path_)) {
qInfo() << "Fragment shader added successfully";
} else {
shader_compiled = false;
qWarning() << "Fragment shader could not be added";
}
}
if (shader_compiled) {
if (shader_program_->link()) {
qInfo() << "Shader program linked successfully";
} else {
qWarning() << "Shader program failed to link";
}
}
*/
isOpen = true;
}
} else {
isOpen = true;
}
}
void Effect::close() {
if (!isOpen) {
qWarning() << "Tried to close an effect that was already closed";
}
delete_texture();
shader_program_ = nullptr;
isOpen = false;
}
bool Effect::is_shader_linked() {
return shader_program_ != nullptr && shader_program_->isLinked();
}
QOpenGLShaderProgram *Effect::GetShaderPipeline()
{
return shader_program_.get();
}
int Effect::Flags()
{
return flags_;
}
void Effect::SetFlags(int flags)
{
flags_ = flags;
}
int Effect::getIterations() {
return iterations;
}
void Effect::setIterations(int i) {
iterations = i;
}
void Effect::process_image(double, uint8_t *, uint8_t *, int){}
EffectPtr Effect::copy(Clip *c) {
EffectPtr copy = Effect::Create(c, meta);
copy->SetEnabled(IsEnabled());
copy_field_keyframes(copy);
return copy;
}
void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) {
/*
shader_program_->bind();
shader_program_->setUniformValue("resolution", parent_clip->media_width(), parent_clip->media_height());
shader_program_->setUniformValue("time", GLfloat(timecode));
shader_program_->setUniformValue("iteration", iteration);
for (int i=0;i<rows.size();i++) {
EffectRow* row = rows.at(i);
for (int j=0;j<row->FieldCount();j++) {
EffectField* field = row->Field(j);
if (!field->id().isEmpty()) {
switch (field->type()) {
case EffectField::EFFECT_FIELD_DOUBLE:
{
DoubleField* double_field = static_cast<DoubleField*>(field);
shader_program_->setUniformValue(double_field->id().toUtf8().constData(),
GLfloat(double_field->GetDoubleAt(timecode)));
}
break;
case EffectField::EFFECT_FIELD_COLOR:
{
ColorField* color_field = static_cast<ColorField *>(field);
shader_program_->setUniformValue(
color_field->id().toUtf8().constData(),
GLfloat(color_field->GetColorAt(timecode).redF()),
GLfloat(color_field->GetColorAt(timecode).greenF()),
GLfloat(color_field->GetColorAt(timecode).blueF())
);
}
break;
case EffectField::EFFECT_FIELD_BOOL:
shader_program_->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toBool());
break;
case EffectField::EFFECT_FIELD_COMBO:
shader_program_->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toInt());
break;
// can you even send a string to a uniform value?
case EffectField::EFFECT_FIELD_STRING:
case EffectField::EFFECT_FIELD_FONT:
case EffectField::EFFECT_FIELD_FILE:
case EffectField::EFFECT_FIELD_UI:
break;
}
}
}
}
shader_program_->release();
*/
}
void Effect::process_coords(double, GLTextureCoords&, int) {}
GLuint Effect::process_superimpose(QOpenGLContext* ctx, double timecode) {
bool dimensions_changed = false;
bool redrew_image = false;
int width = parent_clip->media_width();
int height = parent_clip->media_height();
if (width != img.width() || height != img.height()) {
img = QImage(width, height, QImage::Format_RGBA8888_Premultiplied);
dimensions_changed = true;
}
if (valueHasChanged(timecode) || dimensions_changed || AlwaysUpdate()) {
redraw(timecode);
redrew_image = true;
}
QOpenGLFunctions* f = ctx->functions();
if (texture == 0 || tex_width_ != img.width() || tex_height_ != img.height()) {
delete_texture();
tex_width_ = img.width();
tex_height_ = img.height();
// create texture object
f->glGenTextures(1, &texture);
f->glBindTexture(GL_TEXTURE_2D, texture);
// set texture filtering to bilinear
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
f->glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA8, tex_width_, tex_height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.constBits()
);
f->glBindTexture(GL_TEXTURE_2D, 0);
redrew_image = false;
}
if (redrew_image) {
f->glBindTexture(GL_TEXTURE_2D, texture);
f->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_width_, tex_height_, GL_RGBA, GL_UNSIGNED_BYTE, img.constBits());
f->glBindTexture(GL_TEXTURE_2D, 0);
}
return texture;
}
void Effect::process_audio(double, double, float **, int, int, int) {}
void Effect::gizmo_draw(double, GLTextureCoords &) {}
void Effect::gizmo_move(EffectGizmo* gizmo, int x_movement, int y_movement, double timecode, bool done) {
// Loop through each gizmo to find `gizmo`
for (int i=0;i<gizmos.size();i++) {
if (gizmos.at(i) == gizmo) {
// If (!done && gizmo_dragging_actions_.isEmpty()), that means the drag just started and we're going to save
// the current state of the attach fields' keyframes in KeyframeDataChange objects to make the changes undoable
// by the user later.
if (!done && gizmo_dragging_actions_.isEmpty()) {
if (gizmo->x_field1 != nullptr) {
gizmo_dragging_actions_.append(new KeyframeDataChange(gizmo->x_field1));
}
if (gizmo->y_field1 != nullptr) {
gizmo_dragging_actions_.append(new KeyframeDataChange(gizmo->y_field1));
}
if (gizmo->x_field2 != nullptr) {
gizmo_dragging_actions_.append(new KeyframeDataChange(gizmo->x_field2));
}
if (gizmo->y_field2 != nullptr) {
gizmo_dragging_actions_.append(new KeyframeDataChange(gizmo->y_field2));
}
}
// Update the field values
if (gizmo->x_field1 != nullptr) {
gizmo->x_field1->SetValueAt(timecode,
gizmo->x_field1->GetDoubleAt(timecode) + x_movement*gizmo->x_field_multi1);
}
if (gizmo->y_field1 != nullptr) {
gizmo->y_field1->SetValueAt(timecode,
gizmo->y_field1->GetDoubleAt(timecode) + y_movement*gizmo->y_field_multi1);
}
if (gizmo->x_field2 != nullptr) {
gizmo->x_field2->SetValueAt(timecode,
gizmo->x_field2->GetDoubleAt(timecode) + x_movement*gizmo->x_field_multi2);
}
if (gizmo->y_field2 != nullptr) {
gizmo->y_field2->SetValueAt(timecode,
gizmo->y_field2->GetDoubleAt(timecode) + y_movement*gizmo->y_field_multi2);
}
// If (done && !gizmo_dragging_actions_.isEmpty()), that means the drag just ended and we're going to save
// the new state of the attach fields' keyframes in KeyframeDataChange objects to make the changes undoable
// by the user later.
if (done && !gizmo_dragging_actions_.isEmpty()) {
// Store all the KeyframeDataChange objects into a ComboAction to send to the undo stack (makes them all
// undoable together rather than having to be undone individually).
ComboAction* ca = new ComboAction();
for (int j=0;j<gizmo_dragging_actions_.size();j++) {
// Set the current state of the keyframes as the "new" keyframes (the old values were set earlier when the
// KeyframeDataChange object was constructed).
gizmo_dragging_actions_.at(j)->SetNewKeyframes();
// Add this KeyframeDataChange object to the ComboAction
ca->append(gizmo_dragging_actions_.at(j));
}
olive::undo_stack.push(ca);
gizmo_dragging_actions_.clear();
}
break;
}
}
}
void Effect::gizmo_world_to_screen(const QMatrix4x4& matrix, const QMatrix4x4& projection) {
for (int i=0;i<gizmos.size();i++) {
EffectGizmo* g = gizmos.at(i);
for (int j=0;j<g->get_point_count();j++) {
// Convert the world point from the gizmo into a screen point relative to the sequence's dimensions
QVector3D screen_pos = g->world_pos.at(j).project(matrix,
projection,
QRect(0,
0,
parent_clip->track()->sequence()->width,
parent_clip->track()->sequence()->height));
g->screen_pos[j] = QPoint(screen_pos.x(), parent_clip->track()->sequence()->height-screen_pos.y());
}
}
}
bool Effect::are_gizmos_enabled() {
return (gizmos.size() > 0);
}
double Effect::Now()
{
return playhead_to_clip_seconds(parent_clip, parent_clip->track()->sequence()->playhead);
}
long Effect::NowInFrames()
{
return playhead_to_clip_frame(parent_clip, parent_clip->track()->sequence()->playhead);
}
void Effect::redraw(double) {
/*
// run javascript
QPainter p(&img);
painter_wrapper.img = &img;
painter_wrapper.painter = &p;
jsEngine.globalObject().setProperty("painter", wrapper_obj);
jsEngine.globalObject().setProperty("width", parent_clip->media_width());
jsEngine.globalObject().setProperty("height", parent_clip->media_height());
for (int i=0;i<rows.size();i++) {
EffectRow* row = rows.at(i);
for (int j=0;j<row->fieldCount();j++) {
EffectField* field = row->field(j);
if (!field->id.isEmpty()) {
switch (field->type) {
case EffectField::EFFECT_FIELD_DOUBLE:
jsEngine.globalObject().setProperty(field->id, field->get_double_value(timecode));
break;
case EffectField::EFFECT_FIELD_COLOR:
jsEngine.globalObject().setProperty(field->id, field->get_color_value(timecode).name());
break;
case EffectField::EFFECT_FIELD_STRING:
jsEngine.globalObject().setProperty(field->id, field->get_string_value(timecode));
break;
case EffectField::EFFECT_FIELD_BOOL:
jsEngine.globalObject().setProperty(field->id, field->get_bool_value(timecode));
break;
case EffectField::EFFECT_FIELD_COMBO:
jsEngine.globalObject().setProperty(field->id, field->get_combo_index(timecode));
break;
case EffectField::EFFECT_FIELD_FONT:
jsEngine.globalObject().setProperty(field->id, field->get_font_name(timecode));
break;
}
}
}
}
jsEngine.evaluate(script);
*/
}
bool Effect::valueHasChanged(double timecode) {
if (cachedValues.isEmpty()) {
for (int i=0;i<row_count();i++) {
EffectRow* crow = row(i);
for (int j=0;j<crow->FieldCount();j++) {
cachedValues.append(crow->Field(j)->GetValueAt(timecode));
}
}
return true;
} else {
bool changed = false;
int index = 0;
for (int i=0;i<row_count();i++) {
EffectRow* crow = row(i);
for (int j=0;j<crow->FieldCount();j++) {
EffectField* field = crow->Field(j);
if (cachedValues.at(index) != field->GetValueAt(timecode)) {
changed = true;
}
cachedValues[index] = field->GetValueAt(timecode);
index++;
}
}
return changed;
}
}
void Effect::delete_texture() {
if (texture_ctx != nullptr) {
texture_ctx->functions()->glDeleteTextures(1, &texture);
texture = 0;
texture_ctx = nullptr;
}
}
const EffectMeta* Effect::GetMetaFromName(const QString& input) {
int split_index = input.indexOf('/');
QString category;
if (split_index > -1) {
category = input.left(split_index);
}
QString name = input.mid(split_index + 1);
for (int j=0;j<olive::effects.size();j++) {
if (olive::effects.at(j).name == name
&& (olive::effects.at(j).category == category
|| category.isEmpty())) {
return &olive::effects.at(j);
}
}
return nullptr;
}
-290
View File
@@ -1,290 +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/>.
***/
#ifndef EFFECT_H
#define EFFECT_H
#include <memory>
#include <QObject>
#include <QString>
#include <QVector>
#include <QColor>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QMutex>
#include <QThread>
#include <QLabel>
#include <QWidget>
#include <QGridLayout>
#include <QPushButton>
#include <QMouseEvent>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <random>
#include "ui/collapsiblewidget.h"
#include "effectrow.h"
#include "effectgizmo.h"
#include "rendering/qopenglshaderprogramptr.h"
#include "nodes/inputs.h"
class Clip;
class Effect;
using EffectPtr = std::shared_ptr<Effect>;
struct EffectMeta {
QString name;
QString category;
QString filename;
QString path;
QString tooltip;
int internal;
int type;
int subtype;
};
struct BlendMode {
QString name;
QString url;
QString function_name;
bool loaded;
};
namespace olive {
extern QVector<EffectMeta> effects;
extern QVector<BlendMode> blend_modes;
// TODO weird place to put this?
extern QString generated_blending_shader;
}
double log_volume(double linear);
enum EffectType {
EFFECT_TYPE_INVALID,
EFFECT_TYPE_EFFECT,
EFFECT_TYPE_TRANSITION
};
enum EffectKeyframeType {
EFFECT_KEYFRAME_LINEAR,
EFFECT_KEYFRAME_BEZIER,
EFFECT_KEYFRAME_HOLD
};
enum EffectInternal {
EFFECT_INTERNAL_TRANSFORM,
EFFECT_INTERNAL_TEXT,
EFFECT_INTERNAL_SOLID,
EFFECT_INTERNAL_NOISE,
EFFECT_INTERNAL_VOLUME,
EFFECT_INTERNAL_PAN,
EFFECT_INTERNAL_TONE,
EFFECT_INTERNAL_SHAKE,
EFFECT_INTERNAL_TIMECODE,
EFFECT_INTERNAL_MASK,
EFFECT_INTERNAL_FILLLEFTRIGHT,
EFFECT_INTERNAL_VST,
EFFECT_INTERNAL_CORNERPIN,
EFFECT_INTERNAL_RICHTEXT,
EFFECT_INTERNAL_COUNT
};
struct GLTextureCoords {
QMatrix4x4 matrix;
QVector3D vertex_top_left;
QVector3D vertex_top_right;
QVector3D vertex_bottom_left;
QVector3D vertex_bottom_right;
QVector2D texture_top_left;
QVector2D texture_top_right;
QVector2D texture_bottom_left;
QVector2D texture_bottom_right;
int blendmode;
float opacity;
};
class Effect : public QObject {
Q_OBJECT
public:
Effect(Clip *c, const EffectMeta* em);
~Effect();
Clip* parent_clip;
const EffectMeta* meta;
int id;
QString name;
void AddRow(EffectRow* row);
EffectRow* row(int i);
int row_count();
EffectGizmo* add_gizmo(int type);
EffectGizmo* gizmo(int i);
int gizmo_count();
bool IsEnabled();
bool IsExpanded();
virtual void refresh();
virtual EffectPtr copy(Clip* c);
void copy_field_keyframes(EffectPtr e);
virtual void load(QXmlStreamReader& stream);
virtual void custom_load(QXmlStreamReader& stream);
virtual void save(QXmlStreamWriter& stream);
void load_from_string(const QByteArray &s);
QByteArray save_to_string();
// glsl handling
bool is_open();
void open();
void close();
bool is_shader_linked();
QOpenGLShaderProgram* GetShaderPipeline();
enum VideoEffectFlags {
ShaderFlag = 0x1,
CoordsFlag = 0x2,
SuperimposeFlag = 0x4
};
int Flags();
void SetFlags(int flags);
int getIterations();
void setIterations(int i);
virtual void process_image(double timecode, uint8_t* input, uint8_t* output, int size);
virtual void process_shader(double timecode, GLTextureCoords&, int iteration);
virtual void process_coords(double timecode, GLTextureCoords& coords, int data);
virtual GLuint process_superimpose(QOpenGLContext *ctx, double timecode);
virtual void process_audio(double timecode_start, double timecode_end, float **samples, int nb_samples, int nb_channels, int type);
virtual void gizmo_draw(double timecode, GLTextureCoords& coords);
void gizmo_move(EffectGizmo* sender, int x_movement, int y_movement, double timecode, bool done);
void gizmo_world_to_screen(const QMatrix4x4 &matrix, const QMatrix4x4 &projection);
bool are_gizmos_enabled();
/**
* @brief Get the current clip/media time
*
* A convenience function that can be plugged into GetValueAt() to get the value wherever the appropriate Sequence's
* playhead it.
*
* @return
*
* Current clip/media time in seconds.
*/
double Now();
/**
* @brief Retrieve the current clip as a frame number
*
* Same as Now() but retrieves the value as a frame number (in the appropriate Sequence's frame rate) instead of
* seconds.
*
* @return
*
* The current clip time in frames
*/
long NowInFrames();
template <typename T>
T randomNumber()
{
static std::random_device device;
static std::mt19937 generator(device());
static std::uniform_int_distribution<> distribution(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
return distribution(generator);
}
template <typename T>
T randomFloat()
{
static std::random_device device;
static std::mt19937 generator(device());
static std::uniform_int_distribution<> distribution(-1.0, 1.0);
return distribution(generator);
}
static EffectPtr Create(Clip *c, const EffectMeta *em);
static const EffectMeta* GetInternalMeta(int internal_id, int type);
static const EffectMeta* GetMetaFromName(const QString& input);
public slots:
void FieldChanged();
void SetEnabled(bool b);
void SetExpanded(bool e);
signals:
void EnabledChanged(bool);
private slots:
void delete_self();
void move_up();
void move_down();
void save_to_file();
void load_from_file();
protected:
// glsl effect
QOpenGLShaderProgramPtr shader_program_;
QString shader_vert_path_;
QString shader_frag_path_;
QString shader_function_name_;
// superimpose effect
QImage img;
GLuint texture;
QOpenGLContext* texture_ctx;
int tex_width_;
int tex_height_;
// enable effect to update constantly
virtual bool AlwaysUpdate();
private:
bool isOpen;
QVector<EffectRow*> rows;
QVector<EffectGizmo*> gizmos;
bool bound;
int iterations;
bool enabled_;
bool expanded_;
int flags_;
QVector<KeyframeDataChange*> gizmo_dragging_actions_;
// superimpose functions
virtual void redraw(double timecode);
bool valueHasChanged(double timecode);
QVector<QVariant> cachedValues;
void delete_texture();
void validate_meta_path();
};
#endif // EFFECT_H
+1 -1
View File
@@ -27,7 +27,7 @@
#include "global/config.h"
#include "global/timing.h"
#include "effects/effectrow.h"
#include "effects/effect.h"
#include "nodes/node.h"
#include "undo/undo.h"
#include "timeline/clip.h"
#include "timeline/sequence.h"
-1
View File
@@ -26,7 +26,6 @@
#include <QVector>
#include "effects/keyframe.h"
#include "undo/undo.h"
#include "undo/undostack.h"
#include "nodes/nodedatatypes.h"
+2 -2
View File
@@ -22,9 +22,9 @@
#include "ui/labelslider.h"
#include "effects/fields/doublefield.h"
#include "effects/effect.h"
#include "nodes/node.h"
EffectGizmo::EffectGizmo(Effect *parent, int type) :
EffectGizmo::EffectGizmo(Node *parent, int type) :
QObject(parent),
x_field1(nullptr),
x_field_multi1(1.0),
+2 -2
View File
@@ -39,12 +39,12 @@ enum GizmoType {
#include <QColor>
class DoubleField;
class Effect;
class Node;
class EffectGizmo : public QObject {
Q_OBJECT
public:
EffectGizmo(Effect* parent, int type);
EffectGizmo(Node* parent, int type);
QVector<QVector3D> world_pos;
QVector<QPoint> screen_pos;
+82 -143
View File
@@ -24,13 +24,36 @@
#include <QXmlStreamReader>
#include <QDebug>
#include "effects/effect.h"
#include "nodes/node.h"
#include "effects/transition.h"
#include "global/path.h"
#include "panels/panels.h"
#include "panels/effectcontrols.h"
#include "global/config.h"
#include "effects/internal/transformeffect.h"
#include "effects/internal/texteffect.h"
#include "effects/internal/timecodeeffect.h"
#include "effects/internal/solideffect.h"
#include "effects/internal/audionoiseeffect.h"
#include "effects/internal/toneeffect.h"
#include "effects/internal/volumeeffect.h"
#include "effects/internal/paneffect.h"
#include "effects/internal/shakeeffect.h"
#include "effects/internal/cornerpineffect.h"
#include "effects/internal/vsthost.h"
#include "effects/internal/fillleftrighteffect.h"
#include "effects/internal/richtexteffect.h"
#include "effects/internal/crossdissolvetransition.h"
#include "effects/internal/linearfadetransition.h"
#include "effects/internal/logarithmicfadetransition.h"
#include "effects/internal/exponentialfadetransition.h"
#include "nodes/nodes/nodemedia.h"
#include "nodes/nodes/nodeimageoutput.h"
#include "nodes/nodes/nodeshader.h"
QMutex olive::effects_loaded;
void load_internal_effects() {
@@ -38,103 +61,35 @@ void load_internal_effects() {
qWarning() << "Shaders are disabled, some effects may be nonfunctional";
}
EffectMeta em;
olive::node_library.resize(kInvalidNode);
olive::node_library.fill(nullptr);
// load internal effects
em.path = ":/internalshaders";
em.type = EFFECT_TYPE_EFFECT;
em.subtype = Track::kTypeAudio;
em.name = "Volume";
em.internal = EFFECT_INTERNAL_VOLUME;
olive::effects.append(em);
em.name = "Pan";
em.internal = EFFECT_INTERNAL_PAN;
olive::effects.append(em);
em.name = "VST Plugin 2.x";
em.internal = EFFECT_INTERNAL_VST;
olive::effects.append(em);
em.name = "Tone";
em.internal = EFFECT_INTERNAL_TONE;
olive::effects.append(em);
em.name = "Noise";
em.internal = EFFECT_INTERNAL_NOISE;
olive::effects.append(em);
em.name = "Fill Left/Right";
em.internal = EFFECT_INTERNAL_FILLLEFTRIGHT;
olive::effects.append(em);
em.subtype = Track::kTypeVideo;
em.name = "Transform";
em.category = "Distort";
em.internal = EFFECT_INTERNAL_TRANSFORM;
olive::effects.append(em);
em.name = "Corner Pin";
em.internal = EFFECT_INTERNAL_CORNERPIN;
olive::effects.append(em);
/*em.name = "Mask";
em.internal = EFFECT_INTERNAL_MASK;
olive::effects.append(em);*/
em.name = "Shake";
em.internal = EFFECT_INTERNAL_SHAKE;
olive::effects.append(em);
em.name = "Text";
em.category = "Render";
em.internal = EFFECT_INTERNAL_TEXT;
olive::effects.append(em);
em.name = "Rich Text";
em.category = "Render";
em.internal = EFFECT_INTERNAL_RICHTEXT;
olive::effects.append(em);
em.name = "Timecode";
em.internal = EFFECT_INTERNAL_TIMECODE;
olive::effects.append(em);
em.name = "Solid";
em.internal = EFFECT_INTERNAL_SOLID;
olive::effects.append(em);
// internal transitions
em.type = EFFECT_TYPE_TRANSITION;
em.category = "";
em.name = "Cross Dissolve";
em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE;
olive::effects.append(em);
em.subtype = Track::kTypeAudio;
em.name = "Linear Fade";
em.internal = TRANSITION_INTERNAL_LINEARFADE;
olive::effects.append(em);
em.name = "Exponential Fade";
em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE;
olive::effects.append(em);
em.name = "Logarithmic Fade";
em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE;
olive::effects.append(em);
olive::node_library[kTransformEffect] = std::make_shared<TransformEffect>(nullptr);
olive::node_library[kTextInput] = std::make_shared<TextEffect>(nullptr);
olive::node_library[kSolidInput] = std::make_shared<SolidEffect>(nullptr);
olive::node_library[kNoiseInput] = std::make_shared<AudioNoiseEffect>(nullptr);
olive::node_library[kVolumeEffect] = std::make_shared<VolumeEffect>(nullptr);
olive::node_library[kPanEffect] = std::make_shared<PanEffect>(nullptr);
olive::node_library[kToneInput] = std::make_shared<ToneEffect>(nullptr);
olive::node_library[kShakeEffect] = std::make_shared<ShakeEffect>(nullptr);
olive::node_library[kTimecodeEffect] = std::make_shared<TimecodeEffect>(nullptr);
olive::node_library[kFillLeftRightEffect] = std::make_shared<FillLeftRightEffect>(nullptr);
olive::node_library[kVstEffect] = std::make_shared<VSTHost>(nullptr);
olive::node_library[kCornerPinEffect] = std::make_shared<CornerPinEffect>(nullptr);
olive::node_library[kRichTextInput] = std::make_shared<RichTextEffect>(nullptr);
olive::node_library[kMediaInput] = std::make_shared<NodeMedia>(nullptr);
olive::node_library[kImageOutput] = std::make_shared<NodeImageOutput>(nullptr);
olive::node_library[kCrossDissolveTransition] = std::make_shared<CrossDissolveTransition>(nullptr);
olive::node_library[kLinearFadeTransition] = std::make_shared<LinearFadeTransition>(nullptr);
olive::node_library[kExponentialFadeTransition] = std::make_shared<ExponentialFadeTransition>(nullptr);
olive::node_library[kLogarithmicFadeTransition] = std::make_shared<LogarithmicFadeTransition>(nullptr);
}
void load_shader_effects_worker(const QString& effects_path) {
QDir effects_dir(effects_path);
if (effects_dir.exists()) {
QList<QString> entries = effects_dir.entryList({"*.xml", "*.blend"},
QList<QString> entries = effects_dir.entryList({"*.xml"},
QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
for (int i=0;i<entries.size();i++) {
@@ -144,60 +99,44 @@ void load_shader_effects_worker(const QString& effects_path) {
} else {
QString file_url = QDir(effects_path).filePath(entries.at(i));
if (file_url.endsWith(".blend", Qt::CaseInsensitive)) {
QFile file(file_url);
// Load blending mode shaders from file
QList<QString> blend_mode_entries = effects_dir.entryList(QStringList("*.blend"), QDir::Files);
for (int i=0;i<blend_mode_entries.size();i++) {
BlendMode b;
b.loaded = false;
b.url = effects_dir.filePath(blend_mode_entries.at(i));
b.name = QFileInfo(b.url).baseName();
olive::blend_modes.append(b);
}
} else {
QFile file(file_url);
if (!file.open(QIODevice::ReadOnly)) {
qCritical() << "Could not open" << entries.at(i);
return;
}
QXmlStreamReader reader(&file);
while (!reader.atEnd()) {
if (reader.name() == "effect") {
QString effect_name = "";
QString effect_cat = "";
const QXmlStreamAttributes attr = reader.attributes();
for (int j=0;j<attr.size();j++) {
if (attr.at(j).name() == "name") {
effect_name = attr.at(j).value().toString();
} else if (attr.at(j).name() == "category") {
effect_cat = attr.at(j).value().toString();
}
}
if (!effect_name.isEmpty()) {
EffectMeta em;
em.type = EFFECT_TYPE_EFFECT;
em.subtype = Track::kTypeVideo;
em.name = effect_name;
em.category = effect_cat;
em.filename = file.fileName();
em.path = effects_path;
em.internal = -1;
olive::effects.append(em);
} else {
qCritical() << "Invalid effect found in" << entries.at(i);
}
break;
}
reader.readNext();
}
file.close();
if (!file.open(QIODevice::ReadOnly)) {
qCritical() << "Could not open" << entries.at(i);
return;
}
QXmlStreamReader reader(&file);
while (!reader.atEnd()) {
if (reader.name() == "effect") {
QString effect_name;
QString effect_cat;
QString effect_id;
const QXmlStreamAttributes attr = reader.attributes();
for (int j=0;j<attr.size();j++) {
if (attr.at(j).name() == "name") {
effect_name = attr.at(j).value().toString();
} else if (attr.at(j).name() == "category") {
effect_cat = attr.at(j).value().toString();
} else if (attr.at(j).name() == "id") {
effect_id = attr.at(j).value().toString();
}
}
if (!effect_name.isEmpty() && !effect_id.isEmpty()) {
olive::node_library.append(std::make_shared<NodeShader>(nullptr,
effect_name,
effect_id,
effect_cat,
file_url));
} else {
qCritical() << "Invalid effect found in" << entries.at(i);
}
break;
}
reader.readNext();
}
file.close();
}
}
}
+5 -5
View File
@@ -32,12 +32,12 @@
#include "panels/effectcontrols.h"
#include "panels/viewer.h"
#include "panels/grapheditor.h"
#include "effect.h"
#include "nodes/node.h"
#include "ui/viewerwidget.h"
#include "ui/keyframenavigator.h"
#include "ui/clickablelabel.h"
EffectRow::EffectRow(Effect *parent,
EffectRow::EffectRow(Node *parent,
const QString &id,
const QString &name,
bool savable,
@@ -77,7 +77,7 @@ bool EffectRow::IsKeyframing() {
}
void EffectRow::SetKeyframingInternal(bool b) {
if (GetParentEffect()->meta->type != EFFECT_TYPE_TRANSITION) {
if (GetParentEffect()->type() != EFFECT_TYPE_TRANSITION) {
keyframing_ = b;
emit KeyframingSetChanged(keyframing_);
}
@@ -315,9 +315,9 @@ void EffectRow::SetKeyframeOnAllFields(ComboAction* ca) {
panel_effect_controls->update_keyframes();
}
Effect *EffectRow::GetParentEffect()
Node *EffectRow::GetParentEffect()
{
return static_cast<Effect*>(parent());
return static_cast<Node*>(parent());
}
const QString &EffectRow::name() {
+3 -3
View File
@@ -24,7 +24,7 @@
#include <QObject>
#include <QVector>
class Effect;
class Node;
class QGridLayout;
class EffectField;
class QLabel;
@@ -83,7 +83,7 @@ public:
* Whether keyframing can be enabled on this row or not. This is true by default. Some values you may want to prevent
* the user from keyframing (e.g. the filename of a VST plugin), which can be done by setting this to false.
*/
EffectRow(Effect* parent,
EffectRow(Node* parent,
const QString& id,
const QString& name,
bool savable = true,
@@ -126,7 +126,7 @@ public:
*
* @return The parent Effect object that this row is attached to.
*/
Effect* GetParentEffect();
Node* GetParentEffect();
/**
* @brief Return the row's name
+2 -1
View File
@@ -22,7 +22,8 @@
#include <QCheckBox>
#include "effects/effect.h"
#include "nodes/node.h"
#include "undo/undo.h"
BoolField::BoolField(EffectRow *parent) :
EffectField(parent, EffectField::EFFECT_FIELD_BOOL)
+2 -1
View File
@@ -23,7 +23,8 @@
#include <QColor>
#include "ui/colorbutton.h"
#include "effects/effect.h"
#include "nodes/node.h"
#include "undo/undo.h"
ColorField::ColorField(EffectRow* parent) :
EffectField(parent, EffectField::EFFECT_FIELD_COLOR)
+2 -1
View File
@@ -22,8 +22,9 @@
#include <QDebug>
#include "effects/effect.h"
#include "nodes/node.h"
#include "ui/comboboxex.h"
#include "undo/undo.h"
ComboField::ComboField(EffectRow* parent) :
EffectField(parent, EffectField::EFFECT_FIELD_COMBO)
+2 -1
View File
@@ -20,7 +20,8 @@
#include "doublefield.h"
#include "effects/effect.h"
#include "nodes/node.h"
#include "undo/undo.h"
DoubleField::DoubleField(EffectRow* parent) :
EffectField(parent, EffectField::EFFECT_FIELD_DOUBLE),
+2
View File
@@ -24,6 +24,8 @@
#include "../effectfield.h"
#include "ui/labelslider.h"
class KeyframeDataChange;
/**
* @brief The DoubleField class
*
+2 -1
View File
@@ -23,7 +23,8 @@
#include <QDebug>
#include "ui/embeddedfilechooser.h"
#include "effects/effect.h"
#include "nodes/node.h"
#include "undo/undo.h"
FileField::FileField(EffectRow* parent) :
EffectField(parent, EffectField::EFFECT_FIELD_FILE)
+2 -1
View File
@@ -24,7 +24,8 @@
#include <QDebug>
#include "ui/comboboxex.h"
#include "effects/effect.h"
#include "nodes/node.h"
#include "undo/undo.h"
// NOTE/TODO: This shares a lot of similarity with ComboInput, and could probably be a derived class of it
+2 -1
View File
@@ -23,9 +23,10 @@
#include <QtMath>
#include <QDebug>
#include "effects/effect.h"
#include "nodes/node.h"
#include "ui/texteditex.h"
#include "global/config.h"
#include "undo/undo.h"
StringField::StringField(EffectRow* parent, bool rich_text) :
EffectField(parent, EffectField::EFFECT_FIELD_STRING),
+31 -1
View File
@@ -23,7 +23,7 @@
#include <QDateTime>
#include <QtMath>
AudioNoiseEffect::AudioNoiseEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
AudioNoiseEffect::AudioNoiseEffect(Clip* c) : Node(c) {
amount_val = new DoubleInput(this, "amount", tr("Amount"));
amount_val->SetMinimum(0);
amount_val->SetDefault(20);
@@ -33,6 +33,36 @@ AudioNoiseEffect::AudioNoiseEffect(Clip* c, const EffectMeta *em) : Effect(c, em
mix_val->SetValueAt(0, true);
}
QString AudioNoiseEffect::name()
{
return tr("Noise");
}
QString AudioNoiseEffect::id()
{
return "org.olivevideoeditor.Olive.noise";
}
QString AudioNoiseEffect::description()
{
return tr("Generate audio noise that can be mixed with this clip.");
}
EffectType AudioNoiseEffect::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType AudioNoiseEffect::subtype()
{
return olive::kTypeAudio;
}
NodePtr AudioNoiseEffect::Create(Clip *c)
{
return std::make_shared<AudioNoiseEffect>(c);
}
void AudioNoiseEffect::process_audio(double timecode_start,
double timecode_end,
float **samples,
+11 -3
View File
@@ -21,12 +21,20 @@
#ifndef AUDIONOISEEFFECT_H
#define AUDIONOISEEFFECT_H
#include "effects/effect.h"
#include "nodes/node.h"
class AudioNoiseEffect : public Effect {
class AudioNoiseEffect : public Node {
Q_OBJECT
public:
AudioNoiseEffect(Clip* c, const EffectMeta* em);
AudioNoiseEffect(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
+37 -2
View File
@@ -24,8 +24,8 @@
#include "timeline/clip.h"
#include "global/debug.h"
CornerPinEffect::CornerPinEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
SetFlags(Effect::CoordsFlag | Effect::ShaderFlag);
CornerPinEffect::CornerPinEffect(Clip* c) : Node(c) {
SetFlags(Node::CoordsFlag | Node::ShaderFlag);
top_left = new Vec2Input(this, "topleft", tr("Top Left"));
@@ -58,6 +58,41 @@ CornerPinEffect::CornerPinEffect(Clip* c, const EffectMeta *em) : Effect(c, em)
shader_frag_path_ = "cornerpin.frag";
}
QString CornerPinEffect::name()
{
return tr("Corner Pin");
}
QString CornerPinEffect::id()
{
return "org.olivevideoeditor.Olive.cornerpin";
}
QString CornerPinEffect::category()
{
return tr("Distort");
}
QString CornerPinEffect::description()
{
return tr("Distort/warp this clip by pinning each of its four corners.");
}
EffectType CornerPinEffect::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType CornerPinEffect::subtype()
{
return olive::kTypeVideo;
}
NodePtr CornerPinEffect::Create(Clip *c)
{
return std::make_shared<CornerPinEffect>(c);
}
void CornerPinEffect::process_coords(double timecode, GLTextureCoords &coords, int) {
coords.vertex_top_left += top_left->GetVector2DAt(timecode);
coords.vertex_top_right += top_right->GetVector2DAt(timecode);
+12 -3
View File
@@ -21,12 +21,21 @@
#ifndef CORNERPINEFFECT_H
#define CORNERPINEFFECT_H
#include "effects/effect.h"
#include "nodes/node.h"
class CornerPinEffect : public Effect {
class CornerPinEffect : public Node {
Q_OBJECT
public:
CornerPinEffect(Clip* c, const EffectMeta* em);
CornerPinEffect(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString category() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
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);
+37 -2
View File
@@ -22,8 +22,43 @@
#include <QOpenGLFunctions>
CrossDissolveTransition::CrossDissolveTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) {
SetFlags(Effect::CoordsFlag);
CrossDissolveTransition::CrossDissolveTransition(Clip* c) : Transition(c) {
SetFlags(Node::CoordsFlag);
}
QString CrossDissolveTransition::name()
{
return tr("Cross Dissolve");
}
QString CrossDissolveTransition::id()
{
return "org.olivevideoeditor.Olive.crossdissolve";
}
QString CrossDissolveTransition::category()
{
return tr("Dissolves");
}
QString CrossDissolveTransition::description()
{
return tr("Dissolve clips evenly.");
}
EffectType CrossDissolveTransition::type()
{
return EFFECT_TYPE_TRANSITION;
}
olive::TrackType CrossDissolveTransition::subtype()
{
return olive::kTypeVideo;
}
NodePtr CrossDissolveTransition::Create(Clip *c)
{
return std::make_shared<CrossDissolveTransition>(c);
}
void CrossDissolveTransition::process_coords(double progress, GLTextureCoords& coords, int data) {
+11 -2
View File
@@ -25,8 +25,17 @@
class CrossDissolveTransition : public Transition {
public:
CrossDissolveTransition(Clip *c, Clip *s, const EffectMeta* em);
void process_coords(double timecode, GLTextureCoords &, int data);
CrossDissolveTransition(Clip *c);
virtual QString name() override;
virtual QString id() override;
virtual QString category() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void process_coords(double timecode, GLTextureCoords &, int data) override;
};
#endif // CROSSDISSOLVETRANSITION_H
+1 -1
View File
@@ -25,7 +25,7 @@
class CubeTransition : public Transition {
public:
CubeTransition(Clip* c, Clip* s, const EffectMeta* em);
CubeTransition(Clip* c, Clip* s);
void process_coords(double timecode, GLTextureCoords &, int data);
};
+34 -1
View File
@@ -22,7 +22,40 @@
#include <QtMath>
ExponentialFadeTransition::ExponentialFadeTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) {}
ExponentialFadeTransition::ExponentialFadeTransition(Clip* c) :
Transition(c)
{
}
QString ExponentialFadeTransition::name()
{
return tr("Exponential Fade");
}
QString ExponentialFadeTransition::id()
{
return "org.olivevideoeditor.Olive.exponentialfade";
}
QString ExponentialFadeTransition::description()
{
return tr("An exponential audio fade that starts slow and ends fast.");
}
EffectType ExponentialFadeTransition::type()
{
return EFFECT_TYPE_TRANSITION;
}
olive::TrackType ExponentialFadeTransition::subtype()
{
return olive::kTypeAudio;
}
NodePtr ExponentialFadeTransition::Create(Clip *c)
{
return std::make_shared<ExponentialFadeTransition>(c);
}
void ExponentialFadeTransition::process_audio(double timecode_start,
double timecode_end,
+9 -1
View File
@@ -25,7 +25,15 @@
class ExponentialFadeTransition : public Transition {
public:
ExponentialFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
ExponentialFadeTransition(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
+31 -1
View File
@@ -25,12 +25,42 @@ enum FillType {
FILL_TYPE_RIGHT
};
FillLeftRightEffect::FillLeftRightEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
FillLeftRightEffect::FillLeftRightEffect(Clip* c) : Node(c) {
fill_type = new ComboInput(this, "type", tr("Type"));
fill_type->AddItem(tr("Fill Left with Right"), FILL_TYPE_LEFT);
fill_type->AddItem(tr("Fill Right with Left"), FILL_TYPE_RIGHT);
}
QString FillLeftRightEffect::name()
{
return tr("Fill Left/Right");
}
QString FillLeftRightEffect::id()
{
return "org.olivevideoeditor.Olive.fillleftright";
}
QString FillLeftRightEffect::description()
{
return tr("Replaces either the left or right channel with the other");
}
EffectType FillLeftRightEffect::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType FillLeftRightEffect::subtype()
{
return olive::kTypeAudio;
}
NodePtr FillLeftRightEffect::Create(Clip *c)
{
return std::make_shared<FillLeftRightEffect>(c);
}
void FillLeftRightEffect::process_audio(double timecode_start,
double timecode_end,
float **samples,
+11 -3
View File
@@ -21,12 +21,20 @@
#ifndef FILLLEFTRIGHTEFFECT_H
#define FILLLEFTRIGHTEFFECT_H
#include "effects/effect.h"
#include "nodes/node.h"
class FillLeftRightEffect : public Effect {
class FillLeftRightEffect : public Node {
Q_OBJECT
public:
FillLeftRightEffect(Clip* c, const EffectMeta* em);
FillLeftRightEffect(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
+31 -1
View File
@@ -20,7 +20,37 @@
#include "linearfadetransition.h"
LinearFadeTransition::LinearFadeTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) {}
LinearFadeTransition::LinearFadeTransition(Clip* c) : Transition(c) {}
QString LinearFadeTransition::name()
{
return tr("Linear Fade");
}
QString LinearFadeTransition::id()
{
return "org.olivevideoeditor.Olive.linearfade";
}
QString LinearFadeTransition::description()
{
return tr("An linear audio fade that fades evenly at a constant rate.");
}
EffectType LinearFadeTransition::type()
{
return EFFECT_TYPE_TRANSITION;
}
olive::TrackType LinearFadeTransition::subtype()
{
return olive::kTypeAudio;
}
NodePtr LinearFadeTransition::Create(Clip *c)
{
return std::make_shared<LinearFadeTransition>(c);
}
void LinearFadeTransition::process_audio(double timecode_start,
double timecode_end,
+9 -1
View File
@@ -25,7 +25,15 @@
class LinearFadeTransition : public Transition {
public:
LinearFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
LinearFadeTransition(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
+34 -1
View File
@@ -22,7 +22,40 @@
#include <QtMath>
LogarithmicFadeTransition::LogarithmicFadeTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) {}
LogarithmicFadeTransition::LogarithmicFadeTransition(Clip* c) :
Transition(c)
{
}
QString LogarithmicFadeTransition::name()
{
return tr("Logarithmic Fade");
}
QString LogarithmicFadeTransition::id()
{
return "org.olivevideoeditor.Olive.logarithmicfade";
}
QString LogarithmicFadeTransition::description()
{
return tr("An logarithmic audio fade that starts fast and ends slow.");
}
EffectType LogarithmicFadeTransition::type()
{
return EFFECT_TYPE_TRANSITION;
}
olive::TrackType LogarithmicFadeTransition::subtype()
{
return olive::kTypeAudio;
}
NodePtr LogarithmicFadeTransition::Create(Clip *c)
{
return std::make_shared<LogarithmicFadeTransition>(c);
}
void LogarithmicFadeTransition::process_audio(double timecode_start,
double timecode_end,
+9 -1
View File
@@ -25,7 +25,15 @@
class LogarithmicFadeTransition : public Transition {
public:
LogarithmicFadeTransition(Clip* c, Clip* s, const EffectMeta* em);
LogarithmicFadeTransition(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip* c) override;
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
+31 -1
View File
@@ -28,13 +28,43 @@
#include "ui/labelslider.h"
#include "ui/collapsiblewidget.h"
PanEffect::PanEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
PanEffect::PanEffect(Clip* c) : Node(c) {
pan_val = new DoubleInput(this, "pan", tr("Pan"));
pan_val->SetMinimum(-100);
pan_val->SetDefault(0);
pan_val->SetMaximum(100);
}
QString PanEffect::name()
{
return tr("Pan");
}
QString PanEffect::id()
{
return "org.olivevideoeditor.Olive.pan";
}
QString PanEffect::description()
{
return tr("Modifying the panning on a stereo audio clip.");
}
EffectType PanEffect::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType PanEffect::subtype()
{
return olive::kTypeAudio;
}
NodePtr PanEffect::Create(Clip *c)
{
return std::make_shared<PanEffect>(c);
}
void PanEffect::process_audio(double timecode_start,
double timecode_end,
float **samples,
+11 -3
View File
@@ -21,12 +21,20 @@
#ifndef PANEFFECT_H
#define PANEFFECT_H
#include "effects/effect.h"
#include "nodes/node.h"
class PanEffect : public Effect {
class PanEffect : public Node {
Q_OBJECT
public:
PanEffect(Clip* c, const EffectMeta* em);
PanEffect(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
+38 -3
View File
@@ -34,10 +34,10 @@ enum AutoscrollDirection {
SCROLL_RIGHT,
};
RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) :
Effect(c, em)
RichTextEffect::RichTextEffect(Clip *c) :
Node(c)
{
SetFlags(Effect::SuperimposeFlag);
SetFlags(Node::SuperimposeFlag);
text_val = new StringInput(this, "text", tr("Text"));
@@ -82,6 +82,41 @@ RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) :
"</html>");
}
QString RichTextEffect::name()
{
return tr("Rich Text");
}
QString RichTextEffect::id()
{
return "org.olivevideoeditor.Olive.richtext";
}
QString RichTextEffect::category()
{
return tr("Render");
}
QString RichTextEffect::description()
{
return tr("Render formatted rich text over a clip.");
}
EffectType RichTextEffect::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType RichTextEffect::subtype()
{
return olive::kTypeVideo;
}
NodePtr RichTextEffect::Create(Clip *c)
{
return std::make_shared<RichTextEffect>(c);
}
void RichTextEffect::redraw(double timecode)
{
QPainter p(&img);
+13 -3
View File
@@ -21,13 +21,23 @@
#ifndef RICHTEXTEFFECT_H
#define RICHTEXTEFFECT_H
#include "effects/effect.h"
#include "nodes/node.h"
class RichTextEffect : public Effect {
class RichTextEffect : public Node {
Q_OBJECT
public:
RichTextEffect(Clip* c, const EffectMeta *em);
RichTextEffect(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString category() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void redraw(double timecode) override;
protected:
virtual bool AlwaysUpdate() override;
private:
+37 -2
View File
@@ -32,8 +32,8 @@
#include "panels/timeline.h"
#include "global/debug.h"
ShakeEffect::ShakeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
SetFlags(Effect::CoordsFlag);
ShakeEffect::ShakeEffect(Clip* c) : Node(c) {
SetFlags(Node::CoordsFlag);
intensity_val = new DoubleInput(this, "intensity", tr("Intensity"));
intensity_val->SetMinimum(0);
@@ -79,3 +79,38 @@ void ShakeEffect::process_coords(double timecode, GLTextureCoords& coords, int)
coords.matrix.rotate(QQuaternion::fromEulerAngles(0.0f, 0.0f, rotoff));
}
QString ShakeEffect::name()
{
return tr("Shake");
}
QString ShakeEffect::id()
{
return "org.olivevideoeditor.Olive.shake";
}
QString ShakeEffect::category()
{
return tr("Distort");
}
QString ShakeEffect::description()
{
return tr("Simulate a camera shake movement.");
}
EffectType ShakeEffect::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType ShakeEffect::subtype()
{
return olive::kTypeVideo;
}
NodePtr ShakeEffect::Create(Clip *c)
{
return std::make_shared<ShakeEffect>(c);
}
+11 -3
View File
@@ -21,16 +21,24 @@
#ifndef SHAKEEFFECT_H
#define SHAKEEFFECT_H
#include "effects/effect.h"
#include "nodes/node.h"
#define RANDOM_VAL_SIZE 30
class ShakeEffect : public Effect {
class ShakeEffect : public Node {
Q_OBJECT
public:
ShakeEffect(Clip* c, const EffectMeta* em);
ShakeEffect(Clip* c);
virtual void process_coords(double timecode, GLTextureCoords& coords, int data) override;
virtual QString name() override;
virtual QString id() override;
virtual QString category() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
DoubleInput* intensity_val;
DoubleInput* rotation_val;
DoubleInput* frequency_val;
+38 -3
View File
@@ -34,10 +34,10 @@ const int SMPTE_BARS = 7;
const int SMPTE_STRIP_COUNT = 3;
const int SMPTE_LOWER_BARS = 4;
SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) :
Effect(c, em)
SolidEffect::SolidEffect(Clip* c) :
Node(c)
{
SetFlags(Effect::SuperimposeFlag);
SetFlags(Node::SuperimposeFlag);
// Field for solid type
solid_type = new ComboInput(this, "type", tr("Type"));
@@ -69,6 +69,41 @@ SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) :
fragPath = ":/shaders/solideffect.frag";*/
}
QString SolidEffect::name()
{
return tr("Solid");
}
QString SolidEffect::id()
{
return "org.olivevideoeditor.Olive.solid";
}
QString SolidEffect::category()
{
return tr("Render");
}
QString SolidEffect::description()
{
return tr("Render a solid color over this clip.");
}
EffectType SolidEffect::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType SolidEffect::subtype()
{
return olive::kTypeVideo;
}
NodePtr SolidEffect::Create(Clip *c)
{
return std::make_shared<SolidEffect>(c);
}
void SolidEffect::redraw(double timecode) {
int w = img.width();
int h = img.height();
+12 -3
View File
@@ -21,11 +21,11 @@
#ifndef SOLIDEFFECT_H
#define SOLIDEFFECT_H
#include "effects/effect.h"
#include "nodes/node.h"
#include <QImage>
class SolidEffect : public Effect {
class SolidEffect : public Node {
Q_OBJECT
public:
enum SolidType {
@@ -34,7 +34,16 @@ public:
SOLID_TYPE_CHECKERBOARD
};
SolidEffect(Clip* c, const EffectMeta *em);
SolidEffect(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString category() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void redraw(double timecode) override;
void SetType(SolidType type);
+38 -3
View File
@@ -42,10 +42,10 @@
#include "ui/blur.h"
#include "global/config.h"
TextEffect::TextEffect(Clip* c, const EffectMeta* em) :
Effect(c, em)
TextEffect::TextEffect(Clip* c) :
Node(c)
{
SetFlags(Effect::SuperimposeFlag);
SetFlags(Node::SuperimposeFlag);
text_val = new StringInput(this, "text", tr("Text"), false);
@@ -121,6 +121,41 @@ TextEffect::TextEffect(Clip* c, const EffectMeta* em) :
shader_frag_path_ = "dropshadow.frag";
}
QString TextEffect::name()
{
return tr("Text");
}
QString TextEffect::id()
{
return "org.olivevideoeditor.Olive.text";
}
QString TextEffect::category()
{
return tr("Render");
}
QString TextEffect::description()
{
return tr("Generate simple text over this clip");
}
EffectType TextEffect::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType TextEffect::subtype()
{
return olive::kTypeVideo;
}
NodePtr TextEffect::Create(Clip *c)
{
return std::make_shared<TextEffect>(c);
}
void TextEffect::redraw(double timecode) {
QColor bkg = set_color_button->GetColorAt(timecode);
bkg.setAlpha(0);
+12 -3
View File
@@ -21,15 +21,24 @@
#ifndef TEXTEFFECT_H
#define TEXTEFFECT_H
#include "effects/effect.h"
#include "nodes/node.h"
#include <QFont>
#include <QImage>
class TextEffect : public Effect {
class TextEffect : public Node {
Q_OBJECT
public:
TextEffect(Clip* c, const EffectMeta *em);
TextEffect(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString category() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void redraw(double timecode) override;
private slots:
void outline_enable(bool);
+38 -3
View File
@@ -42,10 +42,10 @@
#include "ui/colorbutton.h"
#include "global/config.h"
TimecodeEffect::TimecodeEffect(Clip* c, const EffectMeta* em) :
Effect(c, em)
TimecodeEffect::TimecodeEffect(Clip* c) :
Node(c)
{
SetFlags(Effect::SuperimposeFlag);
SetFlags(Node::SuperimposeFlag);
tc_select = new ComboInput(this, "tc_selector", tr("Timecode"));
tc_select->AddItem(tr("Sequence"), true);
@@ -74,6 +74,41 @@ TimecodeEffect::TimecodeEffect(Clip* c, const EffectMeta* em) :
prepend_text = new StringInput(this, "prepend", tr("Prepend"), false);
}
QString TimecodeEffect::name()
{
return tr("Timecode");
}
QString TimecodeEffect::id()
{
return "org.olivevideoeditor.Olive.timecode";
}
QString TimecodeEffect::category()
{
return tr("Render");
}
QString TimecodeEffect::description()
{
return tr("Render the media or sequence timecode on this clip.");
}
EffectType TimecodeEffect::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType TimecodeEffect::subtype()
{
return olive::kTypeVideo;
}
NodePtr TimecodeEffect::Create(Clip *c)
{
return std::make_shared<TimecodeEffect>(c);
}
void TimecodeEffect::redraw(double timecode) {
Sequence* sequence = parent_clip->track()->sequence();
+12 -3
View File
@@ -21,15 +21,24 @@
#ifndef TIMECODEEFFECT_H
#define TIMECODEEFFECT_H
#include "effects/effect.h"
#include "nodes/node.h"
#include <QFont>
#include <QImage>
class TimecodeEffect : public Effect {
class TimecodeEffect : public Node {
Q_OBJECT
public:
TimecodeEffect(Clip* c, const EffectMeta *em);
TimecodeEffect(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString category() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void redraw(double timecode) override;
DoubleInput* scale_val;
ColorInput* color_val;
+31 -1
View File
@@ -27,7 +27,7 @@
#include "timeline/clip.h"
#include "timeline/sequence.h"
ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_MIN) {
ToneEffect::ToneEffect(Clip* c) : Node(c), sinX(INT_MIN) {
type_val = new ComboInput(this, "type", tr("Type"));
type_val->AddItem(tr("Sine"), TONE_TYPE_SINE);
@@ -45,6 +45,36 @@ ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_
mix_val->SetValueAt(0, true);
}
QString ToneEffect::name()
{
return tr("Tone");
}
QString ToneEffect::id()
{
return "org.olivevideoeditor.Olive.tone";
}
QString ToneEffect::description()
{
return tr("Generate a sine wave tone to mix into this clip's audio.");
}
EffectType ToneEffect::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType ToneEffect::subtype()
{
return olive::kTypeAudio;
}
NodePtr ToneEffect::Create(Clip *c)
{
return std::make_shared<ToneEffect>(c);
}
void ToneEffect::process_audio(double timecode_start,
double timecode_end,
float **samples,
+13 -4
View File
@@ -21,12 +21,20 @@
#ifndef TONEEFFECT_H
#define TONEEFFECT_H
#include "effects/effect.h"
#include "nodes/node.h"
class ToneEffect : public Effect {
class ToneEffect : public Node {
Q_OBJECT
public:
ToneEffect(Clip* c, const EffectMeta* em);
ToneEffect(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
@@ -34,11 +42,12 @@ public:
int channel_count,
int type) override;
private:
ComboInput* type_val;
DoubleInput* freq_val;
DoubleInput* amount_val;
BoolInput* mix_val;
private:
int sinX;
};
+37 -2
View File
@@ -43,8 +43,8 @@
#include "panels/viewer.h"
#include "ui/viewerwidget.h"
TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) {
SetFlags(Effect::CoordsFlag);
TransformEffect::TransformEffect(Clip* c) : Node(c) {
SetFlags(Node::CoordsFlag);
position = new Vec2Input(this, "pos", tr("Position"));
@@ -125,6 +125,41 @@ TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em)
refresh();
}
QString TransformEffect::name()
{
return tr("Transform");
}
QString TransformEffect::id()
{
return "org.olivevideoeditor.Olive.transform";
}
QString TransformEffect::category()
{
return tr("Distort");
}
QString TransformEffect::description()
{
return tr("Transform the position, scale, and rotation of this clip.");
}
EffectType TransformEffect::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType TransformEffect::subtype()
{
return olive::kTypeVideo;
}
NodePtr TransformEffect::Create(Clip *c)
{
return std::make_shared<TransformEffect>(c);
}
void TransformEffect::refresh() {
if (parent_clip != nullptr && parent_clip->track()->sequence() != nullptr) {
+12 -3
View File
@@ -21,12 +21,21 @@
#ifndef TRANSFORMEFFECT_H
#define TRANSFORMEFFECT_H
#include "effects/effect.h"
#include "nodes/node.h"
class TransformEffect : public Effect {
class TransformEffect : public Node {
Q_OBJECT
public:
TransformEffect(Clip* c, const EffectMeta* em);
TransformEffect(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString category() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void refresh() override;
virtual void process_coords(double timecode, GLTextureCoords& coords, int data) override;
+50 -19
View File
@@ -27,24 +27,55 @@
#include "ui/collapsiblewidget.h"
#include "global/debug.h"
VoidEffect::VoidEffect(Clip* c, const QString& n) : Effect(c, nullptr) {
QString display_name;
if (n.isEmpty()) {
display_name = tr("(unknown)");
} else {
display_name = n;
VoidEffect::VoidEffect(Clip* c, const QString& n, const QString& id) :
Node(c),
display_name_(n),
id_(id)
{
if (display_name_.isEmpty()) {
display_name_ = tr("(unknown)");
}
new LabelWidget(this, tr("Missing Effect"), display_name);
name = display_name;
void_meta.type = EFFECT_TYPE_EFFECT;
meta = &void_meta;
new LabelWidget(this, tr("Missing Effect"), display_name_);
}
EffectPtr VoidEffect::copy(Clip* c) {
EffectPtr copy = std::make_shared<VoidEffect>(c, name);
QString VoidEffect::name()
{
return display_name_;
}
QString VoidEffect::id()
{
return id_;
}
QString VoidEffect::description()
{
return QString();
}
EffectType VoidEffect::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType VoidEffect::subtype()
{
return olive::kTypeVideo;
}
bool VoidEffect::IsCreatable()
{
return false;
}
NodePtr VoidEffect::Create(Clip *)
{
return nullptr;
}
NodePtr VoidEffect::copy(Clip* c) {
NodePtr copy = std::make_shared<VoidEffect>(c, display_name_, id_);
copy->SetEnabled(IsEnabled());
copy_field_keyframes(copy);
return copy;
@@ -53,7 +84,7 @@ EffectPtr VoidEffect::copy(Clip* c) {
void VoidEffect::load(QXmlStreamReader &stream) {
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())) {
@@ -75,18 +106,18 @@ void VoidEffect::load(QXmlStreamReader &stream) {
}
void VoidEffect::save(QXmlStreamWriter &stream) {
if (!name.isEmpty()) {
stream.writeAttribute("name", name);
if (!display_name_.isEmpty()) {
stream.writeAttribute("name", display_name_);
stream.writeAttribute("enabled", QString::number(IsEnabled()));
// force xml writer to expand <effect> tag, ignored when loading
stream.writeStartElement("void");
stream.writeEndElement();
if (!bytes.isEmpty()) {
if (!bytes_.isEmpty()) {
// write stored data
QIODevice* device = stream.device();
device->write(bytes);
device->write(bytes_);
}
}
}
+15 -6
View File
@@ -27,19 +27,28 @@
* isn't lost if the user saves over the project.
*/
#include "effects/effect.h"
#include "nodes/node.h"
class VoidEffect : public Effect {
class VoidEffect : public Node {
Q_OBJECT
public:
VoidEffect(Clip* c, const QString& n);
VoidEffect(Clip* c, const QString& n, const QString &id);
virtual QString name() override;
virtual QString id() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual bool IsCreatable() override;
virtual NodePtr Create(Clip *c) override;
virtual NodePtr copy(Clip* c) 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_;
QString display_name_;
QString id_;
};
#endif // VOIDEFFECT_H
+31 -1
View File
@@ -28,7 +28,7 @@
#include "ui/labelslider.h"
#include "ui/collapsiblewidget.h"
VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
VolumeEffect::VolumeEffect(Clip* c) : Node(c) {
volume_val = new DoubleInput(this, "volume", tr("Volume"));
// set defaults
@@ -36,6 +36,36 @@ VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
volume_val->SetDisplayType(LabelSlider::Decibel);
}
QString VolumeEffect::name()
{
return tr("Volume");
}
QString VolumeEffect::id()
{
return "org.olivevideoeditor.Olive.volume";
}
QString VolumeEffect::description()
{
return tr("Adjust the volume of this clip's audio");
}
EffectType VolumeEffect::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType VolumeEffect::subtype()
{
return olive::kTypeAudio;
}
NodePtr VolumeEffect::Create(Clip *c)
{
return std::make_shared<VolumeEffect>(c);
}
void VolumeEffect::process_audio(double timecode_start,
double timecode_end,
float **samples,
+12 -3
View File
@@ -21,12 +21,20 @@
#ifndef VOLUMEEFFECT_H
#define VOLUMEEFFECT_H
#include "effects/effect.h"
#include "nodes/node.h"
class VolumeEffect : public Effect {
class VolumeEffect : public Node {
Q_OBJECT
public:
VolumeEffect(Clip* c, const EffectMeta* em);
VolumeEffect(Clip* c);
virtual QString name() override;
virtual QString id() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
@@ -34,6 +42,7 @@ public:
int channel_count,
int type) override;
private:
DoubleInput* volume_val;
};
+33 -3
View File
@@ -227,8 +227,8 @@ void VSTHost::send_data_cache_to_plugin()
dispatcher(plugin, effSetChunk, 0, int32_t(data_cache.size()), static_cast<void*>(data_cache.data()), 0);
}
VSTHost::VSTHost(Clip* c, const EffectMeta *em) :
Effect(c, em),
VSTHost::VSTHost(Clip* c) :
Node(c),
plugin(nullptr),
dialog(nullptr),
input_cache(BLOCK_SIZE),
@@ -249,6 +249,36 @@ VSTHost::~VSTHost() {
freePlugin();
}
QString VSTHost::name()
{
return tr("VST Plugin 2.x");
}
QString VSTHost::id()
{
return "org.olivevideoeditor.Olive.vst2x";
}
QString VSTHost::description()
{
return tr("Use a VST 2.x plugin on this clip's audio.");
}
EffectType VSTHost::type()
{
return EFFECT_TYPE_EFFECT;
}
olive::TrackType VSTHost::subtype()
{
return olive::kTypeAudio;
}
NodePtr VSTHost::Create(Clip *c)
{
return std::make_shared<VSTHost>(c);
}
void VSTHost::process_audio(double timecode_start,
double timecode_end,
float **samples,
@@ -291,7 +321,7 @@ void VSTHost::custom_load(QXmlStreamReader &stream) {
}
void VSTHost::save(QXmlStreamWriter &stream) {
Effect::save(stream);
Node::save(stream);
if (plugin != nullptr) {
char* p = nullptr;
int32_t length = int32_t(dispatcher(plugin, effGetChunk, 0, 0, &p, 0));
+12 -4
View File
@@ -24,7 +24,7 @@
#include <QDialog>
#include <QLibrary>
#include "effects/effect.h"
#include "nodes/node.h"
#include "include/vestige.h"
// Plugin's dispatcher function
@@ -46,11 +46,19 @@ private:
void destroy();
};
class VSTHost : public Effect {
class VSTHost : public Node {
Q_OBJECT
public:
VSTHost(Clip* c, const EffectMeta* em);
~VSTHost();
VSTHost(Clip* c);
virtual ~VSTHost() override;
virtual QString name() override;
virtual QString id() override;
virtual QString description() override;
virtual EffectType type() override;
virtual olive::TrackType subtype() override;
virtual NodePtr Create(Clip *c) override;
virtual void process_audio(double timecode_start,
double timecode_end,
float **samples,
+22 -24
View File
@@ -40,27 +40,34 @@
#include <QMessageBox>
#include <QCoreApplication>
Transition::Transition(Clip *c, Clip *s, const EffectMeta* em) :
Effect(c, em),
secondary_clip(s)
Transition::Transition(Clip *c) :
Node(c),
secondary_clip(nullptr)
{
length_field = new DoubleInput(this, "length", tr("Length"), false, false);
length_field->SetDefault(30);
length_field->SetMinimum(1);
length_field->SetDisplayType(LabelSlider::FrameNumber);
length_field->SetFrameRate(parent_clip->track()->sequence() == nullptr ?
parent_clip->cached_frame_rate() : parent_clip->track()->sequence()->frame_rate);
if (parent_clip != nullptr) {
length_field->SetFrameRate(parent_clip->track()->sequence() == nullptr ?
parent_clip->cached_frame_rate() : parent_clip->track()->sequence()->frame_rate);
}
connect(length_field, SIGNAL(Changed()), this, SLOT(UpdateMaximumLength()));
}
TransitionPtr Transition::copy(Clip *c, Clip *s) {
return Transition::Create(c, s, meta, get_true_length());
NodePtr Transition::copy(Clip *c) {
NodePtr node = Node::copy(c);
static_cast<Transition*>(node.get())->set_length(get_true_length());
return node;
}
void Transition::save(QXmlStreamWriter &stream) {
stream.writeAttribute("length", QString::number(get_true_length()));
Effect::save(stream);
Node::save(stream);
}
void Transition::set_length(int l) {
@@ -96,17 +103,18 @@ Clip* Transition::get_closed_clip() {
return nullptr;
}
TransitionPtr Transition::CreateFromMeta(Clip* c, Clip* s, const EffectMeta* em) {
/*
TransitionPtr Transition::CreateFromMeta(Clip* c, Clip* s) {
if (!em->filename.isEmpty()) {
// load effect from file
return TransitionPtr(new Transition(c, s, em));
} else if (em->internal >= 0 && em->internal < TRANSITION_INTERNAL_COUNT) {
// must be an internal effect
switch (em->internal) {
case TRANSITION_INTERNAL_CROSSDISSOLVE: return TransitionPtr(new CrossDissolveTransition(c, s, em));
case TRANSITION_INTERNAL_LINEARFADE: return TransitionPtr(new LinearFadeTransition(c, s, em));
case TRANSITION_INTERNAL_EXPONENTIALFADE: return TransitionPtr(new ExponentialFadeTransition(c, s, em));
case TRANSITION_INTERNAL_LOGARITHMICFADE: return TransitionPtr(new LogarithmicFadeTransition(c, s, em));
case kCrossDissolveTransition: return TransitionPtr(new CrossDissolveTransition(c, s, em));
case kLinearFadeTransition: return TransitionPtr(new LinearFadeTransition(c, s, em));
case kExponentialFadeTransition: return TransitionPtr(new ExponentialFadeTransition(c, s, em));
case kLogarithmicFadeTransition: return TransitionPtr(new LogarithmicFadeTransition(c, s, em));
//case TRANSITION_INTERNAL_CUBE: return TransitionPtr(new CubeTransition(c, s, em));
}
} else {
@@ -118,6 +126,7 @@ TransitionPtr Transition::CreateFromMeta(Clip* c, Clip* s, const EffectMeta* em)
}
return nullptr;
}
*/
void Transition::UpdateMaximumLength()
{
@@ -154,14 +163,3 @@ long Transition::GetMaximumEmptySpaceOnClip(Clip *c)
return maximum_transition_length;
}
TransitionPtr Transition::Create(Clip* c, Clip* s, const EffectMeta* em, long length) {
TransitionPtr t(CreateFromMeta(c, s, em));
if (t != nullptr) {
if (length > 0) {
t->set_length(length);
}
return t;
}
return nullptr;
}
+7 -15
View File
@@ -21,7 +21,8 @@
#ifndef TRANSITION_H
#define TRANSITION_H
#include "effect.h"
#include "nodes/node.h"
#include "nodes/inputs.h"
enum TransitionType {
kTransitionNone,
@@ -29,23 +30,16 @@ enum TransitionType {
kTransitionClosing
};
enum TransitionInternal {
TRANSITION_INTERNAL_CROSSDISSOLVE,
TRANSITION_INTERNAL_LINEARFADE,
TRANSITION_INTERNAL_EXPONENTIALFADE,
TRANSITION_INTERNAL_LOGARITHMICFADE,
//TRANSITION_INTERNAL_CUBE,
TRANSITION_INTERNAL_COUNT
};
class Transition;
using TransitionPtr = std::shared_ptr<Transition>;
class Transition : public Effect {
class Transition : public Node {
Q_OBJECT
public:
Transition(Clip* c, Clip* s, const EffectMeta* em);
virtual TransitionPtr copy(Clip* c, Clip* s);
Transition(Clip* c);
virtual NodePtr copy(Clip* c) override;
Clip* secondary_clip;
virtual void save(QXmlStreamWriter& stream) override;
@@ -57,8 +51,6 @@ public:
Clip* get_opened_clip();
Clip* get_closed_clip();
static TransitionPtr Create(Clip* c, Clip* s, const EffectMeta* em, long length = 0);
static TransitionPtr CreateFromMeta(Clip *c, Clip *s, const EffectMeta* em);
private:
DoubleInput* length_field;