work on internal color management

This commit is contained in:
itsmattkc
2019-09-28 01:38:15 +10:00
parent 4c90405feb
commit d2dc0d2823
24 changed files with 983 additions and 175 deletions
+13 -5
View File
@@ -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()
+5
View File
@@ -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
*/
+2
View File
@@ -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
@@ -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 <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
dialog/footageproperties/footageproperties.h
dialog/footageproperties/footageproperties.cpp
PARENT_SCOPE
)
@@ -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 <http://www.gnu.org/licenses/>.
***/
#include "footageproperties.h"
#include <QGridLayout>
#include <QLabel>
#include <QComboBox>
#include <QLineEdit>
#include <QDialogButtonBox>
#include <QTreeWidgetItem>
#include <QGroupBox>
#include <QListWidget>
#include <QCheckBox>
#include <QSpinBox>
#include <OpenColorIO/OpenColorIO.h>
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;i<config->getNumColorSpaces();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;i<track_list->count();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;j<f->video_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;j<f->audio_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();
}
@@ -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 <http://www.gnu.org/licenses/>.
***/
#ifndef MEDIAPROPERTIESDIALOG_H
#define MEDIAPROPERTIESDIALOG_H
#include <QDialog>
#include <QComboBox>
#include <QLineEdit>
#include <QListWidget>
#include <QDoubleSpinBox>
#include <QCheckBox>
#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
@@ -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 <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
dialog/projectproperties/projectproperties.h
dialog/projectproperties/projectproperties.cpp
PARENT_SCOPE
)
@@ -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 <http://www.gnu.org/licenses/>.
***/
#include "projectproperties.h"
#include <QDialogButtonBox>
#include <QFileDialog>
#include <QGridLayout>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <OpenColorIO/OpenColorIO.h>
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);
}
}
@@ -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 <http://www.gnu.org/licenses/>.
***/
#ifndef PROJECTPROPERTIESDIALOG_H
#define PROJECTPROPERTIESDIALOG_H
#include <QDialog>
#include <QLineEdit>
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
+4 -4
View File
@@ -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<ColorService>("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_);
}
}
+2 -2
View File
@@ -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_;
+12 -1
View File
@@ -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) {
+5
View File
@@ -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<Stream>;
+4 -2
View File
@@ -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
+155
View File
@@ -0,0 +1,155 @@
#include "colormanager.h"
#include <QFloat16>
#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;i<number_of_displays;i++) {
displays.append(config->getDisplay(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;i<number_of_views;i++) {
views.append(config->getView(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;i<number_of_looks;i++) {
looks.append(config->getLookNameByIndex(i));
}
return looks;
}
ColorManager::ColorManager()
{
}
void ColorManager::AssociateAlphaPixFmtFilter(ColorManager::AlphaAction action, FramePtr f)
{
int pixel_count = f->width() * f->height() * kRGBAChannels;
switch (static_cast<olive::PixelFormat>(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<qfloat16>(action, reinterpret_cast<qfloat16*>(f->data()), pixel_count);
break;
}
case olive::PIX_FMT_RGBA32F:
{
AssociateAlphaInternal<float>(action, reinterpret_cast<float*>(f->data()), pixel_count);
break;
}
}
}
template<typename T>
void ColorManager::AssociateAlphaInternal(ColorManager::AlphaAction action, T *data, int pix_count)
{
for (int i=0;i<pix_count;i+=kRGBAChannels) {
T alpha = data[i+kRGBChannels];
if (action == kAssociate || alpha > 0) {
for (int j=0;j<kRGBChannels;j++) {
if (action == kDisassociate) {
data[i+j] /= alpha;
} else {
data[i+j] *= alpha;
}
}
}
}
}
+60
View File
@@ -0,0 +1,60 @@
#ifndef COLORSERVICE_H
#define COLORSERVICE_H
#include <memory>
#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<typename T>
static void AssociateAlphaInternal(AlphaAction action, T* data, int pix_count);
};
#endif // COLORSERVICE_H
+62
View File
@@ -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<float*>(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<ColorProcessor>(source_space, dest_space);
}
ColorProcessorPtr ColorProcessor::Create(const QString &source_space, const QString &display, const QString &view, const QString &look)
{
return std::make_shared<ColorProcessor>(source_space, display, view, look);
}
OpenColorIO::v1::ConstProcessorRcPtr ColorProcessor::GetProcessor()
{
return processor;
}
+38
View File
@@ -0,0 +1,38 @@
#ifndef COLORPROCESSOR_H
#define COLORPROCESSOR_H
#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE::v1;
#include "decoder/frame.h"
class ColorProcessor;
using ColorProcessorPtr = std::shared_ptr<ColorProcessor>;
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
-102
View File
@@ -1,102 +0,0 @@
#include "colorservice.h"
#include <QFloat16>
#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<ColorService>(source_space, dest_space);
}
void ColorService::ConvertFrame(FramePtr f)
{
OCIO::PackedImageDesc img(reinterpret_cast<float*>(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<olive::PixelFormat>(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<qfloat16>(action, reinterpret_cast<qfloat16*>(f->data()), pixel_count);
break;
}
case olive::PIX_FMT_RGBA32F:
{
AssociateAlphaInternal<float>(action, reinterpret_cast<float*>(f->data()), pixel_count);
break;
}
}
}
template<typename T>
void ColorService::AssociateAlphaInternal(ColorService::AlphaAction action, T *data, int pix_count)
{
for (int i=0;i<pix_count;i+=kRGBAChannels) {
T alpha = data[i+kRGBChannels];
if (action == kAssociate || alpha > 0) {
for (int j=0;j<kRGBChannels;j++) {
if (action == kDisassociate) {
data[i+j] /= alpha;
} else {
data[i+j] *= alpha;
}
}
}
}
}
-48
View File
@@ -1,48 +0,0 @@
#ifndef COLORSERVICE_H
#define COLORSERVICE_H
#include <memory>
#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE::v1;
#include "decoder/frame.h"
#include "render/gl/shadergenerators.h"
class ColorService;
using ColorServicePtr = std::shared_ptr<ColorService>;
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<typename T>
static void AssociateAlphaInternal(AlphaAction action, T* data, int pix_count);
};
#endif // COLORSERVICE_H
+75 -7
View File
@@ -20,6 +20,7 @@
#include "viewerglwidget.h"
#include <QMenu>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
@@ -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();
}
}
+69 -2
View File
@@ -23,7 +23,7 @@
#include <QOpenGLWidget>
#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
+5 -2
View File
@@ -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
+1
View File
@@ -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_;