/***
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 .
***/
#include "effectloaders.h"
#include "project/effect.h"
#include "project/transition.h"
#include "io/path.h"
#include "panels/panels.h"
#include "panels/effectcontrols.h"
#include "io/crossplatformlib.h"
#include "io/config.h"
#include
#include
#include
QMutex olive::effects_loaded;
#ifndef NO_FREI0R
#include
typedef void (*f0rGetPluginInfo)(f0r_plugin_info_t* info);
#endif
void load_internal_effects() {
if (!olive::CurrentRuntimeConfig.shaders_are_enabled) qWarning() << "Shaders are disabled, some effects may be nonfunctional";
EffectMeta em;
// load internal effects
em.path = ":/internalshaders";
em.type = EFFECT_TYPE_EFFECT;
em.subtype = EFFECT_TYPE_AUDIO;
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 = EFFECT_TYPE_VIDEO;
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 = "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 = EFFECT_TYPE_AUDIO;
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);
}
void load_shader_effects() {
QList effects_paths = get_effects_paths();
for (int h=0;h entries = effects_dir.entryList(QStringList("*.xml"), QDir::Files);
for (int i=0;i blend_mode_entries = effects_dir.entryList(QStringList("*.blend"), QDir::Files);
for (int i=0;istart();
}
#ifndef NO_FREI0R
void load_frei0r_effects_worker(const QString& dir, EffectMeta& em, QVector& loaded_names) {
QDir search_dir(dir);
if (search_dir.exists()) {
QList entry_list = search_dir.entryList(LibFilter(), QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
for (int j=0;j(LibAddress(effect, "f0r_get_plugin_info"));
if (get_info_func != nullptr) {
f0r_plugin_info_t info;
get_info_func(&info);
if (!loaded_names.contains(info.name)
&& info.plugin_type == F0R_PLUGIN_TYPE_FILTER
&& info.color_model == F0R_COLOR_MODEL_RGBA8888) {
em.name = info.name;
em.path = dir;
em.filename = entry_list.at(j);
em.tooltip = QString("%1\n%2\n%3\n%4").arg(em.name, info.author, info.explanation, em.filename);
loaded_names.append(em.name);
olive::effects.append(em);
}
// qDebug() << "Found:" << info.name << "by" << info.author;
}
LibClose(effect);
}
// qDebug() << search_dir.filePath(entry_list.at(j));
}
}
}
}
void load_frei0r_effects() {
QList effect_dirs = get_effects_paths();
// add defined paths for frei0r plugins on unix
#if defined(__APPLE__) || defined(__linux__) || defined(__HAIKU__)
effect_dirs.prepend("/usr/lib/frei0r-1");
effect_dirs.prepend("/usr/local/lib/frei0r-1");
effect_dirs.prepend(QDir::homePath() + "/.frei0r-1/lib");
#endif
QString env_path(qgetenv("FREI0R_PATH"));
if (!env_path.isEmpty()) effect_dirs.append(env_path);
QVector loaded_names;
// search for paths
EffectMeta em;
em.category = "Frei0r";
em.type = EFFECT_TYPE_EFFECT;
em.subtype = EFFECT_TYPE_VIDEO;
em.internal = EFFECT_INTERNAL_FREI0R;
for (int i=0;i 0 && line.at(0) == '#') {
if (line.startsWith("#olive name ")) {
// The blending mode can specify its own name
b.name = line.mid(12);
} else if (line.startsWith("#pragma glslify: export(")) {
// Get function name
b.function_name = line.mid(24, line.length()-25);
} else if (line.contains("require")) {
// This function wanted to include an external shader
int index_of_last_bracked = line.lastIndexOf('(') + 1;
QString include_fn = line.mid(index_of_last_bracked, line.length() - index_of_last_bracked - 1);
include_fn.append(".blend");
QString include_path = QFileInfo(b.url).dir().filePath(include_fn);
// see if this file is already in the blend modes list
bool found = false;
for (int i=0;i 0.0) {\n"
" float true_opacity = opacity * fg_color.a;\n"
" vec3 unmultipled_fg = max(vec3(0.0), min(vec3(1.0), fg_color.rgb / fg_color.a));\n"
" vec3 blended_rgb = blend(bg_color.rgb, unmultipled_fg, true_opacity);\n" // Use switcher function above to blend RGBs
" vec4 composite = vec4(blended_rgb, bg_color.a + true_opacity);\n"
" gl_FragColor = composite;\n"
" } else {\n"
" gl_FragColor = bg_color;\n"
" }\n"
"}\n");
}
EffectInit::EffectInit() {
olive::effects_loaded.lock();
}
void EffectInit::run() {
qInfo() << "Initializing effects...";
load_internal_effects();
load_shader_effects();
#ifndef NO_FREI0R
load_frei0r_effects();
#endif
GenerateBlendingShader();
olive::effects_loaded.unlock();
qInfo() << "Finished initializing effects";
}