diff --git a/app/node/factory.cpp b/app/node/factory.cpp index 9e18f0a99..9f6c7f335 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -33,6 +33,7 @@ #include "distort/transform/transformdistortnode.h" #include "generator/matrix/matrix.h" #include "generator/polygon/polygon.h" +#include "generator/shape/shapenode.h" #include "generator/solid/solid.h" #include "generator/text/text.h" #include "filter/blur/blur.h" @@ -239,13 +240,14 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id) return new TimeRemapNode(); case kSubtitleBlock: return new SubtitleBlock(); + case kShapeGenerator: + return new ShapeNode(); case kInternalNodeCount: break; } - // We should never get here - abort(); + return nullptr; } } diff --git a/app/node/factory.h b/app/node/factory.h index 8ba811cd3..a53a3d6ff 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -59,6 +59,7 @@ public: kValueNode, kTimeRemapNode, kSubtitleBlock, + kShapeGenerator, // Count value kInternalNodeCount diff --git a/app/node/generator/CMakeLists.txt b/app/node/generator/CMakeLists.txt index 8c5706e50..dfdabb071 100644 --- a/app/node/generator/CMakeLists.txt +++ b/app/node/generator/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory(matrix) add_subdirectory(polygon) +add_subdirectory(shape) add_subdirectory(solid) add_subdirectory(text) diff --git a/app/node/generator/shape/CMakeLists.txt b/app/node/generator/shape/CMakeLists.txt new file mode 100644 index 000000000..b3d0fed04 --- /dev/null +++ b/app/node/generator/shape/CMakeLists.txt @@ -0,0 +1,24 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2021 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/generator/shape/shapenode.cpp + node/generator/shape/shapenode.h + node/generator/shape/shapenodebase.cpp + node/generator/shape/shapenodebase.h + PARENT_SCOPE +) diff --git a/app/node/generator/shape/shapenode.cpp b/app/node/generator/shape/shapenode.cpp new file mode 100644 index 000000000..0c8f258a4 --- /dev/null +++ b/app/node/generator/shape/shapenode.cpp @@ -0,0 +1,89 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 "shapenode.h" + +namespace olive { + +#define super ShapeNodeBase + +QString ShapeNode::kTypeInput = QStringLiteral("type_in"); + +ShapeNode::ShapeNode() +{ + PrependInput(kTypeInput, NodeValue::kCombo); +} + +QString ShapeNode::Name() const +{ + return tr("Shape"); +} + +QString ShapeNode::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.shape"); +} + +QVector ShapeNode::Category() const +{ + return {kCategoryGenerator}; +} + +QString ShapeNode::Description() const +{ + return tr("Generate a 2D primitive shape."); +} + +void ShapeNode::Retranslate() +{ + super::Retranslate(); + + SetInputName(kTypeInput, tr("Type")); + + // Coordinate with Type enum + SetComboBoxStrings(kTypeInput, {tr("Rectangle"), tr("Ellipse")}); +} + +ShaderCode ShapeNode::GetShaderCode(const QString &shader_id) const +{ + Q_UNUSED(shader_id) + + return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/shape.frag"))); +} + +NodeValueTable ShapeNode::Value(const QString &output, NodeValueDatabase &value) const +{ + Q_UNUSED(output) + + ShaderJob job; + + job.InsertValue(this, kTypeInput, value); + job.InsertValue(this, kPositionInput, value); + job.InsertValue(this, kSizeInput, value); + job.InsertValue(this, kColorInput, value); + job.InsertValue(QStringLiteral("resolution_in"), value[QStringLiteral("global")].GetWithMeta(NodeValue::kVec2, QStringLiteral("resolution"))); + job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); + + NodeValueTable table = value.Merge(); + table.Push(NodeValue::kShaderJob, QVariant::fromValue(job), this); + return table; +} + +} diff --git a/app/node/generator/shape/shapenode.h b/app/node/generator/shape/shapenode.h new file mode 100644 index 000000000..0381be00d --- /dev/null +++ b/app/node/generator/shape/shapenode.h @@ -0,0 +1,61 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 SHAPENODE_H +#define SHAPENODE_H + +#include "shapenodebase.h" + +namespace olive { + +class ShapeNode : public ShapeNodeBase +{ + Q_OBJECT +public: + ShapeNode(); + + enum Type { + kRectangle, + kEllipse + }; + + NODE_DEFAULT_DESTRUCTOR(ShapeNode) + NODE_COPY_FUNCTION(ShapeNode) + + virtual QString Name() const override; + virtual QString id() const override; + virtual QVector Category() const override; + virtual QString Description() const override; + + virtual void Retranslate() override; + + virtual ShaderCode GetShaderCode(const QString& shader_id) const override; + virtual NodeValueTable Value(const QString& output, NodeValueDatabase& value) const override; + + static QString kTypeInput; + +private: + + +}; + +} + +#endif // SHAPENODE_H diff --git a/app/node/generator/shape/shapenodebase.cpp b/app/node/generator/shape/shapenodebase.cpp new file mode 100644 index 000000000..e8e77db77 --- /dev/null +++ b/app/node/generator/shape/shapenodebase.cpp @@ -0,0 +1,49 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 "shapenodebase.h" + +#include + +namespace olive { + +#define super Node + +QString ShapeNodeBase::kPositionInput = QStringLiteral("pos_in"); +QString ShapeNodeBase::kSizeInput = QStringLiteral("size_in"); +QString ShapeNodeBase::kColorInput = QStringLiteral("color_in"); + +ShapeNodeBase::ShapeNodeBase() +{ + AddInput(kPositionInput, NodeValue::kVec2, QVector2D(10, 10)); + AddInput(kSizeInput, NodeValue::kVec2, QVector2D(100, 100)); + AddInput(kColorInput, NodeValue::kColor, QVariant::fromValue(Color(1.0, 0.0, 0.0, 1.0))); +} + +void ShapeNodeBase::Retranslate() +{ + super::Retranslate(); + + SetInputName(kPositionInput, tr("Position")); + SetInputName(kSizeInput, tr("Size")); + SetInputName(kColorInput, tr("Color")); +} + +} diff --git a/app/node/generator/shape/shapenodebase.h b/app/node/generator/shape/shapenodebase.h new file mode 100644 index 000000000..368b3f20a --- /dev/null +++ b/app/node/generator/shape/shapenodebase.h @@ -0,0 +1,46 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 SHAPENODEBASE_H +#define SHAPENODEBASE_H + +#include "node/node.h" + +namespace olive { + +class ShapeNodeBase : public Node +{ + Q_OBJECT +public: + ShapeNodeBase(); + + NODE_DEFAULT_DESTRUCTOR(ShapeNodeBase) + + virtual void Retranslate() override; + + static QString kPositionInput; + static QString kSizeInput; + static QString kColorInput; + +}; + +} + +#endif // SHAPENODEBASE_H diff --git a/app/node/node.h b/app/node/node.h index 22c02b528..dde2e706f 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -46,7 +46,11 @@ namespace olive { -#define NODE_DEFAULT_DESTRUCTOR(x) virtual ~x() override {DisconnectAll();} +#define NODE_DEFAULT_DESTRUCTOR(x) \ + virtual ~x() override {DisconnectAll();} + +#define NODE_COPY_FUNCTION(x) \ + virtual Node *copy() const override {return new x();} class NodeGraph; class Folder; diff --git a/app/shaders/shape.frag b/app/shaders/shape.frag new file mode 100644 index 000000000..2c379b586 --- /dev/null +++ b/app/shaders/shape.frag @@ -0,0 +1,39 @@ +// Input texture coordinate +varying vec2 ove_texcoord; + +// Match with ShapeNode::Type +#define SHAPE_RECTANGLE 0 +#define SHAPE_ELLIPSE 1 + +uniform vec2 pos_in; +uniform vec2 size_in; +uniform int type_in; +uniform vec2 resolution_in; +uniform vec4 color_in; + +void main() { + vec2 real_position = pos_in/resolution_in; + vec2 real_size = size_in/resolution_in; + + vec4 col = vec4(0.0); + + if (type_in == SHAPE_RECTANGLE) { + if (ove_texcoord.x >= real_position.x && ove_texcoord.y >= real_position.y + && ove_texcoord.x < real_position.x+real_size.x && ove_texcoord.y < real_position.y+real_size.y) { + col = color_in; + } + } else if (type_in == SHAPE_ELLIPSE) { + vec2 center = pos_in+size_in*0.5; + float radius = size_in.y*0.5; + float aspect_ratio = size_in.x/size_in.y; + + vec2 offset = ove_texcoord*resolution_in - center; + offset.x /= aspect_ratio; + float d = length(offset)-radius; + float t = clamp(d, 0.0, 1.0); + + col = color_in * (1.0-t); + } + + gl_FragColor = col; +}