diff --git a/app/codec/oiio/oiiodecoder.cpp b/app/codec/oiio/oiiodecoder.cpp index 27e02991f..1f2b136b3 100644 --- a/app/codec/oiio/oiiodecoder.cpp +++ b/app/codec/oiio/oiiodecoder.cpp @@ -174,9 +174,10 @@ FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const int& divider FramePtr frame = Frame::Create(); - frame->set_video_params(VideoRenderingParams(buffer_->spec().width / divider, - buffer_->spec().height / divider, - pix_fmt_)); + frame->set_video_params(VideoRenderingParams(buffer_->spec().width, + buffer_->spec().height, + pix_fmt_, + divider)); frame->allocate(); if (divider == 1) { diff --git a/app/config/config.cpp b/app/config/config.cpp index 6870ad296..a5d031c47 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -83,6 +83,16 @@ void Config::SetDefaults() config_map_["DropWithoutSequenceBehavior"] = TimelineWidget::kDWSAsk; config_map_["Loop"] = false; + config_map_["NodeCatColor0"] = QVariant::fromValue(Color(0.25, 0.25, 0.65)); + config_map_["NodeCatColor1"] = QVariant::fromValue(Color(0.6, 0.6, 0.85)); + config_map_["NodeCatColor2"] = QVariant::fromValue(Color(0.75, 0.75, 0.45)); + config_map_["NodeCatColor3"] = QVariant::fromValue(Color(0.25, 0.5, 0.25)); + config_map_["NodeCatColor4"] = QVariant::fromValue(Color(0.25, 0.65, 0.25)); + config_map_["NodeCatColor5"] = QVariant::fromValue(Color(0.35, 0.35, 0.35)); + config_map_["NodeCatColor6"] = QVariant::fromValue(Color(0.45, 0.45, 0.45)); + config_map_["NodeCatColor7"] = QVariant::fromValue(Color(0.7, 0.3, 0.7)); + config_map_["NodeCatColor8"] = QVariant::fromValue(Color(0.85, 0.65, 0.4)); + config_map_["AudioOutput"] = QString(); config_map_["AudioInput"] = QString(); diff --git a/app/dialog/preferences/tabs/preferencesappearancetab.cpp b/app/dialog/preferences/tabs/preferencesappearancetab.cpp index 0324fc661..4078c1f0f 100644 --- a/app/dialog/preferences/tabs/preferencesappearancetab.cpp +++ b/app/dialog/preferences/tabs/preferencesappearancetab.cpp @@ -20,10 +20,14 @@ #include "preferencesappearancetab.h" +#include #include #include +#include #include -#include + +#include "node/node.h" +#include "widget/colorbutton/colorbutton.h" OLIVE_NAMESPACE_ENTER @@ -44,7 +48,7 @@ PreferencesAppearanceTab::PreferencesAppearanceTab() style_list_ = StyleManager::ListInternal(); - foreach (StyleDescriptor s, style_list_) { + foreach (const StyleDescriptor& s, style_list_) { style_->addItem(s.name(), s.path()); if (s.path() == StyleManager::GetStyle()) { @@ -52,10 +56,34 @@ PreferencesAppearanceTab::PreferencesAppearanceTab() } } - appearance_layout->addWidget(style_, row, 1, 1, 2); + appearance_layout->addWidget(style_, row, 1); row++; + { + QGroupBox* color_group = new QGroupBox(); + color_group->setTitle(tr("Node Color Scheme")); + + QGridLayout* color_layout = new QGridLayout(color_group); + + for (int i=0; i(i)); + color_layout->addWidget(new QLabel(cat_name), i, 0); + + Color c = Config::Current()[QStringLiteral("NodeCatColor%1").arg(i)].value(); + colors_.append(c.toQColor()); + + QPushButton* color_btn = new QPushButton(); + connect(color_btn, &QPushButton::clicked, this, &PreferencesAppearanceTab::ColorButtonClicked); + color_layout->addWidget(color_btn, i, 1); + color_btns_.append(color_btn); + + UpdateButtonColor(i); + } + + appearance_layout->addWidget(color_group, row, 0, 1, 2); + } + layout->addStretch(); } @@ -67,6 +95,29 @@ void PreferencesAppearanceTab::Accept() StyleManager::SetStyle(style_path); Config::Current()["Style"] = style_path; } + + for (int i=0;isetStyleSheet(QStringLiteral("background: %1;") + .arg(colors_.at(index).name())); +} + +void PreferencesAppearanceTab::ColorButtonClicked() +{ + int index = color_btns_.indexOf(static_cast(sender())); + + QColor new_color = QColorDialog::getColor(colors_.at(index), this); + + if (new_color.isValid()) { + colors_.replace(index, new_color); + + UpdateButtonColor(index); + } } OLIVE_NAMESPACE_EXIT diff --git a/app/dialog/preferences/tabs/preferencesappearancetab.h b/app/dialog/preferences/tabs/preferencesappearancetab.h index cf3b97d71..1ab267eb5 100644 --- a/app/dialog/preferences/tabs/preferencesappearancetab.h +++ b/app/dialog/preferences/tabs/preferencesappearancetab.h @@ -23,6 +23,7 @@ #include #include +#include #include "preferencestab.h" #include "ui/style/style.h" @@ -43,6 +44,8 @@ private: */ void BrowseForCSS(); + void UpdateButtonColor(int index); + /** * @brief UI widget for selecting the current UI style */ @@ -54,6 +57,14 @@ private: QList style_list_; QString custom_style_path_; + + QList colors_; + + QList color_btns_; + +private slots: + void ColorButtonClicked(); + }; OLIVE_NAMESPACE_EXIT diff --git a/app/dialog/projectproperties/projectproperties.cpp b/app/dialog/projectproperties/projectproperties.cpp index 6e79a1aae..e8dc50195 100644 --- a/app/dialog/projectproperties/projectproperties.cpp +++ b/app/dialog/projectproperties/projectproperties.cpp @@ -177,7 +177,7 @@ void ProjectPropertiesDialog::OCIOFilenameUpdated() if (ocio_filename_->text().isEmpty()) { c = ColorManager::GetDefaultConfig(); } else { - c = OCIO::Config::CreateFromFile(ocio_filename_->text().toUtf8()); + c = ColorManager::CreateConfigFromFile(ocio_filename_->text()); } ocio_filename_->setStyleSheet(QString()); diff --git a/app/node/CMakeLists.txt b/app/node/CMakeLists.txt index 965982241..8930b3979 100644 --- a/app/node/CMakeLists.txt +++ b/app/node/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory(audio) add_subdirectory(block) +add_subdirectory(filter) add_subdirectory(generator) add_subdirectory(input) add_subdirectory(math) @@ -27,8 +28,6 @@ set(OLIVE_SOURCES node/dependency.cpp node/edge.h node/edge.cpp - node/external.h - node/external.cpp node/factory.h node/factory.cpp node/graph.h @@ -39,8 +38,6 @@ set(OLIVE_SOURCES node/inputarray.cpp node/keyframe.h node/keyframe.cpp - node/metareader.h - node/metareader.cpp node/node.h node/node.cpp node/output.h diff --git a/app/node/audio/pan/pan.cpp b/app/node/audio/pan/pan.cpp index baa9f4123..c9ef24520 100644 --- a/app/node/audio/pan/pan.cpp +++ b/app/node/audio/pan/pan.cpp @@ -49,9 +49,9 @@ QString PanNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.pan"); } -QString PanNode::Category() const +QList PanNode::Category() const { - return tr("Audio"); + return {kCategoryChannels}; } QString PanNode::Description() const @@ -64,7 +64,7 @@ Node::Capabilities PanNode::GetCapabilities(const NodeValueDatabase &) const return kSampleProcessor; } -NodeInput *PanNode::ProcessesSamplesFrom(const NodeValueDatabase &value) const +NodeInput *PanNode::ProcessesSamplesFrom(const NodeValueDatabase &) const { return samples_input_; } diff --git a/app/node/audio/pan/pan.h b/app/node/audio/pan/pan.h index b5e15b452..d4392ff9f 100644 --- a/app/node/audio/pan/pan.h +++ b/app/node/audio/pan/pan.h @@ -34,7 +34,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual Capabilities GetCapabilities(const NodeValueDatabase&) const override; diff --git a/app/node/audio/volume/volume.cpp b/app/node/audio/volume/volume.cpp index 5d1c90b4f..9d815b19a 100644 --- a/app/node/audio/volume/volume.cpp +++ b/app/node/audio/volume/volume.cpp @@ -48,9 +48,9 @@ QString VolumeNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.volume"); } -QString VolumeNode::Category() const +QList VolumeNode::Category() const { - return tr("Audio"); + return {kCategoryFilter}; } QString VolumeNode::Description() const diff --git a/app/node/audio/volume/volume.h b/app/node/audio/volume/volume.h index db1f781af..71149f0bf 100644 --- a/app/node/audio/volume/volume.h +++ b/app/node/audio/volume/volume.h @@ -34,7 +34,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual Capabilities GetCapabilities(const NodeValueDatabase&) const override; diff --git a/app/node/block/block.cpp b/app/node/block/block.cpp index 06e0237f6..1597d737d 100644 --- a/app/node/block/block.cpp +++ b/app/node/block/block.cpp @@ -63,9 +63,9 @@ Block::Block() : set_length_and_media_out(1); } -QString Block::Category() const +QList Block::Category() const { - return tr("Block"); + return {kCategoryTimeline}; } const rational &Block::in() const @@ -365,4 +365,9 @@ void Block::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput * Node::InvalidateCache(range, from, source); } +void Block::Hash(QCryptographicHash &, const rational &) const +{ + // A block does nothing by default +} + OLIVE_NAMESPACE_EXIT diff --git a/app/node/block/block.h b/app/node/block/block.h index a36f91754..f69b568b8 100644 --- a/app/node/block/block.h +++ b/app/node/block/block.h @@ -49,7 +49,7 @@ public: virtual Type type() const = 0; - virtual QString Category() const override; + virtual QList Category() const override; const rational& in() const; const rational& out() const; @@ -99,6 +99,8 @@ public: virtual void InvalidateCache(const TimeRange& range, NodeInput* from, NodeInput* source) override; + virtual void Hash(QCryptographicHash &hash, const rational &time) const override; + public slots: signals: diff --git a/app/node/block/clip/clip.cpp b/app/node/block/clip/clip.cpp index 8db5efdd5..413050d98 100644 --- a/app/node/block/clip/clip.cpp +++ b/app/node/block/clip/clip.cpp @@ -119,4 +119,13 @@ void ClipBlock::Retranslate() texture_input_->set_name(tr("Buffer")); } +void ClipBlock::Hash(QCryptographicHash &hash, const rational &time) const +{ + if (texture_input_->IsConnected()) { + rational t = InputTimeAdjustment(texture_input_, TimeRange(time, time)).in(); + + texture_input_->get_connected_node()->Hash(hash, t); + } +} + OLIVE_NAMESPACE_EXIT diff --git a/app/node/block/clip/clip.h b/app/node/block/clip/clip.h index 56f81c927..375f319ce 100644 --- a/app/node/block/clip/clip.h +++ b/app/node/block/clip/clip.h @@ -54,6 +54,8 @@ public: virtual void Retranslate() override; + virtual void Hash(QCryptographicHash &hash, const rational &time) const override; + signals: void PreviewUpdated(); diff --git a/app/node/block/transition/CMakeLists.txt b/app/node/block/transition/CMakeLists.txt index 0ca1160b9..65f672588 100644 --- a/app/node/block/transition/CMakeLists.txt +++ b/app/node/block/transition/CMakeLists.txt @@ -16,8 +16,6 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} - node/block/transition/externaltransition.h - node/block/transition/externaltransition.cpp node/block/transition/transition.h node/block/transition/transition.cpp PARENT_SCOPE diff --git a/app/node/block/transition/externaltransition.cpp b/app/node/block/transition/externaltransition.cpp deleted file mode 100644 index 74bbf817d..000000000 --- a/app/node/block/transition/externaltransition.cpp +++ /dev/null @@ -1,93 +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 . - -***/ - -#include "externaltransition.h" - -OLIVE_NAMESPACE_ENTER - -ExternalTransition::ExternalTransition(const QString &xml_meta_filename) : - meta_(xml_meta_filename) -{ - foreach (NodeInput* input, meta_.inputs()) { - AddInput(input); - } -} - -Node *ExternalTransition::copy() const -{ - return new ExternalTransition(meta_.filename()); -} - -QString ExternalTransition::Name() const -{ - return meta_.Name(); -} - -QString ExternalTransition::ShortName() const -{ - return meta_.ShortName(); -} - -QString ExternalTransition::id() const -{ - return meta_.id(); -} - -QString ExternalTransition::Category() const -{ - return meta_.Category(); -} - -QString ExternalTransition::Description() const -{ - return meta_.Description(); -} - -void ExternalTransition::Retranslate() -{ - meta_.Retranslate(); -} - -Node::Capabilities ExternalTransition::GetCapabilities(const NodeValueDatabase &) const -{ - return kShader; -} - -QString ExternalTransition::ShaderVertexCode(const NodeValueDatabase &) const -{ - return meta_.vert_code(); -} - -QString ExternalTransition::ShaderFragmentCode(const NodeValueDatabase&) const -{ - return meta_.frag_code(); -} - -int ExternalTransition::ShaderIterations() const -{ - return meta_.iterations(); -} - -NodeInput *ExternalTransition::ShaderIterativeInput() const -{ - return meta_.iteration_input(); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/node/block/transition/transition.cpp b/app/node/block/transition/transition.cpp index cdb0b8489..e0d66e69e 100644 --- a/app/node/block/transition/transition.cpp +++ b/app/node/block/transition/transition.cpp @@ -131,8 +131,6 @@ double TransitionBlock::GetInProgress(const rational &time) const void TransitionBlock::Hash(QCryptographicHash &hash, const rational &time) const { - Block::Hash(hash, time); - double all_prog = GetTotalProgress(time); double in_prog = GetInProgress(time); double out_prog = GetOutProgress(time); @@ -140,6 +138,14 @@ void TransitionBlock::Hash(QCryptographicHash &hash, const rational &time) const hash.addData(reinterpret_cast(&all_prog), sizeof(double)); hash.addData(reinterpret_cast(&in_prog), sizeof(double)); hash.addData(reinterpret_cast(&out_prog), sizeof(double)); + + if (out_block_input_->IsConnected()) { + out_block_input_->get_connected_node()->Hash(hash, time); + } + + if (in_block_input_->IsConnected()) { + in_block_input_->get_connected_node()->Hash(hash, time); + } } double TransitionBlock::GetInternalTransitionTime(const rational &time) const diff --git a/app/node/external.cpp b/app/node/external.cpp deleted file mode 100644 index 6d6a20ac9..000000000 --- a/app/node/external.cpp +++ /dev/null @@ -1,95 +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 . - -***/ - -#include "external.h" - -#include - -OLIVE_NAMESPACE_ENTER - -ExternalNode::ExternalNode(const QString &xml_meta_filename) : - meta_(xml_meta_filename) -{ - foreach (NodeInput* input, meta_.inputs()) { - AddInput(input); - } -} - -Node *ExternalNode::copy() const -{ - return new ExternalNode(meta_.filename()); -} - -QString ExternalNode::Name() const -{ - return meta_.Name(); -} - -QString ExternalNode::ShortName() const -{ - return meta_.ShortName(); -} - -QString ExternalNode::id() const -{ - return meta_.id(); -} - -QString ExternalNode::Category() const -{ - return meta_.Category(); -} - -QString ExternalNode::Description() const -{ - return meta_.Description(); -} - -void ExternalNode::Retranslate() -{ - meta_.Retranslate(); -} - -Node::Capabilities ExternalNode::GetCapabilities(const NodeValueDatabase &) const -{ - return kShader; -} - -QString ExternalNode::ShaderVertexCode(const NodeValueDatabase&) const -{ - return meta_.vert_code(); -} - -QString ExternalNode::ShaderFragmentCode(const NodeValueDatabase&) const -{ - return meta_.frag_code(); -} - -int ExternalNode::ShaderIterations() const -{ - return meta_.iterations(); -} - -NodeInput *ExternalNode::ShaderIterativeInput() const -{ - return meta_.iteration_input(); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/node/factory.cpp b/app/node/factory.cpp index d276b94da..8111d8ad9 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -24,17 +24,19 @@ #include "audio/volume/volume.h" #include "block/clip/clip.h" #include "block/gap/gap.h" -#include "block/transition/externaltransition.h" #include "generator/matrix/matrix.h" #include "generator/polygon/polygon.h" +#include "generator/solid/solid.h" +#include "filter/blur/blur.h" +#include "filter/stroke/stroke.h" #include "input/media/video/video.h" #include "input/media/audio/audio.h" #include "input/time/timeinput.h" #include "math/math/math.h" +#include "math/merge/merge.h" #include "math/trigonometry/trigonometry.h" #include "output/track/track.h" #include "output/viewer/viewer.h" -#include "external.h" OLIVE_NAMESPACE_ENTER QList NodeFactory::library_; @@ -48,13 +50,10 @@ void NodeFactory::Initialize() library_.append(CreateInternal(static_cast(i))); } - library_.append(new ExternalNode(":/shaders/blur.xml")); - library_.append(new ExternalNode(":/shaders/solid.xml")); - library_.append(new ExternalNode(":/shaders/stroke.xml")); - library_.append(new ExternalNode(":/shaders/alphaover.xml")); - library_.append(new ExternalNode(":/shaders/dropshadow.xml")); + /* library_.append(new ExternalTransition(":/shaders/crossdissolve.xml")); library_.append(new ExternalTransition(":/shaders/diptoblack.xml")); + */ } void NodeFactory::Destroy() @@ -74,34 +73,25 @@ Menu *NodeFactory::CreateMenu(QWidget* parent) // Make sure nodes are up-to-date with the current translation n->Retranslate(); - QStringList path = n->Category().split('/'); + Menu* destination = nullptr; - Menu* destination = menu; + QString category_name = Node::GetCategoryName(n->Category().isEmpty() + ? Node::kCategoryUnknown + : n->Category().first()); - // Find destination menu based on category hierarchy - foreach (const QString& dir_name, path) { - // Ignore an empty directory - if (dir_name.isEmpty()) { - continue; + // See if a menu with this category name already exists + QList menu_actions = menu->actions(); + foreach (QAction* action, menu_actions) { + if (action->menu() && action->menu()->title() == category_name) { + destination = static_cast(action->menu()); + break; } + } - // See if a menu with this dir_name already exists - bool found_cat = false; - QList menu_actions = destination->actions(); - foreach (QAction* action, menu_actions) { - if (action->menu() && action->menu()->title() == dir_name) { - destination = static_cast(action->menu()); - found_cat = true; - break; - } - } - - // Create menu here if it doesn't exist - if (!found_cat) { - Menu* new_category = new Menu(dir_name, destination); - destination->InsertAlphabetically(new_category); - destination = new_category; - } + // Create menu here if it doesn't exist + if (!destination) { + destination = new Menu(category_name, menu); + menu->InsertAlphabetically(destination); } // Add entry to menu @@ -164,6 +154,14 @@ Node *NodeFactory::CreateInternal(const NodeFactory::InternalID &id) return new TrigonometryNode(); case kTime: return new TimeInput(); + case kBlurFilter: + return new BlurFilterNode(); + case kSolidGenerator: + return new SolidGenerator(); + case kMerge: + return new MergeNode(); + case kStrokeFilter: + return new StrokeFilterNode(); case kInternalNodeCount: break; diff --git a/app/node/factory.h b/app/node/factory.h index f17a476dd..6b17bd792 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -45,6 +45,10 @@ public: kMath, kTime, kTrigonometry, + kBlurFilter, + kSolidGenerator, + kMerge, + kStrokeFilter, // Count value kInternalNodeCount diff --git a/app/node/filter/CMakeLists.txt b/app/node/filter/CMakeLists.txt new file mode 100644 index 000000000..4d7db901d --- /dev/null +++ b/app/node/filter/CMakeLists.txt @@ -0,0 +1,23 @@ +# 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 . + +add_subdirectory(blur) +add_subdirectory(stroke) + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + PARENT_SCOPE +) diff --git a/app/node/filter/blur/CMakeLists.txt b/app/node/filter/blur/CMakeLists.txt new file mode 100644 index 000000000..50bd90ad5 --- /dev/null +++ b/app/node/filter/blur/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/filter/blur/blur.h + node/filter/blur/blur.cpp + PARENT_SCOPE +) diff --git a/app/node/filter/blur/blur.cpp b/app/node/filter/blur/blur.cpp new file mode 100644 index 000000000..64d634d0c --- /dev/null +++ b/app/node/filter/blur/blur.cpp @@ -0,0 +1,104 @@ +/*** + + 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 "blur.h" + +OLIVE_NAMESPACE_ENTER + +BlurFilterNode::BlurFilterNode() +{ + texture_input_ = new NodeInput("tex_in", NodeParam::kTexture); + AddInput(texture_input_); + + method_input_ = new NodeInput("method_in", NodeParam::kCombo, 0); + AddInput(method_input_); + + radius_input_ = new NodeInput("radius_in", NodeParam::kFloat, 10.0f); + radius_input_->set_property(QStringLiteral("min"), 0.0f); + AddInput(radius_input_); + + horiz_input_ = new NodeInput("horiz_in", NodeParam::kBoolean, true); + AddInput(horiz_input_); + + vert_input_ = new NodeInput("vert_in", NodeParam::kBoolean, true); + AddInput(vert_input_); + + repeat_edge_pixels_input_ = new NodeInput("repeat_edge_pixels_in", NodeParam::kBoolean, false); + AddInput(repeat_edge_pixels_input_); +} + +Node *BlurFilterNode::copy() const +{ + return new BlurFilterNode(); +} + +QString BlurFilterNode::Name() const +{ + return tr("Blur"); +} + +QString BlurFilterNode::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.blur"); +} + +QList BlurFilterNode::Category() const +{ + return {kCategoryFilter}; +} + +QString BlurFilterNode::Description() const +{ + return tr("Blurs an image."); +} + +void BlurFilterNode::Retranslate() +{ + texture_input_->set_name(tr("Input")); + method_input_->set_name(tr("Method")); + method_input_->set_combobox_strings({ tr("Box"), tr("Gaussian") }); + radius_input_->set_name(tr("Radius")); + horiz_input_->set_name(tr("Horizontal")); + vert_input_->set_name(tr("Vertical")); + repeat_edge_pixels_input_->set_name(tr("Repeat Edge Pixels")); +} + +Node::Capabilities BlurFilterNode::GetCapabilities(const NodeValueDatabase &) const +{ + return kShader; +} + +QString BlurFilterNode::ShaderFragmentCode(const NodeValueDatabase &) const +{ + return ReadFileAsString(":/shaders/blur.frag"); +} + +int BlurFilterNode::ShaderIterations() const +{ + // FIXME: Optimize if horiz_in or vert_in is disabled + return 2; +} + +NodeInput *BlurFilterNode::ShaderIterativeInput() const +{ + return texture_input_; +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/node/block/transition/externaltransition.h b/app/node/filter/blur/blur.h similarity index 74% rename from app/node/block/transition/externaltransition.h rename to app/node/filter/blur/blur.h index 91cbd0ca9..142f03985 100644 --- a/app/node/block/transition/externaltransition.h +++ b/app/node/filter/blur/blur.h @@ -18,40 +18,48 @@ ***/ -#ifndef EXTERNALTRANSITION_H -#define EXTERNALTRANSITION_H +#ifndef BLURFILTERNODE_H +#define BLURFILTERNODE_H -#include "transition.h" - -#include "node/metareader.h" +#include "node/node.h" OLIVE_NAMESPACE_ENTER -class ExternalTransition : public TransitionBlock +class BlurFilterNode : public Node { public: - ExternalTransition(const QString& xml_meta_filename); + BlurFilterNode(); virtual Node* copy() const override; virtual QString Name() const override; - virtual QString ShortName() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; virtual Capabilities GetCapabilities(const NodeValueDatabase&) const override; - virtual QString ShaderVertexCode(const NodeValueDatabase&) const override; virtual QString ShaderFragmentCode(const NodeValueDatabase&) const override; + virtual int ShaderIterations() const override; virtual NodeInput* ShaderIterativeInput() const override; private: - NodeMetaReader meta_; + NodeInput* texture_input_; + + NodeInput* method_input_; + + NodeInput* radius_input_; + + NodeInput* horiz_input_; + + NodeInput* vert_input_; + + NodeInput* repeat_edge_pixels_input_; + }; OLIVE_NAMESPACE_EXIT -#endif // EXTERNALTRANSITION_H +#endif // BLURFILTERNODE_H diff --git a/app/node/filter/stroke/CMakeLists.txt b/app/node/filter/stroke/CMakeLists.txt new file mode 100644 index 000000000..212f3bfe2 --- /dev/null +++ b/app/node/filter/stroke/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/filter/stroke/stroke.h + node/filter/stroke/stroke.cpp + PARENT_SCOPE +) diff --git a/app/node/filter/stroke/stroke.cpp b/app/node/filter/stroke/stroke.cpp new file mode 100644 index 000000000..e87449db2 --- /dev/null +++ b/app/node/filter/stroke/stroke.cpp @@ -0,0 +1,95 @@ +/*** + + 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 "stroke.h" + +#include "render/color.h" + +OLIVE_NAMESPACE_ENTER + +StrokeFilterNode::StrokeFilterNode() +{ + tex_input_ = new NodeInput("tex_in", NodeParam::kTexture); + AddInput(tex_input_); + + color_input_ = new NodeInput("color_in", + NodeParam::kColor, + QVariant::fromValue(Color(1.0f, 1.0f, 1.0f, 1.0f))); + AddInput(color_input_); + + radius_input_ = new NodeInput("radius_in", NodeParam::kFloat, 10.0f); + radius_input_->set_property("min", 0.0f); + AddInput(radius_input_); + + opacity_input_ = new NodeInput("opacity_in", NodeParam::kFloat, 1.0f); + opacity_input_->set_property("view", "percent"); + opacity_input_->set_property("min", 0.0f); + opacity_input_->set_property("max", 1.0f); + AddInput(opacity_input_); + + inner_input_ = new NodeInput("inner_in", NodeParam::kBoolean, false); + AddInput(inner_input_); +} + +Node *StrokeFilterNode::copy() const +{ + return new StrokeFilterNode(); +} + +QString StrokeFilterNode::Name() const +{ + return tr("Stroke"); +} + +QString StrokeFilterNode::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.stroke"); +} + +QList StrokeFilterNode::Category() const +{ + return {kCategoryFilter}; +} + +QString StrokeFilterNode::Description() const +{ + return tr("Creates a stroke outline around an image."); +} + +void StrokeFilterNode::Retranslate() +{ + tex_input_->set_name(tr("Input")); + color_input_->set_name(tr("Color")); + radius_input_->set_name(tr("Radius")); + opacity_input_->set_name(tr("Opacity")); + inner_input_->set_name(tr("Inner")); +} + +Node::Capabilities StrokeFilterNode::GetCapabilities(const NodeValueDatabase &) const +{ + return kShader; +} + +QString StrokeFilterNode::ShaderFragmentCode(const NodeValueDatabase &) const +{ + return ReadFileAsString(":/shaders/stroke.frag"); +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/node/external.h b/app/node/filter/stroke/stroke.h similarity index 65% rename from app/node/external.h rename to app/node/filter/stroke/stroke.h index b9a50a313..06eb97f64 100644 --- a/app/node/external.h +++ b/app/node/filter/stroke/stroke.h @@ -18,44 +18,43 @@ ***/ -#ifndef EXTERNALNODE_H -#define EXTERNALNODE_H +#ifndef STROKEFILTERNODE_H +#define STROKEFILTERNODE_H -#include - -#include "node.h" -#include "metareader.h" +#include "node/node.h" OLIVE_NAMESPACE_ENTER -/** - * @brief A node generated from an external XML metadata file - */ -class ExternalNode : public Node +class StrokeFilterNode : public Node { public: - ExternalNode(const QString& xml_meta_filename); + StrokeFilterNode(); virtual Node* copy() const override; virtual QString Name() const override; - virtual QString ShortName() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; virtual Capabilities GetCapabilities(const NodeValueDatabase&) const override; - virtual QString ShaderVertexCode(const NodeValueDatabase&) const override; virtual QString ShaderFragmentCode(const NodeValueDatabase&) const override; - virtual int ShaderIterations() const override; - virtual NodeInput* ShaderIterativeInput() const override; private: - NodeMetaReader meta_; + NodeInput* tex_input_; + + NodeInput* color_input_; + + NodeInput* radius_input_; + + NodeInput* opacity_input_; + + NodeInput* inner_input_; + }; OLIVE_NAMESPACE_EXIT -#endif // EXTERNALNODE_H +#endif // STROKEFILTERNODE_H diff --git a/app/node/generator/CMakeLists.txt b/app/node/generator/CMakeLists.txt index 88c7de6d8..52d74e469 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(solid) set(OLIVE_SOURCES ${OLIVE_SOURCES} diff --git a/app/node/generator/matrix/matrix.cpp b/app/node/generator/matrix/matrix.cpp index c1b7452ca..046aca78d 100644 --- a/app/node/generator/matrix/matrix.cpp +++ b/app/node/generator/matrix/matrix.cpp @@ -69,9 +69,9 @@ QString MatrixGenerator::id() const return QStringLiteral("org.olivevideoeditor.Olive.transform"); } -QString MatrixGenerator::Category() const +QList MatrixGenerator::Category() const { - return tr("Generator"); + return {kCategoryGenerator, kCategoryMath}; } QString MatrixGenerator::Description() const diff --git a/app/node/generator/matrix/matrix.h b/app/node/generator/matrix/matrix.h index 2181e5791..25d4ef989 100644 --- a/app/node/generator/matrix/matrix.h +++ b/app/node/generator/matrix/matrix.h @@ -36,7 +36,7 @@ public: virtual QString Name() const override; virtual QString ShortName() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; diff --git a/app/node/generator/solid/CMakeLists.txt b/app/node/generator/solid/CMakeLists.txt new file mode 100644 index 000000000..df388a97d --- /dev/null +++ b/app/node/generator/solid/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/solid/solid.h + node/generator/solid/solid.cpp + PARENT_SCOPE +) diff --git a/app/node/generator/solid/solid.cpp b/app/node/generator/solid/solid.cpp new file mode 100644 index 000000000..d2ef7fd74 --- /dev/null +++ b/app/node/generator/solid/solid.cpp @@ -0,0 +1,76 @@ +/*** + + 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 "solid.h" + +#include "render/color.h" + +OLIVE_NAMESPACE_ENTER + +SolidGenerator::SolidGenerator() +{ + // Default to a color that isn't black + color_input_ = new NodeInput("color_in", + NodeInput::kColor, + QVariant::fromValue(Color(1.0f, 0.0f, 0.0f, 1.0f))); + AddInput(color_input_); +} + +Node *SolidGenerator::copy() const +{ + return new SolidGenerator(); +} + +QString SolidGenerator::Name() const +{ + return tr("Solid"); +} + +QString SolidGenerator::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.solidgenerator"); +} + +QList SolidGenerator::Category() const +{ + return {kCategoryGenerator}; +} + +QString SolidGenerator::Description() const +{ + return tr("Generate a solid color."); +} + +void SolidGenerator::Retranslate() +{ + color_input_->set_name(tr("Color")); +} + +Node::Capabilities SolidGenerator::GetCapabilities(const NodeValueDatabase &) const +{ + return kShader; +} + +QString SolidGenerator::ShaderFragmentCode(const NodeValueDatabase &) const +{ + return ReadFileAsString(":/shaders/solid.frag"); +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/node/generator/solid/solid.h b/app/node/generator/solid/solid.h new file mode 100644 index 000000000..8e5433e69 --- /dev/null +++ b/app/node/generator/solid/solid.h @@ -0,0 +1,52 @@ +/*** + + 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 SOLIDGENERATOR_H +#define SOLIDGENERATOR_H + +#include "node/node.h" + +OLIVE_NAMESPACE_ENTER + +class SolidGenerator : public Node +{ +public: + SolidGenerator(); + + 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 Capabilities GetCapabilities(const NodeValueDatabase&) const override; + virtual QString ShaderFragmentCode(const NodeValueDatabase&) const override; + +private: + NodeInput* color_input_; + +}; + +OLIVE_NAMESPACE_EXIT + +#endif // SOLIDGENERATOR_H diff --git a/app/node/input/media/media.cpp b/app/node/input/media/media.cpp index b7bad0efc..b3a3697f0 100644 --- a/app/node/input/media/media.cpp +++ b/app/node/input/media/media.cpp @@ -35,9 +35,9 @@ MediaInput::MediaInput() : AddInput(footage_input_); } -QString MediaInput::Category() const +QList MediaInput::Category() const { - return tr("Input"); + return {kCategoryInput}; } StreamPtr MediaInput::footage() diff --git a/app/node/input/media/media.h b/app/node/input/media/media.h index a7c15e37b..ba89f3168 100644 --- a/app/node/input/media/media.h +++ b/app/node/input/media/media.h @@ -35,7 +35,7 @@ class MediaInput : public Node public: MediaInput(); - virtual QString Category() const override; + virtual QList Category() const override; StreamPtr footage(); void SetFootage(StreamPtr f); diff --git a/app/node/input/time/timeinput.cpp b/app/node/input/time/timeinput.cpp index fa15de735..fee052c3c 100644 --- a/app/node/input/time/timeinput.cpp +++ b/app/node/input/time/timeinput.cpp @@ -41,9 +41,9 @@ QString TimeInput::id() const return QStringLiteral("org.olivevideoeditor.Olive.time"); } -QString TimeInput::Category() const +QList TimeInput::Category() const { - return tr("Input"); + return {kCategoryInput}; } QString TimeInput::Description() const diff --git a/app/node/input/time/timeinput.h b/app/node/input/time/timeinput.h index b912ed4b1..e79d1b333 100644 --- a/app/node/input/time/timeinput.h +++ b/app/node/input/time/timeinput.h @@ -35,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual NodeValueTable Value(NodeValueDatabase& value) const override; diff --git a/app/node/math/CMakeLists.txt b/app/node/math/CMakeLists.txt index 1ae06847e..32ad7e923 100644 --- a/app/node/math/CMakeLists.txt +++ b/app/node/math/CMakeLists.txt @@ -15,6 +15,7 @@ # along with this program. If not, see . add_subdirectory(math) +add_subdirectory(merge) add_subdirectory(trigonometry) set(OLIVE_SOURCES diff --git a/app/node/math/math/math.cpp b/app/node/math/math/math.cpp index 93e802481..9f2f4ca3e 100644 --- a/app/node/math/math/math.cpp +++ b/app/node/math/math/math.cpp @@ -61,9 +61,9 @@ QString MathNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.math"); } -QString MathNode::Category() const +QList MathNode::Category() const { - return tr("Math"); + return {kCategoryMath}; } QString MathNode::Description() const diff --git a/app/node/math/math/math.h b/app/node/math/math/math.h index 1909c4bd5..4327bb36a 100644 --- a/app/node/math/math/math.h +++ b/app/node/math/math/math.h @@ -34,7 +34,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; diff --git a/app/node/math/merge/CMakeLists.txt b/app/node/math/merge/CMakeLists.txt new file mode 100644 index 000000000..a7472ded0 --- /dev/null +++ b/app/node/math/merge/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/math/merge/merge.h + node/math/merge/merge.cpp + PARENT_SCOPE +) diff --git a/app/node/math/merge/merge.cpp b/app/node/math/merge/merge.cpp new file mode 100644 index 000000000..e5c039a6e --- /dev/null +++ b/app/node/math/merge/merge.cpp @@ -0,0 +1,96 @@ +/*** + + 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 "merge.h" + +OLIVE_NAMESPACE_ENTER + +MergeNode::MergeNode() +{ + base_in_ = new NodeInput("base_in", NodeParam::kTexture); + AddInput(base_in_); + + blend_in_ = new NodeInput("blend_in", NodeParam::kTexture); + AddInput(blend_in_); +} + +Node *MergeNode::copy() const +{ + return new MergeNode(); +} + +QString MergeNode::Name() const +{ + return tr("Merge"); +} + +QString MergeNode::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.merge"); +} + +QList MergeNode::Category() const +{ + return {kCategoryMath}; +} + +QString MergeNode::Description() const +{ + return tr("Merge two textures together."); +} + +void MergeNode::Retranslate() +{ + base_in_->set_name(tr("Base")); + blend_in_->set_name(tr("Blend")); +} + +Node::Capabilities MergeNode::GetCapabilities(const NodeValueDatabase &) const +{ + return kShader; +} + +QString MergeNode::ShaderFragmentCode(const NodeValueDatabase &) const +{ + return ReadFileAsString(":/shaders/alphaover.frag"); +} + +NodeInput *MergeNode::base_in() const +{ + return base_in_; +} + +NodeInput *MergeNode::blend_in() const +{ + return blend_in_; +} + +void MergeNode::Hash(QCryptographicHash &hash, const rational &time) const +{ + if (base_in_->IsConnected()) { + base_in_->get_connected_node()->Hash(hash, time); + } + + if (blend_in_->IsConnected()) { + blend_in_->get_connected_node()->Hash(hash, time); + } +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/node/math/merge/merge.h b/app/node/math/merge/merge.h new file mode 100644 index 000000000..63a17cb2d --- /dev/null +++ b/app/node/math/merge/merge.h @@ -0,0 +1,59 @@ +/*** + + 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 MERGENODE_H +#define MERGENODE_H + +#include "node/node.h" + +OLIVE_NAMESPACE_ENTER + +class MergeNode : public Node +{ +public: + MergeNode(); + + 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 Capabilities GetCapabilities(const NodeValueDatabase&) const override; + virtual QString ShaderFragmentCode(const NodeValueDatabase&) const override; + + NodeInput* base_in() const; + NodeInput* blend_in() const; + + virtual void Hash(QCryptographicHash &hash, const rational &time) const override; + +private: + NodeInput* base_in_; + + NodeInput* blend_in_; + +}; + +OLIVE_NAMESPACE_EXIT + +#endif // MERGENODE_H diff --git a/app/node/math/trigonometry/trigonometry.cpp b/app/node/math/trigonometry/trigonometry.cpp index af073c3c5..7ab8ddb3a 100644 --- a/app/node/math/trigonometry/trigonometry.cpp +++ b/app/node/math/trigonometry/trigonometry.cpp @@ -48,9 +48,9 @@ QString TrigonometryNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.trigonometry"); } -QString TrigonometryNode::Category() const +QList TrigonometryNode::Category() const { - return tr("Math"); + return {kCategoryMath}; } QString TrigonometryNode::Description() const diff --git a/app/node/math/trigonometry/trigonometry.h b/app/node/math/trigonometry/trigonometry.h index c999104eb..9af68472f 100644 --- a/app/node/math/trigonometry/trigonometry.h +++ b/app/node/math/trigonometry/trigonometry.h @@ -34,7 +34,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; diff --git a/app/node/metareader.cpp b/app/node/metareader.cpp deleted file mode 100644 index 007d7ec7b..000000000 --- a/app/node/metareader.cpp +++ /dev/null @@ -1,386 +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 . - -***/ - -#include "metareader.h" - -#include - -#include "common/xmlutils.h" -#include "config/config.h" -#include "node.h" - -OLIVE_NAMESPACE_ENTER - -NodeMetaReader::NodeMetaReader(const QString &xml_meta_filename) : - xml_filename_(xml_meta_filename), - iterations_(1), - iteration_input_(nullptr) -{ - QFile metadata_file(xml_filename_); - - if (metadata_file.open(QFile::ReadOnly)) { - QXmlStreamReader reader(&metadata_file); - - while (XMLReadNextStartElement(&reader)) { - if (reader.name() == QStringLiteral("effect")) { - XMLReadEffect(&reader); - } else { - reader.skipCurrentElement(); - } - } - - metadata_file.close(); - } else { - qWarning() << "Failed to load node metadata file" << xml_filename_; - } -} - -QString NodeMetaReader::Name() const -{ - return GetStringForCurrentLanguage(&names_); -} - -QString NodeMetaReader::ShortName() const -{ - if (short_names_.isEmpty()) { - return Name(); - } else { - return GetStringForCurrentLanguage(&short_names_); - } -} - -const QString &NodeMetaReader::id() const -{ - return id_; -} - -QString NodeMetaReader::Category() const -{ - return GetStringForCurrentLanguage(&categories_); -} - -QString NodeMetaReader::Description() const -{ - return GetStringForCurrentLanguage(&descriptions_); -} - -const QString &NodeMetaReader::filename() const -{ - return xml_filename_; -} - -const QString &NodeMetaReader::frag_code() const -{ - return frag_code_; -} - -const QString &NodeMetaReader::vert_code() const -{ - return vert_code_; -} - -const int &NodeMetaReader::iterations() const -{ - return iterations_; -} - -NodeInput *NodeMetaReader::iteration_input() const -{ - return iteration_input_; -} - -const QList &NodeMetaReader::inputs() const -{ - return inputs_; -} - -void NodeMetaReader::Retranslate() -{ - { - // Re-translate every parameter name - QMap::const_iterator iterator; - - // Iterate through parameter language tables that we have - for (iterator=param_names_.begin();iterator!=param_names_.end();iterator++) { - NodeInput* this_input = GetInputWithID(iterator.key()); - this_input->set_name(GetStringForCurrentLanguage(&iterator.value())); - } - } - - { - // Re-translate any combobox items - QMap >::const_iterator param_it; - - for (param_it=combo_names_.begin(); param_it!=combo_names_.end(); param_it++) { - NodeInput* input = GetInputWithID(param_it.key()); - - QStringList combo_items; - - foreach (const LanguageMap& lang_map, param_it.value()) { - combo_items.append(GetStringForCurrentLanguage(&lang_map)); - } - - input->set_combobox_strings(combo_items); - } - } -} - -void NodeMetaReader::XMLReadLanguageString(QXmlStreamReader* reader, LanguageMap* map) -{ - QString lang; - - // Traverse through name attributes for its language - XMLAttributeLoop(reader, attr) { - if (attr.name() == QStringLiteral("lang")) { - lang = attr.value().toString(); - - // We don't recognize any other "name" attributes at this time - break; - } - } - - // Insert name with language into map - map->insert(lang, reader->readElementText().trimmed()); -} - -void NodeMetaReader::XMLReadEffect(QXmlStreamReader* reader) -{ - // Traverse through effect attributes for an ID - XMLAttributeLoop(reader, attr) { - if (attr.name() == QStringLiteral("id")) { - id_ = attr.value().toString(); - - // We don't recognize any other "effect" attributes at this time - break; - } - } - - if (id_.isEmpty()) { - qWarning() << "Effect metadata" << xml_filename_ << "has no ID"; - return; - } - - // Continue reading for other metadata - while (XMLReadNextStartElement(reader)) { - if (reader->name() == QStringLiteral("name")) { - // Pick up name - XMLReadLanguageString(reader, &names_); - } else if (reader->name() == QStringLiteral("shortnames")) { - // Pick up short name - XMLReadLanguageString(reader, &short_names_); - } else if (reader->name() == QStringLiteral("category")) { - // Pick up category - XMLReadLanguageString(reader, &categories_); - } else if (reader->name() == QStringLiteral("description")) { - // Pick up description - XMLReadLanguageString(reader, &descriptions_); - } else if (reader->name() == QStringLiteral("iterations")) { - // Pick up iterations - XMLReadIterations(reader); - } else if (reader->name() == QStringLiteral("fragment")) { - // Pick up fragment shader code - XMLReadShader(reader, frag_code_); - } else if (reader->name() == QStringLiteral("vertex")) { - // Pick up vertex shader code - XMLReadShader(reader, vert_code_); - } else if (reader->name() == QStringLiteral("param")) { - // Pick up a parameter - XMLReadParam(reader); - } else { - reader->skipCurrentElement(); - } - } -} - -void NodeMetaReader::XMLReadIterations(QXmlStreamReader* reader) -{ - int iteration_pickup = reader->readElementText().toInt(); - - if (iterations_ > 0) { - iterations_ = iteration_pickup; - } else { - // If the iteration value is invalid, don't set it, print an error instead - qWarning() << "Invalid iteration number in" << xml_filename_ << "- setting to default (1)"; - } -} - -void NodeMetaReader::XMLReadParam(QXmlStreamReader *reader) -{ - QString param_id; - NodeParam::DataType param_type = NodeParam::kAny; - bool is_iterative = false; - - // Traverse through parameter attributes for an ID - XMLAttributeLoop(reader, attr) { - if (attr.name() == QStringLiteral("id")) { - param_id = attr.value().toString(); - } else if (attr.name() == QStringLiteral("type")) { - param_type = NodeParam::StringToDataType(attr.value().toString()); - } else if (attr.name() == QStringLiteral("iterative_input")) { - is_iterative = true; - } - } - - if (param_id.isEmpty()) { - qWarning() << "Effect metadata" << xml_filename_ << "contains a parameter with no ID - parameter was not added"; - return; - } - - QVector default_val; - QHash properties; - LanguageMap param_names; - QList combo_names; - QList combo_descriptions; - - // Traverse through param contents for more data - while (XMLReadNextStartElement(reader)) { - // NOTE: readElementText() returns a string, but for number types (which min and max apply to), QVariant will - // convert them automatically - if (reader->name() == QStringLiteral("name")) { - - // Insert language into map - XMLReadLanguageString(reader, ¶m_names); - - } else if (reader->name() == QStringLiteral("default")) { - - // Reads the default value - while (XMLReadNextStartElement(reader)) { - if (reader->name() == QStringLiteral("value")) { - default_val.append(NodeInput::StringToValue(param_type, reader->readElementText())); - } else { - reader->skipCurrentElement(); - } - } - - } else if (reader->name() == QStringLiteral("option")) { - - // Read names and descriptions - LanguageMap names; - LanguageMap descriptions; - - while (XMLReadNextStartElement(reader)) { - if (reader->name() == QStringLiteral("name")) { - XMLReadLanguageString(reader, &names); - } else if (reader->name() == QStringLiteral("description")) { - XMLReadLanguageString(reader, &descriptions); - } else { - reader->skipCurrentElement(); - } - } - - combo_names.append(names); - combo_descriptions.append(descriptions); - - } else { - properties.insert(reader->name().toString(), reader->readElementText()); - } - } - - param_names_.insert(param_id, param_names); - - // Insert combo options if they exist - if (!combo_names.isEmpty()) { - combo_names_.insert(param_id, combo_names); - combo_descriptions_.insert(param_id, combo_descriptions); - } - - NodeInput* input = new NodeInput(param_id, param_type, default_val); - - QHash::const_iterator iterator; - - for (iterator=properties.begin();iterator!=properties.end();iterator++) { - input->set_property(iterator.key(), iterator.value()); - } - - if (is_iterative) { - iteration_input_ = input; - } - - inputs_.append(input); -} - -void NodeMetaReader::XMLReadShader(QXmlStreamReader *reader, QString &destination) -{ - QString code_url; - - // Traverse through parameter attributes for an ID - XMLAttributeLoop(reader, attr) { - if (attr.name() == QStringLiteral("url")) { - code_url = attr.value().toString(); - - // We don't recognize any other "shader" attributes at this time - break; - } - } - - // Add code in file from URL - if (!code_url.isEmpty()) { - destination.append(Node::ReadFileAsString(code_url)); - } - - // Add any code that's inline in the XML - QString element_text = reader->readElementText().trimmed(); - if (!element_text.isEmpty()) { - destination.append(element_text); - } -} - -QString NodeMetaReader::GetStringForCurrentLanguage(const LanguageMap *language_map) -{ - if (language_map->isEmpty()) { - // There are no entries for this map, this must be an empty string - return QString(); - } - - // Get current language config - QString language = Config::Current()[QStringLiteral("Language")].toString(); - - // See if our map has an exact language match - QString str_for_lang = language_map->value(language); - if (!str_for_lang.isEmpty()) { - return str_for_lang; - } - - // If not, try to find a match with the same language but not the same derivation - QString base_lang = language.split('_').first(); - QList available_languages = language_map->keys(); - foreach (const QString& l, available_languages) { - if (l.startsWith(base_lang)) { - // This is the same language, so we can return this - return language_map->value(l); - } - } - - // We couldn't find an exact or close match, just return the first in the list - // (assume a string in the wrong language is better than no string at all) - return language_map->first(); -} - -NodeInput *NodeMetaReader::GetInputWithID(const QString &id) const -{ - foreach (NodeInput* input, inputs_) { - if (input->id() == id) { - return input; - } - } - return nullptr; -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/node/metareader.h b/app/node/metareader.h deleted file mode 100644 index 13c965a87..000000000 --- a/app/node/metareader.h +++ /dev/null @@ -1,91 +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 . - -***/ - -#ifndef NODEMETAREADER_H -#define NODEMETAREADER_H - -#include -#include -#include - -#include "input.h" - -OLIVE_NAMESPACE_ENTER - -class NodeMetaReader -{ -public: - NodeMetaReader(const QString& xml_meta_filename); - - QString Name() const; - QString ShortName() const; - const QString& id() const; - QString Category() const; - QString Description() const; - - const QString& filename() const; - - const QString& frag_code() const; - const QString& vert_code() const; - - const int& iterations() const; - NodeInput* iteration_input() const; - - const QList& inputs() const; - - void Retranslate(); - -private: - using LanguageMap = QMap; - - void XMLReadLanguageString(QXmlStreamReader* reader, LanguageMap *map); - void XMLReadEffect(QXmlStreamReader *reader); - void XMLReadIterations(QXmlStreamReader* reader); - void XMLReadParam(QXmlStreamReader* reader); - void XMLReadShader(QXmlStreamReader* reader, QString& destination); - - static QString GetStringForCurrentLanguage(const LanguageMap *language_map); - - NodeInput* GetInputWithID(const QString& id) const; - - QString xml_filename_; - - LanguageMap names_; - LanguageMap short_names_; - LanguageMap descriptions_; - LanguageMap categories_; - QMap param_names_; - QMap > combo_names_; - QMap > combo_descriptions_; - - QString id_; - - QString frag_code_; - QString vert_code_; - - int iterations_; - NodeInput* iteration_input_; - - QList inputs_; -}; - -OLIVE_NAMESPACE_EXIT - -#endif // NODEMETAREADER_H diff --git a/app/node/node.cpp b/app/node/node.cpp index f370e0fec..54518e258 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -127,12 +127,6 @@ QString Node::ShortName() const return Name(); } -QString Node::Category() const -{ - // Return an empty category for any nodes that don't use one - return QString(); -} - QString Node::Description() const { // Return an empty string by default @@ -582,6 +576,35 @@ void Node::DisconnectAll() } } +QString Node::GetCategoryName(const CategoryID &c) +{ + switch (c) { + case kCategoryInput: + return tr("Input"); + case kCategoryOutput: + return tr("Output"); + case kCategoryGeneral: + return tr("General"); + case kCategoryMath: + return tr("Math"); + case kCategoryColor: + return tr("Color"); + case kCategoryFilter: + return tr("Filter"); + case kCategoryTimeline: + return tr("Timeline"); + case kCategoryGenerator: + return tr("Generator"); + case kCategoryChannels: + return tr("Channel"); + case kCategoryUnknown: + case kCategoryCount: + break; + } + + return tr("Uncategorized"); +} + QList Node::TransformTimeTo(const TimeRange &time, Node *target, NodeParam::Type direction) { QList paths_found; diff --git a/app/node/node.h b/app/node/node.h index 317bebcb4..75632cf8e 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -62,6 +62,22 @@ public: kSampleProcessor = 0x2 }; + enum CategoryID { + kCategoryUnknown = -1, + + kCategoryInput, + kCategoryOutput, + kCategoryGenerator, + kCategoryMath, + kCategoryFilter, + kCategoryColor, + kCategoryGeneral, + kCategoryTimeline, + kCategoryChannels, + + kCategoryCount + }; + Node(); virtual ~Node() override; @@ -116,7 +132,7 @@ public: * interpreted as an empty string category. This value should be run through a translator as its largely user * oriented. */ - virtual QString Category() const; + virtual QList Category() const = 0; /** * @brief Return a description of this node's purpose (optional for subclassing, but recommended) @@ -242,6 +258,11 @@ public: */ void DisconnectAll(); + /** + * @brief Get the human-readable name for any category + */ + static QString GetCategoryName(const CategoryID &c); + /** * @brief Transforms time from this node through the connections it takes to get to the specified node */ diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index da545cd6e..240dc514e 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -80,9 +80,9 @@ QString TrackOutput::id() const return QStringLiteral("org.olivevideoeditor.Olive.track"); } -QString TrackOutput::Category() const +QList TrackOutput::Category() const { - return tr("Output"); + return {kCategoryTimeline}; } QString TrackOutput::Description() const @@ -420,11 +420,11 @@ NodeInputArray *TrackOutput::block_input() const void TrackOutput::Hash(QCryptographicHash &hash, const rational &time) const { - // Resolve block list Block* b = BlockAtTime(time); + // Defer to block at this time, don't add any of our own information to the hash if (b) { - return b->Hash(hash, time); + b->Hash(hash, time); } } diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h index 0922d54fc..781c4eb96 100644 --- a/app/node/output/track/track.h +++ b/app/node/output/track/track.h @@ -44,7 +44,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; QString GetTrackName(); diff --git a/app/node/output/track/tracklist.cpp b/app/node/output/track/tracklist.cpp index 07b7678c0..6165c11fb 100644 --- a/app/node/output/track/tracklist.cpp +++ b/app/node/output/track/tracklist.cpp @@ -22,6 +22,7 @@ #include "node/factory.h" #include "node/math/math/math.h" +#include "node/math/merge/merge.h" #include "node/output/viewer/viewer.h" OLIVE_NAMESPACE_ENTER @@ -104,11 +105,11 @@ TrackOutput* TrackList::AddTrack() switch (type_) { case Timeline::kTrackTypeVideo: { - Node* blend = NodeFactory::CreateFromID(QStringLiteral("org.olivevideoeditor.Olive.alphaoverblend")); + MergeNode* blend = new MergeNode(); GetParentGraph()->AddNode(blend); - NodeParam::ConnectEdge(track->output(), static_cast(blend->GetInputWithID("blend_in"))); - NodeParam::ConnectEdge(last_track->output(), static_cast(blend->GetInputWithID("base_in"))); + NodeParam::ConnectEdge(track->output(), blend->blend_in()); + NodeParam::ConnectEdge(last_track->output(), blend->base_in()); NodeParam::ConnectEdge(blend->output(), edge->input()); break; } diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index e06c5443d..445598cb0 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -72,9 +72,9 @@ QString ViewerOutput::id() const return QStringLiteral("org.olivevideoeditor.Olive.vieweroutput"); } -QString ViewerOutput::Category() const +QList ViewerOutput::Category() const { - return tr("Output"); + return {kCategoryOutput}; } QString ViewerOutput::Description() const diff --git a/app/node/output/viewer/viewer.h b/app/node/output/viewer/viewer.h index 57101b67a..3a5b3fa78 100644 --- a/app/node/output/viewer/viewer.h +++ b/app/node/output/viewer/viewer.h @@ -49,7 +49,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; NodeInput* texture_input() const; diff --git a/app/render/color.cpp b/app/render/color.cpp index 14f7e62e1..e0b20d6e2 100644 --- a/app/render/color.cpp +++ b/app/render/color.cpp @@ -78,6 +78,14 @@ Color::Color(const char *data, const PixelFormat::Format &format) } } +Color::Color(const QColor &c) +{ + set_red(c.redF()); + set_green(c.greenF()); + set_blue(c.blueF()); + set_alpha(c.alphaF()); +} + void Color::toHsv(float *hue, float *sat, float *val) const { float fCMax = qMax(qMax(red(), green()), blue()); @@ -207,6 +215,11 @@ QColor Color::toQColor() const return c; } +float Color::GetRoughLuminance() const +{ + return (2*red()+blue()+3*green())/6.0f; +} + const Color &Color::operator+=(const Color &rhs) { for (int i=0;isetLooksOverrideEnabled(true); } + OCIO_SET_C_LOCALE_FOR_SCOPE; processor_ = config->GetConfig()->getProcessor(display_transform); } else { + OCIO_SET_C_LOCALE_FOR_SCOPE; processor_ = config->GetConfig()->getProcessor(input.toUtf8(), output.toUtf8()); diff --git a/app/render/ocioconf/CMakeLists.txt b/app/render/ocioconf/CMakeLists.txt index 72fff96aa..faa7b5e40 100644 --- a/app/render/ocioconf/CMakeLists.txt +++ b/app/render/ocioconf/CMakeLists.txt @@ -14,8 +14,16 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +file(GLOB_RECURSE OCIOCONF_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.ocio *.spi3d *.spi1d) +set(QRC_BODY "") +foreach(OCIOCONF_FILE ${OCIOCONF_RESOURCES}) + string(APPEND QRC_BODY "${OCIOCONF_FILE}\n") + configure_file(${OCIOCONF_FILE} ${OCIOCONF_FILE} COPYONLY) +endforeach() +configure_file(ocioconf.qrc.in ocioconf.qrc @ONLY) + set(OLIVE_RESOURCES ${OLIVE_RESOURCES} - render/ocioconf/ocioconf.qrc + ${CMAKE_CURRENT_BINARY_DIR}/ocioconf.qrc PARENT_SCOPE ) diff --git a/app/render/ocioconf/gen-qrc.sh b/app/render/ocioconf/gen-qrc.sh deleted file mode 100755 index 448f6b4b2..000000000 --- a/app/render/ocioconf/gen-qrc.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -ourbasename=$(basename "$0") - -rm ocioconf.qrc -echo "" >> ocioconf.qrc -echo " " >> ocioconf.qrc - -for f in $(find * -type f) -do - if [ "$f" != "CMakeLists.txt" ] && [ "$f" != "ocioconf.qrc" ] && [ "$f" != "$ourbasename" ] - then - echo " $f" >> ocioconf.qrc - fi -done - -echo " " >> ocioconf.qrc -echo "" >> ocioconf.qrc diff --git a/app/render/ocioconf/ocioconf.qrc b/app/render/ocioconf/ocioconf.qrc deleted file mode 100644 index badfdb9b2..000000000 --- a/app/render/ocioconf/ocioconf.qrc +++ /dev/null @@ -1,19 +0,0 @@ - - - config.ocio - looks/Filmic_False_Colour.spi3d - looks/Filmic_to_0-35_1-30.spi1d - looks/Filmic_to_0-48_1-09.spi1d - looks/Filmic_to_0-60_1-04.spi1d - looks/Filmic_to_0-70_1-03.spi1d - looks/Filmic_to_0-85_1-011.spi1d - looks/Filmic_to_0.99_1-0075.spi1d - looks/Filmic_to_1.20_1-00.spi1d - luts/F-Log_to_Linear.spi1d - luts/V-Log_to_linear.spi1d - luts/V3_LogC_400_to_linear.spi1d - luts/V3_LogC_800_to_linear.spi1d - luts/desat65cube.spi3d - luts/sRGB_OETF_to_Linear.spi1d - - diff --git a/app/render/ocioconf/ocioconf.qrc.in b/app/render/ocioconf/ocioconf.qrc.in new file mode 100644 index 000000000..7d9cdfce9 --- /dev/null +++ b/app/render/ocioconf/ocioconf.qrc.in @@ -0,0 +1,5 @@ + + + @QRC_BODY@ + + diff --git a/app/shaders/CMakeLists.txt b/app/shaders/CMakeLists.txt index 762945e1b..a9ad28c12 100644 --- a/app/shaders/CMakeLists.txt +++ b/app/shaders/CMakeLists.txt @@ -14,8 +14,16 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +file(GLOB_RECURSE SHADER_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.frag *.vert) +set(QRC_BODY "") +foreach(SHADER_FILE ${SHADER_RESOURCES}) + string(APPEND QRC_BODY "${SHADER_FILE}\n") + configure_file(${SHADER_FILE} ${SHADER_FILE} COPYONLY) +endforeach() +configure_file(shaders.qrc.in shaders.qrc @ONLY) + set(OLIVE_RESOURCES ${OLIVE_RESOURCES} - shaders/shaders.qrc + ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc PARENT_SCOPE ) diff --git a/app/shaders/alphaover.xml b/app/shaders/alphaover.xml deleted file mode 100644 index e9df1a47b..000000000 --- a/app/shaders/alphaover.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - Alpha Over - - - Blend - - - - A blending node that composites one texture over another using its alpha channel. - - - - - Base - - - Blend - - - - - diff --git a/app/shaders/blur.xml b/app/shaders/blur.xml deleted file mode 100644 index 2d49a43b6..000000000 --- a/app/shaders/blur.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - Blur - - - Blur - - - - Blurs an image. - - - - - Input - - - - - Method - - - - - - - Radius - 0 - - 10 - - - - - - Horizontal - - 1 - - - - - - Vertical - - 1 - - - - - - Repeat Edge Pixels - - 0 - - - - - - - - 2 - diff --git a/app/shaders/crossdissolve.xml b/app/shaders/crossdissolve.xml deleted file mode 100644 index 7e7c1855f..000000000 --- a/app/shaders/crossdissolve.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Cross Dissolve - - - Transition - - - - A smooth fade transition from one video clip to another. - - - - - diff --git a/app/shaders/diptoblack.xml b/app/shaders/diptoblack.xml deleted file mode 100644 index 7a4127ded..000000000 --- a/app/shaders/diptoblack.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Dip to Black - - - Transition - - - - A smooth dip to transparency and back into another clip. - - - - - diff --git a/app/shaders/dropshadow.frag b/app/shaders/dropshadow.frag deleted file mode 100644 index 0a35c7517..000000000 --- a/app/shaders/dropshadow.frag +++ /dev/null @@ -1,62 +0,0 @@ -#version 150 - -#define M_PI 3.1415926535897932384626433832795 - -uniform sampler2D tex_in; -uniform vec3 color_in; -uniform float softness_in; -uniform float opacity_in; -uniform float distance_in; -uniform float direction_in; - -uniform vec2 ove_resolution; - -in vec2 ove_texcoord; - -out vec4 fragColor; - -void main(void) { - // Use pythagoras with the distance (hypotenuse) to find the shadow offset - float direction_radians = direction_in * (M_PI / 180.0); - - float opposite = sin(direction_radians) * distance_in; - float adjacent = cos(direction_radians) * distance_in; - - vec2 angle = vec2(adjacent, opposite); - - // Convert distance from pixels to 0.0 - 1.0 texture coordinates - angle /= ove_resolution; - - float shadow_alpha; - - // For a soft shadow, we use a box blur-like formula - if (softness_in > 0.0) { - float radius = ceil(softness_in); - float divider = 1.0 / pow(softness_in, 2.0); - shadow_alpha = 0.0; - - for (float x = -radius + 0.5; x <= radius; x += 2.0) { - for (float y = -radius + 0.5; y <= radius; y += 2.0) { - vec2 pixel_coord = ove_texcoord - angle; - pixel_coord.x += x / ove_resolution.x; - pixel_coord.y += y / ove_resolution.y; - vec4 pixel_color = texture(tex_in, pixel_coord); - - shadow_alpha += pixel_color.a * divider; - } - } - } else { - // Perfectly hard shadow - vec4 src_color = texture(tex_in, ove_texcoord - angle); - shadow_alpha = src_color.a; - } - - vec4 shadow_px = vec4(color_in, shadow_alpha * opacity_in * 0.01); - - // Get current pixel and perform an alpha over for it over the shadow we've made - vec4 dst_color = texture(tex_in, ove_texcoord); - shadow_px *= (1.0 - dst_color.a); - shadow_px += dst_color; - - fragColor = shadow_px; -} diff --git a/app/shaders/dropshadow.xml b/app/shaders/dropshadow.xml deleted file mode 100644 index 20e77fb84..000000000 --- a/app/shaders/dropshadow.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - Drop Shadow - - - Stylize - Stylise - - - - Generate a drop shadow of a clip. - - - - - Input - - - - - Color - Colour - - - - - Softness - 0 - - 10 - - - - - - Opacity - 0 - - 80 - - 100 - - - - - Distance - 0 - - 10 - - - - - - Direction - - 45 - - - - - - diff --git a/app/shaders/rgbwaveform.frag b/app/shaders/rgbwaveform.frag index 3e839b386..4e6b13f08 100644 --- a/app/shaders/rgbwaveform.frag +++ b/app/shaders/rgbwaveform.frag @@ -52,7 +52,7 @@ void main(void) { float waveform_x = (ove_texcoord.x - waveform_uv.x) / waveform_scale; float waveform_y = (ove_texcoord.y - waveform_uv.y) / waveform_scale; for (int i = 0; i < waveform_dims.y; i++) { - ratio = float(i) / float(waveform_dims.y); + ratio = float(i) / float(waveform_dims.y - 1); cur_col = texture( ove_maintex, vec2(waveform_x, ratio) diff --git a/app/shaders/shaders.qrc.in b/app/shaders/shaders.qrc.in new file mode 100644 index 000000000..e1366f006 --- /dev/null +++ b/app/shaders/shaders.qrc.in @@ -0,0 +1,5 @@ + + + @QRC_BODY@ + + diff --git a/app/shaders/solid.xml b/app/shaders/solid.xml deleted file mode 100644 index d45fef56f..000000000 --- a/app/shaders/solid.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - Solid - - - Generator - - - - Generate a solid color. - - - Generate a solid colour. - - - - - Color - Colour - - 1.0 - 0.0 - 0.0 - 1.0 - - - - - - diff --git a/app/shaders/stroke.frag b/app/shaders/stroke.frag index 8d43b34ea..bdd7d2691 100644 --- a/app/shaders/stroke.frag +++ b/app/shaders/stroke.frag @@ -2,7 +2,7 @@ // Node parameter inputs uniform sampler2D tex_in; -uniform vec3 color_in; +uniform vec4 color_in; uniform float radius_in; uniform float opacity_in; uniform bool inner_in; @@ -61,15 +61,14 @@ void main(void) { } } - stroke_weight *= opacity_in * 0.01; + stroke_weight *= opacity_in; if (inner_in) { stroke_weight *= pixel_here.a; } // Make RGBA color - vec4 stroke_col = vec4(vec3(1.0) * stroke_weight, stroke_weight); - //vec4 stroke_col = vec4(color_in * stroke_weight, stroke_weight); + vec4 stroke_col = color_in * stroke_weight; if (inner_in) { // Alpha over the stroke over the texture diff --git a/app/shaders/stroke.xml b/app/shaders/stroke.xml deleted file mode 100644 index 1f562eef0..000000000 --- a/app/shaders/stroke.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - Stroke - - - Stylize - Stylise - - - - Creates a stroke outline around an image. - - - - - Input - - - - - Color - Colour - - - - - Radius - 0 - - 10 - - - - - - Opacity - 0 - - 100 - - 100 - - - - - Inner - - false - - - - - - diff --git a/app/widget/colorwheel/colorswatchwidget.cpp b/app/widget/colorwheel/colorswatchwidget.cpp index eca418525..f243e46e2 100644 --- a/app/widget/colorwheel/colorswatchwidget.cpp +++ b/app/widget/colorwheel/colorswatchwidget.cpp @@ -77,9 +77,7 @@ void ColorSwatchWidget::SelectedColorChangedEvent(const Color &, bool) Qt::GlobalColor ColorSwatchWidget::GetUISelectorColor() const { - float rough_color_luma = (GetSelectedColor().red()+GetSelectedColor().red()+GetSelectedColor().blue()+GetSelectedColor().green()+GetSelectedColor().green()+GetSelectedColor().green())/6; - - if (rough_color_luma > 0.66) { + if (GetSelectedColor().GetRoughLuminance() > 0.66) { return Qt::black; } else { return Qt::white; diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp index 45eafa7e2..763b10281 100644 --- a/app/widget/nodeview/nodeviewitem.cpp +++ b/app/widget/nodeview/nodeviewitem.cpp @@ -28,6 +28,7 @@ #include "common/flipmodifiers.h" #include "common/qtutils.h" +#include "config/config.h" #include "core.h" #include "nodeview.h" #include "nodeviewscene.h" @@ -260,8 +261,11 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti // Draw the titlebar if (!hide_titlebar_ && node_) { + Color node_color = Config::Current()[QStringLiteral("NodeCatColor%1") + .arg(node_->Category().first())].value(); + painter->setPen(Qt::black); - painter->setBrush(css_proxy_.TitleBarColor()); + painter->setBrush(node_color.toQColor()); painter->drawRect(title_bar_rect_); @@ -293,6 +297,12 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti } } + if (node_color.GetRoughLuminance() > 0.66) { + painter->setPen(Qt::black); + } else { + painter->setPen(Qt::white); + } + // Draw the text in a rect (the rect is sized around text already in the constructor) painter->drawText(title_bar_rect_, Qt::AlignCenter, @@ -307,7 +317,7 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti if (option->state & QStyle::State_Selected) { border_pen.setColor(app_pal.color(QPalette::Highlight)); } else { - border_pen.setColor(css_proxy_.BorderColor()); + border_pen.setColor(Qt::black); } painter->setPen(border_pen); diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h index 0a02b7e3e..226929872 100644 --- a/app/widget/nodeview/nodeviewitem.h +++ b/app/widget/nodeview/nodeviewitem.h @@ -130,13 +130,6 @@ private: */ QList node_inputs_; - /** - * @brief A QWidget that can receive CSS properties that NodeViewItem can use - * - * \see NodeViewItemWidget - */ - NodeViewItemWidget css_proxy_; - /** * @brief Rectangle of the Node's title bar (equal to rect() when collapsed) */ diff --git a/app/widget/scope/CMakeLists.txt b/app/widget/scope/CMakeLists.txt index a14b351dd..91c4f0b44 100644 --- a/app/widget/scope/CMakeLists.txt +++ b/app/widget/scope/CMakeLists.txt @@ -15,6 +15,7 @@ # along with this program. If not, see . add_subdirectory(histogram) +add_subdirectory(scopebase) add_subdirectory(waveform) set(OLIVE_SOURCES diff --git a/app/widget/scope/histogram/histogram.cpp b/app/widget/scope/histogram/histogram.cpp index b9028f85a..9665e32de 100644 --- a/app/widget/scope/histogram/histogram.cpp +++ b/app/widget/scope/histogram/histogram.cpp @@ -29,189 +29,8 @@ OLIVE_NAMESPACE_ENTER HistogramScope::HistogramScope(QWidget* parent) : - ManagedDisplayWidget(parent), - buffer_(nullptr) + ScopeBase(parent) { - EnableDefaultContextMenu(); - - connect(&worker_, &HistogramScopeWorker::Finished, this, &HistogramScope::FinishedProcessing, Qt::QueuedConnection); - worker_.start(QThread::IdlePriority); -} - -HistogramScope::~HistogramScope() -{ - worker_.Cancel(); - worker_.quit(); - worker_.wait(); -} - -void HistogramScope::SetBuffer(Frame* frame) -{ - buffer_ = frame; - - if (isVisible()) { - StartUpdate(); - } -} - -void HistogramScope::FinishedProcessing(QVector red, QVector green, QVector blue) -{ - red_val_ = red; - green_val_ = green; - blue_val_ = blue; - - update(); -} - -void HistogramScope::paintGL() -{ - QVector red_lines(red_val_.size()); - QVector green_lines(green_val_.size()); - QVector blue_lines(blue_val_.size()); - - for (int i=0;i data(w * kRGBChannels, 0); - - int max_w = w-1; - - for (int x=0;xConvertColor(c); - } - - data[qFloor(clamp(c.red(), 0.0f, 1.0f) * max_w)]++; - data[qFloor(clamp(c.green(), 0.0f, 1.0f) * max_w) + w]++; - data[qFloor(clamp(c.blue(), 0.0f, 1.0f) * max_w) + w * 2]++; - } - } - - int max_val = 0; - - foreach (const int& i, data) { - if (i > max_val) { - max_val = i; - } - } - - if (!max_val) { - // Prevent divide by zero - return; - } - - QVector red_lines(w); - QVector green_lines(w); - QVector blue_lines(w); - - for (int i=0;i(data.at(i)) / static_cast(max_val)); - green_lines.replace(i, static_cast(data.at(i + w)) / static_cast(max_val)); - blue_lines.replace(i, static_cast(data.at(i + w * 2)) / static_cast(max_val)); - } - - emit Finished(red_lines, green_lines, blue_lines); - } -} - -void HistogramScopeWorker::QueueNext(const Frame &f, ColorProcessorPtr processor, int width) -{ - next_lock_.lock(); - - next_ = f; - next_width_ = width; - next_processor_ = processor; - - next_wait_.wakeOne(); - - next_lock_.unlock(); -} - -void HistogramScopeWorker::Cancel() -{ - cancelled_ = true; - next_lock_.lock(); - next_wait_.wakeOne(); - next_lock_.unlock(); } OLIVE_NAMESPACE_EXIT diff --git a/app/widget/scope/histogram/histogram.h b/app/widget/scope/histogram/histogram.h index 3efad3919..625074a89 100644 --- a/app/widget/scope/histogram/histogram.h +++ b/app/widget/scope/histogram/histogram.h @@ -21,80 +21,20 @@ #ifndef HISTOGRAMSCOPE_H #define HISTOGRAMSCOPE_H -#include -#include -#include - -#include "codec/frame.h" -#include "render/colorprocessor.h" -#include "widget/manageddisplay/manageddisplay.h" +#include "widget/scope/scopebase/scopebase.h" OLIVE_NAMESPACE_ENTER -class HistogramScopeWorker : public QThread -{ - Q_OBJECT -public: - HistogramScopeWorker(); - - // Thread-safe - void QueueNext(const Frame& f, ColorProcessorPtr processor, int width); - - // Thread-safe - void Cancel(); - -protected: - virtual void run() override; - -signals: - void Finished(QVector red, QVector green, QVector blue); - -private: - QAtomicInt cancelled_; - - QMutex next_lock_; - QWaitCondition next_wait_; - Frame next_; - int next_width_; - ColorProcessorPtr next_processor_; - -}; - -class HistogramScope : public ManagedDisplayWidget +class HistogramScope : public ScopeBase { Q_OBJECT public: HistogramScope(QWidget* parent = nullptr); - virtual ~HistogramScope() override; - -public slots: - void SetBuffer(Frame* frame); - protected: - virtual void paintGL() override; + //virtual OpenGLShaderPtr CreateShader() override; - virtual void resizeEvent(QResizeEvent* e) override; - - virtual void ColorProcessorChangedEvent() override; - - virtual void showEvent(QShowEvent* e) override; - -private: - void StartUpdate(); - - Frame* buffer_; - - QVector red_val_; - - QVector green_val_; - - QVector blue_val_; - - HistogramScopeWorker worker_; - -private slots: - void FinishedProcessing(QVector red, QVector green, QVector blue); + //virtual void DrawScope() override; }; diff --git a/app/widget/scope/scopebase/CMakeLists.txt b/app/widget/scope/scopebase/CMakeLists.txt new file mode 100644 index 000000000..ca6d924c3 --- /dev/null +++ b/app/widget/scope/scopebase/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} + widget/scope/scopebase/scopebase.h + widget/scope/scopebase/scopebase.cpp + PARENT_SCOPE +) diff --git a/app/widget/scope/scopebase/scopebase.cpp b/app/widget/scope/scopebase/scopebase.cpp new file mode 100644 index 000000000..c58b9e8bd --- /dev/null +++ b/app/widget/scope/scopebase/scopebase.cpp @@ -0,0 +1,163 @@ +/*** + + 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 "scopebase.h" + +#include "render/backend/opengl/openglrenderfunctions.h" + +OLIVE_NAMESPACE_ENTER + +ScopeBase::ScopeBase(QWidget* parent) : + ManagedDisplayWidget(parent), + buffer_(nullptr) +{ + EnableDefaultContextMenu(); +} + +ScopeBase::~ScopeBase() +{ + CleanUp(); + + if (context()) { + disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ScopeBase::CleanUp); + } +} + +void ScopeBase::SetBuffer(Frame *frame) +{ + buffer_ = frame; + + UploadTextureFromBuffer(); +} + +void ScopeBase::showEvent(QShowEvent* e) +{ + ManagedDisplayWidget::showEvent(e); + + UploadTextureFromBuffer(); +} + +OpenGLShaderPtr ScopeBase::CreateShader() +{ + return OpenGLShader::CreateDefault(); +} + +void ScopeBase::DrawScope() +{ + managed_tex().Bind(); + + OpenGLRenderFunctions::Blit(pipeline()); + + managed_tex().Release(); +} + +OpenGLShaderPtr ScopeBase::pipeline() +{ + return pipeline_; +} + +OpenGLTexture &ScopeBase::managed_tex() +{ + return managed_tex_; +} + +void ScopeBase::UploadTextureFromBuffer() +{ + if (!isVisible()) { + return; + } + + if (buffer_) { + makeCurrent(); + + if (!texture_.IsCreated() + || texture_.width() != buffer_->width() + || texture_.height() != buffer_->height() + || texture_.format() != buffer_->format()) { + texture_.Destroy(); + managed_tex_.Destroy(); + + texture_.Create(context(), buffer_); + managed_tex_.Create(context(), buffer_->video_params()); + } else { + texture_.Upload(buffer_); + } + + doneCurrent(); + } + + update(); +} + +void ScopeBase::CleanUp() +{ + makeCurrent(); + + pipeline_ = nullptr; + texture_.Destroy(); + managed_tex_.Destroy(); + framebuffer_.Destroy(); + + doneCurrent(); +} + +void ScopeBase::initializeGL() +{ + ManagedDisplayWidget::initializeGL(); + + pipeline_ = CreateShader(); + + framebuffer_.Create(context()); + + connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ScopeBase::CleanUp, Qt::DirectConnection); + + UploadTextureFromBuffer(); +} + +void ScopeBase::paintGL() +{ + QOpenGLFunctions* f = context()->functions(); + + f->glClearColor(0, 0, 0, 0); + f->glClear(GL_COLOR_BUFFER_BIT); + + if (buffer_ && pipeline() && texture_.IsCreated()) { + // Convert reference frame to display space + framebuffer_.Attach(&managed_tex_); + framebuffer_.Bind(); + + texture_.Bind(); + + f->glViewport(0, 0, texture_.width(), texture_.height()); + + color_service()->ProcessOpenGL(); + + texture_.Release(); + + framebuffer_.Release(); + framebuffer_.Detach(); + + f->glViewport(0, 0, width(), height()); + + DrawScope(); + } +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/widget/scope/scopebase/scopebase.h b/app/widget/scope/scopebase/scopebase.h new file mode 100644 index 000000000..3098af212 --- /dev/null +++ b/app/widget/scope/scopebase/scopebase.h @@ -0,0 +1,78 @@ +/*** + + 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 SCOPEBASE_H +#define SCOPEBASE_H + +#include "codec/frame.h" +#include "render/backend/opengl/openglcolorprocessor.h" +#include "render/backend/opengl/openglframebuffer.h" +#include "render/backend/opengl/openglshader.h" +#include "render/backend/opengl/opengltexture.h" +#include "widget/manageddisplay/manageddisplay.h" + +OLIVE_NAMESPACE_ENTER + +class ScopeBase : public ManagedDisplayWidget +{ +public: + ScopeBase(QWidget* parent = nullptr); + + virtual ~ScopeBase() override; + +public slots: + void SetBuffer(Frame* frame); + +protected: + virtual void initializeGL() override; + + virtual void paintGL() override; + + virtual void showEvent(QShowEvent* e) override; + + virtual OpenGLShaderPtr CreateShader(); + + virtual void DrawScope(); + + OpenGLShaderPtr pipeline(); + + OpenGLTexture& managed_tex(); + +private: + void UploadTextureFromBuffer(); + + OpenGLShaderPtr pipeline_; + + OpenGLTexture texture_; + + OpenGLTexture managed_tex_; + + OpenGLFramebuffer framebuffer_; + + Frame* buffer_; + +private slots: + void CleanUp(); + +}; + +OLIVE_NAMESPACE_EXIT + +#endif // SCOPEBASE_H diff --git a/app/widget/scope/waveform/waveform.cpp b/app/widget/scope/waveform/waveform.cpp index 5f9225b3f..daefe84e7 100644 --- a/app/widget/scope/waveform/waveform.cpp +++ b/app/widget/scope/waveform/waveform.cpp @@ -32,59 +32,24 @@ OLIVE_NAMESPACE_ENTER WaveformScope::WaveformScope(QWidget* parent) : - ManagedDisplayWidget(parent), - buffer_(nullptr) + ScopeBase(parent) { - EnableDefaultContextMenu(); } -WaveformScope::~WaveformScope() +OpenGLShaderPtr WaveformScope::CreateShader() { - CleanUp(); + OpenGLShaderPtr pipeline = OpenGLShader::Create(); - if (context()) { - disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &WaveformScope::CleanUp); - } + pipeline->create(); + pipeline->addShaderFromSourceCode(QOpenGLShader::Vertex, OpenGLShader::CodeDefaultVertex()); + pipeline->addShaderFromSourceCode(QOpenGLShader::Fragment, Node::ReadFileAsString(":/shaders/rgbwaveform.frag")); + pipeline->link(); + + return pipeline; } -void WaveformScope::SetBuffer(Frame *frame) +void WaveformScope::DrawScope() { - buffer_ = frame; - - UploadTextureFromBuffer(); -} - -void WaveformScope::showEvent(QShowEvent* e) -{ - ManagedDisplayWidget::showEvent(e); - - UploadTextureFromBuffer(); -} - -void WaveformScope::initializeGL() -{ - ManagedDisplayWidget::initializeGL(); - - pipeline_ = OpenGLShader::Create(); - pipeline_->create(); - pipeline_->addShaderFromSourceCode(QOpenGLShader::Vertex, OpenGLShader::CodeDefaultVertex()); - pipeline_->addShaderFromSourceCode(QOpenGLShader::Fragment, Node::ReadFileAsString(":/shaders/rgbwaveform.frag")); - pipeline_->link(); - - framebuffer_.Create(context()); - - connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &WaveformScope::CleanUp, Qt::DirectConnection); - - UploadTextureFromBuffer(); -} - -void WaveformScope::paintGL() -{ - QOpenGLFunctions* f = context()->functions(); - - f->glClearColor(0, 0, 0, 0); - f->glClear(GL_COLOR_BUFFER_BIT); - float waveform_scale = 0.80f; float waveform_dim_x = width() * waveform_scale; float waveform_dim_y = height() * waveform_scale; @@ -93,66 +58,47 @@ void WaveformScope::paintGL() float waveform_end_dim_x = width() - waveform_start_dim_x; float waveform_end_dim_y = height() - waveform_start_dim_y; - if (buffer_ && pipeline_ && texture_.IsCreated()) { - // Convert reference frame to display space - framebuffer_.Attach(&managed_tex_); - framebuffer_.Bind(); + // Draw waveform through shader + pipeline()->bind(); + pipeline()->setUniformValue("ove_resolution", managed_tex().width(), managed_tex().height()); + pipeline()->setUniformValue("ove_viewport", width(), height()); + GLfloat luma[3] = {0.0, 0.0, 0.0}; + color_manager()->GetDefaultLumaCoefs(luma); + pipeline()->setUniformValue("luma_coeffs", luma[0], luma[1], luma[2]); - texture_.Bind(); + // Scale of the waveform relative to the viewport surface. + pipeline()->setUniformValue("waveform_scale", waveform_scale); + pipeline()->setUniformValue( + "waveform_dims", waveform_dim_x, waveform_dim_y); - f->glViewport(0, 0, texture_.width(), texture_.height()); + pipeline()->setUniformValue( + "waveform_region", + waveform_start_dim_x, waveform_start_dim_y, + waveform_end_dim_x, waveform_end_dim_y); - color_service()->ProcessOpenGL(); + float waveform_start_uv_x = waveform_start_dim_x / width(); + float waveform_start_uv_y = waveform_start_dim_y / height(); + float waveform_end_uv_x = waveform_end_dim_x / width(); + float waveform_end_uv_y = waveform_end_dim_y / height(); + pipeline()->setUniformValue( + "waveform_uv", + waveform_start_uv_x, waveform_start_uv_y, + waveform_end_uv_x, waveform_end_uv_y); - texture_.Release(); + pipeline()->release(); - framebuffer_.Release(); - framebuffer_.Detach(); + managed_tex().Bind(); - // Draw waveform through shader - pipeline_->bind(); - pipeline_->setUniformValue("ove_resolution", texture_.width(), texture_.height()); - pipeline_->setUniformValue("ove_viewport", width(), height()); - GLfloat luma[3] = {0.0, 0.0, 0.0}; - color_manager()->GetDefaultLumaCoefs(luma); - pipeline_->setUniformValue("luma_coeffs", luma[0], luma[1], luma[2]); + OpenGLRenderFunctions::Blit(pipeline()); - // Scale of the waveform relative to the viewport surface. - pipeline_->setUniformValue("waveform_scale", waveform_scale); - pipeline_->setUniformValue( - "waveform_dims", waveform_dim_x, waveform_dim_y); - - pipeline_->setUniformValue( - "waveform_region", - waveform_start_dim_x, waveform_start_dim_y, - waveform_end_dim_x, waveform_end_dim_y); - - float waveform_start_uv_x = waveform_start_dim_x / width(); - float waveform_start_uv_y = waveform_start_dim_y / height(); - float waveform_end_uv_x = waveform_end_dim_x / width(); - float waveform_end_uv_y = waveform_end_dim_y / height(); - pipeline_->setUniformValue( - "waveform_uv", - waveform_start_uv_x, waveform_start_uv_y, - waveform_end_uv_x, waveform_end_uv_y); - - pipeline_->release(); - - f->glViewport(0, 0, width(), height()); - - managed_tex_.Bind(); - - OpenGLRenderFunctions::Blit(pipeline_); - - managed_tex_.Release(); - } + managed_tex().Release(); // Draw line overlays QPainter p(this); QFontMetrics font_metrics = QFontMetrics(QFont()); QString label; float ire_increment = 0.1f; - float ire_steps = int(1.0 / ire_increment); + int ire_steps = qRound(1.0 / ire_increment); QVector ire_lines(ire_steps + 1); int font_x_offset = 0; int font_y_offset = font_metrics.capHeight() / 2.0f; @@ -179,44 +125,4 @@ void WaveformScope::paintGL() p.drawLines(ire_lines); } -void WaveformScope::UploadTextureFromBuffer() -{ - if (!isVisible()) { - return; - } - - if (buffer_) { - makeCurrent(); - - if (!texture_.IsCreated() - || texture_.width() != buffer_->width() - || texture_.height() != buffer_->height() - || texture_.format() != buffer_->format()) { - texture_.Destroy(); - managed_tex_.Destroy(); - - texture_.Create(context(), buffer_); - managed_tex_.Create(context(), buffer_->video_params()); - } else { - texture_.Upload(buffer_); - } - - doneCurrent(); - } - - update(); -} - -void WaveformScope::CleanUp() -{ - makeCurrent(); - - pipeline_ = nullptr; - texture_.Destroy(); - managed_tex_.Destroy(); - framebuffer_.Destroy(); - - doneCurrent(); -} - OLIVE_NAMESPACE_EXIT diff --git a/app/widget/scope/waveform/waveform.h b/app/widget/scope/waveform/waveform.h index 4243a9d3a..04a464e52 100644 --- a/app/widget/scope/waveform/waveform.h +++ b/app/widget/scope/waveform/waveform.h @@ -21,48 +21,20 @@ #ifndef WAVEFORMSCOPE_H #define WAVEFORMSCOPE_H -#include "codec/frame.h" -#include "render/backend/opengl/openglcolorprocessor.h" -#include "render/backend/opengl/openglframebuffer.h" -#include "render/backend/opengl/openglshader.h" -#include "render/backend/opengl/opengltexture.h" -#include "widget/manageddisplay/manageddisplay.h" +#include "widget/scope/scopebase/scopebase.h" OLIVE_NAMESPACE_ENTER -class WaveformScope : public ManagedDisplayWidget +class WaveformScope : public ScopeBase { Q_OBJECT public: WaveformScope(QWidget* parent = nullptr); - virtual ~WaveformScope() override; - -public slots: - void SetBuffer(Frame* frame); - protected: - virtual void initializeGL() override; + virtual OpenGLShaderPtr CreateShader() override; - virtual void paintGL() override; - - virtual void showEvent(QShowEvent* e) override; - -private: - void UploadTextureFromBuffer(); - - OpenGLShaderPtr pipeline_; - - OpenGLTexture texture_; - - OpenGLTexture managed_tex_; - - OpenGLFramebuffer framebuffer_; - - Frame* buffer_; - -private slots: - void CleanUp(); + virtual void DrawScope() override; };