two step process and configurable colorspaces
This commit is contained in:
@@ -30,6 +30,10 @@
|
||||
#include <QListWidget>
|
||||
#include <QCheckBox>
|
||||
#include <QSpinBox>
|
||||
#ifndef NO_OCIO
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE;
|
||||
#endif
|
||||
|
||||
#include "project/footage.h"
|
||||
#include "project/media.h"
|
||||
@@ -103,7 +107,7 @@ MediaPropertiesDialog::MediaPropertiesDialog(QWidget *parent, Media *i) :
|
||||
|
||||
// premultiplied alpha mode
|
||||
premultiply_alpha_setting = new QCheckBox(tr("Alpha is Premultiplied"), this);
|
||||
premultiply_alpha_setting->setChecked(f->alpha_is_premultiplied);
|
||||
premultiply_alpha_setting->setChecked(f->alpha_is_associated);
|
||||
grid->addWidget(premultiply_alpha_setting, row, 0);
|
||||
|
||||
row++;
|
||||
@@ -128,6 +132,28 @@ MediaPropertiesDialog::MediaPropertiesDialog(QWidget *parent, Media *i) :
|
||||
grid->addWidget(interlacing_box, row, 1);
|
||||
|
||||
row++;
|
||||
|
||||
#ifndef NO_OCIO
|
||||
color_management = new QComboBox(this);
|
||||
|
||||
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
|
||||
|
||||
for (int i=0;i<config->getNumColorSpaces();i++) {
|
||||
QString colorspace = config->getColorSpaceNameByIndex(i);
|
||||
|
||||
color_management->addItem(colorspace);
|
||||
|
||||
if (colorspace == f->colorspace) {
|
||||
color_management->setCurrentIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
grid->addWidget(new QLabel(tr("Color Space:")), row, 0);
|
||||
grid->addWidget(color_management, row, 1);
|
||||
|
||||
row++;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
name_box = new QLineEdit(item->get_name(), this);
|
||||
@@ -192,9 +218,13 @@ void MediaPropertiesDialog::accept() {
|
||||
}
|
||||
|
||||
// set premultiplied alpha
|
||||
f->alpha_is_premultiplied = premultiply_alpha_setting->isChecked();
|
||||
f->alpha_is_associated = premultiply_alpha_setting->isChecked();
|
||||
}
|
||||
|
||||
#ifndef NO_OCIO
|
||||
f->colorspace = color_management->currentText();
|
||||
#endif
|
||||
|
||||
// set name
|
||||
MediaRename* mr = new MediaRename(item, name_box->text());
|
||||
|
||||
|
||||
@@ -32,18 +32,19 @@
|
||||
#include "project/media.h"
|
||||
|
||||
class MediaPropertiesDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
public:
|
||||
MediaPropertiesDialog(QWidget *parent, Media* i);
|
||||
MediaPropertiesDialog(QWidget *parent, Media* i);
|
||||
private:
|
||||
QComboBox* interlacing_box;
|
||||
QLineEdit* name_box;
|
||||
Media* item;
|
||||
QListWidget* track_list;
|
||||
QDoubleSpinBox* conform_fr;
|
||||
QCheckBox* premultiply_alpha_setting;
|
||||
QComboBox* interlacing_box;
|
||||
QLineEdit* name_box;
|
||||
Media* item;
|
||||
QListWidget* track_list;
|
||||
QDoubleSpinBox* conform_fr;
|
||||
QCheckBox* premultiply_alpha_setting;
|
||||
QComboBox* color_management;
|
||||
private slots:
|
||||
void accept();
|
||||
void accept();
|
||||
};
|
||||
|
||||
#endif // MEDIAPROPERTIESDIALOG_H
|
||||
|
||||
+171
-22
@@ -20,13 +20,6 @@
|
||||
|
||||
#include "preferencesdialog.h"
|
||||
|
||||
#include "global/global.h"
|
||||
#include "global/config.h"
|
||||
#include "global/path.h"
|
||||
#include "rendering/audio.h"
|
||||
#include "panels/panels.h"
|
||||
#include "ui/mainwindow.h"
|
||||
|
||||
#include <QMenuBar>
|
||||
#include <QAction>
|
||||
#include <QVBoxLayout>
|
||||
@@ -51,6 +44,13 @@
|
||||
#include <QProcess>
|
||||
#include <QDebug>
|
||||
|
||||
#include "global/global.h"
|
||||
#include "global/config.h"
|
||||
#include "global/path.h"
|
||||
#include "rendering/audio.h"
|
||||
#include "panels/panels.h"
|
||||
#include "ui/mainwindow.h"
|
||||
|
||||
KeySequenceEditor::KeySequenceEditor(QWidget* parent, QAction* a)
|
||||
: QKeySequenceEdit(parent), action(a) {
|
||||
setKeySequence(action->shortcut());
|
||||
@@ -108,12 +108,28 @@ void PreferencesDialog::setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem*
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::delete_previews(char type) {
|
||||
if (type != 't' && type != 'w' && type != 1) return;
|
||||
void PreferencesDialog::delete_previews(PreviewDeleteTypes type) {
|
||||
char delete_char = 0;
|
||||
|
||||
switch (type) {
|
||||
case DELETE_WAVEFORMS:
|
||||
delete_char = 'w';
|
||||
break;
|
||||
case DELETE_THUMBNAILS:
|
||||
delete_char = 't';
|
||||
break;
|
||||
case DELETE_BOTH:
|
||||
delete_char = 1;
|
||||
break;
|
||||
case DELETE_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (delete_char != 't' && delete_char != 'w' && delete_char != 1) return;
|
||||
|
||||
QDir preview_path(get_data_path() + "/previews");
|
||||
|
||||
if (type == 1) {
|
||||
if (delete_char == 1) {
|
||||
// indiscriminately delete everything
|
||||
preview_path.removeRecursively();
|
||||
} else {
|
||||
@@ -134,13 +150,85 @@ void PreferencesDialog::delete_previews(char type) {
|
||||
|
||||
// thumbnails will have a 't' towards the end of the filenames, waveforms will have a 'w'
|
||||
// if they match the type of preview we're deleting, remove them
|
||||
if (preview_file_str.at(identifier_char_index) == type) {
|
||||
if (preview_file_str.at(identifier_char_index) == delete_char) {
|
||||
QFile::remove(preview_path.filePath(preview_file_str));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::populate_ocio_menus(OCIO::ConstConfigRcPtr config)
|
||||
{
|
||||
// Get current display name (if the config is empty, get the current default display)
|
||||
QString current_display = olive::CurrentConfig.ocio_display;
|
||||
if (current_display.isEmpty()) {
|
||||
current_display = config->getDefaultDisplay();
|
||||
}
|
||||
|
||||
// Populate the display menu
|
||||
ocio_display->clear();
|
||||
for (int i=0;i<config->getNumDisplays();i++) {
|
||||
ocio_display->addItem(config->getDisplay(i));
|
||||
|
||||
// Check if this index is the currently selected
|
||||
if (config->getDisplay(i) == current_display) {
|
||||
ocio_display->setCurrentIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
update_ocio_view_menu(config);
|
||||
|
||||
// Populate the look menu
|
||||
ocio_look->clear();
|
||||
ocio_look->addItem(tr("(None)"), QString());
|
||||
for (int i=0;i<config->getNumLooks();i++) {
|
||||
const char* look = config->getLookNameByIndex(i);
|
||||
|
||||
ocio_look->addItem(look, look);
|
||||
|
||||
if (look == olive::CurrentConfig.ocio_look) {
|
||||
ocio_look->setCurrentIndex(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::update_ocio_view_menu(OCIO::ConstConfigRcPtr config)
|
||||
{
|
||||
|
||||
// Get views for the current display set in `ocio_display`
|
||||
QString display = ocio_display->currentText();
|
||||
|
||||
// Get current view
|
||||
QString current_view = olive::CurrentConfig.ocio_view;
|
||||
if (current_view.isEmpty()) {
|
||||
current_view = config->getDefaultView(display.toUtf8());
|
||||
}
|
||||
|
||||
// Populate the view menu
|
||||
int ocio_view_count = config->getNumViews(display.toUtf8());
|
||||
ocio_view->clear();
|
||||
for (int i=0;i<ocio_view_count;i++) {
|
||||
const char* view = config->getView(display.toUtf8(), i);
|
||||
|
||||
ocio_view->addItem(view);
|
||||
|
||||
if (current_view == view) {
|
||||
ocio_view->setCurrentIndex(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::update_ocio_config(const QString &s)
|
||||
{
|
||||
if (!s.isEmpty() && QFileInfo::exists(s)) {
|
||||
try {
|
||||
OCIO::ConstConfigRcPtr file_config = OCIO::Config::CreateFromFile(s.toUtf8());
|
||||
|
||||
populate_ocio_menus(file_config);
|
||||
} catch (OCIO::Exception& e) {}
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::setup_kbd_shortcuts(QMenuBar* menubar) {
|
||||
QList<QAction*> menus = menubar->actions();
|
||||
|
||||
@@ -209,9 +297,9 @@ void PreferencesDialog::save() {
|
||||
if (olive::CurrentConfig.use_software_fallback != use_software_fallbacks_checkbox->isChecked()
|
||||
|| olive::CurrentConfig.thumbnail_resolution != thumbnail_res_spinbox->value()
|
||||
|| olive::CurrentConfig.waveform_resolution != waveform_res_spinbox->value()
|
||||
#ifdef Q_OS_WIN32
|
||||
#ifdef Q_OS_WIN32
|
||||
|| olive::CurrentConfig.use_native_menu_styling != native_menus->isChecked()
|
||||
#endif
|
||||
#endif
|
||||
|| olive::CurrentConfig.style != static_cast<olive::styling::Style>(ui_style->currentData().toInt())) {
|
||||
|
||||
// any changes to these settings will require a restart - ask the user if we should do one now or later
|
||||
@@ -274,7 +362,31 @@ void PreferencesDialog::save() {
|
||||
olive::CurrentConfig.language_file = language_combobox->currentData().toString();
|
||||
|
||||
olive::CurrentConfig.enable_color_management = enable_color_management->isChecked();
|
||||
olive::CurrentConfig.ocio_config_path = ocio_config_file->text();
|
||||
|
||||
#ifndef NO_OCIO
|
||||
if (olive::CurrentConfig.ocio_config_path != ocio_config_file->text()) {
|
||||
try {
|
||||
OCIO::SetCurrentConfig(OCIO::Config::CreateFromFile(ocio_config_file->text().toUtf8()));
|
||||
|
||||
olive::CurrentConfig.ocio_config_path = ocio_config_file->text();
|
||||
} catch (OCIO::Exception& e) {
|
||||
QMessageBox::critical(this,
|
||||
tr("OpenColorIO Config Error"),
|
||||
tr("Failed to set OpenColorIO configuration: %1").arg(e.what()),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
olive::CurrentConfig.ocio_display = ocio_display->currentText();
|
||||
olive::CurrentConfig.ocio_view = ocio_view->currentText();
|
||||
|
||||
// We use data here instead of text because there's a "(None)" option with an empty string
|
||||
olive::CurrentConfig.ocio_look = ocio_look->currentData().toString();
|
||||
|
||||
olive::CurrentRuntimeConfig.ocio_config_date = QDateTime::currentMSecsSinceEpoch();
|
||||
#endif
|
||||
|
||||
|
||||
olive::CurrentConfig.style = static_cast<olive::styling::Style>(ui_style->currentData().toInt());
|
||||
#ifdef Q_OS_WIN
|
||||
@@ -287,14 +399,14 @@ void PreferencesDialog::save() {
|
||||
// we're changing the size of thumbnails and waveforms, so let's delete them and regenerate them next start
|
||||
|
||||
// delete nothing
|
||||
char delete_match = 0;
|
||||
PreviewDeleteTypes delete_type = DELETE_NONE;
|
||||
|
||||
if (olive::CurrentConfig.thumbnail_resolution != thumbnail_res_spinbox->value()) {
|
||||
// delete existing thumbnails
|
||||
olive::CurrentConfig.thumbnail_resolution = thumbnail_res_spinbox->value();
|
||||
|
||||
// delete only thumbnails
|
||||
delete_match = 't';
|
||||
delete_type = DELETE_THUMBNAILS;
|
||||
}
|
||||
|
||||
if (olive::CurrentConfig.waveform_resolution != waveform_res_spinbox->value()) {
|
||||
@@ -302,16 +414,16 @@ void PreferencesDialog::save() {
|
||||
olive::CurrentConfig.waveform_resolution = waveform_res_spinbox->value();
|
||||
|
||||
// if we're already deleting thumbnails
|
||||
if (delete_match == 't') {
|
||||
if (delete_type == DELETE_THUMBNAILS) {
|
||||
// delete all
|
||||
delete_match = 1;
|
||||
delete_type = DELETE_BOTH;
|
||||
} else {
|
||||
// just delete waveforms
|
||||
delete_match = 'w';
|
||||
delete_type = DELETE_WAVEFORMS;
|
||||
}
|
||||
}
|
||||
|
||||
delete_previews(delete_match);
|
||||
delete_previews(delete_type);
|
||||
}
|
||||
|
||||
// Save keyboard shortcuts
|
||||
@@ -476,12 +588,17 @@ void PreferencesDialog::browse_ocio_config()
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::update_ocio_view_menu()
|
||||
{
|
||||
update_ocio_view_menu(OCIO::GetCurrentConfig());
|
||||
}
|
||||
|
||||
void PreferencesDialog::delete_all_previews() {
|
||||
if (QMessageBox::question(this,
|
||||
tr("Delete All Previews"),
|
||||
tr("Are you sure you want to delete all previews?"),
|
||||
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||
delete_previews(1);
|
||||
delete_previews(DELETE_BOTH);
|
||||
QMessageBox::information(this,
|
||||
tr("Previews Deleted"),
|
||||
tr("All previews deleted succesfully. You may have to re-open your current project for "
|
||||
@@ -772,32 +889,64 @@ void PreferencesDialog::setup_ui() {
|
||||
|
||||
#ifdef NO_OCIO
|
||||
QLabel* no_ocio_available_lbl = new QLabel(tr("<html><b>Color management is unavailable because Olive was "
|
||||
"compiled without OpenColorIO support.</b></html>"));
|
||||
"compiled without OpenColorIO support.</b></html>"));
|
||||
no_ocio_available_lbl->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
|
||||
color_management_layout->addWidget(no_ocio_available_lbl, row, 0, 1, 3);
|
||||
row++;
|
||||
#endif
|
||||
|
||||
// COLOR MANAGEMENT -> Enable Color Management
|
||||
enable_color_management = new QCheckBox(tr("Enable Color Management"));
|
||||
enable_color_management->setChecked(olive::CurrentConfig.enable_color_management);
|
||||
color_management_layout->addWidget(enable_color_management, row, 0, 1, 3);
|
||||
|
||||
row++;
|
||||
|
||||
// COLOR MANAGEMENT -> OpenColorIO Config File
|
||||
color_management_layout->addWidget(new QLabel(tr("OpenColorIO Config File:")), row, 0);
|
||||
|
||||
ocio_config_file = new QLineEdit();
|
||||
ocio_config_file->setText(olive::CurrentConfig.ocio_config_path);
|
||||
connect(ocio_config_file, SIGNAL(textChanged(const QString &)), this, SLOT(update_ocio_config(const QString&)));
|
||||
color_management_layout->addWidget(ocio_config_file, row, 1);
|
||||
|
||||
QPushButton* ocio_config_browse_btn = new QPushButton(tr("Browse"));
|
||||
connect(ocio_config_browse_btn, SIGNAL(clicked(bool)), this, SLOT(browse_ocio_config()));
|
||||
color_management_layout->addWidget(ocio_config_browse_btn, row, 2);
|
||||
|
||||
row++;
|
||||
|
||||
// COLOR MANAGEMENT -> Display
|
||||
ocio_display = new QComboBox();
|
||||
connect(ocio_display, SIGNAL(currentIndexChanged(int)), this, SLOT(update_ocio_view_menu()));
|
||||
color_management_layout->addWidget(new QLabel("Display:"), row, 0);
|
||||
color_management_layout->addWidget(ocio_display, row, 1);
|
||||
|
||||
row++;
|
||||
|
||||
// COLOR MANAGEMENT -> View
|
||||
ocio_view = new QComboBox();
|
||||
color_management_layout->addWidget(new QLabel("View:"), row, 0);
|
||||
color_management_layout->addWidget(ocio_view, row, 1);
|
||||
|
||||
row++;
|
||||
|
||||
// COLOR MANAGEMENT -> Look
|
||||
ocio_look = new QComboBox();
|
||||
color_management_layout->addWidget(new QLabel("Look:"), row, 0);
|
||||
color_management_layout->addWidget(ocio_look, row, 1);
|
||||
|
||||
row++;
|
||||
|
||||
#ifdef NO_OCIO
|
||||
enable_color_management->setEnabled(false);
|
||||
ocio_config_file->setEnabled(false);
|
||||
ocio_config_browse_btn->setEnabled(false);
|
||||
ocio_display->setEnabled(false);
|
||||
ocio_view->setEnabled(false);
|
||||
ocio_look->setEnabled(false);
|
||||
#else
|
||||
populate_ocio_menus(OCIO::GetCurrentConfig());
|
||||
#endif
|
||||
|
||||
tabWidget->addTab(color_management_tab, tr("Color Management"));
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
#include <QCheckBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QSpinBox>
|
||||
#ifndef NO_OCIO
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE;
|
||||
#endif
|
||||
|
||||
#include "timeline/sequence.h"
|
||||
|
||||
@@ -71,10 +75,22 @@ private slots:
|
||||
void browse_css_file();
|
||||
void browse_ocio_config();
|
||||
|
||||
// OCIO function
|
||||
void update_ocio_view_menu();
|
||||
void update_ocio_view_menu(OCIO::ConstConfigRcPtr config);
|
||||
void update_ocio_config(const QString&);
|
||||
|
||||
private:
|
||||
void setup_ui();
|
||||
void setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent);
|
||||
|
||||
enum PreviewDeleteTypes {
|
||||
DELETE_NONE,
|
||||
DELETE_THUMBNAILS,
|
||||
DELETE_WAVEFORMS,
|
||||
DELETE_BOTH
|
||||
};
|
||||
|
||||
// used to delete previews
|
||||
// type can be: 't' for thumbnails, 'w' for waveforms, or 1 for all
|
||||
/**
|
||||
@@ -82,9 +98,11 @@ private:
|
||||
*
|
||||
* @param type
|
||||
*
|
||||
* The types of previews to
|
||||
* The types of previews to delete.
|
||||
*/
|
||||
void delete_previews(char type);
|
||||
void delete_previews(PreviewDeleteTypes type);
|
||||
|
||||
void populate_ocio_menus(OCIO::ConstConfigRcPtr config);
|
||||
|
||||
QLineEdit* custom_css_fn;
|
||||
QLineEdit* imgSeqFormatEdit;
|
||||
@@ -103,8 +121,13 @@ private:
|
||||
QSpinBox* thumbnail_res_spinbox;
|
||||
QSpinBox* waveform_res_spinbox;
|
||||
QCheckBox* add_default_effects_to_clips;
|
||||
|
||||
QCheckBox* enable_color_management;
|
||||
QLineEdit* ocio_config_file;
|
||||
QComboBox* ocio_display;
|
||||
QComboBox* ocio_view;
|
||||
QComboBox* ocio_look;
|
||||
|
||||
QComboBox* ui_style;
|
||||
Sequence sequence_settings;
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
+2
-1
@@ -299,5 +299,6 @@ void Config::save(QString path) {
|
||||
}
|
||||
|
||||
RuntimeConfig::RuntimeConfig() :
|
||||
shaders_are_enabled(true)
|
||||
shaders_are_enabled(true),
|
||||
ocio_config_date(QDateTime::currentMSecsSinceEpoch())
|
||||
{}
|
||||
|
||||
+30
-1
@@ -519,10 +519,31 @@ struct Config {
|
||||
/**
|
||||
* @brief Path to OpenColorIO configuration file
|
||||
*
|
||||
* Used if Config::enable_color_management is **TRUE**.
|
||||
* Used if Config::enable_color_management is true.
|
||||
*/
|
||||
QString ocio_config_path;
|
||||
|
||||
/**
|
||||
* @brief OpenColorIO Display
|
||||
*
|
||||
* Used if Config::enable_color_management is true
|
||||
*/
|
||||
QString ocio_display;
|
||||
|
||||
/**
|
||||
* @brief OpenColorIO View
|
||||
*
|
||||
* Used if Config::enable_color_management is true
|
||||
*/
|
||||
QString ocio_view;
|
||||
|
||||
/**
|
||||
* @brief OpenColorIO Look
|
||||
*
|
||||
* Used if Config::enable_color_management is true
|
||||
*/
|
||||
QString ocio_look;
|
||||
|
||||
/**
|
||||
* @brief Style to use when theming Olive.
|
||||
*
|
||||
@@ -587,6 +608,14 @@ struct RuntimeConfig {
|
||||
* Overrides Config::language_file and sets the path to a language file to use.
|
||||
*/
|
||||
QString external_translation_file;
|
||||
|
||||
/**
|
||||
* @brief OpenColorIO Configuration Time
|
||||
*
|
||||
* A crude but quick way of determining whether the OCIO config has changed and if the rendering threads need to
|
||||
* re-create their OCIO shaders. Not intended to be saved - could be moved
|
||||
*/
|
||||
qint64 ocio_config_date;
|
||||
};
|
||||
|
||||
namespace olive {
|
||||
|
||||
+7
-2
@@ -871,7 +871,12 @@ void Project::process_file_list(QStringList& files, bool recursive, MediaPtr rep
|
||||
item = std::make_shared<Media>(parent);
|
||||
}
|
||||
|
||||
m = FootagePtr(new Footage());
|
||||
m = std::make_shared<Footage>();
|
||||
|
||||
// Edge case for PNGs that standardized unassociated alpha
|
||||
if (file.endsWith("png", Qt::CaseInsensitive)) {
|
||||
m->alpha_is_associated = false;
|
||||
}
|
||||
|
||||
m->using_inout = false;
|
||||
m->url = file;
|
||||
@@ -1107,7 +1112,7 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only,
|
||||
stream.writeAttribute("in", QString::number(f->in));
|
||||
stream.writeAttribute("out", QString::number(f->out));
|
||||
stream.writeAttribute("speed", QString::number(f->speed));
|
||||
stream.writeAttribute("alphapremul", QString::number(f->alpha_is_premultiplied));
|
||||
stream.writeAttribute("alphapremul", QString::number(f->alpha_is_associated));
|
||||
stream.writeAttribute("startnumber", QString::number(f->start_number));
|
||||
|
||||
stream.writeAttribute("proxy", QString::number(f->proxy));
|
||||
|
||||
+11
-11
@@ -27,17 +27,17 @@
|
||||
#include "project/previewgenerator.h"
|
||||
#include "timeline/clip.h"
|
||||
|
||||
Footage::Footage() {
|
||||
ready = (false);
|
||||
preview_gen = (nullptr);
|
||||
invalid = (false);
|
||||
in = (0);
|
||||
out = (0);
|
||||
speed = (1.0);
|
||||
alpha_is_premultiplied = (false);
|
||||
proxy = (false);
|
||||
start_number = 0;
|
||||
|
||||
Footage::Footage() :
|
||||
ready(false),
|
||||
preview_gen(nullptr),
|
||||
invalid(false),
|
||||
in(0),
|
||||
out(0),
|
||||
speed(1.0),
|
||||
alpha_is_associated(true),
|
||||
proxy(false),
|
||||
start_number(0)
|
||||
{
|
||||
ready_lock.lock();
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -81,9 +81,14 @@ struct Footage {
|
||||
bool ready;
|
||||
bool invalid;
|
||||
double speed;
|
||||
bool alpha_is_premultiplied;
|
||||
bool alpha_is_associated;
|
||||
int start_number;
|
||||
|
||||
#ifndef NO_OCIO
|
||||
// color management
|
||||
QString colorspace;
|
||||
#endif
|
||||
|
||||
// proxy config
|
||||
bool proxy;
|
||||
QString proxy_path;
|
||||
|
||||
@@ -280,7 +280,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
|
||||
int folder = 0;
|
||||
|
||||
MediaPtr item = std::make_shared<Media>();
|
||||
FootagePtr f(new Footage());
|
||||
FootagePtr f = std::make_shared<Footage>();
|
||||
|
||||
f->using_inout = false;
|
||||
|
||||
@@ -347,7 +347,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
|
||||
} else if (attr.name() == "speed") {
|
||||
f->speed = attr.value().toDouble();
|
||||
} else if (attr.name() == "alphapremul") {
|
||||
f->alpha_is_premultiplied = (attr.value() == "1");
|
||||
f->alpha_is_associated = (attr.value() == "1");
|
||||
} else if (attr.name() == "proxy") {
|
||||
f->proxy = (attr.value() == "1");
|
||||
} else if (attr.name() == "proxypath") {
|
||||
|
||||
+149
-25
@@ -31,11 +31,6 @@ extern "C" {
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
#include <QDebug>
|
||||
|
||||
#ifndef NO_OCIO
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE;
|
||||
#endif
|
||||
|
||||
#include "timeline/clip.h"
|
||||
#include "timeline/sequence.h"
|
||||
#include "project/media.h"
|
||||
@@ -80,6 +75,14 @@ GLfloat olive::rendering::flipped_blit_texcoords[] = {
|
||||
1.0, 0.0
|
||||
};
|
||||
|
||||
#ifndef NO_OCIO
|
||||
// copied from source code to OCIODisplay
|
||||
const int OCIO_LUT3D_EDGE_SIZE = 32;
|
||||
|
||||
// copied from source code to OCIODisplay, expanded from 3*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE
|
||||
const int OCIO_NUM_3D_ENTRIES = 98304;
|
||||
#endif
|
||||
|
||||
void olive::rendering::Blit(QOpenGLShaderProgram* pipeline, bool flipped, QMatrix4x4 matrix) {
|
||||
|
||||
QOpenGLVertexArrayObject m_vao;
|
||||
@@ -237,6 +240,7 @@ GLuint draw_clip(QOpenGLContext* ctx,
|
||||
const FramebufferObject& fbo,
|
||||
GLuint texture,
|
||||
bool clear) {
|
||||
|
||||
fbo.BindBuffer();
|
||||
|
||||
if (clear) {
|
||||
@@ -252,6 +256,7 @@ GLuint draw_clip(QOpenGLContext* ctx,
|
||||
fbo.ReleaseBuffer();
|
||||
|
||||
return fbo.texture();
|
||||
|
||||
}
|
||||
|
||||
void process_effect(QOpenGLContext* ctx,
|
||||
@@ -305,7 +310,7 @@ void process_effect(QOpenGLContext* ctx,
|
||||
}
|
||||
|
||||
GLuint compose_sequence(ComposeSequenceParams ¶ms) {
|
||||
GLuint final_fbo = params.main_buffer;
|
||||
GLuint final_fbo = params.video ? params.main_buffer->buffer() : 0;
|
||||
|
||||
Sequence* s = params.seq;
|
||||
long playhead = s->playhead;
|
||||
@@ -511,7 +516,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) {
|
||||
|
||||
} else if (c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
|
||||
if (!c->media()->to_footage()->alpha_is_premultiplied) {
|
||||
if (!c->media()->to_footage()->alpha_is_associated) {
|
||||
|
||||
// alpha is not premultiplied, we'll need to multiply it for the rest of the pipeline
|
||||
params.ctx->functions()->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ZERO, GL_ONE, GL_ZERO);
|
||||
@@ -525,27 +530,52 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) {
|
||||
}
|
||||
|
||||
#ifndef NO_OCIO
|
||||
// convert to linear colorspace
|
||||
if (olive::CurrentConfig.enable_color_management && params.ocio_shader != nullptr)
|
||||
// Convert frame from source to linear colorspace
|
||||
if (olive::CurrentConfig.enable_color_management)
|
||||
{
|
||||
|
||||
params.ctx->extraFunctions()->glActiveTexture(GL_TEXTURE2);
|
||||
params.ctx->extraFunctions()->glBindTexture(GL_TEXTURE_3D, params.ocio_lut_texture);
|
||||
params.ctx->extraFunctions()->glActiveTexture(GL_TEXTURE0);
|
||||
if (c->ocio_shader == nullptr) {
|
||||
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
|
||||
|
||||
params.ocio_shader->bind();
|
||||
QString input_cs = OCIO::ROLE_SCENE_LINEAR;
|
||||
|
||||
params.ocio_shader->setUniformValue("tex2", 2);
|
||||
if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
|
||||
textureID = draw_clip(params.ctx, params.ocio_shader, c->fbo.at(fbo_switcher), textureID, true);
|
||||
if (!c->media()->to_footage()->colorspace.isEmpty()) {
|
||||
|
||||
params.ocio_shader->release();
|
||||
input_cs = c->media()->to_footage()->colorspace;
|
||||
|
||||
params.ctx->extraFunctions()->glActiveTexture(GL_TEXTURE2);
|
||||
params.ctx->extraFunctions()->glBindTexture(GL_TEXTURE_3D, 0);
|
||||
params.ctx->extraFunctions()->glActiveTexture(GL_TEXTURE0);
|
||||
} else {
|
||||
|
||||
fbo_switcher = !fbo_switcher;
|
||||
// If this is a footage clip, try to guess the color space from the filename
|
||||
QString guess_colorspace = config->parseColorSpaceFromString(c->media()->to_footage()->url.toUtf8());
|
||||
|
||||
if (!guess_colorspace.isEmpty()) {
|
||||
input_cs = guess_colorspace;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
OCIO::ConstProcessorRcPtr processor = config->getProcessor(input_cs.toUtf8(),
|
||||
OCIO::ROLE_SCENE_LINEAR);
|
||||
|
||||
c->ocio_shader = olive::rendering::SetupOCIO(params.ctx, c->ocio_lut_texture, processor);
|
||||
} catch (OCIO::Exception& e) {
|
||||
qWarning() << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
if (c->ocio_shader != nullptr) {
|
||||
textureID = olive::rendering::OCIOBlit(c->ocio_shader.get(),
|
||||
c->ocio_lut_texture,
|
||||
c->fbo.at(fbo_switcher),
|
||||
textureID);
|
||||
|
||||
fbo_switcher = !fbo_switcher;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -640,9 +670,9 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) {
|
||||
backend_tex_1 = params.nests.last()->fbo[1].texture();
|
||||
backend_tex_2 = params.nests.last()->fbo[2].texture();
|
||||
} else {
|
||||
back_buffer_1 = params.backend_buffer1;
|
||||
backend_tex_1 = params.backend_attachment1;
|
||||
backend_tex_2 = params.backend_attachment2;
|
||||
back_buffer_1 = params.backend_buffer1->buffer();
|
||||
backend_tex_1 = params.backend_buffer1->texture();
|
||||
backend_tex_2 = params.backend_buffer2->texture();
|
||||
}
|
||||
|
||||
// render a backbuffer
|
||||
@@ -743,7 +773,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) {
|
||||
if (params.nests.size() > 0) {
|
||||
draw_clip(params.ctx, params.pipeline, params.nests.last()->fbo[2].buffer(), params.nests.last()->fbo[0].texture(), true);
|
||||
} else {
|
||||
draw_clip(params.ctx, params.pipeline, params.backend_buffer2, params.main_attachment, true);
|
||||
draw_clip(params.ctx, params.pipeline, params.backend_buffer2->buffer(), params.main_buffer->texture(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -909,6 +939,100 @@ void close_active_clips(Sequence* s) {
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateOCIOGLState(const ComposeSequenceParams& params)
|
||||
#ifndef NO_OCIO
|
||||
QOpenGLShaderProgramPtr olive::rendering::SetupOCIO(QOpenGLContext* ctx,
|
||||
GLuint& lut_texture,
|
||||
OCIO::ConstProcessorRcPtr processor)
|
||||
{
|
||||
|
||||
QOpenGLExtraFunctions* xf = ctx->extraFunctions();
|
||||
|
||||
// Create LUT texture
|
||||
xf->glGenTextures(1, &lut_texture);
|
||||
|
||||
// Bind LUT
|
||||
xf->glBindTexture(GL_TEXTURE_3D, lut_texture);
|
||||
|
||||
// Set texture parameters
|
||||
xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// Allocate storage for texture
|
||||
xf->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB,
|
||||
OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE,
|
||||
0, GL_RGB,GL_FLOAT, nullptr);
|
||||
|
||||
//
|
||||
// SET UP GLSL SHADER
|
||||
//
|
||||
|
||||
OCIO::GpuShaderDesc shaderDesc;
|
||||
shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0);
|
||||
shaderDesc.setFunctionName("OCIODisplay");
|
||||
shaderDesc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE);
|
||||
|
||||
//
|
||||
// COMPUTE 3D LUT
|
||||
//
|
||||
|
||||
GLfloat* ocio_lut_data = new GLfloat[OCIO_NUM_3D_ENTRIES];
|
||||
processor->getGpuLut3D(ocio_lut_data, shaderDesc);
|
||||
|
||||
// Upload LUT data to texture
|
||||
xf->glTexSubImage3D(GL_TEXTURE_3D, 0,
|
||||
0, 0, 0,
|
||||
OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE,
|
||||
GL_RGB, GL_FLOAT, ocio_lut_data);
|
||||
|
||||
delete [] ocio_lut_data;
|
||||
|
||||
// Create OCIO shader code
|
||||
QString shader_text(processor->getGpuShaderText(shaderDesc));
|
||||
shader_text.append("\n"
|
||||
"uniform sampler3D tex2;\n"
|
||||
"\n"
|
||||
"vec4 process(vec4 col) {\n"
|
||||
" return OCIODisplay(col, tex2);\n"
|
||||
"}\n");
|
||||
|
||||
|
||||
// Get pipeline-based shader to inject OCIO shader into
|
||||
QOpenGLShaderProgramPtr shader = olive::rendering::GetPipeline(shader_text);
|
||||
|
||||
// Release LUT
|
||||
xf->glBindTexture(GL_TEXTURE_3D, 0);
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
GLuint olive::rendering::OCIOBlit(QOpenGLShaderProgram *pipeline,
|
||||
GLuint lut,
|
||||
const FramebufferObject& fbo,
|
||||
GLuint texture)
|
||||
{
|
||||
QOpenGLContext* ctx = QOpenGLContext::currentContext();
|
||||
QOpenGLExtraFunctions* xf = ctx->extraFunctions();
|
||||
|
||||
xf->glActiveTexture(GL_TEXTURE2);
|
||||
xf->glBindTexture(GL_TEXTURE_3D, lut);
|
||||
xf->glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
pipeline->bind();
|
||||
|
||||
pipeline->setUniformValue("tex2", 2);
|
||||
|
||||
//textureID = draw_clip(params.ctx, pipeline, c->fbo.at(fbo_switcher), textureID, true);
|
||||
GLuint textureID = draw_clip(ctx, pipeline, fbo, texture, true);
|
||||
|
||||
pipeline->release();
|
||||
|
||||
xf->glActiveTexture(GL_TEXTURE2);
|
||||
xf->glBindTexture(GL_TEXTURE_3D, 0);
|
||||
xf->glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
return textureID;
|
||||
}
|
||||
#endif
|
||||
|
||||
+14
-38
@@ -24,6 +24,10 @@
|
||||
#include <QOpenGLContext>
|
||||
#include <QVector>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#ifndef NO_OCIO
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE;
|
||||
#endif
|
||||
|
||||
#include "timeline/sequence.h"
|
||||
#include "effects/effect.h"
|
||||
@@ -168,16 +172,7 @@ struct ComposeSequenceParams {
|
||||
*
|
||||
* When compose_sequence() is rendering the final image, this framebuffer will be bound.
|
||||
*/
|
||||
GLuint main_buffer;
|
||||
|
||||
/**
|
||||
* @brief The attachment to the framebuffer in main_buffer
|
||||
*
|
||||
* Used only for video rendering. Never accessed with audio rendering.
|
||||
*
|
||||
* The OpenGL texture attached to the framebuffer referenced by main_buffer.
|
||||
*/
|
||||
GLuint main_attachment;
|
||||
const FramebufferObject* main_buffer;
|
||||
|
||||
/**
|
||||
* @brief Backend OpenGL framebuffer 1 used for further processing before rendering to main_buffer
|
||||
@@ -185,15 +180,7 @@ struct ComposeSequenceParams {
|
||||
* In some situations, compose_sequence() will do some processing through shaders that requires "ping-ponging"
|
||||
* between framebuffers. backend_buffer1 and backend_buffer2 are used for this purpose.
|
||||
*/
|
||||
GLuint backend_buffer1;
|
||||
|
||||
/**
|
||||
* @brief Backend OpenGL framebuffer 1's texture attachment
|
||||
*
|
||||
* The texture that ComposeSequenceParams::backend_buffer1 renders to. Bound and drawn to
|
||||
* ComposeSequenceParams::backend_buffer2 to "ping-pong" between them and various shaders.
|
||||
*/
|
||||
GLuint backend_attachment1;
|
||||
const FramebufferObject* backend_buffer1;
|
||||
|
||||
/**
|
||||
* @brief Backend OpenGL framebuffer 2 used for further processing before rendering to main_buffer
|
||||
@@ -201,25 +188,7 @@ struct ComposeSequenceParams {
|
||||
* In some situations, compose_sequence() will do some processing through shaders that requires "ping-ponging"
|
||||
* between framebuffers. backend_buffer1 and backend_buffer2 are used for this purpose.
|
||||
*/
|
||||
GLuint backend_buffer2;
|
||||
|
||||
/**
|
||||
* @brief Backend OpenGL framebuffer 2's texture attachment
|
||||
*
|
||||
* The texture that ComposeSequenceParams::backend_buffer2 renders to. Bound and drawn to
|
||||
* ComposeSequenceParams::backend_buffer1 to "ping-pong" between them and various shaders.
|
||||
*/
|
||||
GLuint backend_attachment2;
|
||||
|
||||
/**
|
||||
* @brief OpenGL shader containing OpenColorIO shader information
|
||||
*/
|
||||
QOpenGLShaderProgram* ocio_shader;
|
||||
|
||||
/**
|
||||
* @brief OpenGL texture containing LUT obtained form OpenColorIO
|
||||
*/
|
||||
GLuint ocio_lut_texture;
|
||||
const FramebufferObject* backend_buffer2;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -417,6 +386,13 @@ namespace olive {
|
||||
extern GLfloat flipped_blit_texcoords[];
|
||||
void Blit(QOpenGLShaderProgram* pipeline, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4());
|
||||
QOpenGLShaderProgramPtr GetPipeline(const QString &shader_code = QString());
|
||||
#ifndef NO_OCIO
|
||||
QOpenGLShaderProgramPtr SetupOCIO(QOpenGLContext *ctx, GLuint &lut_texture, OCIO::ConstProcessorRcPtr processor);
|
||||
GLuint OCIOBlit(QOpenGLShaderProgram *pipeline,
|
||||
GLuint lut,
|
||||
const FramebufferObject& fbo,
|
||||
GLuint texture);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+71
-116
@@ -47,10 +47,13 @@ RenderThread::RenderThread() :
|
||||
tex_height(-1),
|
||||
queued(false),
|
||||
texture_failed(false),
|
||||
#ifndef NO_OCIO
|
||||
ocio_lut_texture(0),
|
||||
ocio_shader(nullptr),
|
||||
#endif
|
||||
running(true),
|
||||
front_buffer_switcher(false)
|
||||
front_buffer_switcher(false),
|
||||
ocio_config_date(0)
|
||||
{
|
||||
surface.create();
|
||||
}
|
||||
@@ -85,6 +88,9 @@ void RenderThread::run() {
|
||||
}
|
||||
|
||||
// create any buffers that don't yet exist
|
||||
if (!composite_buffer.IsCreated()) {
|
||||
composite_buffer.Create(ctx, seq->width, seq->height);
|
||||
}
|
||||
if (!front_buffer_1.IsCreated()) {
|
||||
front_buffer_1.Create(ctx, seq->width, seq->height);
|
||||
}
|
||||
@@ -113,9 +119,11 @@ void RenderThread::run() {
|
||||
}
|
||||
|
||||
#ifndef NO_OCIO
|
||||
// If there's no OpenColorIO shader, create it now
|
||||
// If there's no OpenColorIO shader or the configuration has changed, (re-)create it now
|
||||
if (olive::CurrentConfig.enable_color_management
|
||||
&& (ocio_shader == nullptr || ocio_loaded_config != olive::CurrentConfig.ocio_config_path)) {
|
||||
&& (ocio_shader == nullptr || ocio_config_date != olive::CurrentRuntimeConfig.ocio_config_date)) {
|
||||
ocio_config_date = olive::CurrentRuntimeConfig.ocio_config_date;
|
||||
|
||||
destroy_ocio();
|
||||
|
||||
set_up_ocio();
|
||||
@@ -152,102 +160,43 @@ const GLuint &RenderThread::get_texture()
|
||||
#ifndef NO_OCIO
|
||||
void RenderThread::set_up_ocio()
|
||||
{
|
||||
// Create LUT texture
|
||||
ctx->extraFunctions()->glGenTextures(1, &ocio_lut_texture);
|
||||
|
||||
// Bind LUT
|
||||
ctx->extraFunctions()->glBindTexture(GL_TEXTURE_3D, ocio_lut_texture);
|
||||
|
||||
// Set texture parameters
|
||||
ctx->extraFunctions()->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
ctx->extraFunctions()->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
ctx->extraFunctions()->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
ctx->extraFunctions()->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
ctx->extraFunctions()->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// Allocate storage for texture
|
||||
ctx->extraFunctions()->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB,
|
||||
OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE,
|
||||
0, GL_RGB,GL_FLOAT, nullptr);
|
||||
|
||||
OCIO::ConstConfigRcPtr config;
|
||||
|
||||
// Set current config to the file specified in Config
|
||||
if (QFileInfo::exists(olive::CurrentConfig.ocio_config_path)) {
|
||||
|
||||
config = OCIO::Config::CreateFromFile(olive::CurrentConfig.ocio_config_path.toUtf8());
|
||||
OCIO::SetCurrentConfig(config);
|
||||
ocio_loaded_config = olive::CurrentConfig.ocio_config_path;
|
||||
|
||||
} else {
|
||||
|
||||
config = OCIO::GetCurrentConfig();
|
||||
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
|
||||
|
||||
// Get current OCIO display from Config (or defaults if there is no setting)
|
||||
QString display = olive::CurrentConfig.ocio_display;
|
||||
if (display.isEmpty()) {
|
||||
display = config->getDefaultDisplay();
|
||||
}
|
||||
|
||||
const char* display = config->getDefaultDisplay();
|
||||
|
||||
QString view = olive::CurrentConfig.ocio_view;
|
||||
if (view.isEmpty()) {
|
||||
view = config->getDefaultView(display.toUtf8());
|
||||
}
|
||||
|
||||
// Get current display stats
|
||||
OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create();
|
||||
transform->setInputColorSpaceName(OCIO::ROLE_SCENE_LINEAR);
|
||||
transform->setDisplay(display);
|
||||
transform->setView(config->getDefaultView(display));
|
||||
transform->setDisplay(display.toUtf8());
|
||||
transform->setView(view.toUtf8());
|
||||
|
||||
|
||||
OCIO::ConstProcessorRcPtr processor;
|
||||
OCIO::GpuShaderDesc shaderDesc;
|
||||
|
||||
// Get processor for this configuration
|
||||
if (!olive::CurrentConfig.ocio_look.isEmpty()) {
|
||||
transform->setLooksOverride(olive::CurrentConfig.ocio_look.toUtf8());
|
||||
transform->setLooksOverrideEnabled(true);
|
||||
}
|
||||
|
||||
try {
|
||||
processor = config->getProcessor(transform);
|
||||
|
||||
// Using the current configuration, try to get an OCIO processor with a corresponding input and output colorspace
|
||||
OCIO::ConstProcessorRcPtr processor = config->getProcessor(transform);
|
||||
|
||||
// Create a OCIO shader with this processor
|
||||
ocio_shader = olive::rendering::SetupOCIO(ctx, ocio_lut_texture, processor);
|
||||
|
||||
} catch(OCIO::Exception & e) {
|
||||
qCritical() << e.what();
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// SET UP GLSL SHADER
|
||||
//
|
||||
|
||||
shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0);
|
||||
shaderDesc.setFunctionName("OCIODisplay");
|
||||
shaderDesc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE);
|
||||
|
||||
//
|
||||
// COMPUTE 3D LUT
|
||||
//
|
||||
|
||||
processor->getGpuLut3D(ocio_lut_data, shaderDesc);
|
||||
|
||||
|
||||
// Upload LUT data to texture
|
||||
ctx->extraFunctions()->glTexSubImage3D(GL_TEXTURE_3D, 0,
|
||||
0, 0, 0,
|
||||
OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE,
|
||||
GL_RGB, GL_FLOAT, ocio_lut_data);
|
||||
|
||||
|
||||
// Create OCIO shader code
|
||||
QString shader_text(processor->getGpuShaderText(shaderDesc));
|
||||
shader_text.append("\n"
|
||||
"uniform sampler3D tex2;\n"
|
||||
"\n"
|
||||
"vec4 process(vec4 col) {\n"
|
||||
" return OCIODisplay(col, tex2);\n"
|
||||
"}\n");
|
||||
|
||||
|
||||
// Get pipeline-based shader to inject OCIO shader into
|
||||
ocio_shader = olive::rendering::GetPipeline(shader_text);
|
||||
|
||||
|
||||
// Release LUT
|
||||
ctx->extraFunctions()->glBindTexture(GL_TEXTURE_3D, 0);
|
||||
|
||||
}
|
||||
|
||||
void RenderThread::destroy_ocio()
|
||||
@@ -272,38 +221,43 @@ void RenderThread::paint() {
|
||||
params.playback_speed = 1;
|
||||
params.blend_mode_program = blend_mode_program.get();
|
||||
params.pipeline = pipeline_program.get();
|
||||
#ifndef NO_OCIO
|
||||
params.ocio_shader = ocio_shader.get();
|
||||
params.ocio_lut_texture = ocio_lut_texture;
|
||||
#endif
|
||||
params.backend_buffer1 = back_buffer_1.buffer();
|
||||
params.backend_buffer2 = back_buffer_2.buffer();
|
||||
params.backend_attachment1 = back_buffer_1.texture();
|
||||
params.backend_attachment2 = back_buffer_2.texture();
|
||||
params.main_buffer = front_buffer_switcher ? front_buffer_1.buffer() : front_buffer_2.buffer();
|
||||
params.main_attachment = front_buffer_switcher ? front_buffer_1.texture() : front_buffer_2.texture();
|
||||
params.backend_buffer1 = &back_buffer_1;
|
||||
params.backend_buffer2 = &back_buffer_2;
|
||||
params.main_buffer = &composite_buffer;
|
||||
|
||||
// get currently selected gizmos
|
||||
gizmos = seq->GetSelectedGizmo();
|
||||
params.gizmos = gizmos;
|
||||
|
||||
QOpenGLFunctions* f = ctx->functions();
|
||||
|
||||
f->glEnable(GL_BLEND);
|
||||
|
||||
// bind composite framebuffer for drawing
|
||||
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, composite_buffer.buffer());
|
||||
|
||||
// Clear framebuffer to nothing
|
||||
f->glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
f->glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Compose the current frame
|
||||
compose_sequence(params);
|
||||
|
||||
// Copy composite buffer to front buffer
|
||||
// First lock the appropriate mutex for exclusivity
|
||||
QMutex& active_mutex = front_buffer_switcher ? front_mutex1 : front_mutex2;
|
||||
active_mutex.lock();
|
||||
|
||||
ctx->functions()->glEnable(GL_BLEND);
|
||||
|
||||
// bind framebuffer for drawing
|
||||
ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, params.main_buffer);
|
||||
|
||||
ctx->functions()->glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
ctx->functions()->glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
compose_sequence(params);
|
||||
// Convert linear frame to display color space
|
||||
olive::rendering::OCIOBlit(ocio_shader.get(),
|
||||
ocio_lut_texture,
|
||||
front_buffer_switcher ? front_buffer_1 : front_buffer_2,
|
||||
composite_buffer.texture());
|
||||
|
||||
// flush changes
|
||||
ctx->functions()->glFinish();
|
||||
f->glFinish();
|
||||
|
||||
ctx->functions()->glDisable(GL_BLEND);
|
||||
f->glDisable(GL_BLEND);
|
||||
|
||||
texture_failed = params.texture_failed;
|
||||
|
||||
@@ -314,11 +268,11 @@ void RenderThread::paint() {
|
||||
// texture failed, try again
|
||||
queued = true;
|
||||
} else {
|
||||
ctx->functions()->glBindFramebuffer(GL_READ_FRAMEBUFFER, params.main_buffer);
|
||||
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, composite_buffer.buffer());
|
||||
QImage img(tex_width, tex_height, QImage::Format_RGBA8888);
|
||||
ctx->functions()->glReadPixels(0, 0, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
|
||||
f->glReadPixels(0, 0, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
|
||||
img.save(save_fn);
|
||||
ctx->functions()->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
save_fn = "";
|
||||
}
|
||||
}
|
||||
@@ -326,25 +280,25 @@ void RenderThread::paint() {
|
||||
if (pixel_buffer != nullptr) {
|
||||
|
||||
// set main framebuffer to the current read buffer
|
||||
ctx->functions()->glBindFramebuffer(GL_READ_FRAMEBUFFER, params.main_buffer);
|
||||
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, composite_buffer.buffer());
|
||||
|
||||
// store pixels in buffer
|
||||
ctx->functions()->glReadPixels(0,
|
||||
0,
|
||||
pixel_buffer_linesize == 0 ? tex_width : pixel_buffer_linesize,
|
||||
tex_height,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
pixel_buffer);
|
||||
f->glReadPixels(0,
|
||||
0,
|
||||
pixel_buffer_linesize == 0 ? tex_width : pixel_buffer_linesize,
|
||||
tex_height,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
pixel_buffer);
|
||||
|
||||
// release current read buffer
|
||||
ctx->functions()->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
|
||||
pixel_buffer = nullptr;
|
||||
}
|
||||
|
||||
// release
|
||||
ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void RenderThread::start_render(QOpenGLContext *share,
|
||||
@@ -390,6 +344,7 @@ void RenderThread::cancel() {
|
||||
}
|
||||
|
||||
void RenderThread::delete_buffers() {
|
||||
composite_buffer.Destroy();
|
||||
front_buffer_1.Destroy();
|
||||
front_buffer_2.Destroy();
|
||||
back_buffer_1.Destroy();
|
||||
|
||||
@@ -34,14 +34,6 @@
|
||||
#include "rendering/framebufferobject.h"
|
||||
#include "qopenglshaderprogramptr.h"
|
||||
|
||||
#ifndef NO_OCIO
|
||||
// copied from source code to OCIODisplay
|
||||
const int OCIO_LUT3D_EDGE_SIZE = 32;
|
||||
|
||||
// copied from source code to OCIODisplay, expanded from 3*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE
|
||||
const int OCIO_NUM_3D_ENTRIES = 98304;
|
||||
#endif
|
||||
|
||||
class RenderThread : public QThread {
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -80,10 +72,9 @@ private:
|
||||
void destroy_ocio();
|
||||
|
||||
// OpenColorIO variables
|
||||
float ocio_lut_data[OCIO_NUM_3D_ENTRIES];
|
||||
GLuint ocio_lut_texture;
|
||||
QOpenGLShaderProgramPtr ocio_shader;
|
||||
QString ocio_loaded_config;
|
||||
qint64 ocio_config_date;
|
||||
#endif
|
||||
|
||||
FramebufferObject front_buffer_1;
|
||||
@@ -92,6 +83,8 @@ private:
|
||||
FramebufferObject front_buffer_2;
|
||||
QMutex front_mutex2;
|
||||
|
||||
FramebufferObject composite_buffer;
|
||||
|
||||
bool front_buffer_switcher;
|
||||
|
||||
QWaitCondition wait_cond_;
|
||||
|
||||
+7
-2
@@ -516,6 +516,11 @@ void Clip::Close(bool wait) {
|
||||
// delete framebuffers
|
||||
fbo.clear();
|
||||
|
||||
#ifndef NO_OCIO
|
||||
// delete OCIO shader
|
||||
ocio_shader = nullptr;
|
||||
#endif
|
||||
|
||||
if (UsesCacher()) {
|
||||
cacher.Close(wait);
|
||||
} else {
|
||||
@@ -605,8 +610,8 @@ bool Clip::Retrieve()
|
||||
}
|
||||
|
||||
texture->setData(QOpenGLTexture::RGBA,
|
||||
QOpenGLTexture::UInt8,
|
||||
const_cast<const uint8_t*>(using_db_1 ? data_buffer_1 : data_buffer_2));
|
||||
QOpenGLTexture::UInt8,
|
||||
const_cast<const uint8_t*>(using_db_1 ? data_buffer_1 : data_buffer_2));
|
||||
|
||||
if (data_buffer_1 != frame->data[0]) {
|
||||
delete [] data_buffer_1;
|
||||
|
||||
@@ -157,6 +157,11 @@ public:
|
||||
QOpenGLTexture* texture;
|
||||
long texture_frame;
|
||||
|
||||
#ifndef NO_OCIO
|
||||
QOpenGLShaderProgramPtr ocio_shader;
|
||||
GLuint ocio_lut_texture;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// timeline variables (should be copied in copy())
|
||||
bool enabled_;
|
||||
|
||||
@@ -273,6 +273,20 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
olive::icon::Initialize();
|
||||
|
||||
#ifndef NO_OCIO
|
||||
// Load OpenColorIO configuration if set
|
||||
if (olive::CurrentConfig.enable_color_management && !olive::CurrentConfig.ocio_config_path.isEmpty()) {
|
||||
try {
|
||||
OCIO::SetCurrentConfig(OCIO::Config::CreateFromFile(olive::CurrentConfig.ocio_config_path.toUtf8()));
|
||||
} catch (OCIO::Exception& e) {
|
||||
QMessageBox::critical(this,
|
||||
tr("OpenColorIO Config Error"),
|
||||
tr("Failed to set OpenColorIO configuration: %1").arg(e.what()),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
alloc_panels(this);
|
||||
|
||||
// populate menu bars
|
||||
|
||||
Reference in New Issue
Block a user