merged effects into node structure
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <QVector>
|
||||
|
||||
#include "effects/keyframe.h"
|
||||
#include "undo/undo.h"
|
||||
#include "undo/undostack.h"
|
||||
#include "nodes/nodedatatypes.h"
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "../effectfield.h"
|
||||
#include "ui/labelslider.h"
|
||||
|
||||
class KeyframeDataChange;
|
||||
|
||||
/**
|
||||
* @brief The DoubleField class
|
||||
*
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user