further progress on better blending
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#version 110
|
||||
|
||||
varying vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
vTexCoord = gl_MultiTexCoord0.xy;
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<RCC>
|
||||
<qresource prefix="/internalshaders">
|
||||
<file>blending.frag</file>
|
||||
<file>common.vert</file>
|
||||
<file>cornerpin.frag</file>
|
||||
<file>cornerpin.vert</file>
|
||||
<file>premultiply.frag</file>
|
||||
<file>dropshadow.frag</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -256,7 +256,8 @@ unix:!mac {
|
||||
}
|
||||
|
||||
RESOURCES += \
|
||||
icons/icons.qrc
|
||||
icons/icons.qrc \
|
||||
effects/internal/internalshaders.qrc
|
||||
|
||||
unix:!mac:isEmpty(PREFIX) {
|
||||
PREFIX = /usr/local
|
||||
|
||||
+4
-7
@@ -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<enum AVPixelFormat>(clip->stream->codecpar->format), 1, nullptr);
|
||||
clip->pix_fmt = AV_PIX_FMT_RGBA;
|
||||
const char* chosen_format = av_get_pix_fmt_name(static_cast<enum AVPixelFormat>(clip->pix_fmt));
|
||||
snprintf(filter_args, sizeof(filter_args), "pix_fmts=%s", chosen_format);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+23
-17
@@ -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) {}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+5
-3
@@ -9,9 +9,11 @@
|
||||
#include <QPixmap>
|
||||
#include <QIcon>
|
||||
|
||||
#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;
|
||||
|
||||
+102
-82
@@ -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;k<rows;k++) {
|
||||
float row_prog = float(k)/rows;
|
||||
float next_row_prog = float(k+1)/rows;
|
||||
for (int j=0;j<cols;j++) {
|
||||
float col_prog = float(j)/cols;
|
||||
float next_col_prog = float(j+1)/cols;
|
||||
for (int k=0;k<rows;k++) {
|
||||
float row_prog = float(k)/rows;
|
||||
float next_row_prog = float(k+1)/rows;
|
||||
for (int j=0;j<cols;j++) {
|
||||
float col_prog = float(j)/cols;
|
||||
float next_col_prog = float(j+1)/cols;
|
||||
|
||||
float vertexTLX = float_lerp(coords.vertexTopLeftX, coords.vertexBottomLeftX, row_prog);
|
||||
float vertexTRX = float_lerp(coords.vertexTopRightX, coords.vertexBottomRightX, row_prog);
|
||||
float vertexBLX = float_lerp(coords.vertexTopLeftX, coords.vertexBottomLeftX, next_row_prog);
|
||||
float vertexBRX = float_lerp(coords.vertexTopRightX, coords.vertexBottomRightX, next_row_prog);
|
||||
float vertexTLX = float_lerp(coords.vertexTopLeftX, coords.vertexBottomLeftX, row_prog);
|
||||
float vertexTRX = float_lerp(coords.vertexTopRightX, coords.vertexBottomRightX, row_prog);
|
||||
float vertexBLX = float_lerp(coords.vertexTopLeftX, coords.vertexBottomLeftX, next_row_prog);
|
||||
float vertexBRX = float_lerp(coords.vertexTopRightX, coords.vertexBottomRightX, next_row_prog);
|
||||
|
||||
float vertexTLY = float_lerp(coords.vertexTopLeftY, coords.vertexTopRightY, col_prog);
|
||||
float vertexTRY = float_lerp(coords.vertexTopLeftY, coords.vertexTopRightY, next_col_prog);
|
||||
float vertexBLY = float_lerp(coords.vertexBottomLeftY, coords.vertexBottomRightY, col_prog);
|
||||
float vertexBRY = float_lerp(coords.vertexBottomLeftY, coords.vertexBottomRightY, next_col_prog);
|
||||
float vertexTLY = float_lerp(coords.vertexTopLeftY, coords.vertexTopRightY, col_prog);
|
||||
float vertexTRY = float_lerp(coords.vertexTopLeftY, coords.vertexTopRightY, next_col_prog);
|
||||
float vertexBLY = float_lerp(coords.vertexBottomLeftY, coords.vertexBottomRightY, col_prog);
|
||||
float vertexBRY = float_lerp(coords.vertexBottomLeftY, coords.vertexBottomRightY, next_col_prog);
|
||||
|
||||
glTexCoord2f(float_lerp(coords.textureTopLeftX, coords.textureTopRightX, col_prog), float_lerp(coords.textureTopLeftY, coords.textureBottomLeftY, row_prog)); // top left
|
||||
glVertex2f(float_lerp(vertexTLX, vertexTRX, col_prog), float_lerp(vertexTLY, vertexBLY, row_prog)); // top left
|
||||
glTexCoord2f(float_lerp(coords.textureTopLeftX, coords.textureTopRightX, next_col_prog), float_lerp(coords.textureTopRightY, coords.textureBottomRightY, row_prog)); // top right
|
||||
glVertex2f(float_lerp(vertexTLX, vertexTRX, next_col_prog), float_lerp(vertexTRY, vertexBRY, row_prog)); // top right
|
||||
glTexCoord2f(float_lerp(coords.textureBottomLeftX, coords.textureBottomRightX, next_col_prog), float_lerp(coords.textureTopRightY, coords.textureBottomRightY, next_row_prog)); // bottom right
|
||||
glVertex2f(float_lerp(vertexBLX, vertexBRX, next_col_prog), float_lerp(vertexTRY, vertexBRY, next_row_prog)); // bottom right
|
||||
glTexCoord2f(float_lerp(coords.textureBottomLeftX, coords.textureBottomRightX, col_prog), float_lerp(coords.textureTopLeftY, coords.textureBottomLeftY, next_row_prog)); // bottom left
|
||||
glVertex2f(float_lerp(vertexBLX, vertexBRX, col_prog), float_lerp(vertexTLY, vertexBLY, next_row_prog)); // bottom left
|
||||
glTexCoord2f(float_lerp(coords.textureTopLeftX, coords.textureTopRightX, col_prog), float_lerp(coords.textureTopLeftY, coords.textureBottomLeftY, row_prog)); // top left
|
||||
glVertex2f(float_lerp(vertexTLX, vertexTRX, col_prog), float_lerp(vertexTLY, vertexBLY, row_prog)); // top left
|
||||
glTexCoord2f(float_lerp(coords.textureTopLeftX, coords.textureTopRightX, next_col_prog), float_lerp(coords.textureTopRightY, coords.textureBottomRightY, row_prog)); // top right
|
||||
glVertex2f(float_lerp(vertexTLX, vertexTRX, next_col_prog), float_lerp(vertexTRY, vertexBRY, row_prog)); // top right
|
||||
glTexCoord2f(float_lerp(coords.textureBottomLeftX, coords.textureBottomRightX, next_col_prog), float_lerp(coords.textureTopRightY, coords.textureBottomRightY, next_row_prog)); // bottom right
|
||||
glVertex2f(float_lerp(vertexBLX, vertexBRX, next_col_prog), float_lerp(vertexTRY, vertexBRY, next_row_prog)); // bottom right
|
||||
glTexCoord2f(float_lerp(coords.textureBottomLeftX, coords.textureBottomRightX, col_prog), float_lerp(coords.textureTopLeftY, coords.textureBottomLeftY, next_row_prog)); // bottom left
|
||||
glVertex2f(float_lerp(vertexBLX, vertexBRX, col_prog), float_lerp(vertexTLY, vertexBLY, next_row_prog)); // bottom left
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
+12
-2
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user