diff --git a/effects/effect.cpp b/effects/effect.cpp index e87bae604..c0ef931e0 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -735,12 +735,12 @@ void Effect::open() { } else { shader_program_ = std::make_shared(); validate_meta_path(); - bool glsl_compiled = true; + bool shader_compiled = true; if (!shader_vert_path_.isEmpty()) { if (shader_program_->addShaderFromSourceFile(QOpenGLShader::Vertex, meta->path + "/" + shader_vert_path_)) { qInfo() << "Vertex shader added successfully"; } else { - glsl_compiled = false; + shader_compiled = false; qWarning() << "Vertex shader could not be added"; } } @@ -748,11 +748,11 @@ void Effect::open() { if (shader_program_->addShaderFromSourceFile(QOpenGLShader::Fragment, meta->path + "/" + shader_frag_path_)) { qInfo() << "Fragment shader added successfully"; } else { - glsl_compiled = false; + shader_compiled = false; qWarning() << "Fragment shader could not be added"; } } - if (glsl_compiled) { + if (shader_compiled) { if (shader_program_->link()) { qInfo() << "Shader program linked successfully"; } else { @@ -775,7 +775,7 @@ void Effect::close() { isOpen = false; } -bool Effect::is_glsl_linked() { +bool Effect::is_shader_linked() { return shader_program_ != nullptr && shader_program_->isLinked(); } @@ -983,20 +983,12 @@ void Effect::gizmo_move(EffectGizmo* gizmo, int x_movement, int y_movement, doub } } -void Effect::gizmo_world_to_screen() { - GLfloat view_val[16]; - GLfloat projection_val[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, view_val); - glGetFloatv(GL_PROJECTION_MATRIX, projection_val); - - QMatrix4x4 view_matrix(view_val); - QMatrix4x4 projection_matrix(projection_val); - +void Effect::gizmo_world_to_screen(const QMatrix4x4& matrix, const QMatrix4x4& projection) { for (int i=0;iget_point_count();j++) { - QVector4D screen_pos = QVector4D(g->world_pos[j].x(), g->world_pos[j].y(), 0, 1.0) * (view_matrix * projection_matrix); + QVector4D screen_pos = QVector4D(g->world_pos[j].x(), g->world_pos[j].y(), 0, 1.0) * (matrix * projection); int adjusted_sx1 = qRound(((screen_pos.x()*0.5f)+0.5f)*parent_clip->sequence->width); int adjusted_sy1 = qRound((1.0f-((screen_pos.y()*0.5f)+0.5f))*parent_clip->sequence->height); diff --git a/effects/effect.h b/effects/effect.h index 5172d9d33..ffca12806 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -172,7 +172,7 @@ public: bool is_open(); void open(); void close(); - bool is_glsl_linked(); + bool is_shader_linked(); virtual void startEffect(); virtual void endEffect(); @@ -198,7 +198,7 @@ public: virtual void gizmo_draw(double timecode, GLTextureCoords& coords); void gizmo_move(EffectGizmo* sender, int x_movement, int y_movement, double timecode, bool done); - void gizmo_world_to_screen(); + void gizmo_world_to_screen(const QMatrix4x4 &matrix, const QMatrix4x4 &projection); bool are_gizmos_enabled(); template diff --git a/effects/internal/pipeline.frag b/effects/internal/pipeline.frag index 71719c428..5875c7e0f 100644 --- a/effects/internal/pipeline.frag +++ b/effects/internal/pipeline.frag @@ -4,8 +4,10 @@ precision mediump float; #endif uniform sampler2D texture; +uniform float opacity; varying vec2 v_texcoord; void main() { - gl_FragColor = texture2D(texture, v_texcoord); + vec4 color = texture2D(texture, v_texcoord)*opacity; + gl_FragColor = color; } \ No newline at end of file diff --git a/effects/internal/shakeeffect.cpp b/effects/internal/shakeeffect.cpp index b8b92a496..3b4d16ba5 100644 --- a/effects/internal/shakeeffect.cpp +++ b/effects/internal/shakeeffect.cpp @@ -78,10 +78,7 @@ void ShakeEffect::process_coords(double timecode, GLTextureCoords& coords, int) yoff *= multiplier; rotoff *= rotmult; - coords.vertex_top_left += QVector3D(xoff, yoff, 0.0); - coords.vertex_top_right += QVector3D(xoff, yoff, 0.0); - coords.vertex_bottom_left += QVector3D(xoff, yoff, 0.0); - coords.vertex_bottom_right += QVector3D(xoff, yoff, 0.0); + coords.matrix.translate(xoff, yoff, 0.0); - glRotatef(rotoff, 0, 0, 1); + coords.matrix.rotate(QQuaternion::fromEulerAngles(0.0f, 0.0f, rotoff)); } diff --git a/effects/internal/transformeffect.cpp b/effects/internal/transformeffect.cpp index 0e766ff1b..a96df512a 100644 --- a/effects/internal/transformeffect.cpp +++ b/effects/internal/transformeffect.cpp @@ -190,9 +190,9 @@ void TransformEffect::toggle_uniform_scale(bool enabled) { void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, int) { // position - glTranslated(position_x->GetDoubleAt(timecode)-(parent_clip->sequence->width/2), - position_y->GetDoubleAt(timecode)-(parent_clip->sequence->height/2), - 0); + coords.matrix.translate(position_x->GetDoubleAt(timecode)-(parent_clip->sequence->width/2), + position_y->GetDoubleAt(timecode)-(parent_clip->sequence->height/2), + 0); // anchor point int anchor_x_offset = qRound(anchor_x_box->GetDoubleAt(timecode)); @@ -204,12 +204,12 @@ void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, i coords.vertex_bottom_right -= QVector3D(anchor_x_offset, anchor_y_offset, 0.0f); // rotation - glRotated(rotation->GetDoubleAt(timecode), 0, 0, 1); + coords.matrix.rotate(QQuaternion::fromEulerAngles(0, 0, rotation->GetDoubleAt(timecode))); // scale double sx = scale_x->GetDoubleAt(timecode)*0.01; double sy = (uniform_scale_field->GetBoolAt(timecode)) ? sx : scale_y->GetDoubleAt(timecode)*0.01; - glScaled(sx, sy, 1); + coords.matrix.scale(sx, sy); // blend mode coords.blendmode = blend_mode_box->GetValueAt(timecode).toInt(); diff --git a/rendering/framebufferobject.cpp b/rendering/framebufferobject.cpp index cf2f7d0cb..f55eb4777 100644 --- a/rendering/framebufferobject.cpp +++ b/rendering/framebufferobject.cpp @@ -81,7 +81,7 @@ void FramebufferObject::BindBuffer() const if (ctx_ == nullptr) { return; } - ctx_->functions()->glBindFramebuffer(GL_TEXTURE_2D, buffer_); + ctx_->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer_); } void FramebufferObject::ReleaseBuffer() const @@ -89,7 +89,7 @@ void FramebufferObject::ReleaseBuffer() const if (ctx_ == nullptr) { return; } - ctx_->functions()->glBindFramebuffer(GL_TEXTURE_2D, 0); + ctx_->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } void FramebufferObject::BindTexture() const diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index fffdd566b..753e38528 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -26,6 +26,7 @@ extern "C" { #include #include +#include #include #ifndef NO_OCIO @@ -67,12 +68,23 @@ GLfloat olive::rendering::blit_texcoords[] = { 1.0, 1.0 }; -void olive::rendering::Blit(QOpenGLShaderProgram* pipeline) { +GLfloat olive::rendering::flipped_blit_texcoords[] = { + 0.0, 1.0, + 1.0, 1.0, + 1.0, 0.0, + + 0.0, 1.0, + 0.0, 0.0, + 1.0, 0.0 +}; + +void olive::rendering::Blit(QOpenGLShaderProgram* pipeline, bool flipped, QMatrix4x4 matrix) { + QOpenGLFunctions* func = QOpenGLContext::currentContext()->functions(); pipeline->bind(); - pipeline->setUniformValue("mvp_matrix", QMatrix4x4()); + pipeline->setUniformValue("mvp_matrix", matrix); pipeline->setUniformValue("texture", 0); GLuint vertex_location = pipeline->attributeLocation("a_position"); @@ -81,21 +93,90 @@ void olive::rendering::Blit(QOpenGLShaderProgram* pipeline) { GLuint tex_location = pipeline->attributeLocation("a_texcoord"); func->glEnableVertexAttribArray(tex_location); - func->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, blit_texcoords); + func->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, flipped ? flipped_blit_texcoords : blit_texcoords); func->glDrawArrays(GL_TRIANGLES, 0, 6); pipeline->release(); + } -QOpenGLShaderProgramPtr olive::rendering::GetPipeline() +QOpenGLShaderProgramPtr olive::rendering::GetPipeline(const QString& shader_code) { QOpenGLShaderProgramPtr program = std::make_shared(); - program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/internalshaders/pipeline.vert"); - program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/internalshaders/pipeline.frag"); + // Generate vertex shader + QString vert_shader = "#ifdef GL_ES\n" + "precision mediump int;\n" + "precision mediump float;\n" + "#endif\n" + "\n" + "uniform mat4 mvp_matrix;\n" + "\n" + "attribute vec4 a_position;\n" + "attribute vec2 a_texcoord;\n" + "\n" + "varying vec2 v_texcoord;\n" + "\n" + "void main() {\n" + " gl_Position = mvp_matrix * a_position;\n" + " v_texcoord = a_texcoord;\n" + "}\n"; + + // Generate fragment shader + QString frag_shader = "#ifdef GL_ES\n" + "precision mediump int;\n" + "precision mediump float;\n" + "#endif\n" + "\n" + "uniform sampler2D texture;\n" + "uniform float opacity;\n" + "varying vec2 v_texcoord;\n" + "\n"; + + // Finish the function with the main function + + // Check if additional code was passed to this function, add it here + if (shader_code.isEmpty()) { + + // If not, just add a pure main() function + + frag_shader.append("\n" + "void main() {\n" + " vec4 color = texture2D(texture, v_texcoord)*opacity;\n" + " gl_FragColor = color;\n" + "}\n"); + + } else { + + // 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 + // acquired through `v_texcoord`. + + frag_shader.append(shader_code); + + frag_shader.append("\n" + "void main() {\n" + " vec4 color = process(texture2D(texture, v_texcoord))*opacity;\n" + " gl_FragColor = color;\n" + "}\n"); + + } + + + + + // Add shaders to program + program->addShaderFromSourceCode(QOpenGLShader::Vertex, vert_shader); + program->addShaderFromSourceCode(QOpenGLShader::Fragment, frag_shader); program->link(); + // Set opacity default to 100% + program->bind(); + program->setUniformValue("opacity", 1.0f); + program->release(); + return program; } @@ -158,10 +239,10 @@ 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 (can_process_shaders && e->is_glsl_linked()) { + 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[fbo_switcher], composite_texture, true); + composite_texture = draw_clip(ctx, pipeline, c->fbo.at(fbo_switcher), composite_texture, true); fbo_switcher = !fbo_switcher; } } @@ -179,11 +260,11 @@ void process_effect(QOpenGLContext* ctx, } else { // if the source texture is not already a framebuffer texture, // we'll need to make it one before drawing a superimpose effect on it - if (composite_texture != c->fbo[0].texture() && composite_texture != c->fbo[1].texture()) { - draw_clip(ctx, pipeline, c->fbo[!fbo_switcher], composite_texture, true); + if (composite_texture != c->fbo.at(0).texture() && composite_texture != c->fbo.at(1).texture()) { + draw_clip(ctx, pipeline, c->fbo.at(!fbo_switcher), composite_texture, true); } - composite_texture = draw_clip(ctx, pipeline, c->fbo[!fbo_switcher], superimpose_texture, false); + composite_texture = draw_clip(ctx, pipeline, c->fbo.at(!fbo_switcher), superimpose_texture, false); } } e->endEffect(); @@ -205,9 +286,9 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { } if (params.video && !params.nests.last()->fbo.isEmpty()) { - params.nests.last()->fbo[0].BindBuffer(); - glClear(GL_COLOR_BUFFER_BIT); - final_fbo = params.nests.last()->fbo[0].buffer(); + params.nests.last()->fbo.at(0).BindBuffer(); + params.ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); + final_fbo = params.nests.last()->fbo.at(0).buffer(); } } @@ -308,14 +389,11 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { if (params.video) { // set default coordinates based on the sequence, with 0 in the direct center - //glPushMatrix(); - //glLoadIdentity(); params.ctx->functions()->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); int half_width = s->width/2; int half_height = s->height/2; - //glOrtho(-half_width, half_width, -half_height, half_height, -1, 10); projection.ortho(-half_width, half_width, -half_height, half_height, -1, 1); } @@ -406,7 +484,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // 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); - textureID = draw_clip(params.ctx, params.pipeline, c->fbo[fbo_switcher], textureID, true); + textureID = draw_clip(params.ctx, params.pipeline, c->fbo.at(fbo_switcher), textureID, true); params.ctx->functions()->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -418,15 +496,23 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // convert to linear colorspace if (olive::CurrentConfig.enable_color_management && params.ocio_shader != nullptr) { + + params.ctx->extraFunctions()->glActiveTexture(GL_TEXTURE2); + params.ctx->extraFunctions()->glBindTexture(GL_TEXTURE_3D, params.ocio_lut_texture); + params.ctx->extraFunctions()->glActiveTexture(GL_TEXTURE0); + params.ocio_shader->bind(); - params.ocio_shader->setUniformValue("tex1", 0); params.ocio_shader->setUniformValue("tex2", 2); - textureID = draw_clip(params.ctx, params.pipeline, c->fbo[fbo_switcher], textureID, true); + textureID = draw_clip(params.ctx, params.ocio_shader, c->fbo.at(fbo_switcher), textureID, true); params.ocio_shader->release(); + params.ctx->extraFunctions()->glActiveTexture(GL_TEXTURE2); + params.ctx->extraFunctions()->glBindTexture(GL_TEXTURE_3D, 0); + params.ctx->extraFunctions()->glActiveTexture(GL_TEXTURE0); + fbo_switcher = !fbo_switcher; } @@ -459,7 +545,6 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { Effect* e = c->effects.at(j).get(); process_effect(params.ctx, params.pipeline, c, e, timecode, coords, textureID, fbo_switcher, params.texture_failed, kTransitionNone); - } // if the clip has an opening transition, process that now @@ -482,27 +567,29 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // Check whether the parent clip is auto-scaled - // TODO redo this - /* if (c->autoscaled() && (video_width != s->width && video_height != s->height)) { float width_multiplier = float(s->width) / float(video_width); float height_multiplier = float(s->height) / float(video_height); float scale_multiplier = qMin(width_multiplier, height_multiplier); - glScalef(scale_multiplier, scale_multiplier, 1); + + coords.matrix.scale(scale_multiplier, scale_multiplier); } - */ // Configure effect gizmos if they exist if (params.gizmos != nullptr) { - params.gizmos->gizmo_draw(timecode, coords); // set correct gizmo coords - params.gizmos->gizmo_world_to_screen(); // convert gizmo coords to screen coords + // set correct gizmo coords at this matrix + params.gizmos->gizmo_draw(timecode, coords); + + // convert gizmo coords to screen coords + params.gizmos->gizmo_world_to_screen(coords.matrix, projection); } if (textureID > 0) { + // set viewport to sequence size params.ctx->functions()->glViewport(0, 0, s->width, s->height); @@ -542,8 +629,9 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // draw clip on screen according to gl coordinates params.pipeline->bind(); - params.pipeline->setUniformValue("mvp_matrix", projection); + params.pipeline->setUniformValue("mvp_matrix", projection * coords.matrix); params.pipeline->setUniformValue("texture", 0); + params.pipeline->setUniformValue("opacity", coords.opacity); GLfloat vertices[] = { coords.vertex_top_left.x(), coords.vertex_top_left.y(), 0.0f, @@ -576,6 +664,8 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { params.ctx->functions()->glDrawArrays(GL_TRIANGLES, 0, 6); + params.pipeline->setUniformValue("opacity", 1.0f); + params.pipeline->release(); // release final clip texture @@ -700,10 +790,6 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { params.viewer->play_wake(); } - if (params.video) { - glPopMatrix(); - } - if (!params.nests.isEmpty() && !params.nests.last()->fbo.isEmpty()) { // returns nested clip's texture return params.nests.last()->fbo[0].texture(); diff --git a/rendering/renderfunctions.h b/rendering/renderfunctions.h index 03bffa4e3..d9894eea2 100644 --- a/rendering/renderfunctions.h +++ b/rendering/renderfunctions.h @@ -414,8 +414,9 @@ namespace olive { namespace rendering { extern GLfloat blit_vertices[]; extern GLfloat blit_texcoords[]; - void Blit(QOpenGLShaderProgram* pipeline); - QOpenGLShaderProgramPtr GetPipeline(); + extern GLfloat flipped_blit_texcoords[]; + void Blit(QOpenGLShaderProgram* pipeline, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4()); + QOpenGLShaderProgramPtr GetPipeline(const QString &shader_code = QString()); } } diff --git a/rendering/renderthread.cpp b/rendering/renderthread.cpp index 9741814bc..f0ad91e69 100644 --- a/rendering/renderthread.cpp +++ b/rendering/renderthread.cpp @@ -149,47 +149,26 @@ const GLuint &RenderThread::get_texture() return front_buffer_switcher ? front_buffer_2.texture() : front_buffer_1.texture(); } -const char * g_fragShaderText = "" - "\n" - "uniform sampler2D tex1;\n" - "uniform sampler3D tex2;\n" - "\n" - "void main()\n" - "{\n" - " vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n" - " gl_FragColor = OCIODisplay(col, tex2);\n" - "}\n"; - #ifndef NO_OCIO void RenderThread::set_up_ocio() { - - // - // SETUP LUT TEXTURE - // - // Create LUT texture - ctx->functions()->glGenTextures(1, &ocio_lut_texture); + ctx->extraFunctions()->glGenTextures(1, &ocio_lut_texture); - // Bind texture to GL_TEXTURE_3D and GL_TEXTURE2 - ctx->functions()->glActiveTexture(GL_TEXTURE2); - ctx->functions()->glBindTexture(GL_TEXTURE_3D, ocio_lut_texture); + // Bind LUT + ctx->extraFunctions()->glBindTexture(GL_TEXTURE_3D, ocio_lut_texture); // Set texture parameters - ctx->functions()->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - ctx->functions()->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - ctx->functions()->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - ctx->functions()->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - ctx->functions()->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + 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, ocio_lut_data); - - // - // SET UP OCIO DISPLAY - // + 0, GL_RGB,GL_FLOAT, nullptr); OCIO::ConstConfigRcPtr config; @@ -208,30 +187,32 @@ void RenderThread::set_up_ocio() const char* display = config->getDefaultDisplay(); + OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create(); transform->setInputColorSpaceName(OCIO::ROLE_SCENE_LINEAR); transform->setDisplay(display); transform->setView(config->getDefaultView(display)); - // - // GET OCIO PROCESSOR - // OCIO::ConstProcessorRcPtr processor; + OCIO::GpuShaderDesc shaderDesc; + + // Get processor for this configuration + try { - processor = OCIO::GetCurrentConfig()->getProcessor(transform); + processor = config->getProcessor(transform); + + + } catch(OCIO::Exception & e) { qCritical() << e.what(); - ctx->functions()->glActiveTexture(GL_TEXTURE0); return; } - // // SET UP GLSL SHADER // - OCIO::GpuShaderDesc shaderDesc; shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0); shaderDesc.setFunctionName("OCIODisplay"); shaderDesc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE); @@ -242,22 +223,31 @@ void RenderThread::set_up_ocio() processor->getGpuLut3D(ocio_lut_data, shaderDesc); - ctx->extraFunctions()->glBindTexture(GL_TEXTURE_3D, ocio_lut_texture); + + // 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); + GL_RGB, GL_FLOAT, ocio_lut_data); - QString shader_text = processor->getGpuShaderText(shaderDesc); - shader_text.append("\n"); - shader_text.append(g_fragShaderText); - ocio_shader = std::make_shared(); - ocio_shader->addShaderFromSourceCode(QOpenGLShader::Fragment, shader_text); - ocio_shader->link(); + // 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); - // Reset active texture to 0 for the rest of the pipeline - ctx->functions()->glActiveTexture(GL_TEXTURE0); } void RenderThread::destroy_ocio() @@ -284,6 +274,7 @@ void RenderThread::paint() { 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(); @@ -299,6 +290,8 @@ void RenderThread::paint() { 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); @@ -310,6 +303,8 @@ void RenderThread::paint() { // flush changes ctx->functions()->glFinish(); + ctx->functions()->glDisable(GL_BLEND); + texture_failed = params.texture_failed; active_mutex.unlock(); @@ -321,7 +316,7 @@ void RenderThread::paint() { } else { ctx->functions()->glBindFramebuffer(GL_READ_FRAMEBUFFER, params.main_buffer); QImage img(tex_width, tex_height, QImage::Format_RGBA8888); - glReadPixels(0, 0, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); + ctx->functions()->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); save_fn = ""; diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 35e167882..7c6bb8681 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -567,20 +567,20 @@ void ViewerWidget::paintGL() { // draw texture from render thread - // TODO fix zooming double zoom_factor = container->zoom/(double(width())/double(viewer->seq->width)); double zoom_size = (zoom_factor*2.0) - 2.0; - double zoom_left = -zoom_size*x_scroll - 1.0; - double zoom_right = zoom_size*(1.0-x_scroll) + 1.0; - double zoom_bottom = -zoom_size*(1.0-y_scroll) - 1.0; - double zoom_top = zoom_size*(y_scroll) + 1.0; + QMatrix4x4 matrix; + if (zoom_factor > 1.0) { + matrix.translate((-(x_scroll-0.5))*zoom_size, (y_scroll-0.5)*zoom_size); + matrix.scale(zoom_factor); + } f->glViewport(0, 0, width(), height()); f->glBindTexture(GL_TEXTURE_2D, tex); - olive::rendering::Blit(pipeline_.get()); + olive::rendering::Blit(pipeline_.get(), true, matrix); f->glBindTexture(GL_TEXTURE_2D, 0); diff --git a/ui/viewerwindow.cpp b/ui/viewerwindow.cpp index 69bb74053..922b1a4cc 100644 --- a/ui/viewerwindow.cpp +++ b/ui/viewerwindow.cpp @@ -28,27 +28,26 @@ #include #include #include - #include -#include "mainwindow.h" +#include "rendering/renderfunctions.h" ViewerWindow::ViewerWindow(QWidget *parent) : QOpenGLWidget(parent, Qt::Window), - texture(0), - mutex(nullptr), - show_fullscreen_msg(false) + texture_(0), + mutex_(nullptr), + show_fullscreen_msg_(false) { setMouseTracking(true); - fullscreen_msg_timer.setInterval(2000); - connect(&fullscreen_msg_timer, SIGNAL(timeout()), this, SLOT(fullscreen_msg_timeout())); + fullscreen_msg_timer_.setInterval(2000); + connect(&fullscreen_msg_timer_, SIGNAL(timeout()), this, SLOT(fullscreen_msg_timeout())); } void ViewerWindow::set_texture(GLuint t, double iar, QMutex* imutex) { - texture = t; - ar = iar; - mutex = imutex; + texture_ = t; + ar_ = iar; + mutex_ = imutex; update(); } @@ -59,71 +58,66 @@ void ViewerWindow::keyPressEvent(QKeyEvent *e) { } void ViewerWindow::mousePressEvent(QMouseEvent *e) { - if (show_fullscreen_msg && fullscreen_msg_rect.contains(e->pos())) { + if (show_fullscreen_msg_ && fullscreen_msg_rect_.contains(e->pos())) { hide(); } } void ViewerWindow::mouseMoveEvent(QMouseEvent *) { - fullscreen_msg_timer.start(); - if (!show_fullscreen_msg) { - show_fullscreen_msg = true; + fullscreen_msg_timer_.start(); + if (!show_fullscreen_msg_) { + show_fullscreen_msg_ = true; update(); } } +void ViewerWindow::initializeGL() +{ + pipeline_ = olive::rendering::GetPipeline(); +} + void ViewerWindow::paintGL() { - if (texture > 0) { - if (mutex != nullptr) mutex->lock(); + if (texture_ > 0) { + if (mutex_ != nullptr) mutex_->lock(); - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_TEXTURE_2D); + QOpenGLFunctions* f = context()->functions(); + //QOpenGLExtraFunctions* xf = context()->extraFunctions(); - glBindTexture(GL_TEXTURE_2D, texture); + makeCurrent(); - glLoadIdentity(); - glOrtho(0, 1, 0, 1, -1, 1); + // clear to solid black + f->glClearColor(0.0, 0.0, 0.0, 0.0); + f->glClear(GL_COLOR_BUFFER_BIT); - glBegin(GL_QUADS); - double top = 0; - double left = 0; - double right = 1; - double bottom = 1; + // draw texture from render thread - double widget_ar = double(width()) / double(height()); - if (widget_ar > ar) { - double width = 1.0 * ar / widget_ar; - left = (1.0 - width)*0.5; - right = left + width; + QMatrix4x4 matrix; + + double widget_ar = (double(width()) / double(height())); + if (widget_ar > ar_) { + matrix.scale(ar_ / widget_ar, 1.0); } else { - double height = 1.0 / ar * widget_ar; - top = (1.0 - height)*0.5; - bottom = top + height; + matrix.scale(1.0f, widget_ar / ar_); } - glVertex2d(left, top); - glTexCoord2d(0, 0); - glVertex2d(left, bottom); - glTexCoord2d(1, 0); - glVertex2d(right, bottom); - glTexCoord2d(1, 1); - glVertex2d(right, top); - glTexCoord2d(0, 1); - glEnd(); + f->glViewport(0, 0, width(), height()); - glBindTexture(GL_TEXTURE_2D, 0); + f->glBindTexture(GL_TEXTURE_2D, texture_); - glDisable(GL_TEXTURE_2D); + olive::rendering::Blit(pipeline_.get(), true, matrix); - if (mutex != nullptr) mutex->unlock(); + f->glBindTexture(GL_TEXTURE_2D, 0); + + + + if (mutex_ != nullptr) mutex_->unlock(); } - if (show_fullscreen_msg) { + if (show_fullscreen_msg_) { QPainter p(this); QFont f = p.font(); @@ -143,21 +137,21 @@ void ViewerWindow::paintGL() { int rect_padding = 8; - fullscreen_msg_rect = QRect(text_x-rect_padding, + fullscreen_msg_rect_ = QRect(text_x-rect_padding, fm.height()-rect_padding, text_width+rect_padding+rect_padding, fm.height()+rect_padding+rect_padding); - p.drawRect(fullscreen_msg_rect); + p.drawRect(fullscreen_msg_rect_); p.drawText(text_x, text_y, fs_str); } } void ViewerWindow::fullscreen_msg_timeout() { - fullscreen_msg_timer.stop(); - if (show_fullscreen_msg) { - show_fullscreen_msg = false; + fullscreen_msg_timer_.stop(); + if (show_fullscreen_msg_) { + show_fullscreen_msg_ = false; update(); } } diff --git a/ui/viewerwindow.h b/ui/viewerwindow.h index ccba77452..7ae9c0cc4 100644 --- a/ui/viewerwindow.h +++ b/ui/viewerwindow.h @@ -23,33 +23,34 @@ #include #include +#include -class QMutex; -class QMenu; -class QShortcut; +#include "rendering/qopenglshaderprogramptr.h" class ViewerWindow : public QOpenGLWidget { - Q_OBJECT + Q_OBJECT public: - ViewerWindow(QWidget *parent); - void set_texture(GLuint t, double iar, QMutex *imutex); + ViewerWindow(QWidget *parent); + void set_texture(GLuint t, double iar, QMutex *imutex); protected: - virtual void keyPressEvent(QKeyEvent*) override; - virtual void mousePressEvent(QMouseEvent*) override; - virtual void mouseMoveEvent(QMouseEvent*) override; + virtual void keyPressEvent(QKeyEvent*) override; + virtual void mousePressEvent(QMouseEvent*) override; + virtual void mouseMoveEvent(QMouseEvent*) override; - virtual void paintGL() override; + virtual void initializeGL() override; + virtual void paintGL() override; private: - GLuint texture; - double ar; - QMutex* mutex; + GLuint texture_; + double ar_; + QMutex* mutex_; + QOpenGLShaderProgramPtr pipeline_; - // exit full screen message - QTimer fullscreen_msg_timer; - bool show_fullscreen_msg; - QRect fullscreen_msg_rect; + // exit full screen message + QTimer fullscreen_msg_timer_; + bool show_fullscreen_msg_; + QRect fullscreen_msg_rect_; private slots: - void fullscreen_msg_timeout(); + void fullscreen_msg_timeout(); }; #endif // VIEWERWINDOW_H