diff --git a/app/core.cpp b/app/core.cpp
index 16cab3c1e..18b077042 100644
--- a/app/core.cpp
+++ b/app/core.cpp
@@ -34,11 +34,12 @@
#include "dialog/about/about.h"
#include "dialog/sequence/sequence.h"
#include "dialog/preferences/preferences.h"
+#include "dialog/projectproperties/projectproperties.h"
#include "panel/panelmanager.h"
#include "panel/project/project.h"
#include "project/item/footage/footage.h"
#include "project/item/sequence/sequence.h"
-#include "render/colorservice.h"
+#include "render/colormanager.h"
#include "task/import/import.h"
#include "task/taskmanager.h"
#include "ui/style/style.h"
@@ -92,6 +93,9 @@ void Core::Start()
// Load application config
Config::Load();
+ // Set up color manager
+ ColorManager::CreateInstance();
+
//
// Start GUI (FIXME CLI mode)
@@ -108,6 +112,8 @@ void Core::Stop()
{
AudioManager::DestroyInstance();
+ ColorManager::DestroyInstance();
+
delete main_window_;
}
@@ -208,6 +214,12 @@ void Core::DialogPreferencesShow()
pd.exec();
}
+void Core::DialogProjectPropertiesShow()
+{
+ ProjectPropertiesDialog ppd(main_window_);
+ ppd.exec();
+}
+
void Core::CreateNewFolder()
{
// Locate the most recently focused Project panel (assume that's the panel the user wants to import into)
@@ -334,12 +346,8 @@ void Core::StartGUI(bool full_screen)
// When a new project is opened, update the mainwindow
connect(this, SIGNAL(ProjectOpened(Project*)), main_window_, SLOT(ProjectOpen(Project*)));
- // Initialize color service
- ColorService::Init();
-
// Initialize audio service
AudioManager::CreateInstance();
-
}
Project *Core::GetActiveProject()
diff --git a/app/core.h b/app/core.h
index 88e1e0593..d723c5731 100644
--- a/app/core.h
+++ b/app/core.h
@@ -129,6 +129,11 @@ public slots:
*/
void DialogPreferencesShow();
+ /**
+ * @brief Show Project Properties dialog
+ */
+ void DialogProjectPropertiesShow();
+
/**
* @brief Create a new folder in the currently active project
*/
diff --git a/app/dialog/CMakeLists.txt b/app/dialog/CMakeLists.txt
index 4c13cbc0c..0e8af7660 100644
--- a/app/dialog/CMakeLists.txt
+++ b/app/dialog/CMakeLists.txt
@@ -16,7 +16,9 @@
add_subdirectory(about)
add_subdirectory(actionsearch)
+add_subdirectory(footageproperties)
add_subdirectory(preferences)
+add_subdirectory(projectproperties)
add_subdirectory(sequence)
set(OLIVE_SOURCES
diff --git a/app/dialog/footageproperties/CMakeLists.txt b/app/dialog/footageproperties/CMakeLists.txt
new file mode 100644
index 000000000..3c4ee65c3
--- /dev/null
+++ b/app/dialog/footageproperties/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}
+ dialog/footageproperties/footageproperties.h
+ dialog/footageproperties/footageproperties.cpp
+ PARENT_SCOPE
+)
diff --git a/app/dialog/footageproperties/footageproperties.cpp b/app/dialog/footageproperties/footageproperties.cpp
new file mode 100644
index 000000000..d4ea2a2e1
--- /dev/null
+++ b/app/dialog/footageproperties/footageproperties.cpp
@@ -0,0 +1,209 @@
+/***
+
+ 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 "footageproperties.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+namespace OCIO = OCIO_NAMESPACE::v1;
+
+#include "undo/undostack.h"
+
+FootagePropertiesDialog::FootagePropertiesDialog(QWidget *parent, FootagePtr footage) :
+ QDialog(parent),
+ footage_(footage)
+{
+ QGridLayout* layout = new QGridLayout(this);
+
+ setWindowTitle(tr("\"%1\" Properties").arg(footage_->name()));
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+ int row = 0;
+
+ layout->addWidget(new QLabel(tr("Tracks:"), this), row, 0, 1, 2);
+ row++;
+
+ track_list = new QListWidget(this);
+
+ foreach (StreamPtr stream, footage_->streams()) {
+ QListWidgetItem* item = new QListWidgetItem(stream->description(), track_list);
+ item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
+ item->setCheckState(stream->enabled() ? Qt::Checked : Qt::Unchecked);
+ track_list->addItem(item);
+ }
+
+ layout->addWidget(track_list, row, 0, 1, 2);
+ row++;
+
+ /*if (f->video_tracks.size() > 0) {
+ // frame conforming
+ if (!f->video_tracks.at(0).infinite_length) {
+ layout->addWidget(new QLabel(tr("Conform to Frame Rate:"), this), row, 0);
+ conform_fr = new QDoubleSpinBox(this);
+ conform_fr->setMinimum(0.01);
+ conform_fr->setValue(f->video_tracks.at(0).video_frame_rate * f->speed);
+ layout->addWidget(conform_fr, row, 1);
+ }
+
+ row++;
+
+ // premultiplied alpha mode
+ premultiply_alpha_setting = new QCheckBox(tr("Alpha is Premultiplied"), this);
+ premultiply_alpha_setting->setChecked(f->alpha_is_associated);
+ layout->addWidget(premultiply_alpha_setting, row, 0);
+
+ row++;
+
+ // deinterlacing mode
+ interlacing_box = new QComboBox(this);
+ interlacing_box->addItem(
+ tr("Auto (%1)").arg(
+ Footage::get_interlacing_name(f->video_tracks.at(0).video_auto_interlacing)
+ )
+ );
+ interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_PROGRESSIVE));
+ interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_TOP_FIELD_FIRST));
+ interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_BOTTOM_FIELD_FIRST));
+
+ interlacing_box->setCurrentIndex(
+ (f->video_tracks.at(0).video_auto_interlacing == f->video_tracks.at(0).video_interlacing)
+ ? 0
+ : f->video_tracks.at(0).video_interlacing + 1);
+
+ layout->addWidget(new QLabel(tr("Interlacing:"), this), row, 0);
+ layout->addWidget(interlacing_box, row, 1);
+
+ row++;
+
+ input_color_space = new QComboBox(this);
+
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ QString footage_colorspace = f->Colorspace();
+
+ for (int i=0;igetNumColorSpaces();i++) {
+ QString colorspace = config->getColorSpaceNameByIndex(i);
+
+ input_color_space->addItem(colorspace);
+
+ if (colorspace == footage_colorspace) {
+ input_color_space->setCurrentIndex(i);
+ }
+ }
+
+ layout->addWidget(new QLabel(tr("Color Space:")), row, 0);
+ layout->addWidget(input_color_space, row, 1);
+
+ row++;
+
+ }
+ */
+
+ name_box = new QLineEdit(footage_->name(), this);
+ layout->addWidget(new QLabel(tr("Name:"), this), row, 0);
+ layout->addWidget(name_box, row, 1);
+ row++;
+
+ QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
+ buttons->setCenterButtons(true);
+ layout->addWidget(buttons, row, 0, 1, 2);
+
+ connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
+}
+
+void FootagePropertiesDialog::accept() {
+ /*Footage* f = item->to_footage();
+
+ ComboAction* ca = new ComboAction();
+
+ // set track enable
+ for (int i=0;icount();i++) {
+ QListWidgetItem* item = track_list->item(i);
+ const QVariant& data = item->data(Qt::UserRole+1);
+ if (!data.isNull()) {
+ int index = data.toInt();
+ bool found = false;
+ for (int j=0;jvideo_tracks.size();j++) {
+ if (f->video_tracks.at(j).file_index == index) {
+ f->video_tracks[j].enabled = (item->checkState() == Qt::Checked);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ for (int j=0;jaudio_tracks.size();j++) {
+ if (f->audio_tracks.at(j).file_index == index) {
+ f->audio_tracks[j].enabled = (item->checkState() == Qt::Checked);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ bool refresh_clips = false;
+
+ // set interlacing
+ if (f->video_tracks.size() > 0) {
+ if (interlacing_box->currentIndex() > 0) {
+ ca->append(new SetInt(&f->video_tracks[0].video_interlacing, interlacing_box->currentIndex() - 1));
+ } else {
+ ca->append(new SetInt(&f->video_tracks[0].video_interlacing, f->video_tracks.at(0).video_auto_interlacing));
+ }
+
+ // set frame rate conform
+ if (!f->video_tracks.at(0).infinite_length) {
+ if (!qFuzzyCompare(conform_fr->value(), f->video_tracks.at(0).video_frame_rate)) {
+ ca->append(new SetDouble(&f->speed, f->speed, conform_fr->value()/f->video_tracks.at(0).video_frame_rate));
+ refresh_clips = true;
+ }
+ }
+
+ // set premultiplied alpha
+ f->alpha_is_associated = premultiply_alpha_setting->isChecked();
+ }
+
+ f->SetColorspace(input_color_space->currentText());
+
+ // set name
+ MediaRename* mr = new MediaRename(item, name_box->text());
+
+ ca->append(mr);
+ ca->appendPost(new CloseAllClipsCommand());
+ ca->appendPost(new UpdateFootageTooltip(item));
+ if (refresh_clips) {
+ ca->appendPost(new RefreshClips(item));
+ }
+ ca->appendPost(new UpdateViewer());
+
+ olive::undo_stack.push(ca);*/
+
+ QDialog::accept();
+}
diff --git a/app/dialog/footageproperties/footageproperties.h b/app/dialog/footageproperties/footageproperties.h
new file mode 100644
index 000000000..157dbf305
--- /dev/null
+++ b/app/dialog/footageproperties/footageproperties.h
@@ -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 .
+
+***/
+
+#ifndef MEDIAPROPERTIESDIALOG_H
+#define MEDIAPROPERTIESDIALOG_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "project/item/footage/footage.h"
+
+/**
+ * @brief The MediaPropertiesDialog class
+ *
+ * A dialog for setting properties on Media. This can be loaded from any part of the application provided it's given
+ * a valid Media object.
+ */
+class FootagePropertiesDialog : public QDialog {
+ Q_OBJECT
+public:
+ /**
+ * @brief MediaPropertiesDialog Constructor
+ *
+ * @param parent
+ *
+ * QWidget parent. Usually MainWindow or Project panel.
+ *
+ * @param i
+ *
+ * Media object to set properties for.
+ */
+ FootagePropertiesDialog(QWidget *parent, FootagePtr footage);
+private:
+ /**
+ * @brief ComboBox for interlacing setting
+ */
+ QComboBox* interlacing_box;
+
+ /**
+ * @brief Media name text field
+ */
+ QLineEdit* name_box;
+
+ /**
+ * @brief Internal pointer to Media object (set in constructor)
+ */
+ FootagePtr footage_;
+
+ /**
+ * @brief A list widget for listing the tracks in Media
+ */
+ QListWidget* track_list;
+
+ /**
+ * @brief Frame rate to conform to
+ */
+ QDoubleSpinBox* conform_fr;
+
+ /**
+ * @brief Setting for associated/premultiplied alpha
+ */
+ QCheckBox* premultiply_alpha_setting;
+
+ /**
+ * @brief Setting for this media's color space
+ */
+ QComboBox* input_color_space;
+private slots:
+ /**
+ * @brief Overridden accept function for saving the properties back to the Media class
+ */
+ void accept();
+};
+
+#endif // MEDIAPROPERTIESDIALOG_H
diff --git a/app/dialog/projectproperties/CMakeLists.txt b/app/dialog/projectproperties/CMakeLists.txt
new file mode 100644
index 000000000..7763f8c34
--- /dev/null
+++ b/app/dialog/projectproperties/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}
+ dialog/projectproperties/projectproperties.h
+ dialog/projectproperties/projectproperties.cpp
+ PARENT_SCOPE
+)
diff --git a/app/dialog/projectproperties/projectproperties.cpp b/app/dialog/projectproperties/projectproperties.cpp
new file mode 100644
index 000000000..ae31a7966
--- /dev/null
+++ b/app/dialog/projectproperties/projectproperties.cpp
@@ -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 .
+
+***/
+
+#include "projectproperties.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+namespace OCIO = OCIO_NAMESPACE::v1;
+
+#include "render/colormanager.h"
+
+ProjectPropertiesDialog::ProjectPropertiesDialog(QWidget *parent) :
+ QDialog(parent)
+{
+ QGridLayout* layout = new QGridLayout(this);
+
+ setWindowTitle(tr("Project Properties"));
+
+ layout->addWidget(new QLabel(tr("OpenColorIO Configuration:")), 0, 0);
+
+ ocio_filename_ = new QLineEdit();
+ layout->addWidget(ocio_filename_, 0, 1);
+
+ QPushButton* browse_btn = new QPushButton(tr("Browse"));
+ layout->addWidget(browse_btn, 0, 2);
+ connect(browse_btn, SIGNAL(clicked(bool)), this, SLOT(BrowseForOCIOConfig()));
+
+ QDialogButtonBox* dialog_btns = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal);
+ layout->addWidget(dialog_btns, 1, 0, 1, 3);
+ connect(dialog_btns, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(dialog_btns, SIGNAL(rejected()), this, SLOT(reject()));
+}
+
+void ProjectPropertiesDialog::accept()
+{
+ try {
+ OCIO::ConstConfigRcPtr config = OCIO::Config::CreateFromFile(ocio_filename_->text().toUtf8());
+
+ ColorManager::instance()->SetConfig(config);
+
+ QDialog::accept();
+ } catch (OCIO::Exception& e) {
+ QMessageBox::critical(this,
+ tr("OpenColorIO Config Error"),
+ tr("Failed to set OpenColorIO configuration: %1").arg(e.what()),
+ QMessageBox::Ok);
+ }
+}
+
+void ProjectPropertiesDialog::BrowseForOCIOConfig()
+{
+ QString fn = QFileDialog::getOpenFileName(this, tr("Browse for OpenColorIO configuration"));
+ if (!fn.isEmpty()) {
+ ocio_filename_->setText(fn);
+ }
+}
diff --git a/app/dialog/projectproperties/projectproperties.h b/app/dialog/projectproperties/projectproperties.h
new file mode 100644
index 000000000..6700e9c50
--- /dev/null
+++ b/app/dialog/projectproperties/projectproperties.h
@@ -0,0 +1,44 @@
+/***
+
+ 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 PROJECTPROPERTIESDIALOG_H
+#define PROJECTPROPERTIESDIALOG_H
+
+#include
+#include
+
+class ProjectPropertiesDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ ProjectPropertiesDialog(QWidget* parent);
+
+public slots:
+ virtual void accept() override;
+
+private:
+ QLineEdit* ocio_filename_;
+
+private slots:
+ void BrowseForOCIOConfig();
+
+};
+
+#endif // PROJECTPROPERTIESDIALOG_H
diff --git a/app/node/input/media/media.cpp b/app/node/input/media/media.cpp
index 7a94db510..3d769be86 100644
--- a/app/node/input/media/media.cpp
+++ b/app/node/input/media/media.cpp
@@ -154,7 +154,7 @@ QVariant MediaInput::Value(NodeOutput *output, const rational &time)
if (color_service_ == nullptr) {
// FIXME: Hardcoded values for testing
- color_service_ = std::make_shared("srgb", OCIO::ROLE_SCENE_LINEAR);
+ color_service_ = ColorProcessor::Create("srgb", OCIO::ROLE_SCENE_LINEAR);
}
// OpenColorIO v1's color transforms can be done on GPU, which improves performance but reduces accuracy. When
@@ -166,7 +166,7 @@ QVariant MediaInput::Value(NodeOutput *output, const rational &time)
if (alpha_is_associated) {
// Unassociate alpha here if associated
- ColorService::DisassociateAlpha(frame_);
+ ColorManager::DisassociateAlpha(frame_);
}
// Transform color to reference space
@@ -174,10 +174,10 @@ QVariant MediaInput::Value(NodeOutput *output, const rational &time)
if (alpha_is_associated) {
// If alpha was associated, reassociate here
- ColorService::ReassociateAlpha(frame_);
+ ColorManager::ReassociateAlpha(frame_);
} else {
// If alpha was not associated, associate here
- ColorService::AssociateAlpha(frame_);
+ ColorManager::AssociateAlpha(frame_);
}
}
diff --git a/app/node/input/media/media.h b/app/node/input/media/media.h
index c1dede3d0..23a7c28de 100644
--- a/app/node/input/media/media.h
+++ b/app/node/input/media/media.h
@@ -25,7 +25,7 @@
#include "decoder/decoder.h"
#include "node/node.h"
-#include "render/colorservice.h"
+#include "render/colormanager.h"
#include "render/rendertexture.h"
#include "render/gl/shadergenerators.h"
@@ -69,7 +69,7 @@ private:
DecoderPtr decoder_;
- ColorServicePtr color_service_;
+ ColorProcessorPtr color_service_;
ShaderPtr pipeline_;
diff --git a/app/project/item/footage/stream.cpp b/app/project/item/footage/stream.cpp
index c1b89c9eb..eb364d1f0 100644
--- a/app/project/item/footage/stream.cpp
+++ b/app/project/item/footage/stream.cpp
@@ -24,7 +24,8 @@
Stream::Stream() :
footage_(nullptr),
- type_(kUnknown)
+ type_(kUnknown),
+ enabled_(true)
{
}
@@ -88,6 +89,16 @@ void Stream::set_duration(const int64_t &duration)
duration_ = duration;
}
+bool Stream::enabled()
+{
+ return enabled_;
+}
+
+void Stream::set_enabled(bool e)
+{
+ enabled_ = e;
+}
+
QIcon Stream::IconFromType(const Stream::Type &type)
{
switch (type) {
diff --git a/app/project/item/footage/stream.h b/app/project/item/footage/stream.h
index 23106d8e2..f187d0613 100644
--- a/app/project/item/footage/stream.h
+++ b/app/project/item/footage/stream.h
@@ -78,6 +78,9 @@ public:
const int64_t& duration() const;
void set_duration(const int64_t& duration);
+ bool enabled();
+ void set_enabled(bool e);
+
static QIcon IconFromType(const Type& type);
private:
@@ -91,6 +94,8 @@ private:
Type type_;
+ bool enabled_;
+
};
using StreamPtr = std::shared_ptr;
diff --git a/app/render/CMakeLists.txt b/app/render/CMakeLists.txt
index 3a0a6a23b..5a26e69d0 100644
--- a/app/render/CMakeLists.txt
+++ b/app/render/CMakeLists.txt
@@ -18,8 +18,10 @@ add_subdirectory(gl)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
- render/colorservice.h
- render/colorservice.cpp
+ render/colormanager.h
+ render/colormanager.cpp
+ render/colorprocessor.h
+ render/colorprocessor.cpp
render/pixelformat.h
render/pixelformat.cpp
render/pixelservice.h
diff --git a/app/render/colormanager.cpp b/app/render/colormanager.cpp
new file mode 100644
index 000000000..aab542b72
--- /dev/null
+++ b/app/render/colormanager.cpp
@@ -0,0 +1,155 @@
+#include "colormanager.h"
+
+#include
+
+#include "common/define.h"
+
+ColorManager* ColorManager::instance_ = nullptr;
+
+void ColorManager::SetConfig(const QString &filename)
+{
+ SetConfig(OCIO::Config::CreateFromFile(filename.toUtf8()));
+}
+
+void ColorManager::SetConfig(OpenColorIO::v1::ConstConfigRcPtr config)
+{
+ OCIO::SetCurrentConfig(config);
+
+ emit ConfigChanged();
+}
+
+void ColorManager::CreateInstance()
+{
+ if (instance_ == nullptr) {
+ instance_ = new ColorManager();
+ }
+}
+
+ColorManager *ColorManager::instance()
+{
+ return instance_;
+}
+
+void ColorManager::DestroyInstance()
+{
+ delete instance_;
+ instance_ = nullptr;
+}
+
+void ColorManager::DisassociateAlpha(FramePtr f)
+{
+ AssociateAlphaPixFmtFilter(kDisassociate, f);
+}
+
+void ColorManager::AssociateAlpha(FramePtr f)
+{
+ AssociateAlphaPixFmtFilter(kAssociate, f);
+}
+
+void ColorManager::ReassociateAlpha(FramePtr f)
+{
+ AssociateAlphaPixFmtFilter(kReassociate, f);
+}
+
+QStringList ColorManager::ListAvailableDisplays()
+{
+ QStringList displays;
+
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ int number_of_displays = config->getNumDisplays();
+
+ for (int i=0;igetDisplay(i));
+ }
+
+ return displays;
+}
+
+QString ColorManager::GetDefaultDisplay()
+{
+ return OCIO::GetCurrentConfig()->getDefaultDisplay();
+}
+
+QStringList ColorManager::ListAvailableViews(QString display)
+{
+ QStringList views;
+
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ int number_of_views = config->getNumViews(display.toUtf8());
+
+ for (int i=0;igetView(display.toUtf8(), i));
+ }
+
+ return views;
+}
+
+QString ColorManager::GetDefaultView(const QString &display)
+{
+ return OCIO::GetCurrentConfig()->getDefaultView(display.toUtf8());
+}
+
+QStringList ColorManager::ListAvailableLooks()
+{
+ QStringList looks;
+
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ int number_of_looks = config->getNumLooks();
+
+ for (int i=0;igetLookNameByIndex(i));
+ }
+
+ return looks;
+}
+
+ColorManager::ColorManager()
+{
+}
+
+void ColorManager::AssociateAlphaPixFmtFilter(ColorManager::AlphaAction action, FramePtr f)
+{
+ int pixel_count = f->width() * f->height() * kRGBAChannels;
+
+ switch (static_cast(f->format())) {
+ case olive::PIX_FMT_INVALID:
+ case olive::PIX_FMT_COUNT:
+ qWarning() << "Alpha association functions received an invalid pixel format";
+ break;
+ case olive::PIX_FMT_RGBA8:
+ case olive::PIX_FMT_RGBA16U:
+ qWarning() << "Alpha association functions only works on float-based pixel formats at this time";
+ break;
+ case olive::PIX_FMT_RGBA16F:
+ {
+ AssociateAlphaInternal(action, reinterpret_cast(f->data()), pixel_count);
+ break;
+ }
+ case olive::PIX_FMT_RGBA32F:
+ {
+ AssociateAlphaInternal(action, reinterpret_cast(f->data()), pixel_count);
+ break;
+ }
+ }
+}
+
+template
+void ColorManager::AssociateAlphaInternal(ColorManager::AlphaAction action, T *data, int pix_count)
+{
+ for (int i=0;i 0) {
+ for (int j=0;j
+
+#include "colorprocessor.h"
+#include "decoder/frame.h"
+#include "render/gl/shadergenerators.h"
+
+class ColorManager : public QObject
+{
+ Q_OBJECT
+public:
+ void SetConfig(const QString& filename);
+
+ void SetConfig(OCIO::ConstConfigRcPtr config);
+
+ static void CreateInstance();
+
+ static ColorManager* instance();
+
+ static void DestroyInstance();
+
+ static void DisassociateAlpha(FramePtr f);
+
+ static void AssociateAlpha(FramePtr f);
+
+ static void ReassociateAlpha(FramePtr f);
+
+ static QStringList ListAvailableDisplays();
+
+ static QString GetDefaultDisplay();
+
+ static QStringList ListAvailableViews(QString display);
+
+ static QString GetDefaultView(const QString& display);
+
+ static QStringList ListAvailableLooks();
+
+signals:
+ void ConfigChanged();
+
+private:
+ ColorManager();
+
+ static ColorManager* instance_;
+
+ enum AlphaAction {
+ kAssociate,
+ kDisassociate,
+ kReassociate
+ };
+
+ static void AssociateAlphaPixFmtFilter(AlphaAction action, FramePtr f);
+
+ template
+ static void AssociateAlphaInternal(AlphaAction action, T* data, int pix_count);
+};
+
+#endif // COLORSERVICE_H
diff --git a/app/render/colorprocessor.cpp b/app/render/colorprocessor.cpp
new file mode 100644
index 000000000..eeb334ea4
--- /dev/null
+++ b/app/render/colorprocessor.cpp
@@ -0,0 +1,62 @@
+#include "colorprocessor.h"
+
+#include "common/define.h"
+
+ColorProcessor::ColorProcessor(const QString& source_space, const QString& dest_space)
+{
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ processor = config->getProcessor(source_space.toUtf8(),
+ dest_space.toUtf8());
+}
+
+ColorProcessor::ColorProcessor(const QString& source_space,
+ QString display,
+ QString view,
+ const QString& look)
+{
+ OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
+
+ if (display.isEmpty()) {
+ display = config->getDefaultDisplay();
+ }
+
+ if (view.isEmpty()) {
+ view = config->getDefaultView(display.toUtf8());
+ }
+
+ // Get current display stats
+ OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create();
+ transform->setInputColorSpaceName(source_space.toUtf8());
+ transform->setDisplay(display.toUtf8());
+ transform->setView(view.toUtf8());
+
+ if (!look.isEmpty()) {
+ transform->setLooksOverride(look.toUtf8());
+ transform->setLooksOverrideEnabled(true);
+ }
+
+ processor = config->getProcessor(transform);
+}
+
+void ColorProcessor::ConvertFrame(FramePtr f)
+{
+ OCIO::PackedImageDesc img(reinterpret_cast(f->data()), f->width(), f->height(), kRGBAChannels);
+
+ processor->apply(img);
+}
+
+ColorProcessorPtr ColorProcessor::Create(const QString& source_space, const QString& dest_space)
+{
+ return std::make_shared(source_space, dest_space);
+}
+
+ColorProcessorPtr ColorProcessor::Create(const QString &source_space, const QString &display, const QString &view, const QString &look)
+{
+ return std::make_shared(source_space, display, view, look);
+}
+
+OpenColorIO::v1::ConstProcessorRcPtr ColorProcessor::GetProcessor()
+{
+ return processor;
+}
diff --git a/app/render/colorprocessor.h b/app/render/colorprocessor.h
new file mode 100644
index 000000000..e575e2574
--- /dev/null
+++ b/app/render/colorprocessor.h
@@ -0,0 +1,38 @@
+#ifndef COLORPROCESSOR_H
+#define COLORPROCESSOR_H
+
+#include
+namespace OCIO = OCIO_NAMESPACE::v1;
+
+#include "decoder/frame.h"
+
+class ColorProcessor;
+using ColorProcessorPtr = std::shared_ptr;
+
+class ColorProcessor
+{
+public:
+ ColorProcessor(const QString &source_space, const QString &dest_space);
+
+ ColorProcessor(const QString& source_space,
+ QString display,
+ QString view,
+ const QString& look);
+
+ static ColorProcessorPtr Create(const QString& source_space, const QString& dest_space);
+
+ static ColorProcessorPtr Create(const QString& source_space,
+ const QString& display,
+ const QString& view,
+ const QString& look);
+
+ OCIO::ConstProcessorRcPtr GetProcessor();
+
+ void ConvertFrame(FramePtr f);
+
+private:
+ OCIO::ConstProcessorRcPtr processor;
+
+};
+
+#endif // COLORPROCESSOR_H
diff --git a/app/render/colorservice.cpp b/app/render/colorservice.cpp
deleted file mode 100644
index bd3335c00..000000000
--- a/app/render/colorservice.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-#include "colorservice.h"
-
-#include
-
-#include "common/define.h"
-
-ColorService::ColorService(const char* source_space, const char* dest_space)
-{
- OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
-
- processor = config->getProcessor(source_space,
- dest_space);
-}
-
-void ColorService::Init()
-{
- // FIXME: Load configured config file for this session
- /*try {
- // FIXME: Hardcoded values for testing purposes
- OCIO::ConstConfigRcPtr config = OCIO::Config::CreateFromFile("/run/media/matt/Home/OpenColorIO/ocio.configs.0.7v4/nuke-default/config.ocio");
-
- OCIO::SetCurrentConfig(config);
- } catch (OCIO::Exception& exception) {
- qWarning() << "OpenColorIO Error:" << exception.what();
- }*/
-}
-
-ColorServicePtr ColorService::Create(const char *source_space, const char *dest_space)
-{
- return std::make_shared(source_space, dest_space);
-}
-
-void ColorService::ConvertFrame(FramePtr f)
-{
- OCIO::PackedImageDesc img(reinterpret_cast(f->data()), f->width(), f->height(), kRGBAChannels);
-
- processor->apply(img);
-}
-
-void ColorService::DisassociateAlpha(FramePtr f)
-{
- AssociateAlphaPixFmtFilter(kDisassociate, f);
-}
-
-void ColorService::AssociateAlpha(FramePtr f)
-{
- AssociateAlphaPixFmtFilter(kAssociate, f);
-}
-
-void ColorService::ReassociateAlpha(FramePtr f)
-{
- AssociateAlphaPixFmtFilter(kReassociate, f);
-}
-
-OpenColorIO::v1::ConstProcessorRcPtr ColorService::GetProcessor()
-{
- return processor;
-}
-
-void ColorService::AssociateAlphaPixFmtFilter(ColorService::AlphaAction action, FramePtr f)
-{
- int pixel_count = f->width() * f->height() * kRGBAChannels;
-
- switch (static_cast(f->format())) {
- case olive::PIX_FMT_INVALID:
- case olive::PIX_FMT_COUNT:
- qWarning() << "Alpha association functions received an invalid pixel format";
- break;
- case olive::PIX_FMT_RGBA8:
- case olive::PIX_FMT_RGBA16U:
- qWarning() << "Alpha association functions only works on float-based pixel formats at this time";
- break;
- case olive::PIX_FMT_RGBA16F:
- {
- AssociateAlphaInternal(action, reinterpret_cast(f->data()), pixel_count);
- break;
- }
- case olive::PIX_FMT_RGBA32F:
- {
- AssociateAlphaInternal(action, reinterpret_cast(f->data()), pixel_count);
- break;
- }
- }
-}
-
-template
-void ColorService::AssociateAlphaInternal(ColorService::AlphaAction action, T *data, int pix_count)
-{
- for (int i=0;i 0) {
- for (int j=0;j
-#include
-namespace OCIO = OCIO_NAMESPACE::v1;
-
-#include "decoder/frame.h"
-#include "render/gl/shadergenerators.h"
-
-class ColorService;
-using ColorServicePtr = std::shared_ptr;
-
-class ColorService
-{
-public:
- ColorService(const char *source_space, const char *dest_space);
-
- static void Init();
-
- static ColorServicePtr Create(const char *source_space, const char *dest_space);
-
- void ConvertFrame(FramePtr f);
-
- static void DisassociateAlpha(FramePtr f);
-
- static void AssociateAlpha(FramePtr f);
-
- static void ReassociateAlpha(FramePtr f);
-
- OCIO::ConstProcessorRcPtr GetProcessor();
-
-private:
- OCIO::ConstProcessorRcPtr processor;
-
- enum AlphaAction {
- kAssociate,
- kDisassociate,
- kReassociate
- };
-
- static void AssociateAlphaPixFmtFilter(AlphaAction action, FramePtr f);
-
- template
- static void AssociateAlphaInternal(AlphaAction action, T* data, int pix_count);
-};
-
-#endif // COLORSERVICE_H
diff --git a/app/widget/viewer/viewerglwidget.cpp b/app/widget/viewer/viewerglwidget.cpp
index 751fb62cd..a13585546 100644
--- a/app/widget/viewer/viewerglwidget.cpp
+++ b/app/widget/viewer/viewerglwidget.cpp
@@ -20,6 +20,7 @@
#include "viewerglwidget.h"
+#include
#include
#include
#include
@@ -32,8 +33,17 @@ ViewerGLWidget::ViewerGLWidget(QWidget *parent) :
texture_(0),
ocio_lut_(0)
{
- // FIXME: Hardcoded values for testing
- color_service_ = ColorService::Create(OCIO::ROLE_SCENE_LINEAR, "srgb");
+ connect(ColorManager::instance(), SIGNAL(ConfigChanged()), this, SLOT(ColorConfigChangedSlot()));
+
+ RefreshColorSettings();
+
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(ShowContextMenu(const QPoint&)));
+}
+
+ViewerGLWidget::~ViewerGLWidget()
+{
+ ContextCleanup();
}
void ViewerGLWidget::SetTexture(GLuint tex)
@@ -47,11 +57,7 @@ void ViewerGLWidget::SetTexture(GLuint tex)
void ViewerGLWidget::initializeGL()
{
- // Re-retrieve pipeline pertaining to this context
- pipeline_ = olive::ShaderGenerator::OCIOPipeline(context(),
- ocio_lut_,
- color_service_->GetProcessor(),
- true);
+ SetupPipeline();
connect(context(), SIGNAL(aboutToBeDestroyed()), this, SLOT(ContextCleanup()), Qt::DirectConnection);
}
@@ -78,6 +84,31 @@ void ViewerGLWidget::paintGL()
}
}
+void ViewerGLWidget::SetupPipeline()
+{
+ // Re-retrieve pipeline pertaining to this context
+ pipeline_ = olive::ShaderGenerator::OCIOPipeline(context(),
+ ocio_lut_,
+ color_service_->GetProcessor(),
+ true);
+}
+
+void ViewerGLWidget::RefreshColorSettings()
+{
+ // FIXME: Should probably check first whether the new config has the existing settings
+
+ ocio_display_ = ColorManager::GetDefaultDisplay();
+ ocio_view_ = ColorManager::GetDefaultView(ocio_display_);
+ ocio_look_.clear();
+
+ SetupColorProcessor();
+}
+
+void ViewerGLWidget::SetupColorProcessor()
+{
+ color_service_ = ColorProcessor::Create(OCIO::ROLE_SCENE_LINEAR, ocio_display_, ocio_view_, ocio_look_);
+}
+
void ViewerGLWidget::ContextCleanup()
{
makeCurrent();
@@ -91,3 +122,40 @@ void ViewerGLWidget::ContextCleanup()
doneCurrent();
}
+
+void ViewerGLWidget::ShowContextMenu(const QPoint &pos)
+{
+ QMenu menu;
+
+ QStringList displays = ColorManager::ListAvailableDisplays();
+ QMenu* ocio_display_menu = menu.addMenu(tr("OCIO Display"));
+ foreach (QString d, displays) {
+ QAction* action = ocio_display_menu->addAction(d);
+ action->setChecked(ocio_display_ == d);
+ }
+
+ QStringList views = ColorManager::ListAvailableViews(ocio_display_);
+ QMenu* ocio_view_menu = menu.addMenu(tr("OCIO View"));
+ foreach (QString v, views) {
+ QAction* action = ocio_view_menu->addAction(v);
+ action->setChecked(ocio_view_ == v);
+ }
+
+ QStringList looks = ColorManager::ListAvailableLooks();
+ QMenu* ocio_look_menu = menu.addMenu(tr("OCIO Look"));
+ foreach (QString l, looks) {
+ QAction* action = ocio_look_menu->addAction(l);
+ action->setChecked(ocio_look_ == l);
+ }
+
+ menu.exec(mapToGlobal(pos));
+}
+
+void ViewerGLWidget::ColorConfigChangedSlot()
+{
+ RefreshColorSettings();
+
+ if (pipeline_ != nullptr) {
+ SetupPipeline();
+ }
+}
diff --git a/app/widget/viewer/viewerglwidget.h b/app/widget/viewer/viewerglwidget.h
index 8dee3c379..17c4d2548 100644
--- a/app/widget/viewer/viewerglwidget.h
+++ b/app/widget/viewer/viewerglwidget.h
@@ -23,7 +23,7 @@
#include
-#include "render/colorservice.h"
+#include "render/colormanager.h"
#include "render/gl/shaderptr.h"
/**
@@ -54,6 +54,28 @@ public:
*/
ViewerGLWidget(QWidget* parent);
+ virtual ~ViewerGLWidget() override;
+
+ /**
+ * @brief Deleted copy constructor
+ */
+ ViewerGLWidget(const ViewerGLWidget& other) = delete;
+
+ /**
+ * @brief Deleted move constructor
+ */
+ ViewerGLWidget(ViewerGLWidget&& other) = delete;
+
+ /**
+ * @brief Deleted copy assignment
+ */
+ ViewerGLWidget& operator=(const ViewerGLWidget& other) = delete;
+
+ /**
+ * @brief Deleted move assignment
+ */
+ ViewerGLWidget& operator=(ViewerGLWidget&& other) = delete;
+
public slots:
/**
* @brief Set the texture to draw and draw it
@@ -79,6 +101,38 @@ protected:
*/
virtual void paintGL() override;
private:
+ /**
+ * @brief Creates the render pipeline shader
+ *
+ * If it already exists, it will be deleted.
+ */
+ void SetupPipeline();
+
+ /**
+ * @brief Sets all color settings to the defaults pertaining to this configuration
+ */
+ void RefreshColorSettings();
+
+ /**
+ * @brief Call this if this user has selected a different display/view/look to recreate the processor
+ */
+ void SetupColorProcessor();
+
+ /**
+ * @brief Internal variable to set color space to
+ */
+ QString ocio_display_;
+
+ /**
+ * @brief Internal variable to set color space to
+ */
+ QString ocio_view_;
+
+ /**
+ * @brief Internal variable to set color space to
+ */
+ QString ocio_look_;
+
/**
* @brief Internal reference to the OpenGL texture to draw. Set in SetTexture() and used in paintGL().
*/
@@ -99,10 +153,23 @@ private:
/**
* @brief Color management service
*/
- ColorServicePtr color_service_;
+ ColorProcessorPtr color_service_;
private slots:
+ /**
+ * @brief Slot to connect just before the OpenGL context is destroyed to clean up resources
+ */
void ContextCleanup();
+
+ /**
+ * @brief Show context menu
+ */
+ void ShowContextMenu(const QPoint& pos);
+
+ /**
+ * @brief Slot called whenever the color configuration changes
+ */
+ void ColorConfigChangedSlot();
};
#endif // VIEWERGLWIDGET_H
diff --git a/app/window/mainwindow/mainmenu.cpp b/app/window/mainwindow/mainmenu.cpp
index 415be884a..40061c2bf 100644
--- a/app/window/mainwindow/mainmenu.cpp
+++ b/app/window/mainwindow/mainmenu.cpp
@@ -49,6 +49,8 @@ MainMenu::MainMenu(QMainWindow *parent) :
file_menu_->addSeparator();
file_export_item_ = file_menu_->AddItem("export", nullptr, nullptr, "Ctrl+M");
file_menu_->addSeparator();
+ file_project_properties_item_ = file_menu_->AddItem("projectproperties", &olive::core, SLOT(DialogProjectPropertiesShow()));
+ file_menu_->addSeparator();
file_exit_item_ = file_menu_->AddItem("exit", parent, SLOT(close()), "Ctrl+Q");
//
@@ -477,12 +479,13 @@ void MainMenu::Retranslate()
file_menu_->setTitle(tr("&File"));
file_new_menu_->setTitle(tr("&New"));
file_open_item_->setText(tr("&Open Project"));
- file_open_recent_menu_->setTitle(tr("Open Recent"));
- file_open_recent_clear_item_->setText(tr("Clear Recent List"));
+ file_open_recent_menu_->setTitle(tr("Open &Recent"));
+ file_open_recent_clear_item_->setText(tr("&Clear Recent List"));
file_save_item_->setText(tr("&Save Project"));
file_save_as_item_->setText(tr("Save Project &As"));
file_import_item_->setText(tr("&Import..."));
file_export_item_->setText(tr("&Export..."));
+ file_project_properties_item_->setText(tr("&Project Properties..."));
file_exit_item_->setText(tr("E&xit"));
// Edit menu
diff --git a/app/window/mainwindow/mainmenu.h b/app/window/mainwindow/mainmenu.h
index 913133473..82fbe4668 100644
--- a/app/window/mainwindow/mainmenu.h
+++ b/app/window/mainwindow/mainmenu.h
@@ -136,6 +136,7 @@ private:
QAction* file_save_as_item_;
QAction* file_import_item_;
QAction* file_export_item_;
+ QAction* file_project_properties_item_;
QAction* file_exit_item_;
Menu* edit_menu_;