diff --git a/effects/chromakey.frag b/effects/chromakey.frag index a94b03f79..4f57d8b1e 100644 --- a/effects/chromakey.frag +++ b/effects/chromakey.frag @@ -47,11 +47,15 @@ void main(void) { float mask = colorclose(cb, cr, cb_key, cr_key, (tola/100.0), (tolb/100.0)); if (mode == 0) { // composite - float submask = 1.0-mask; + //float submask = 1.0-mask; + float submask = 0.0; texture_color.r = max(texture_color.r - submask*key_color.r, 0.0) + submask; texture_color.g = max(texture_color.g - submask*key_color.g, 0.0) + submask; texture_color.b = max(texture_color.b - submask*key_color.b, 0.0) + submask; texture_color.a *= mask; + + // premultiply + texture_color.rgb *= texture_color.a; } else if (mode == 1) { // alpha texture_color.rgb = vec3(mask); } else if (mode == 2) { // original diff --git a/effects/blending.frag b/effects/internal/blending.frag similarity index 88% rename from effects/blending.frag rename to effects/internal/blending.frag index b418137b5..3507705c5 100644 --- a/effects/blending.frag +++ b/effects/internal/blending.frag @@ -32,6 +32,6 @@ uniform sampler2D texture; varying vec2 vTexCoord; void main(void) { - gl_FragColor = texture2D(background, vTexCoord); - // gl_FragColor = texture2D(texture, vTexCoord)*2.0; + // gl_FragColor = texture2D(background, vTexCoord); + gl_FragColor = texture2D(texture, vTexCoord); } \ No newline at end of file diff --git a/effects/internal/common.vert b/effects/internal/common.vert new file mode 100644 index 000000000..2d088fa2f --- /dev/null +++ b/effects/internal/common.vert @@ -0,0 +1,8 @@ +#version 110 + +varying vec2 vTexCoord; + +void main() { + vTexCoord = gl_MultiTexCoord0.xy; + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} \ No newline at end of file diff --git a/effects/cornerpin.frag b/effects/internal/cornerpin.frag similarity index 100% rename from effects/cornerpin.frag rename to effects/internal/cornerpin.frag diff --git a/effects/cornerpin.vert b/effects/internal/cornerpin.vert similarity index 100% rename from effects/cornerpin.vert rename to effects/internal/cornerpin.vert diff --git a/effects/internal/cornerpineffect.cpp b/effects/internal/cornerpineffect.cpp index c48526601..11730619e 100644 --- a/effects/internal/cornerpineffect.cpp +++ b/effects/internal/cornerpineffect.cpp @@ -8,23 +8,23 @@ CornerPinEffect::CornerPinEffect(Clip *c, const EffectMeta *em) : Effect(c, em) enable_coords = true; enable_shader = true; - EffectRow* top_left = add_row(tr("Top Left")); + EffectRow* top_left = add_row(tr("Top Left")); top_left_x = top_left->add_field(EFFECT_FIELD_DOUBLE, "topleftx"); top_left_y = top_left->add_field(EFFECT_FIELD_DOUBLE, "toplefty"); - EffectRow* top_right = add_row(tr("Top Right")); + EffectRow* top_right = add_row(tr("Top Right")); top_right_x = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprightx"); top_right_y = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprighty"); - EffectRow* bottom_left = add_row(tr("Bottom Left")); + EffectRow* bottom_left = add_row(tr("Bottom Left")); bottom_left_x = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomleftx"); bottom_left_y = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomlefty"); - EffectRow* bottom_right = add_row(tr("Bottom Right")); + EffectRow* bottom_right = add_row(tr("Bottom Right")); bottom_right_x = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrightx"); bottom_right_y = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrighty"); - perspective = add_row(tr("Perspective"))->add_field(EFFECT_FIELD_BOOL, "perspective"); + perspective = add_row(tr("Perspective"))->add_field(EFFECT_FIELD_BOOL, "perspective"); perspective->set_bool_value(true); top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); diff --git a/effects/dropshadow.frag b/effects/internal/dropshadow.frag similarity index 95% rename from effects/dropshadow.frag rename to effects/internal/dropshadow.frag index 1bed6e491..402c4c547 100644 --- a/effects/dropshadow.frag +++ b/effects/internal/dropshadow.frag @@ -13,6 +13,7 @@ uniform float shadowdistance; varying vec2 vTexCoord; void main(void) { + /* vec4 master_px = texture2D(image, vTexCoord); if (shadow == 1) { vec2 shadow_dist = vec2(shadowdistance)/resolution; @@ -39,5 +40,7 @@ void main(void) { gl_FragColor = composition; } else { gl_FragColor = master_px; - } + } + */ + gl_FragColor = texture2D(image, vTexCoord); } \ No newline at end of file diff --git a/effects/internal/internalshaders.qrc b/effects/internal/internalshaders.qrc new file mode 100644 index 000000000..39b1a3aee --- /dev/null +++ b/effects/internal/internalshaders.qrc @@ -0,0 +1,10 @@ + + + blending.frag + common.vert + cornerpin.frag + cornerpin.vert + premultiply.frag + dropshadow.frag + + diff --git a/effects/internal/premultiply.frag b/effects/internal/premultiply.frag new file mode 100644 index 000000000..bc16e5cb4 --- /dev/null +++ b/effects/internal/premultiply.frag @@ -0,0 +1,10 @@ +#version 110 + +uniform sampler2D tex; +varying vec2 vTexCoord; + +void main(void) { + vec4 c = texture2D(tex, vTexCoord); + c.rgb *= c.a; + gl_FragColor = c; +} \ No newline at end of file diff --git a/effects/internal/texteffect.cpp b/effects/internal/texteffect.cpp index afdbf2607..7f4c36940 100644 --- a/effects/internal/texteffect.cpp +++ b/effects/internal/texteffect.cpp @@ -94,67 +94,67 @@ TextEffect::TextEffect(Clip *c, const EffectMeta* em) : } void blurred2(QImage& result, const QRect& rect, int radius, bool alphaOnly = false) { - int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; - int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; + int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; + int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; - int r1 = rect.top(); - int r2 = rect.bottom(); - int c1 = rect.left(); - int c2 = rect.right(); + int r1 = rect.top(); + int r2 = rect.bottom(); + int c1 = rect.left(); + int c2 = rect.right(); - int bpl = result.bytesPerLine(); - int rgba[4]; - unsigned char* p; + int bpl = result.bytesPerLine(); + int rgba[4]; + unsigned char* p; - int i1 = 0; - int i2 = 3; + int i1 = 0; + int i2 = 3; - if (alphaOnly) - i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); + if (alphaOnly) + i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r1) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + for (int col = c1; col <= c2; col++) { + p = result.scanLine(r1) + col * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; - p += bpl; - for (int j = r1; j < r2; j++, p += bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } + p += bpl; + for (int j = r1; j < r2; j++, p += bpl) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c1 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + for (int row = r1; row <= r2; row++) { + p = result.scanLine(row) + c1 * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; - p += 4; - for (int j = c1; j < c2; j++, p += 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } + p += 4; + for (int j = c1; j < c2; j++, p += 4) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r2) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + for (int col = c1; col <= c2; col++) { + p = result.scanLine(r2) + col * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; - p -= bpl; - for (int j = r1; j < r2; j++, p -= bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } + p -= bpl; + for (int j = r1; j < r2; j++, p -= bpl) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c2 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + for (int row = r1; row <= r2; row++) { + p = result.scanLine(row) + c2 * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; - p -= 4; - for (int j = c1; j < c2; j++, p -= 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } + p -= 4; + for (int j = c1; j < c2; j++, p -= 4) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } } void TextEffect::redraw(double timecode) { @@ -254,25 +254,25 @@ void TextEffect::redraw(double timecode) { path.addText(text_x, text_y, font, lines.at(i)); } - // draw software shadow - if (!enable_shader && shadow_bool->get_bool_value(timecode)) { - p.setPen(Qt::NoPen); - int shadow_offset = shadow_distance->get_double_value(timecode); + // draw software shadow + if (shadow_bool->get_bool_value(timecode)) { + p.setPen(Qt::NoPen); + int shadow_offset = shadow_distance->get_double_value(timecode); - QPainterPath shadow_path(path); - shadow_path.translate(shadow_offset, shadow_offset); + QPainterPath shadow_path(path); + shadow_path.translate(shadow_offset, shadow_offset); - QColor col = shadow_color->get_color_value(timecode); - col.setAlpha(0); - img.fill(col); + QColor col = shadow_color->get_color_value(timecode); + col.setAlpha(0); + img.fill(col); - col.setAlphaF(shadow_opacity->get_double_value(timecode)*0.01); - p.setBrush(col); - p.drawPath(shadow_path); + col.setAlphaF(shadow_opacity->get_double_value(timecode)*0.01); + p.setBrush(col); + p.drawPath(shadow_path); - int blurSoftness = shadow_softness->get_double_value(timecode); - if (blurSoftness > 0) blurred2(img, img.rect(), blurSoftness, false); - } + int blurSoftness = shadow_softness->get_double_value(timecode); + if (blurSoftness > 0) blurred2(img, img.rect(), blurSoftness, false); + } // draw outline int outline_width_val = outline_width->get_double_value(timecode); @@ -288,10 +288,11 @@ void TextEffect::redraw(double timecode) { p.setPen(Qt::NoPen); p.setBrush(set_color_button->get_color_value(timecode)); p.drawPath(path); + + p.end(); } void TextEffect::shadow_enable(bool e) { - enable_shader = (e && !config.use_software_fallback); close(); shadow_color->set_enabled(e); diff --git a/olive.pro b/olive.pro index 344dcc27e..115c65575 100644 --- a/olive.pro +++ b/olive.pro @@ -256,7 +256,8 @@ unix:!mac { } RESOURCES += \ - icons/icons.qrc + icons/icons.qrc \ + effects/internal/internalshaders.qrc unix:!mac:isEmpty(PREFIX) { PREFIX = /usr/local diff --git a/playback/cacher.cpp b/playback/cacher.cpp index 7e096fe92..ae08fbb69 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -777,6 +777,8 @@ void open_clip_worker(Clip* clip) { last_filter = yadif_filter; } + // ffmpeg premultiplier + /* if (!clip->media->to_footage()->alpha_is_premultiplied) { AVFilterContext* premultiply_filter; snprintf(filter_args, sizeof(filter_args), "inplace=1"); @@ -785,6 +787,7 @@ void open_clip_worker(Clip* clip) { avfilter_link(last_filter, 0, premultiply_filter, 0); last_filter = premultiply_filter; } + */ /* stabilization code */ /*bool stabilize = false; @@ -801,13 +804,7 @@ void open_clip_worker(Clip* clip) { } }*/ - enum AVPixelFormat valid_pix_fmts[] = { -// AV_PIX_FMT_RGB24, - AV_PIX_FMT_RGBA, - AV_PIX_FMT_NONE - }; - - clip->pix_fmt = avcodec_find_best_pix_fmt_of_list(valid_pix_fmts, static_cast(clip->stream->codecpar->format), 1, nullptr); + clip->pix_fmt = AV_PIX_FMT_RGBA; const char* chosen_format = av_get_pix_fmt_name(static_cast(clip->pix_fmt)); snprintf(filter_args, sizeof(filter_args), "pix_fmts=%s", chosen_format); diff --git a/playback/playback.cpp b/playback/playback.cpp index 9eb56fcfc..1d6289ce8 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -370,9 +370,15 @@ int retrieve_next_frame(Clip* c, AVFrame* f) { } bool is_clip_active(Clip* c, long playhead) { + // these buffers allow clips to be opened and prepared well before they're displayed + // as well as closed a little after they're not needed anymore + int open_buffer = qCeil(c->sequence->frame_rate*2); + int close_buffer = qCeil(c->sequence->frame_rate); + + return c->enabled - && c->get_timeline_in_with_transition() < playhead + ceil(c->sequence->frame_rate*2) - && c->get_timeline_out_with_transition() > playhead + && c->get_timeline_in_with_transition() < playhead + open_buffer + && c->get_timeline_out_with_transition() > playhead - close_buffer && playhead - c->get_timeline_in_with_transition() + c->get_clip_in_with_transition() < c->getMaximumLength(); } diff --git a/project/effect.cpp b/project/effect.cpp index f535b4ff4..b47fa5c6b 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -660,10 +660,6 @@ void Effect::open() { } else { isOpen = true; } - - if (enable_superimpose) { - texture = new QOpenGLTexture(QOpenGLTexture::Target2D); - } } void Effect::close() { @@ -747,30 +743,40 @@ void Effect::process_shader(double timecode, GLTextureCoords&) { void Effect::process_coords(double, GLTextureCoords&, int) {} GLuint Effect::process_superimpose(double timecode) { - bool recreate_texture = false; + bool dimensions_changed = false; + bool redrew_image = false; + int width = parent_clip->getWidth(); int height = parent_clip->getHeight(); if (width != img.width() || height != img.height()) { img = QImage(width, height, QImage::Format_RGBA8888_Premultiplied); - recreate_texture = true; + dimensions_changed = true; } - if (valueHasChanged(timecode) || recreate_texture || enable_always_update) { + if (valueHasChanged(timecode) || dimensions_changed || enable_always_update) { redraw(timecode); + redrew_image = true; } - if (texture != nullptr) { - if (recreate_texture || texture->width() != img.width() || texture->height() != img.height()) { - delete_texture(); - texture = new QOpenGLTexture(QOpenGLTexture::Target2D); - texture->setData(img); - } else { - texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, img.constBits()); - } - return texture->textureId(); + if (texture == nullptr || texture->width() != img.width() || texture->height() != img.height()) { + delete_texture(); + + texture = new QOpenGLTexture(QOpenGLTexture::Target2D); + texture->setSize(img.width(), img.height()); + texture->setFormat(QOpenGLTexture::RGBA8_UNorm); + texture->setMipLevels(texture->maximumMipLevels()); + texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); + texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); + + redrew_image = true; } - return 0; + + if (redrew_image) { + texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, img.constBits()); + } + + return texture->textureId(); } void Effect::process_audio(double, double, quint8*, int, int) {} diff --git a/project/effectloaders.cpp b/project/effectloaders.cpp index 716145695..e9cee3c69 100644 --- a/project/effectloaders.cpp +++ b/project/effectloaders.cpp @@ -22,7 +22,9 @@ void load_internal_effects() { EffectMeta em; - // internal effects + // load internal effects + em.path = ":/internalshaders"; + em.type = EFFECT_TYPE_EFFECT; em.subtype = EFFECT_TYPE_AUDIO; diff --git a/project/footage.h b/project/footage.h index 4c12e7edc..56ae6cace 100644 --- a/project/footage.h +++ b/project/footage.h @@ -9,9 +9,11 @@ #include #include -#define VIDEO_PROGRESSIVE 0 -#define VIDEO_TOP_FIELD_FIRST 1 -#define VIDEO_BOTTOM_FIELD_FIRST 2 +enum VideoInterlacingMode { + VIDEO_PROGRESSIVE, + VIDEO_TOP_FIELD_FIRST, + VIDEO_BOTTOM_FIELD_FIRST +}; struct Sequence; struct Clip; diff --git a/ui/renderfunctions.cpp b/ui/renderfunctions.cpp index bf1266948..d0697056a 100644 --- a/ui/renderfunctions.cpp +++ b/ui/renderfunctions.cpp @@ -78,22 +78,26 @@ void process_effect(Clip* c, } if (e->enable_superimpose) { GLuint superimpose_texture = e->process_superimpose(timecode); + qDebug() << "superimpose texture was:" << superimpose_texture; + qDebug() << "composite texture was:" << composite_texture; + if (superimpose_texture == 0) { qWarning() << "Superimpose texture was nullptr, retrying..."; texture_failed = true; + } else if (composite_texture == 0) { + // if there is no previous texture, just return the superimposes texture + // UNLESS this is a shader-extended superimpose effect in which case, + // we'll need to draw it below + qDebug() << "returning superimpose directly"; + composite_texture = superimpose_texture; } else { - if (composite_texture == 0) { - // if there is no previous texture, just return the superimposes texture - composite_texture = superimpose_texture; - } 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(c->fbo[!fbo_switcher], composite_texture, true); - } - - composite_texture = draw_clip(c->fbo[!fbo_switcher], superimpose_texture, false); + // 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(c->fbo[!fbo_switcher], composite_texture, true); } + + composite_texture = draw_clip(c->fbo[!fbo_switcher], superimpose_texture, false); } } e->endEffect(); @@ -279,7 +283,8 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { } // if clip should actually be shown on screen in this frame - if (playhead >= c->get_timeline_in_with_transition()) { + if (playhead >= c->get_timeline_in_with_transition() + && playhead < c->get_timeline_out_with_transition()) { glPushMatrix(); // simple bool for switching between the two framebuffers @@ -287,20 +292,31 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { glViewport(0, 0, video_width, video_height); - if (c->media != nullptr && c->media->get_type()== MEDIA_TYPE_SEQUENCE) { - // for a nested sequence, run this function again on that sequence and retrieve the texture + if (c->media != nullptr) { + if (c->media->get_type() == MEDIA_TYPE_SEQUENCE) { + // for a nested sequence, run this function again on that sequence and retrieve the texture - // add nested sequence to nest list - params.nests.append(c); + // add nested sequence to nest list + params.nests.append(c); - // compose sequence - textureID = compose_sequence(params); + // compose sequence + textureID = compose_sequence(params); - // remove sequence from nest list - params.nests.removeLast(); + // remove sequence from nest list + params.nests.removeLast(); - // compose_sequence() would have written to this clip's fbo[0], so we switch to fbo[1] - fbo_switcher = true; + // compose_sequence() would have written to this clip's fbo[0], so we switch to fbo[1] + fbo_switcher = true; + } else if (c->media->get_type() == MEDIA_TYPE_FOOTAGE && !c->media->to_footage()->alpha_is_premultiplied) { + // alpha is not premultiplied, we'll need to premultiply it for the rest of the pipeline + params.premultiply_program->bind(); + + textureID = draw_clip(c->fbo[0], textureID, true); + + params.premultiply_program->release(); + + fbo_switcher = true; + } } // set up default coordinates for drawing the clip @@ -345,6 +361,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { if (e->container->selected) selected_effect = e; } } + qDebug() << "texture ID:" << textureID; // using gizmo data, set definitive gizmo if (selected_effect != nullptr) { @@ -373,80 +390,83 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // == START FINAL DRAW ON SEQUENCE BUFFER == - // bind framebuffer - params.ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, final_fbo); + if (textureID > 0) { + // bind framebuffer + params.ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, final_fbo); - // set viewport to sequence size - glViewport(0, 0, s->width, s->height); + // set viewport to sequence size + glViewport(0, 0, s->width, s->height); - // bind final texture - glBindTexture(GL_TEXTURE_2D, textureID); + // bind final texture + glBindTexture(GL_TEXTURE_2D, textureID); - // set texture filter to bilinear - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // set texture filter to bilinear + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // bind and configure blending mode shader - params.blend_mode_program->bind(); - params.blend_mode_program->setUniformValue("blend_mode", coords.blendmode); - params.blend_mode_program->setUniformValue("opacity", coords.opacity); + // bind and configure blending mode shader + params.blend_mode_program->bind(); + params.blend_mode_program->setUniformValue("blend_mode", coords.blendmode); + params.blend_mode_program->setUniformValue("opacity", coords.opacity); - // draw clip on screen - glBegin(GL_QUADS); + // draw clip on screen + glBegin(GL_QUADS); - if (coords.grid_size <= 1) { - glTexCoord2f(coords.textureTopLeftX, coords.textureTopLeftY); // top left - glVertex2f(coords.vertexTopLeftX, coords.vertexTopLeftY); // top left - glTexCoord2f(coords.textureTopRightX, coords.textureTopRightY); // top right - glVertex2f(coords.vertexTopRightX, coords.vertexTopRightY); // top right - glTexCoord2f(coords.textureBottomRightX, coords.textureBottomRightY); // bottom right - glVertex2f(coords.vertexBottomRightX, coords.vertexBottomRightY); // bottom right - glTexCoord2f(coords.textureBottomLeftX, coords.textureBottomLeftY); // bottom left - glVertex2f(coords.vertexBottomLeftX, coords.vertexBottomLeftY); // bottom left - } else { - float rows = coords.grid_size; - float cols = coords.grid_size; + if (coords.grid_size <= 1) { + glTexCoord2f(coords.textureTopLeftX, coords.textureTopLeftY); // top left + glVertex2f(coords.vertexTopLeftX, coords.vertexTopLeftY); // top left + glTexCoord2f(coords.textureTopRightX, coords.textureTopRightY); // top right + glVertex2f(coords.vertexTopRightX, coords.vertexTopRightY); // top right + glTexCoord2f(coords.textureBottomRightX, coords.textureBottomRightY); // bottom right + glVertex2f(coords.vertexBottomRightX, coords.vertexBottomRightY); // bottom right + glTexCoord2f(coords.textureBottomLeftX, coords.textureBottomLeftY); // bottom left + glVertex2f(coords.vertexBottomLeftX, coords.vertexBottomLeftY); // bottom left + } else { + float rows = coords.grid_size; + float cols = coords.grid_size; - for (int k=0;krelease(); + + // unbind texture + glBindTexture(GL_TEXTURE_2D, 0); + + // unbind framebuffer + params.ctx->functions()->glBindFramebuffer(GL_TEXTURE_2D, 0); + } - glEnd(); - - // release blend mode shader - params.blend_mode_program->release(); - - // unbind texture - glBindTexture(GL_TEXTURE_2D, 0); - - // unbind framebuffer - params.ctx->functions()->glBindFramebuffer(GL_TEXTURE_2D, 0); - // == END FINAL DRAW ON SEQUENCE BUFFER == // prepare gizmos diff --git a/ui/renderfunctions.h b/ui/renderfunctions.h index 3d452f100..852c2a2fe 100644 --- a/ui/renderfunctions.h +++ b/ui/renderfunctions.h @@ -22,6 +22,7 @@ struct ComposeSequenceParams { bool rendering; int playback_speed; QOpenGLShaderProgram* blend_mode_program; + QOpenGLShaderProgram* premultiply_program; GLuint main_buffer; GLuint backend_buffer1; GLuint backend_attachment1; diff --git a/ui/renderthread.cpp b/ui/renderthread.cpp index d7f2b4f72..37face307 100644 --- a/ui/renderthread.cpp +++ b/ui/renderthread.cpp @@ -16,6 +16,7 @@ RenderThread::RenderThread() : share_ctx(nullptr), ctx(nullptr), blend_mode_program(nullptr), + premultiply_program(nullptr), seq(nullptr), tex_width(-1), tex_height(-1), @@ -107,10 +108,16 @@ void RenderThread::run() { if (blend_mode_program == nullptr) { // create shader program to make blending modes work delete_shader_program(); + blend_mode_program = new QOpenGLShaderProgram(); - blend_mode_program->addShaderFromSourceFile(QOpenGLShader::Vertex, "C:/msys64/home/Matt/olive/effects/common.vert"); - blend_mode_program->addShaderFromSourceFile(QOpenGLShader::Fragment, "C:/msys64/home/Matt/olive/effects/blending.frag"); + blend_mode_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/internalshaders/common.vert"); + blend_mode_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/internalshaders/blending.frag"); blend_mode_program->link(); + + premultiply_program = new QOpenGLShaderProgram(); + premultiply_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/internalshaders/common.vert"); + premultiply_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/internalshaders/premultiply.frag"); + premultiply_program->link(); } // bind framebuffer for drawing @@ -161,6 +168,7 @@ void RenderThread::paint() { params.rendering = false; params.playback_speed = 1; params.blend_mode_program = blend_mode_program; + params.premultiply_program = premultiply_program; params.backend_buffer1 = back_buffer_1; params.backend_buffer2 = back_buffer_2; params.backend_attachment1 = back_texture_1; @@ -253,8 +261,10 @@ void RenderThread::delete_fbo() { void RenderThread::delete_shader_program() { if (blend_mode_program != nullptr) { delete blend_mode_program; + delete premultiply_program; } blend_mode_program = nullptr; + premultiply_program = nullptr; } void RenderThread::delete_ctx() { diff --git a/ui/renderthread.h b/ui/renderthread.h index 6ec304d31..201839dce 100644 --- a/ui/renderthread.h +++ b/ui/renderthread.h @@ -43,6 +43,7 @@ private: QOpenGLContext* share_ctx; QOpenGLContext* ctx; QOpenGLShaderProgram* blend_mode_program; + QOpenGLShaderProgram* premultiply_program; GLuint back_buffer_1; GLuint back_buffer_2;