diff --git a/app/node/factory.cpp b/app/node/factory.cpp
index dfd2fef61..ee2fe3892 100644
--- a/app/node/factory.cpp
+++ b/app/node/factory.cpp
@@ -27,6 +27,7 @@
#include "generator/matrix/matrix.h"
#include "generator/polygon/polygon.h"
#include "generator/solid/solid.h"
+#include "generator/text/text.h"
#include "filter/blur/blur.h"
#include "filter/stroke/stroke.h"
#include "input/media/video/video.h"
@@ -201,6 +202,8 @@ Node *NodeFactory::CreateInternal(const NodeFactory::InternalID &id)
return new MergeNode();
case kStrokeFilter:
return new StrokeFilterNode();
+ case kTextGenerator:
+ return new TextGenerator();
case kInternalNodeCount:
break;
diff --git a/app/node/factory.h b/app/node/factory.h
index c82b2b63e..b5c1b6f0f 100644
--- a/app/node/factory.h
+++ b/app/node/factory.h
@@ -49,6 +49,7 @@ public:
kSolidGenerator,
kMerge,
kStrokeFilter,
+ kTextGenerator,
// Count value
kInternalNodeCount
diff --git a/app/node/generator/CMakeLists.txt b/app/node/generator/CMakeLists.txt
index 52d74e469..264d7dade 100644
--- a/app/node/generator/CMakeLists.txt
+++ b/app/node/generator/CMakeLists.txt
@@ -17,6 +17,7 @@
add_subdirectory(matrix)
add_subdirectory(polygon)
add_subdirectory(solid)
+add_subdirectory(text)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
diff --git a/app/node/generator/text/CMakeLists.txt b/app/node/generator/text/CMakeLists.txt
new file mode 100644
index 000000000..ec2049f42
--- /dev/null
+++ b/app/node/generator/text/CMakeLists.txt
@@ -0,0 +1,22 @@
+# 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 .
+
+set(OLIVE_SOURCES
+ ${OLIVE_SOURCES}
+ node/generator/text/text.h
+ node/generator/text/text.cpp
+ PARENT_SCOPE
+)
diff --git a/app/node/generator/text/text.cpp b/app/node/generator/text/text.cpp
new file mode 100644
index 000000000..78a09332a
--- /dev/null
+++ b/app/node/generator/text/text.cpp
@@ -0,0 +1,119 @@
+/***
+
+ 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 "text.h"
+
+#include
+
+OLIVE_NAMESPACE_ENTER
+
+TextGenerator::TextGenerator()
+{
+ QString default_str = QStringLiteral("%1
").arg(tr("Sample Text"));
+
+ text_input_ = new NodeInput(QStringLiteral("text_in"),
+ NodeParam::kText,
+ default_str);
+ AddInput(text_input_);
+
+ color_input_ = new NodeInput(QStringLiteral("color_in"),
+ NodeParam::kColor,
+ QVariant::fromValue(Color(1.0f, 1.0f, 1.0)));
+ AddInput(color_input_);
+}
+
+Node *TextGenerator::copy() const
+{
+ return new TextGenerator();
+}
+
+QString TextGenerator::Name() const
+{
+ return tr("Text");
+}
+
+QString TextGenerator::id() const
+{
+ return QStringLiteral("org.olivevideoeditor.Olive.textgenerator");
+}
+
+QList TextGenerator::Category() const
+{
+ return {kCategoryGenerator};
+}
+
+QString TextGenerator::Description() const
+{
+ return tr("Generate rich text.");
+}
+
+void TextGenerator::Retranslate()
+{
+ text_input_->set_name(tr("Text"));
+ color_input_->set_name(tr("Color"));
+}
+
+NodeValueTable TextGenerator::Value(NodeValueDatabase &value) const
+{
+ GenerateJob job;
+ job.InsertValue(text_input_, value);
+ job.InsertValue(color_input_, value);
+ job.SetAlphaChannelRequired(true);
+
+ NodeValueTable table = value.Merge();
+
+ if (!job.GetValue(text_input_).data().toString().isEmpty()) {
+ table.Push(NodeParam::kGenerateJob, QVariant::fromValue(job), this);
+ }
+
+ return table;
+}
+
+void TextGenerator::GenerateFrame(FramePtr frame, const GenerateJob& job) const
+{
+ // This could probably be more optimized, but for now we use Qt to draw to a QImage.
+ // QImages only support integer pixels and we use float pixels, so what we do here is draw onto
+ // a single-channel QImage (alpha only) and then transplant that alpha channel to our float buffer
+ // with correct float RGB.
+ QImage img(frame->width(), frame->height(), QImage::Format_Grayscale8);
+ img.fill(0);
+
+ QTextDocument text_doc;
+ text_doc.setHtml(job.GetValue(text_input_).data().toString());
+ text_doc.setTextWidth(frame->video_params().width());
+
+ // Draw rich text onto image
+ QPainter p(&img);
+ p.scale(1.0 / frame->video_params().divider(), 1.0 / frame->video_params().divider());
+ text_doc.drawContents(&p);
+
+ // Transplant alpha channel to frame
+ Color rgb = job.GetValue(color_input_).data().value();
+ for (int x=0; xwidth(); x++) {
+ for (int y=0; yheight(); y++) {
+ uchar src_alpha = img.bits()[img.bytesPerLine() * y + x];
+ float alpha = float(src_alpha) / 255.0f;
+
+ frame->set_pixel(x, y, Color(rgb.red() * alpha, rgb.green() * alpha, rgb.blue() * alpha, alpha));
+ }
+ }
+}
+
+OLIVE_NAMESPACE_EXIT
diff --git a/app/node/generator/text/text.h b/app/node/generator/text/text.h
new file mode 100644
index 000000000..3f28626c2
--- /dev/null
+++ b/app/node/generator/text/text.h
@@ -0,0 +1,55 @@
+/***
+
+ 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 .
+
+***/
+
+#ifndef TEXTGENERATOR_H
+#define TEXTGENERATOR_H
+
+#include "node/node.h"
+
+OLIVE_NAMESPACE_ENTER
+
+class TextGenerator : public Node
+{
+public:
+ TextGenerator();
+
+ virtual Node* copy() const override;
+
+ virtual QString Name() const override;
+ virtual QString id() const override;
+ virtual QList Category() const override;
+ virtual QString Description() const override;
+
+ virtual void Retranslate() override;
+
+ virtual NodeValueTable Value(NodeValueDatabase& value) const override;
+
+ virtual void GenerateFrame(FramePtr frame, const GenerateJob &job) const override;
+
+private:
+ NodeInput* text_input_;
+
+ NodeInput* color_input_;
+
+};
+
+OLIVE_NAMESPACE_EXIT
+
+#endif // TEXTGENERATOR_H
diff --git a/app/widget/timelinewidget/tool/add.cpp b/app/widget/timelinewidget/tool/add.cpp
index 19e6f5322..1e1a538e0 100644
--- a/app/widget/timelinewidget/tool/add.cpp
+++ b/app/widget/timelinewidget/tool/add.cpp
@@ -124,8 +124,18 @@ void TimelineWidget::AddTool::MouseRelease(TimelineViewMouseEvent *event)
new NodeEdgeAddCommand(solid->output(), clip->texture_input(), command);
break;
}
- case OLIVE_NAMESPACE::Tool::kAddableBars:
case OLIVE_NAMESPACE::Tool::kAddableTitle:
+ {
+ Node* text = NodeFactory::CreateFromID(QStringLiteral("org.olivevideoeditor.Olive.textgenerator"));
+
+ new NodeAddCommand(graph,
+ text,
+ command);
+
+ new NodeEdgeAddCommand(text->output(), clip->texture_input(), command);
+ break;
+ }
+ case OLIVE_NAMESPACE::Tool::kAddableBars:
case OLIVE_NAMESPACE::Tool::kAddableTone:
// Not implemented yet
qWarning() << "Unimplemented add object:" << Core::instance()->selected_addable_object();