--- /dev/null
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gstgleffects.h>
+
+static gfloat gauss_kernel[9] = { 0.060493, 0.075284, 0.088016,
+ 0.096667, 0.099736, 0.096667,
+ 0.088016, 0.075284, 0.060493 };
+
+static void
+gst_gl_effects_glow_step_one (gint width, gint height, guint texture, gpointer data)
+{
+ GstGLEffects* effects = GST_GL_EFFECTS (data);
+
+ GstGLShader *shader;
+
+ shader = g_hash_table_lookup (effects->shaderstable, "glow0");
+
+ if (!shader) {
+ shader = gst_gl_shader_new ();
+ g_hash_table_insert (effects->shaderstable, "glow0", shader);
+ }
+
+ g_return_if_fail (
+ gst_gl_shader_compile_and_check (shader, luma_threshold_fragment_source,
+ GST_GL_SHADER_FRAGMENT_SOURCE));
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ gst_gl_shader_use (shader);
+
+ glActiveTexture (GL_TEXTURE0);
+ glEnable (GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
+
+ gst_gl_shader_set_uniform_1i (shader, "tex", 0);
+
+ gst_gl_effects_draw_texture (effects, texture);
+}
+
+static void
+gst_gl_effects_glow_step_two (gint width, gint height, guint texture, gpointer stuff)
+{
+ GstGLEffects* effects = GST_GL_EFFECTS (stuff);
+ GstGLShader *shader;
+
+ /* hard coded kernel, it could be easily generated at runtime with a
+ * property to change standard deviation */
+
+ shader = g_hash_table_lookup (effects->shaderstable, "glow1");
+
+ if (!shader) {
+ shader = gst_gl_shader_new ();
+ g_hash_table_insert (effects->shaderstable, "glow1", shader);
+ }
+
+ g_return_if_fail (
+ gst_gl_shader_compile_and_check (shader, hconv9_fragment_source,
+ GST_GL_SHADER_FRAGMENT_SOURCE));
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ gst_gl_shader_use (shader);
+
+ glActiveTexture (GL_TEXTURE1);
+ glEnable (GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
+ glDisable (GL_TEXTURE_RECTANGLE_ARB);
+
+ gst_gl_shader_set_uniform_1i (shader, "tex", 1);
+
+ gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel);
+ gst_gl_shader_set_uniform_1f (shader, "norm_const", 0.740656);
+ gst_gl_shader_set_uniform_1f (shader, "norm_offset", 0.0);
+
+ gst_gl_effects_draw_texture (effects, texture);
+}
+
+void
+gst_gl_effects_glow_step_three (gint width, gint height, guint texture, gpointer stuff)
+{
+ GstGLEffects* effects = GST_GL_EFFECTS (stuff);
+ GstGLShader *shader;
+
+ shader = g_hash_table_lookup (effects->shaderstable, "glow2");
+
+ if (!shader) {
+ shader = gst_gl_shader_new ();
+ g_hash_table_insert (effects->shaderstable, "glow2", shader);
+ }
+
+ g_return_if_fail (
+ gst_gl_shader_compile_and_check (shader, vconv9_fragment_source,
+ GST_GL_SHADER_FRAGMENT_SOURCE));
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ gst_gl_shader_use (shader);
+
+ glActiveTexture (GL_TEXTURE1);
+ glEnable (GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
+ glDisable (GL_TEXTURE_RECTANGLE_ARB);
+
+ gst_gl_shader_set_uniform_1i (shader, "tex", 1);
+
+ gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel);
+ gst_gl_shader_set_uniform_1f (shader, "norm_const", 0.740656);
+ gst_gl_shader_set_uniform_1f (shader, "norm_offset", 0.0);
+
+ gst_gl_effects_draw_texture (effects, texture);
+}
+
+void
+gst_gl_effects_glow_step_four (gint width, gint height, guint texture, gpointer stuff)
+{
+ GstGLEffects* effects = GST_GL_EFFECTS (stuff);
+ GstGLShader *shader;
+
+ shader = g_hash_table_lookup (effects->shaderstable, "glow3");
+
+ if (!shader) {
+ shader = gst_gl_shader_new ();
+ g_hash_table_insert (effects->shaderstable, "glow3", shader);
+ }
+
+ g_return_if_fail (
+ gst_gl_shader_compile_and_check (shader, blend_fragment_source,
+ GST_GL_SHADER_FRAGMENT_SOURCE));
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ gst_gl_shader_use (shader);
+
+ glActiveTexture (GL_TEXTURE2);
+ glEnable (GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, effects->intexture);
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+ gst_gl_shader_set_uniform_1i (shader, "base", 2);
+
+ glActiveTexture (GL_TEXTURE1);
+ glEnable (GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+ gst_gl_shader_set_uniform_1i (shader, "blend", 1);
+
+ gst_gl_effects_draw_texture (effects, texture);
+}
+
+void
+gst_gl_effects_glow (GstGLEffects *effects) {
+ GstGLFilter *filter = GST_GL_FILTER (effects);
+
+ /* threshold */
+ gst_gl_filter_render_to_target (filter, effects->intexture, effects->midtexture[0],
+ gst_gl_effects_glow_step_one, effects);
+ /* blur */
+ gst_gl_filter_render_to_target (filter, effects->midtexture[0], effects->midtexture[1],
+ gst_gl_effects_glow_step_two, effects);
+ gst_gl_filter_render_to_target (filter, effects->midtexture[1], effects->midtexture[2],
+ gst_gl_effects_glow_step_three, effects);
+ /* add blurred luma to intexture */
+ gst_gl_filter_render_to_target (filter, effects->midtexture[2], effects->outtexture,
+ gst_gl_effects_glow_step_four, effects);
+}
/* Squeeze effect */
const gchar *squeeze_fragment_source =
+ "#extension GL_ARB_texture_rectangle : enable\n"
+ "uniform sampler2DRect tex;"
+ "uniform float width, height;"
+ "void main () {"
+ " vec2 tex_size = vec2 (width, height);"
+ " vec2 texturecoord = gl_TexCoord[0].xy;"
+ " vec2 normcoord;"
+ " normcoord = texturecoord / tex_size - 1.0; "
+ " float r = length (normcoord);"
+ " r = pow(r, 0.40)*1.3;"
+ " normcoord = normcoord / r;"
+ " texturecoord = (normcoord + 1.0) * tex_size;"
+ " vec4 color = texture2DRect (tex, texturecoord); "
+ " gl_FragColor = color * gl_Color;"
+ "}";
+
+
+/* Stretch Effect */
+const gchar *stretch_fragment_source =
+ "#extension GL_ARB_texture_rectangle : enable\n"
+ "uniform sampler2DRect tex;"
+ "uniform float width, height;"
+ "void main () {"
+ " vec2 tex_size = vec2 (width, height);"
+ " vec2 texturecoord = gl_TexCoord[0].xy;"
+ " vec2 normcoord;"
+ " normcoord = texturecoord / tex_size - 1.0;"
+ " float r = length (normcoord);"
+ " normcoord *= 2.0 - smoothstep(0.0, 0.7, r);"
+ " texturecoord = (normcoord + 1.0) * tex_size;"
+ " vec4 color = texture2DRect (tex, texturecoord);"
+ " gl_FragColor = color * gl_Color;"
+ "}";
+
+
+const gchar *luma_threshold_fragment_source =
+ "#extension GL_ARB_texture_rectangle : enable\n"
+ "uniform sampler2DRect tex;"
+ "void main () {"
+ " vec2 texturecoord = gl_TexCoord[0].st;"
+ " int i;"
+ " vec4 color = texture2DRect(tex, texturecoord);"
+ " float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));" /* BT.709 (from orange book) */
+ " gl_FragColor = vec4 (vec3 (smoothstep (0.30, 0.50, luma)), color.a);"
+ "}";
+
+/* horizontal convolution */
+const gchar *hconv9_fragment_source =
"#extension GL_ARB_texture_rectangle : enable\n"
"uniform sampler2DRect tex;"
-"uniform float width, height;"
+"uniform float norm_const;"
+"uniform float norm_offset;"
+"uniform float kernel[9];"
"void main () {"
-" vec2 tex_size = vec2 (width, height);"
-" vec2 texturecoord = gl_TexCoord[0].xy;"
-" vec2 normcoord;"
-" normcoord = texturecoord / tex_size - 1.0; "
-" float r = length (normcoord);"
-" r = pow(r, 0.40)*1.3;"
-" normcoord = normcoord / r;"
-" texturecoord = (normcoord + 1.0) * tex_size;"
-" vec4 color = texture2DRect (tex, texturecoord); "
-" gl_FragColor = color * gl_Color;"
+" float offset[9] = float[9] (-4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0);"
+" vec2 texturecoord = gl_TexCoord[0].st;"
+" int i;"
+" vec4 sum = vec4 (0.0);"
+" for (i = 0; i < 9; i++) { "
+" if (kernel[i] != 0.0) {"
+" vec4 neighbor = texture2DRect(tex, vec2(texturecoord.s+offset[i], texturecoord.t)); "
+" sum += neighbor * kernel[i]/norm_const; "
+" }"
+" }"
+" gl_FragColor = sum + norm_offset;"
"}";
-
-/* Stretch Effect */
-const gchar *stretch_fragment_source =
+/* vertical convolution */
+const gchar *vconv9_fragment_source =
"#extension GL_ARB_texture_rectangle : enable\n"
"uniform sampler2DRect tex;"
-"uniform float width, height;"
+"uniform float norm_const;"
+"uniform float norm_offset;"
+"uniform float kernel[9];"
+"void main () {"
+" float offset[9] = float[9] (-4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0);"
+" vec2 texturecoord = gl_TexCoord[0].st;"
+" int i;"
+" vec4 sum = vec4 (0.0);"
+" for (i = 0; i < 9; i++) { "
+" if (kernel[i] != 0.0) {"
+" vec4 neighbor = texture2DRect(tex, vec2(texturecoord.s, texturecoord.t+offset[i])); "
+" sum += neighbor * kernel[i]/norm_const; "
+" }"
+" }"
+" gl_FragColor = sum + norm_offset;"
+"}";
+
+/* TODO: support several blend modes */
+const gchar *blend_fragment_source =
+"#extension GL_ARB_texture_rectangle : enable\n"
+"uniform sampler2DRect base;"
+"uniform sampler2DRect blend;"
"void main () {"
-" vec2 tex_size = vec2 (width, height);"
-" vec2 texturecoord = gl_TexCoord[0].xy;"
-" vec2 normcoord;"
-" normcoord = texturecoord / tex_size - 1.0;"
-" float r = length (normcoord);"
-" normcoord *= 2.0 - smoothstep(0.0, 0.7, r);"
-" texturecoord = (normcoord + 1.0) * tex_size;"
-" vec4 color = texture2DRect (tex, texturecoord);"
-" gl_FragColor = color * gl_Color;"
+" vec4 basecolor = texture2DRect (base, gl_TexCoord[0].st);"
+" vec4 blendcolor = texture2DRect (blend, gl_TexCoord[0].st);"
+" gl_FragColor = basecolor + blendcolor / 3.5;"
"}";