diff --git a/effects/shaders.qrc b/effects/shaders.qrc new file mode 100644 index 000000000..3fd215d0a --- /dev/null +++ b/effects/shaders.qrc @@ -0,0 +1 @@ + diff --git a/effects/video/chromakeyeffect.cpp b/effects/video/chromakeyeffect.cpp index 1d65a3b2e..bb3c09b1d 100644 --- a/effects/video/chromakeyeffect.cpp +++ b/effects/video/chromakeyeffect.cpp @@ -12,8 +12,8 @@ ChromaKeyEffect::ChromaKeyEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_C tolerance_field->set_double_minimum_value(0); tolerance_field->set_double_maximum_value(100); - vert.compileSourceCode("varying vec2 vTexCoord;\nvoid main() {\n\tvTexCoord = gl_MultiTexCoord0.xy;\n\tgl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}"); - frag.compileSourceCode("uniform vec4 keyColor;\nuniform float threshold;\nuniform sampler2D myTexture;\nvarying vec2 vTexCoord;\nvoid main(void) {\n\tvec4 textureColor = texture2D(myTexture, vTexCoord);\nfloat diff = length(keyColor - textureColor);\nif (diff < threshold) {gl_FragColor = vec4(0, 0, 0, 0);} else {gl_FragColor = textureColor;}\n}"); + vert.compileSourceFile(":/shaders/common.vert"); + frag.compileSourceFile(":/shaders/chromakeyeffect.frag"); program.addShader(&vert); program.addShader(&frag); program.link(); diff --git a/effects/video/gaussianblureffect.cpp b/effects/video/gaussianblureffect.cpp index cf7937e8a..9dbf25cec 100644 --- a/effects/video/gaussianblureffect.cpp +++ b/effects/video/gaussianblureffect.cpp @@ -8,108 +8,44 @@ GaussianBlurEffect::GaussianBlurEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, V enable_opengl = true; enable_image = false; - amount_val = add_row("Amount:")->add_field(EFFECT_FIELD_DOUBLE); + kernelsz_val = add_row("Kernel Size:")->add_field(EFFECT_FIELD_DOUBLE); + sigma_val = add_row("Sigma:")->add_field(EFFECT_FIELD_DOUBLE); horiz_val = add_row("Horizontal:")->add_field(EFFECT_FIELD_BOOL); vert_val = add_row("Vertical:")->add_field(EFFECT_FIELD_BOOL); - amount_val->set_double_minimum_value(0); - amount_val->set_double_default_value(20); + kernelsz_val->set_double_minimum_value(0); + sigma_val->set_double_minimum_value(0); + + kernelsz_val->set_double_default_value(9); + sigma_val->set_double_default_value(5.5); + horiz_val->set_bool_value(true); vert_val->set_bool_value(true); - vert.compileSourceCode("void main() {\ngl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}"); -// vert.compileSourceCode("#version 330 core\nin vec2 VertexPosition;\nvoid main(void) {\ngl_Position = vec4(VertexPosition, 0.0, 1.0);\n}"); -// frag.compileSourceCode("#version 330 core\n\nuniform sampler2D image;\n\nout vec4 FragmentColor;\n\nuniform float offset[3] = float[]( 0.0, 1.3846153846, 3.2307692308 );\nuniform float weight[3] = float[]( 0.2270270270, 0.3162162162, 0.0702702703 );\n\nvoid main(void)\n{\n FragmentColor = texture2D( image, vec2(gl_FragCoord)/vec2(640.0, 360.0) ) * weight[0];\n for (int i=1; i<3; i++) {\n FragmentColor += texture2D( image, ( vec2(gl_FragCoord)+vec2(offset[i], 0.0) )/vec2(640.0, 360.0) ) * weight[i];\n FragmentColor += texture2D( image, ( vec2(gl_FragCoord)-vec2(offset[i], 0.0) )/vec2(640.0, 360.0) ) * weight[i];\n }\n}"); - frag.compileSourceCode("#version 330 core\n\nuniform sampler2D image;\n\nout vec4 FragmentColor;\n\nuniform float offset[3] = float[]( 0.0, 1.3846153846, 3.2307692308 );\nuniform float weight[3] = float[]( 0.2270270270, 0.3162162162, 0.0702702703 );\nuniform float halfweight[3] = float[]( 0.1135135135, 0.1581081081, 0.03513513515 );\n\nuniform vec2 resolution;\nuniform bool horiz_blur;\nuniform bool vert_blur;\n\nvoid main(void) {\n FragmentColor = texture2D( image, vec2(gl_FragCoord)/resolution ) * weight[0];\n for (int i=1; i<3; i++) {\n float weight = (horiz_blur && vert_blur) ? halfweight[i] : weight[i];\n\n if (horiz_blur) {\n FragmentColor += texture2D( image, ( vec2(gl_FragCoord)+vec2(offset[i], 0.0) )/resolution ) * weight;\n FragmentColor += texture2D( image, ( vec2(gl_FragCoord)-vec2(offset[i], 0.0) )/resolution ) * weight;\n }\n \n if (vert_blur) {\n FragmentColor += texture2D( image, ( vec2(gl_FragCoord)+vec2(0.0, offset[i]) )/resolution ) * weight;\n FragmentColor += texture2D( image, ( vec2(gl_FragCoord)-vec2(0.0, offset[i]) )/resolution ) * weight;\n } \n }\n}"); + vert.compileSourceFile(":/shaders/common.vert"); + frag.compileSourceFile(":/shaders/gaussianblureffect.frag"); program.addShader(&vert); program.addShader(&frag); - program.link(); + program.link(); - connect(amount_val, SIGNAL(changed()), this, SLOT(field_changed())); + connect(kernelsz_val, SIGNAL(changed()), this, SLOT(field_changed())); + connect(sigma_val, SIGNAL(changed()), this, SLOT(field_changed())); connect(horiz_val, SIGNAL(changed()), this, SLOT(field_changed())); connect(vert_val, SIGNAL(changed()), this, SLOT(field_changed())); refresh(); } -void GaussianBlurEffect::process_image(double timecode, uint8_t *data, int width, int height) { - QImage result(data, width, height, QImage::Format_RGBA8888); // create QImage wrapper - int radius = 5; - - 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 = result.rect().top(); - int r2 = result.rect().bottom(); - int c1 = result.rect().left(); - int c2 = result.rect().right(); - - int bpl = result.bytesPerLine(); - int rgba[4]; - unsigned char* p; - - int i1 = 0; - int i2 = 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; - - 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; - - 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; - - 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; - - 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 GaussianBlurEffect::process_gl(double timecode, GLTextureCoords &coords) { - bound = false; - bool horiz = horiz_val->get_bool_value(timecode); - bool vert = vert_val->get_bool_value(timecode); - int iterationCount = amount_val->get_double_value(timecode); - if (iterationCount > 0 && (horiz || vert)) { - bound = program.bind(); - setIterations(iterationCount); - program.setUniformValue("resolution", parent_clip->getWidth(), parent_clip->getHeight()); - program.setUniformValue("horiz_blur", horiz); - program.setUniformValue("vert_blur", vert); - } + program.bind(); + + program.setUniformValue("resolution", parent_clip->getWidth(), parent_clip->getHeight()); + program.setUniformValue("kernel_size", (GLfloat) kernelsz_val->get_double_value(timecode)); + program.setUniformValue("sigma", (GLfloat) sigma_val->get_double_value(timecode)); + program.setUniformValue("horiz_blur", horiz_val->get_bool_value(timecode)); + program.setUniformValue("vert_blur", vert_val->get_bool_value(timecode)); } -void GaussianBlurEffect::clean_gl() { - if (bound) program.release(); +void GaussianBlurEffect::clean_gl() { + program.release(); } diff --git a/effects/video/gaussianblureffect.h b/effects/video/gaussianblureffect.h index 7212d8876..bdcbb75b1 100644 --- a/effects/video/gaussianblureffect.h +++ b/effects/video/gaussianblureffect.h @@ -6,8 +6,7 @@ class GaussianBlurEffect : public Effect { public: - GaussianBlurEffect(Clip* c); - void process_image(double timecode, uint8_t *data, int width, int height); + GaussianBlurEffect(Clip* c); void process_gl(double timecode, GLTextureCoords &coords); void clean_gl(); private: @@ -15,7 +14,8 @@ private: QOpenGLShader vert; QOpenGLShader frag; - EffectField* amount_val; + EffectField* kernelsz_val; + EffectField* sigma_val; EffectField* horiz_val; EffectField* vert_val; diff --git a/effects/video/glsl/chromakeyeffect.frag b/effects/video/glsl/chromakeyeffect.frag new file mode 100644 index 000000000..7c44e43f4 --- /dev/null +++ b/effects/video/glsl/chromakeyeffect.frag @@ -0,0 +1,16 @@ +#version 110 + +uniform vec4 keyColor; +uniform float threshold; +uniform sampler2D myTexture; +varying vec2 vTexCoord; + +void main(void) { + vec4 textureColor = texture2D(myTexture, vTexCoord); + float diff = length(keyColor - textureColor); + if (diff < threshold) { + gl_FragColor = vec4(0, 0, 0, 0); + } else { + gl_FragColor = textureColor; + } +} \ No newline at end of file diff --git a/effects/video/glsl/common.vert b/effects/video/glsl/common.vert new file mode 100644 index 000000000..2d088fa2f --- /dev/null +++ b/effects/video/glsl/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/video/glsl/gaussianblureffect.frag b/effects/video/glsl/gaussianblureffect.frag new file mode 100644 index 000000000..4a1cbddb7 --- /dev/null +++ b/effects/video/glsl/gaussianblureffect.frag @@ -0,0 +1,67 @@ +#version 110 + +#define M_PI 3.1415926535897932384626433832795 + +uniform sampler2D image; + +uniform float kernel_size; +uniform float sigma; +uniform vec2 resolution; +uniform bool horiz_blur; +uniform bool vert_blur; + +float gaussian(float x, float sigma) { + return (1.0/(sigma*sqrt(2.0*M_PI)))*exp(-0.5*pow(x/sigma, 2.0)); +} + +float gaussian2(float x, float y, float sigma) { + return (1.0/(pow(sigma, 2.0)*2.0*M_PI))*exp(-0.5*((pow(x, 2.0) + pow(y, 2.0))/pow(sigma, 2.0))); +} + +void main(void) { + if (kernel_size == 0.0 || sigma == 0.0 || (!horiz_blur && !vert_blur)) { + gl_FragColor = texture2D(image, gl_FragCoord.xy/resolution); + } else { + float half_kernel = floor(kernel_size*0.5); + + float middleWeight = gaussian(0.0, sigma); + float sum = middleWeight; + + if (horiz_blur && vert_blur) { + for (float x=0.0;x + + gaussianblureffect.frag + common.vert + inverteffect.frag + chromakeyeffect.frag + solideffect.frag + + diff --git a/effects/video/glsl/solideffect.frag b/effects/video/glsl/solideffect.frag new file mode 100644 index 000000000..cda8aafe0 --- /dev/null +++ b/effects/video/glsl/solideffect.frag @@ -0,0 +1,16 @@ +#version 110 + +uniform vec4 solidColor; +uniform float amount_val; +uniform sampler2D myTexture; +varying vec2 vTexCoord; + +void main(void) { + vec4 textureColor = texture2D(myTexture, vTexCoord); + gl_FragColor = vec4( + textureColor.r+((solidColor.r-textureColor.r)*amount_val), + textureColor.g+((solidColor.g-textureColor.g)*amount_val), + textureColor.b+((solidColor.b-textureColor.b)*amount_val), + textureColor.a + ); +} \ No newline at end of file diff --git a/effects/video/inverteffect.cpp b/effects/video/inverteffect.cpp index 8d596f224..1d682fe72 100644 --- a/effects/video/inverteffect.cpp +++ b/effects/video/inverteffect.cpp @@ -22,8 +22,8 @@ InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_ connect(amount_val, SIGNAL(changed()), this, SLOT(field_changed())); - vert.compileSourceCode("varying vec2 vTexCoord;\nvoid main() {\n\tvTexCoord = gl_MultiTexCoord0.xy;\n\tgl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}"); - frag.compileSourceCode("uniform mediump float amount_val;\nuniform sampler2D myTexture;\nvarying vec2 vTexCoord;\nvoid main(void) {\n\tvec4 textureColor = texture2D(myTexture, vTexCoord);\n\tgl_FragColor = vec4(textureColor.r+((1.0-textureColor.r-textureColor.r)*amount_val), textureColor.g+((1.0-textureColor.g-textureColor.g)*amount_val), textureColor.b+((1.0-textureColor.b-textureColor.b)*amount_val), textureColor.a);\n}"); + vert.compileSourceFile(":/shaders/common.vert"); + frag.compileSourceFile(":/shaders/inverteffect.frag"); program.addShader(&vert); program.addShader(&frag); program.link(); diff --git a/effects/video/inverteffect.h b/effects/video/inverteffect.h index 82e9811ae..47743810a 100644 --- a/effects/video/inverteffect.h +++ b/effects/video/inverteffect.h @@ -3,8 +3,6 @@ #include "../effect.h" -//#include - class InvertEffect : public Effect { Q_OBJECT public: diff --git a/effects/video/solideffect.cpp b/effects/video/solideffect.cpp index c0bc14814..d83f041f3 100644 --- a/effects/video/solideffect.cpp +++ b/effects/video/solideffect.cpp @@ -34,8 +34,8 @@ SolidEffect::SolidEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_SOLID_EFF connect(solid_color_field, SIGNAL(changed()), this, SLOT(field_changed())); connect(opacity_field, SIGNAL(changed()), this, SLOT(field_changed())); - vert.compileSourceCode("varying vec2 vTexCoord;\nvoid main() {\n\tvTexCoord = gl_MultiTexCoord0.xy;\n\tgl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}"); - frag.compileSourceCode("uniform vec4 solidColor;\nuniform float amount_val;\nuniform sampler2D myTexture;\nvarying vec2 vTexCoord;\nvoid main(void) {\n\tvec4 textureColor = texture2D(myTexture, vTexCoord);\n\tgl_FragColor = vec4(textureColor.r+((solidColor.r-textureColor.r)*amount_val), textureColor.g+((solidColor.g-textureColor.g)*amount_val), textureColor.b+((solidColor.b-textureColor.b)*amount_val), textureColor.a);\n}"); + vert.compileSourceFile(":/shaders/common.vert"); + frag.compileSourceFile(":/shaders/solideffect.frag"); program.addShader(&vert); program.addShader(&frag); } diff --git a/olive.pro b/olive.pro index 264a011ad..902d9dcd9 100644 --- a/olive.pro +++ b/olive.pro @@ -159,4 +159,5 @@ linux { } RESOURCES += \ - icons/icons.qrc + icons/icons.qrc \ + effects/video/glsl/shaders.qrc diff --git a/project/clip.cpp b/project/clip.cpp index 53a69241f..0813909da 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -192,6 +192,7 @@ int Clip::getWidth() { { MediaStream* ms = static_cast(media)->get_stream_from_file_index(track < 0, media_stream); if (ms != NULL) return ms->video_width; + if (sequence != NULL) return sequence->width; } case MEDIA_TYPE_SEQUENCE: { @@ -209,6 +210,7 @@ int Clip::getHeight() { { MediaStream* ms = static_cast(media)->get_stream_from_file_index(track < 0, media_stream); if (ms != NULL) return ms->video_height; + if (sequence != NULL) return sequence->height; } case MEDIA_TYPE_SEQUENCE: {