diff --git a/dialogs/mediapropertiesdialog.h b/dialogs/mediapropertiesdialog.h index 8f9d7ebd5..5232384ae 100644 --- a/dialogs/mediapropertiesdialog.h +++ b/dialogs/mediapropertiesdialog.h @@ -83,6 +83,9 @@ private: */ QCheckBox* premultiply_alpha_setting; + /** + * @brief Setting for this media's color space + */ QComboBox* input_color_space; private slots: /** diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index 8a23b3275..b39a7f8a4 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -174,11 +174,24 @@ void PreferencesDialog::populate_ocio_menus(OCIO::ConstConfigRcPtr config) // Just clear everything ocio_display->clear(); + ocio_default_input->clear(); ocio_view->clear(); ocio_look->clear(); } else { + // Get input color spaces for setting the default input color space + ocio_default_input->clear(); + for (int i=0;igetNumColorSpaces();i++) { + QString colorspace = config->getColorSpaceNameByIndex(i); + + ocio_default_input->addItem(colorspace); + + if (colorspace == olive::CurrentConfig.ocio_default_input_colorspace) { + ocio_default_input->setCurrentIndex(i); + } + } + // 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()) { @@ -439,6 +452,7 @@ void PreferencesDialog::accept() { olive::CurrentConfig.playback_bit_depth = playback_bit_depth->currentIndex(); olive::CurrentConfig.export_bit_depth = export_bit_depth->currentIndex(); olive::CurrentConfig.ocio_display = ocio_display->currentText(); + olive::CurrentConfig.ocio_default_input_colorspace = ocio_default_input->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 @@ -1072,21 +1086,26 @@ void PreferencesDialog::setup_ui() { connect(ocio_config_browse_btn, SIGNAL(clicked(bool)), this, SLOT(browse_ocio_config())); opencolorio_groupbox_layout->addWidget(ocio_config_browse_btn, 0, 5); + // COLOR MANAGEMENT -> Default Input Color Space + ocio_default_input = new QComboBox(); + opencolorio_groupbox_layout->addWidget(new QLabel(tr("Default Input Color Space:")), 1, 0); + opencolorio_groupbox_layout->addWidget(ocio_default_input, 1, 1, 1, 5); + // COLOR MANAGEMENT -> Display ocio_display = new QComboBox(); connect(ocio_display, SIGNAL(currentIndexChanged(int)), this, SLOT(update_ocio_view_menu())); - opencolorio_groupbox_layout->addWidget(new QLabel(tr("Display:")), 1, 0); - opencolorio_groupbox_layout->addWidget(ocio_display, 1, 1); + opencolorio_groupbox_layout->addWidget(new QLabel(tr("Display:")), 2, 0); + opencolorio_groupbox_layout->addWidget(ocio_display, 2, 1); // COLOR MANAGEMENT -> View ocio_view = new QComboBox(); - opencolorio_groupbox_layout->addWidget(new QLabel(tr("View:")), 1, 2); - opencolorio_groupbox_layout->addWidget(ocio_view, 1, 3); + opencolorio_groupbox_layout->addWidget(new QLabel(tr("View:")), 2, 2); + opencolorio_groupbox_layout->addWidget(ocio_view, 2, 3); // COLOR MANAGEMENT -> Look ocio_look = new QComboBox(); - opencolorio_groupbox_layout->addWidget(new QLabel(tr("Look:")), 1, 4); - opencolorio_groupbox_layout->addWidget(ocio_look, 1, 5); + opencolorio_groupbox_layout->addWidget(new QLabel(tr("Look:")), 2, 4); + opencolorio_groupbox_layout->addWidget(ocio_look, 2, 5); color_management_layout->addWidget(opencolorio_groupbox, row, 0); diff --git a/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h index eb6c5663c..721a2b505 100644 --- a/dialogs/preferencesdialog.h +++ b/dialogs/preferencesdialog.h @@ -264,6 +264,7 @@ private: QCheckBox* enable_color_management; QLineEdit* ocio_config_file; + QComboBox* ocio_default_input; QComboBox* ocio_display; QComboBox* ocio_view; QComboBox* ocio_look; diff --git a/effects/effect.cpp b/effects/effect.cpp index 38b9f2344..4e09326ad 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -52,6 +52,7 @@ #include "global/config.h" #include "transition.h" #include "undo/undostack.h" +#include "rendering/shadergenerators.h" #include "effects/internal/transformeffect.h" #include "effects/internal/texteffect.h" @@ -743,8 +744,23 @@ void Effect::open() { if (QOpenGLContext::currentContext() == nullptr) { qWarning() << "No current context to create a shader program for - will retry next repaint"; } else { - shader_program_ = std::make_shared(); validate_meta_path(); + + QString frag_shader_str; + QString frag_file_url = QDir(meta->path).filePath(shader_frag_path_); + QFile frag_file(frag_file_url); + if (frag_file.open(QFile::ReadOnly)) { + frag_shader_str = frag_file.readAll(); + frag_file.close(); + } else { + qWarning() << "Failed to open" << frag_file_url; + } + + if (!frag_shader_str.isEmpty()) { + shader_program_ = olive::shader::GetPipeline("process", frag_shader_str); + } + + /* bool shader_compiled = true; if (!shader_vert_path_.isEmpty()) { if (shader_program_->addShaderFromSourceFile(QOpenGLShader::Vertex, meta->path + "/" + shader_vert_path_)) { @@ -769,6 +785,7 @@ void Effect::open() { qWarning() << "Shader program failed to link"; } } + */ isOpen = true; } } else { @@ -789,21 +806,9 @@ bool Effect::is_shader_linked() { return shader_program_ != nullptr && shader_program_->isLinked(); } -void Effect::startEffect() { - if (!isOpen) { - open(); - qWarning() << "Tried to start a closed effect - opening"; - } - if (olive::CurrentRuntimeConfig.shaders_are_enabled - && (Flags() & Effect::ShaderFlag) - && shader_program_->isLinked()) { - bound = shader_program_->bind(); - } -} - -void Effect::endEffect() { - if (bound) shader_program_->release(); - bound = false; +QOpenGLShaderProgram *Effect::GetShaderPipeline() +{ + return shader_program_.get(); } int Effect::Flags() @@ -834,6 +839,8 @@ EffectPtr Effect::copy(Clip *c) { } void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { + shader_program_->bind(); + shader_program_->setUniformValue("resolution", parent_clip->media_width(), parent_clip->media_height()); shader_program_->setUniformValue("time", GLfloat(timecode)); shader_program_->setUniformValue("iteration", iteration); @@ -879,6 +886,8 @@ void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { } } } + + shader_program_->release(); } void Effect::process_coords(double, GLTextureCoords&, int) {} diff --git a/effects/effect.h b/effects/effect.h index 9fbc462f8..2e3252d8b 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -172,8 +172,7 @@ public: void open(); void close(); bool is_shader_linked(); - virtual void startEffect(); - virtual void endEffect(); + QOpenGLShaderProgram* GetShaderPipeline(); enum VideoEffectFlags { ShaderFlag = 0x1, diff --git a/global/config.cpp b/global/config.cpp index aaaaa7987..228d8d9de 100644 --- a/global/config.cpp +++ b/global/config.cpp @@ -228,6 +228,18 @@ void Config::load(QString path) { } else if (stream.name() == "OCIOConfigPath") { stream.readNext(); ocio_config_path = stream.text().toString(); + } else if (stream.name() == "OCIODisplay") { + stream.readNext(); + ocio_display = stream.text().toString(); + } else if (stream.name() == "OCIOView") { + stream.readNext(); + ocio_view = stream.text().toString(); + } else if (stream.name() == "OCIOLook") { + stream.readNext(); + ocio_look = stream.text().toString(); + } else if (stream.name() == "OCIODefaultInput") { + stream.readNext(); + ocio_default_input_colorspace = stream.text().toString(); } else if (stream.name() == "Style") { stream.readNext(); style = static_cast(stream.text().toInt()); @@ -327,6 +339,10 @@ void Config::save(QString path) { stream.writeTextElement("AddDefaultEffectsToClips", QString::number(add_default_effects_to_clips)); stream.writeTextElement("EnableColorManagement", QString::number(enable_color_management)); stream.writeTextElement("OCIOConfigPath", ocio_config_path); + stream.writeTextElement("OCIODisplay", ocio_display); + stream.writeTextElement("OCIOView", ocio_view); + stream.writeTextElement("OCIOLook", ocio_look); + stream.writeTextElement("OCIODefaultInput", ocio_default_input_colorspace); stream.writeTextElement("Style", QString::number(style)); stream.writeTextElement("NativeMenuStyling", QString::number(use_native_menu_styling)); stream.writeTextElement("DefaultSequenceWidth", QString::number(default_sequence_width)); diff --git a/global/config.h b/global/config.h index ef5372b16..3d7109e1c 100644 --- a/global/config.h +++ b/global/config.h @@ -554,6 +554,13 @@ struct Config { */ QString ocio_look; + /** + * @brief OpenColorIO Default Input Colorspace + * + * The colorspace to default to if no colorspace can be determined from the filename or a manual setting. + */ + QString ocio_default_input_colorspace; + /** * @brief Style to use when theming Olive. * diff --git a/olive.pro b/olive.pro index 5f3e23a85..83f56d5c2 100644 --- a/olive.pro +++ b/olive.pro @@ -172,7 +172,6 @@ SOURCES += \ effects/internal/richtexteffect.cpp \ ui/blur.cpp \ ui/menu.cpp \ - rendering/qopenglshaderprogramptr.cpp \ timeline/mediaimportdata.cpp \ dialogs/autocutsilencedialog.cpp \ ui/columnedgridlayout.cpp \ diff --git a/project/footage.cpp b/project/footage.cpp index 631c9ae49..61c37b13c 100644 --- a/project/footage.cpp +++ b/project/footage.cpp @@ -28,6 +28,7 @@ namespace OCIO = OCIO_NAMESPACE::v1; #include "project/previewgenerator.h" #include "timeline/clip.h" +#include "global/config.h" Footage::Footage() : ready(false), @@ -61,7 +62,7 @@ QString Footage::Colorspace() return guess_colorspace; } - return OCIO::ROLE_SCENE_LINEAR; + return olive::CurrentConfig.ocio_default_input_colorspace; } void Footage::SetColorspace(const QString &cs) diff --git a/rendering/pixelformats.h b/rendering/pixelformats.h index 2e913c531..37fe34850 100644 --- a/rendering/pixelformats.h +++ b/rendering/pixelformats.h @@ -27,14 +27,6 @@ namespace olive { -struct PixelFormatInfo { - QString name; - GLint internal_format; - GLenum pixel_format; - GLenum pixel_type; - int bytes_per_pixel; -}; - /** * @brief The PixelFormat enum * @@ -49,6 +41,21 @@ enum PixelFormat { PIX_FMT_COUNT }; +/** + * @brief The PixelFormatInfo struct + * + * A struct of information pertaining to each enum PixelFormat. Primarily this is a means of retrieving OpenGL texture + * information for different pixel formats/bit depths. Using the values in pixel_formats is always recommended over + * manually using OpenGL constants (e.g. GL_RGBA or GL_RGBA32F) directly. + */ +struct PixelFormatInfo { + QString name; + GLint internal_format; + GLenum pixel_format; + GLenum pixel_type; + int bytes_per_pixel; +}; + extern QVector pixel_formats; void InitializePixelFormats(); diff --git a/rendering/qopenglshaderprogramptr.cpp b/rendering/qopenglshaderprogramptr.cpp deleted file mode 100644 index 049273bce..000000000 --- a/rendering/qopenglshaderprogramptr.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "qopenglshaderprogramptr.h" - diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index a11057980..d32e00bdb 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -101,6 +101,7 @@ void olive::rendering::Blit(QOpenGLShaderProgram* pipeline, bool flipped, QMatri pipeline->setUniformValue("mvp_matrix", matrix); pipeline->setUniformValue("texture", 0); + GLuint vertex_location = pipeline->attributeLocation("a_position"); m_vbo.bind(); func->glEnableVertexAttribArray(vertex_location); @@ -179,11 +180,15 @@ void process_effect(QOpenGLContext* ctx, } bool can_process_shaders = ((e->Flags() & Effect::ShaderFlag) && olive::CurrentRuntimeConfig.shaders_are_enabled); if (can_process_shaders || (e->Flags() & Effect::SuperimposeFlag)) { - e->startEffect(); + + if (!e->is_open()) { + e->open(); + } + if (can_process_shaders && e->is_shader_linked()) { for (int i=0;igetIterations();i++) { e->process_shader(timecode, coords, i); - composite_texture = draw_clip(ctx, pipeline, c->fbo.at(fbo_switcher), composite_texture, true); + composite_texture = draw_clip(ctx, e->GetShaderPipeline(), c->fbo.at(fbo_switcher), composite_texture, true); fbo_switcher = !fbo_switcher; } } @@ -208,7 +213,6 @@ void process_effect(QOpenGLContext* ctx, composite_texture = draw_clip(ctx, pipeline, c->fbo.at(!fbo_switcher), superimpose_texture, false); } } - e->endEffect(); } } } diff --git a/rendering/shadergenerators.cpp b/rendering/shadergenerators.cpp index 6a6490d63..a9b90c6bc 100644 --- a/rendering/shadergenerators.cpp +++ b/rendering/shadergenerators.cpp @@ -2,7 +2,7 @@ #include -QOpenGLShaderProgramPtr olive::shader::GetPipeline(const QString& shader_code) +QOpenGLShaderProgramPtr olive::shader::GetPipeline(const QString& function_name, const QString& shader_code) { QOpenGLShaderProgramPtr program = std::make_shared(); @@ -62,16 +62,16 @@ QOpenGLShaderProgramPtr olive::shader::GetPipeline(const QString& shader_code) // If additional code was passed, add it and reference it in main(). // - // The function in the additional code is expected to be `vec4 process(vec4 color)`. The texture coordinate can be + // The function in the additional code is expected to be `vec4 function_name(vec4 color)`. The texture coordinate can be // acquired through `v_texcoord`. frag_shader.append(shader_code); - frag_shader.append("\n" + frag_shader.append(QString("\n" "void main() {\n" - " vec4 color = process(texture2D(texture, v_texcoord))*opacity;\n" + " vec4 color = %1(texture2D(texture, v_texcoord))*opacity;\n" " gl_FragColor = color;\n" - "}\n"); + "}\n").arg(function_name)); } @@ -211,16 +211,17 @@ QOpenGLShaderProgramPtr olive::shader::SetupOCIO(QOpenGLContext* ctx, } // Add process() function, which GetPipeline() will call if specified + QString process_function_name = "process"; shader_text.append(QString("\n" "uniform sampler3D tex2;\n" "\n" - "vec4 process(vec4 col) {\n" + "vec4 %2(vec4 col) {\n" " return %1\n" - "}\n").arg(shader_call)); + "}\n").arg(shader_call, process_function_name)); // Get pipeline-based shader to inject OCIO shader into - QOpenGLShaderProgramPtr shader = olive::shader::GetPipeline(shader_text); + QOpenGLShaderProgramPtr shader = olive::shader::GetPipeline(process_function_name, shader_text); // Release LUT xf->glBindTexture(GL_TEXTURE_3D, 0); diff --git a/rendering/shadergenerators.h b/rendering/shadergenerators.h index 5fe5a7370..02123afc6 100644 --- a/rendering/shadergenerators.h +++ b/rendering/shadergenerators.h @@ -9,7 +9,7 @@ namespace OCIO = OCIO_NAMESPACE::v1; namespace olive { namespace shader { -QOpenGLShaderProgramPtr GetPipeline(const QString &shader_code = QString()); +QOpenGLShaderProgramPtr GetPipeline(const QString &function_name = QString(), const QString &shader_code = QString()); QOpenGLShaderProgramPtr SetupOCIO(QOpenGLContext *ctx, GLuint &lut_texture,