diff --git a/app/dialog/projectproperties/projectproperties.cpp b/app/dialog/projectproperties/projectproperties.cpp index 7f7414f3f..a49a7b170 100644 --- a/app/dialog/projectproperties/projectproperties.cpp +++ b/app/dialog/projectproperties/projectproperties.cpp @@ -195,8 +195,10 @@ void ProjectPropertiesDialog::accept() } // This should ripple changes throughout the program that the color config has changed, therefore must be done last - working_project_->color_manager()->SetConfigAndDefaultInput(ocio_filename_->text(), - default_input_colorspace_->currentText()); + ColorManager* color_manager = working_project_->color_manager(); + + color_manager->SetConfigFilename(ocio_filename_->text()); + color_manager->SetDefaultInputColorSpace(default_input_colorspace_->currentText()); QDialog::accept(); } diff --git a/app/project/item/footage/footage.cpp b/app/project/item/footage/footage.cpp index 3a06193a7..1381ded5b 100644 --- a/app/project/item/footage/footage.cpp +++ b/app/project/item/footage/footage.cpp @@ -156,6 +156,15 @@ void Footage::InputValueChangedEvent(const QString &input, int element) } } +QString Footage::GetColorspaceToUse(const VideoParams ¶ms) const +{ + if (params.colorspace().isEmpty()) { + return project()->color_manager()->GetDefaultInputColorSpace(); + } else { + return params.colorspace(); + } +} + Footage::StreamReference Footage::GetReferenceFromOutput(const QString &s) const { Stream::Type type; @@ -525,7 +534,7 @@ void Footage::Hash(const QString& output, QCryptographicHash &hash, const ration if (ref.type() == Stream::kVideo) { // Current color config and space hash.addData(project()->color_manager()->GetConfigFilename().toUtf8()); - hash.addData(params.colorspace().toUtf8()); + hash.addData(GetColorspaceToUse(params).toUtf8()); // Alpha associated setting hash.addData(QString::number(params.premultiplied_alpha()).toUtf8()); @@ -565,9 +574,8 @@ NodeValueTable Footage::Value(const QString &output, NodeValueDatabase &value) c if (ref.type() == Stream::kVideo) { VideoParams vp = GetVideoParams(ref.index()); - if (vp.colorspace().isEmpty()) { - vp.set_colorspace(project()->color_manager()->GetDefaultInputColorSpace()); - } + // Ensure the colorspace is valid and not empty + vp.set_colorspace(GetColorspaceToUse(vp)); job.set_video_params(vp); } else { diff --git a/app/project/item/footage/footage.h b/app/project/item/footage/footage.h index 405f7848c..f6a98ec81 100644 --- a/app/project/item/footage/footage.h +++ b/app/project/item/footage/footage.h @@ -299,6 +299,8 @@ protected: virtual void InputValueChangedEvent(const QString &input, int element) override; private: + QString GetColorspaceToUse(const VideoParams& params) const; + /** * @brief Update the icon based on the Footage status * diff --git a/app/project/project.cpp b/app/project/project.cpp index 0725198a7..b4df36707 100644 --- a/app/project/project.cpp +++ b/app/project/project.cpp @@ -36,12 +36,17 @@ Project::Project() : is_modified_(false), autorecovery_saved_(true) { - root_.setParent(this); + // Adds a color manager "node" to this project so that it synchronizes + color_manager_ = new ColorManager(); + color_manager_->setParent(this); - connect(&color_manager_, &ColorManager::ConfigChanged, - this, &Project::ColorConfigChanged); - connect(&color_manager_, &ColorManager::DefaultInputColorSpaceChanged, - this, &Project::DefaultColorSpaceChanged); + // Folder root for project + root_ = new Folder(); + root_->setParent(this); + root_->SetLabel(tr("Root")); + + connect(color_manager(), &ColorManager::ValueChanged, + this, &Project::ColorManagerValueChanged); } void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, uint version, const QAtomicInt* cancelled) @@ -51,20 +56,7 @@ void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, uint while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("root")) { - root_.Load(reader, xml_node_data, version, cancelled); - - } else if (reader->name() == QStringLiteral("colormanagement")) { - - // Read color management info - while (XMLReadNextStartElement(reader)) { - if (reader->name() == QStringLiteral("config")) { - color_manager_.SetConfig(reader->readElementText()); - } else if (reader->name() == QStringLiteral("default")) { - color_manager_.SetDefaultInputColorSpace(reader->readElementText()); - } else { - reader->skipCurrentElement(); - } - } + root_->Load(reader, xml_node_data, version, cancelled); } else if (reader->name() == QStringLiteral("cachepath")) { @@ -102,7 +94,7 @@ void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, uint Node* node; if (is_root) { - node = &root_; + node = root_; } else { node = NodeFactory::CreateFromID(id); } @@ -138,17 +130,23 @@ void Project::Save(QXmlStreamWriter *writer) const { writer->writeTextElement(QStringLiteral("cachepath"), cache_path(false)); - writer->writeStartElement(QStringLiteral("root")); - root_.Save(writer); - writer->writeEndElement(); + writer->writeStartElement(QStringLiteral("nodes")); - writer->writeStartElement(QStringLiteral("colormanagement")); + foreach (Node* node, nodes()) { + writer->writeStartElement(QStringLiteral("node")); - writer->writeTextElement(QStringLiteral("config"), color_manager_.GetConfigFilename()); + if (node == root_) { + writer->writeAttribute(QStringLiteral("root"), QStringLiteral("1")); + } - writer->writeTextElement(QStringLiteral("default"), color_manager_.GetDefaultInputColorSpace()); + writer->writeAttribute(QStringLiteral("id"), node->id()); - writer->writeEndElement(); // colormanagement + node->Save(writer); + + writer->writeEndElement(); // node + } + + writer->writeEndElement(); // nodes // Save main window project layout MainWindowLayoutInfo main_window_info = Core::instance()->main_window()->SaveLayout(); @@ -157,7 +155,7 @@ void Project::Save(QXmlStreamWriter *writer) const Folder *Project::root() { - return &root_; + return root_; } QString Project::name() const @@ -199,7 +197,7 @@ void Project::set_filename(const QString &s) ColorManager *Project::color_manager() { - return &color_manager_; + return color_manager_; } bool Project::is_modified() const @@ -238,22 +236,15 @@ const QString &Project::cache_path(bool default_if_empty) const return cache_path_; } -void Project::ColorConfigChanged() +void Project::ColorManagerValueChanged(const NodeInput &input, const TimeRange &range) { + Q_UNUSED(range) + QVector footage = root()->ListOutputsOfType(); foreach (Footage* item, footage) { item->InvalidateAll(QString()); //static_cast(s)->ColorConfigChanged(); - } -} - -void Project::DefaultColorSpaceChanged() -{ - QVector footage = root_.ListOutputsOfType(); - - foreach (Footage* item, footage) { - item->InvalidateAll(QString()); //static_cast(s)->DefaultColorSpaceChanged(); } } diff --git a/app/project/project.h b/app/project/project.h index 594f34e17..cfa5cbf3d 100644 --- a/app/project/project.h +++ b/app/project/project.h @@ -74,6 +74,8 @@ public: void set_cache_path(const QString& cache_path) { cache_path_ = cache_path; + + emit CachePathChanged(cache_path_); } signals: @@ -81,12 +83,14 @@ signals: void ModifiedChanged(bool e); + void CachePathChanged(const QString& s); + private: - Folder root_; + Folder* root_; QString filename_; - ColorManager color_manager_; + ColorManager* color_manager_; bool is_modified_; @@ -95,9 +99,7 @@ private: QString cache_path_; private slots: - void ColorConfigChanged(); - - void DefaultColorSpaceChanged(); + void ColorManagerValueChanged(const NodeInput& input, const TimeRange& range); }; diff --git a/app/render/colormanager.cpp b/app/render/colormanager.cpp index b0dd6e4cd..c3a84d8a7 100644 --- a/app/render/colormanager.cpp +++ b/app/render/colormanager.cpp @@ -31,18 +31,27 @@ namespace olive { +const QString ColorManager::kConfigFilenameIn = QStringLiteral("config"); +const QString ColorManager::kDefaultColorspaceIn = QStringLiteral("default_input"); +const QString ColorManager::kReferenceSpaceIn = QStringLiteral("reference_space"); + OCIO::ConstConfigRcPtr ColorManager::default_config_; -ColorManager::ColorManager() +ColorManager::ColorManager() : + config_(nullptr) { - // Set config to our built-in default - config_ = GetDefaultConfig(); + // Filename input + AddInput(kConfigFilenameIn, NodeValue::kFile, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); - // Default input space - default_input_color_space_ = QStringLiteral("sRGB OETF"); + // Colorspace input + AddInput(kDefaultColorspaceIn, NodeValue::kCombo, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); // Default reference space is scene linear - reference_space_ = OCIO::ROLE_SCENE_LINEAR; + AddInput(kReferenceSpaceIn, NodeValue::kText, OCIO::ROLE_SCENE_LINEAR, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); + + // Set config to our built-in default + SetConfig(GetDefaultConfig()); + SetDefaultInputColorSpace(QStringLiteral("sRGB OETF")); } OCIO::ConstConfigRcPtr ColorManager::GetConfig() const @@ -57,9 +66,9 @@ OCIO::ConstConfigRcPtr ColorManager::CreateConfigFromFile(const QString &filenam return OCIO::Config::CreateFromFile(filename.toUtf8()); } -const QString &ColorManager::GetConfigFilename() const +QString ColorManager::GetConfigFilename() const { - return config_filename_; + return GetStandardValue(kConfigFilenameIn).toString(); } OCIO::ConstConfigRcPtr ColorManager::GetDefaultConfig() @@ -96,57 +105,9 @@ void ColorManager::SetUpDefaultConfig() } } -void ColorManager::SetConfig(const QString &filename) +void ColorManager::SetConfigFilename(const QString &filename) { - if (filename != config_filename_) { - SetConfigInternal(filename); - - emit ConfigChanged(); - } -} - -void ColorManager::SetConfigInternal(const QString &filename) -{ - config_filename_ = filename; - - OCIO::ConstConfigRcPtr cfg; - - if (config_filename_.isEmpty()) { - cfg = OCIO::GetCurrentConfig(); - } else { - cfg = OCIO::Config::CreateFromFile(filename.toUtf8()); - } - - config_ = cfg; -} - -void ColorManager::SetDefaultInputColorSpaceInternal(const QString &s) -{ - default_input_color_space_ = s; -} - -void ColorManager::SetConfigAndDefaultInput(const QString &filename, const QString &s) -{ - bool config_changed = false; - bool default_input_changed = false; - - if (filename != config_filename_) { - SetConfigInternal(filename); - config_changed = true; - } - - if (default_input_color_space_ != s) { - SetDefaultInputColorSpaceInternal(s); - default_input_changed = true; - } - - if (config_changed) { - emit ConfigChanged(); - } - - if (default_input_changed) { - emit DefaultInputColorSpaceChanged(); - } + SetStandardValue(kConfigFilenameIn, filename); } QStringList ColorManager::ListAvailableDisplays() @@ -198,35 +159,29 @@ QStringList ColorManager::ListAvailableLooks() return looks; } -QStringList ColorManager::ListAvailableColorspaces() +QStringList ColorManager::ListAvailableColorspaces() const { return ListAvailableColorspaces(config_); } -const QString &ColorManager::GetDefaultInputColorSpace() const +QString ColorManager::GetDefaultInputColorSpace() const { - return default_input_color_space_; + return ListAvailableColorspaces().at(GetStandardValue(kDefaultColorspaceIn).toInt()); } void ColorManager::SetDefaultInputColorSpace(const QString &s) { - if (default_input_color_space_ != s) { - SetDefaultInputColorSpaceInternal(s); - - emit DefaultInputColorSpaceChanged(); - } + SetStandardValue(kDefaultColorspaceIn, ListAvailableColorspaces().indexOf(s)); } -const QString &ColorManager::GetReferenceColorSpace() const +QString ColorManager::GetReferenceColorSpace() const { - return reference_space_; + return GetStandardValue(kReferenceSpaceIn).toString(); } void ColorManager::SetReferenceColorSpace(const QString &s) { - reference_space_ = s; - - emit ConfigChanged(); + SetStandardValue(kReferenceSpaceIn, s); } QString ColorManager::GetCompliantColorSpace(const QString &s) @@ -307,6 +262,26 @@ Color ColorManager::GetDefaultLumaCoefs() const return c; } +void ColorManager::Retranslate() +{ + SetInputName(kConfigFilenameIn, tr("Configuration")); + SetInputName(kDefaultColorspaceIn, tr("Default Input")); + SetInputName(kReferenceSpaceIn, tr("Reference Space")); +} + +void ColorManager::InputValueChangedEvent(const QString &input, int element) +{ + Q_UNUSED(element) + + if (input == kConfigFilenameIn) { + + try { + SetConfig(OCIO::Config::CreateFromFile(GetConfigFilename().toUtf8())); + } catch (OCIO::Exception& e) {} + + } +} + ColorManager::SetLocale::SetLocale(const char* new_locale) { old_locale_ = setlocale(LC_NUMERIC, nullptr); @@ -318,4 +293,11 @@ ColorManager::SetLocale::~SetLocale() setlocale(LC_NUMERIC, old_locale_.toUtf8()); } +void ColorManager::SetConfig(OCIO::ConstConfigRcPtr config) +{ + config_ = config; + + SetComboBoxStrings(kDefaultColorspaceIn, ListAvailableColorspaces()); +} + } diff --git a/app/render/colormanager.h b/app/render/colormanager.h index 286aa69d2..837bacc13 100644 --- a/app/render/colormanager.h +++ b/app/render/colormanager.h @@ -26,30 +26,54 @@ #include "codec/frame.h" #include "colorprocessor.h" +#include "node/node.h" #define OCIO_SET_C_LOCALE_FOR_SCOPE ColorManager::SetLocale d("C") namespace olive { -class ColorManager : public QObject +class ColorManager : public Node { Q_OBJECT public: ColorManager(); + virtual QString Name() const override + { + return tr("Color Manager"); + } + + virtual QString id() const override + { + return QStringLiteral("org.olivevideoeditor.Olive.colormanager"); + } + + virtual QVector Category() const override + { + return {kCategoryColor}; + } + + virtual QString Description() const override + { + return tr("Color management configuration for project."); + } + + virtual Node* copy() const override + { + return new ColorManager(); + } + OCIO::ConstConfigRcPtr GetConfig() const; static OCIO::ConstConfigRcPtr CreateConfigFromFile(const QString& filename); - const QString& GetConfigFilename() const; + QString GetConfigFilename() const; static OCIO::ConstConfigRcPtr GetDefaultConfig(); static void SetUpDefaultConfig(); - void SetConfig(const QString& filename); - - void SetConfigAndDefaultInput(const QString& filename, const QString& s); + void SetConfigFilename(const QString& filename); QStringList ListAvailableDisplays(); @@ -61,13 +85,13 @@ public: QStringList ListAvailableLooks(); - QStringList ListAvailableColorspaces(); + QStringList ListAvailableColorspaces() const; - const QString& GetDefaultInputColorSpace() const; + QString GetDefaultInputColorSpace() const; void SetDefaultInputColorSpace(const QString& s); - const QString& GetReferenceColorSpace() const; + QString GetReferenceColorSpace() const; void SetReferenceColorSpace(const QString& s); @@ -97,24 +121,20 @@ public: return &mutex_; } -signals: - void ConfigChanged(); + static const QString kConfigFilenameIn; + static const QString kDefaultColorspaceIn; + static const QString kReferenceSpaceIn; - void DefaultInputColorSpaceChanged(); + virtual void Retranslate() override; + +protected: + virtual void InputValueChangedEvent(const QString &input, int element) override; private: - void SetConfigInternal(const QString& filename); - - void SetDefaultInputColorSpaceInternal(const QString& s); + void SetConfig(OCIO::ConstConfigRcPtr config); OCIO::ConstConfigRcPtr config_; - QString config_filename_; - - QString default_input_color_space_; - - QString reference_space_; - QMutex mutex_; static OCIO::ConstConfigRcPtr default_config_; diff --git a/app/render/previewautocacher.cpp b/app/render/previewautocacher.cpp index 41a532746..2f706537f 100644 --- a/app/render/previewautocacher.cpp +++ b/app/render/previewautocacher.cpp @@ -287,10 +287,10 @@ void PreviewAutoCacher::AddNode(Node *node) copy->setParent(&copied_project_); // Insert into map - copy_map_.insert(node, copy); + InsertIntoCopyMap(node, copy); - // Copy parameters - Node::CopyInputs(node, copy, false); + // Keep track of our nodes + created_nodes_.append(copy); } void PreviewAutoCacher::RemoveNode(Node *node) @@ -324,6 +324,15 @@ void PreviewAutoCacher::CopyValue(const NodeInput &input) Node::CopyValuesOfElement(input.node(), our_input, input.input(), input.element()); } +void PreviewAutoCacher::InsertIntoCopyMap(Node *node, Node *copy) +{ + // Insert into map + copy_map_.insert(node, copy); + + // Copy parameters + Node::CopyInputs(node, copy, false); +} + void PreviewAutoCacher::SetPlayhead(const rational &playhead) { cache_range_ = TimeRange(playhead - Config::Current()[QStringLiteral("DiskCacheBehind")].value(), @@ -589,9 +598,8 @@ void PreviewAutoCacher::SetViewerNode(Sequence *viewer_node) } // Delete all of our copied nodes - foreach (Node* c, copy_map_) { - delete c; - } + qDeleteAll(created_nodes_); + created_nodes_.clear(); copy_map_.clear(); copied_viewer_node_ = nullptr; graph_update_queue_.clear(); @@ -624,8 +632,11 @@ void PreviewAutoCacher::SetViewerNode(Sequence *viewer_node) NodeGraph* graph = viewer_node_->parent(); // Add all nodes - foreach (Node* node, graph->nodes()) { - AddNode(node); + for (int i=0; inodes().at(i), copied_project_.nodes().at(i)); + } + for (int i=copied_project_.nodes().size(); inodes().size(); i++) { + AddNode(graph->nodes().at(i)); } // Find copied viewer node diff --git a/app/render/previewautocacher.h b/app/render/previewautocacher.h index 36523edf7..b7cd698af 100644 --- a/app/render/previewautocacher.h +++ b/app/render/previewautocacher.h @@ -112,6 +112,8 @@ private: void RemoveEdge(const NodeOutput& output, const NodeInput& input); void CopyValue(const NodeInput& input); + void InsertIntoCopyMap(Node* node, Node* copy); + class QueuedJob { public: enum Type { @@ -135,6 +137,7 @@ private: QVector graph_update_queue_; QHash copy_map_; Sequence* copied_viewer_node_; + QVector created_nodes_; bool paused_; diff --git a/app/widget/manageddisplay/manageddisplay.cpp b/app/widget/manageddisplay/manageddisplay.cpp index 1ac964fd7..3d5e674a7 100644 --- a/app/widget/manageddisplay/manageddisplay.cpp +++ b/app/widget/manageddisplay/manageddisplay.cpp @@ -86,13 +86,13 @@ void ManagedDisplayWidget::ConnectColorManager(ColorManager *color_manager) } if (color_manager_ != nullptr) { - disconnect(color_manager_, &ColorManager::ConfigChanged, this, &ManagedDisplayWidget::ColorConfigChanged); + disconnect(color_manager_, &ColorManager::ValueChanged, this, &ManagedDisplayWidget::ColorManagerValueChanged); } color_manager_ = color_manager; if (color_manager_ != nullptr) { - connect(color_manager_, &ColorManager::ConfigChanged, this, &ManagedDisplayWidget::ColorConfigChanged); + connect(color_manager_, &ColorManager::ValueChanged, this, &ManagedDisplayWidget::ColorManagerValueChanged); } ColorConfigChanged(); @@ -350,4 +350,13 @@ void ManagedDisplayWidget::SetupColorProcessor() emit ColorProcessorChanged(color_service_); } +void ManagedDisplayWidget::ColorManagerValueChanged(const NodeInput &input, const TimeRange &range) +{ + Q_UNUSED(range) + + if (input.input() == ColorManager::kConfigFilenameIn || input.input() == ColorManager::kReferenceSpaceIn) { + ColorConfigChanged(); + } +} + } diff --git a/app/widget/manageddisplay/manageddisplay.h b/app/widget/manageddisplay/manageddisplay.h index 4b08dfead..6a015cbc4 100644 --- a/app/widget/manageddisplay/manageddisplay.h +++ b/app/widget/manageddisplay/manageddisplay.h @@ -246,6 +246,8 @@ private slots: */ void ColorConfigChanged(); + void ColorManagerValueChanged(const NodeInput &input, const TimeRange &range); + /** * @brief The default context menu shown */