diff --git a/app/node/factory.cpp b/app/node/factory.cpp index 6a488f76f..eb0eca531 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -31,6 +31,7 @@ #include "generator/solid/solid.h" #include "generator/text/text.h" #include "filter/blur/blur.h" +#include "filter/mosaic/mosaicfilternode.h" #include "filter/stroke/stroke.h" #include "input/media/media.h" #include "input/time/timeinput.h" @@ -212,6 +213,8 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id) return new CrossDissolveTransition(); case kDipToColorTransition: return new DipToColorTransition(); + case kMosaicFilter: + return new MosaicFilterNode(); case kInternalNodeCount: break; diff --git a/app/node/factory.h b/app/node/factory.h index 63f13f258..4b5942119 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -51,6 +51,7 @@ public: kTextGenerator, kCrossDissolveTransition, kDipToColorTransition, + kMosaicFilter, // Count value kInternalNodeCount diff --git a/app/node/filter/CMakeLists.txt b/app/node/filter/CMakeLists.txt index 6e3351a58..95e7ce21c 100644 --- a/app/node/filter/CMakeLists.txt +++ b/app/node/filter/CMakeLists.txt @@ -15,6 +15,7 @@ # along with this program. If not, see . add_subdirectory(blur) +add_subdirectory(mosaic) add_subdirectory(stroke) set(OLIVE_SOURCES diff --git a/app/node/filter/mosaic/CMakeLists.txt b/app/node/filter/mosaic/CMakeLists.txt new file mode 100644 index 000000000..17c75fa7e --- /dev/null +++ b/app/node/filter/mosaic/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2020 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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + node/filter/mosaic/mosaicfilternode.h + node/filter/mosaic/mosaicfilternode.cpp + PARENT_SCOPE +) diff --git a/app/node/filter/mosaic/mosaicfilternode.cpp b/app/node/filter/mosaic/mosaicfilternode.cpp new file mode 100644 index 000000000..8e657151a --- /dev/null +++ b/app/node/filter/mosaic/mosaicfilternode.cpp @@ -0,0 +1,81 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 "mosaicfilternode.h" + +namespace olive { + +MosaicFilterNode::MosaicFilterNode() +{ + tex_input_ = new NodeInput(QStringLiteral("tex_in"), NodeParam::kTexture); + AddInput(tex_input_); + + horiz_input_ = new NodeInput(QStringLiteral("horiz_in"), NodeParam::kFloat); + horiz_input_->set_property(QStringLiteral("min"), 1.0f); + AddInput(horiz_input_); + + vert_input_ = new NodeInput(QStringLiteral("vert_in"), NodeParam::kFloat); + vert_input_->set_property(QStringLiteral("min"), 1.0f); + AddInput(vert_input_); +} + +void MosaicFilterNode::Retranslate() +{ + tex_input_->set_name(tr("Texture")); + horiz_input_->set_name(tr("Horizontal")); + vert_input_->set_name(tr("Vertical")); +} + +NodeValueTable MosaicFilterNode::Value(NodeValueDatabase &value) const +{ + ShaderJob job; + + job.InsertValue(tex_input_, value); + job.InsertValue(horiz_input_, value); + job.InsertValue(vert_input_, value); + + // Mipmapping makes this look weird + job.SetInterpolation(tex_input_, Texture::kLinear); + + NodeValueTable table = value.Merge(); + + if (!job.GetValue(tex_input_).data.isNull()) { + TexturePtr texture = job.GetValue(tex_input_).data.value(); + + if (texture + && job.GetValue(horiz_input_).data.toInt() != texture->width() + && job.GetValue(vert_input_).data.toInt() != texture->height()) { + table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); + } else { + table.Push(job.GetValue(tex_input_), this); + } + } + + return table; +} + +ShaderCode MosaicFilterNode::GetShaderCode(const QString &shader_id) const +{ + Q_UNUSED(shader_id) + + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/mosaic.frag"), QString()); +} + +} diff --git a/app/node/filter/mosaic/mosaicfilternode.h b/app/node/filter/mosaic/mosaicfilternode.h new file mode 100644 index 000000000..104e05b31 --- /dev/null +++ b/app/node/filter/mosaic/mosaicfilternode.h @@ -0,0 +1,75 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2020 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 . + +***/ + +#ifndef MOSAICFILTERNODE_H +#define MOSAICFILTERNODE_H + +#include "node/node.h" + +namespace olive { + +class MosaicFilterNode : public Node +{ + Q_OBJECT +public: + MosaicFilterNode(); + + virtual Node* copy() const override + { + return new MosaicFilterNode(); + } + + virtual QString Name() const override + { + return tr("Mosaic"); + } + + virtual QString id() const override + { + return QStringLiteral("org.olivevideoeditor.Olive.mosaicfilter"); + } + + virtual QVector Category() const override + { + return {kCategoryFilter}; + } + + virtual QString Description() const override + { + return tr("Apply a pixelated mosaic filter to video."); + } + + virtual void Retranslate() override; + + virtual NodeValueTable Value(NodeValueDatabase &value) const override; + virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + +private: + NodeInput* tex_input_; + + NodeInput* horiz_input_; + + NodeInput* vert_input_; + +}; + +} + +#endif // MOSAICFILTERNODE_H diff --git a/app/shaders/mosaic.frag b/app/shaders/mosaic.frag new file mode 100644 index 000000000..3321e9937 --- /dev/null +++ b/app/shaders/mosaic.frag @@ -0,0 +1,38 @@ +#version 150 + +#ifdef GL_ES +precision highp int; +precision highp float; +#endif + +// Input texture +uniform sampler2D tex_in; + +uniform float horiz_in; +uniform float vert_in; + +// Input texture coordinate +in vec2 ove_texcoord; + +// Output color +out vec4 fragColor; + +void main() { + float x; + float y; + + if (horiz_in > 0.0) { + x = floor(ove_texcoord.x * horiz_in) / horiz_in; + } else { + x = ove_texcoord.x; + } + + if (vert_in > 0.0) { + y = floor(ove_texcoord.y * vert_in) / vert_in; + } else { + y = ove_texcoord.y; + } + + vec4 color = texture(tex_in, vec2(x, y)); + fragColor = color; +}