[428/906] laplacian: Avoid using GLSL 1.20 features in a non-#versioned shader.
[platform/upstream/gstreamer.git] / gst / gl / gstglfilterlaplacian.c
1 /*
2  * GStreamer
3  * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * SECTION:element-glfilterlaplacian
23  *
24  * Laplacian Convolution Demo Filter.
25  *
26  * <refsect2>
27  * <title>Examples</title>
28  * |[
29  * gst-launch videotestsrc ! glupload ! glfilterlaplacian ! glimagesink
30  * ]|
31  * FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
32  * </refsect2>
33  */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include "gstglfilterlaplacian.h"
40
41 #define GST_CAT_DEFAULT gst_gl_filter_laplacian_debug
42 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
43
44 enum
45 {
46   PROP_0
47 };
48
49 #define DEBUG_INIT(bla)                                                 \
50   GST_DEBUG_CATEGORY_INIT (gst_gl_filter_laplacian_debug, "glfilterlaplacian", 0, "glfilterlaplacian element");
51
52 GST_BOILERPLATE_FULL (GstGLFilterLaplacian, gst_gl_filter_laplacian,
53     GstGLFilter, GST_TYPE_GL_FILTER, DEBUG_INIT);
54
55 static void gst_gl_filter_laplacian_set_property (GObject * object,
56     guint prop_id, const GValue * value, GParamSpec * pspec);
57 static void gst_gl_filter_laplacian_get_property (GObject * object,
58     guint prop_id, GValue * value, GParamSpec * pspec);
59
60 static void gst_gl_filter_laplacian_reset (GstGLFilter * filter);
61 static void gst_gl_filter_laplacian_init_shader (GstGLFilter * filter);
62 static gboolean gst_gl_filter_laplacian_filter (GstGLFilter * filter,
63     GstGLBuffer * inbuf, GstGLBuffer * outbuf);
64 static void gst_gl_filter_laplacian_callback (gint width, gint height,
65     guint texture, gpointer stuff);
66
67 static const gchar *convolution_fragment_source =
68     "#extension GL_ARB_texture_rectangle : enable\n"
69     "uniform sampler2DRect tex;"
70     "uniform float norm_const;"
71     "uniform float norm_offset;"
72     "uniform float kernel[9];"
73     "void main () {"
74     "  vec2 offset[9];"
75     "  offset[0] = vec2(-1.0,-1.0);"
76     "  offset[1] = vec2( 0.0,-1.0);"
77     "  offset[2] = vec2( 1.0,-1.0);"
78     "  offset[3] = vec2(-1.0, 0.0);"
79     "  offset[4] = vec2( 0.0, 0.0);"
80     "  offset[5] = vec2( 1.0, 0.0);"
81     "  offset[6] = vec2(-1.0, 1.0);"
82     "  offset[7] = vec2( 0.0, 1.0);"
83     "  offset[8] = vec2( 1.0, 1.0);"
84     "  vec2 texturecoord = gl_TexCoord[0].st;"
85     "  int i;"
86     "  vec4 sum = vec4 (0.0);"
87     "  for (i = 0; i < 9; i++) { "
88     "    if (kernel[i] != 0.0) {"
89     "      vec4 neighbor = texture2DRect(tex, texturecoord + vec2(offset[i])); "
90     "      sum += neighbor * kernel[i]/norm_const; "
91     "    }" "  }" "  gl_FragColor = sum + norm_offset;" "}";
92
93 static void
94 gst_gl_filter_laplacian_base_init (gpointer klass)
95 {
96   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
97
98   gst_element_class_set_details_simple (element_class,
99       "OpenGL laplacian filter", "Filter/Effect",
100       "Laplacian Convolution Demo Filter",
101       "Filippo Argiolas <filippo.argiolas@gmail.com>");
102 }
103
104 static void
105 gst_gl_filter_laplacian_class_init (GstGLFilterLaplacianClass * klass)
106 {
107   GObjectClass *gobject_class;
108
109   gobject_class = (GObjectClass *) klass;
110   gobject_class->set_property = gst_gl_filter_laplacian_set_property;
111   gobject_class->get_property = gst_gl_filter_laplacian_get_property;
112
113   GST_GL_FILTER_CLASS (klass)->filter = gst_gl_filter_laplacian_filter;
114   GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_filter_laplacian_init_shader;
115   GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_filter_laplacian_reset;
116 }
117
118 static void
119 gst_gl_filter_laplacian_init (GstGLFilterLaplacian * filter,
120     GstGLFilterLaplacianClass * klass)
121 {
122   filter->shader = NULL;
123 }
124
125 static void
126 gst_gl_filter_laplacian_reset (GstGLFilter * filter)
127 {
128   GstGLFilterLaplacian *laplacian_filter = GST_GL_FILTER_LAPLACIAN (filter);
129
130   //blocking call, wait the opengl thread has destroyed the shader
131   gst_gl_display_del_shader (filter->display, laplacian_filter->shader);
132 }
133
134 static void
135 gst_gl_filter_laplacian_set_property (GObject * object, guint prop_id,
136     const GValue * value, GParamSpec * pspec)
137 {
138   //GstGLFilterLaplacian *filter = GST_GL_FILTER_LAPLACIAN (object);
139
140   switch (prop_id) {
141     default:
142       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
143       break;
144   }
145 }
146
147 static void
148 gst_gl_filter_laplacian_get_property (GObject * object, guint prop_id,
149     GValue * value, GParamSpec * pspec)
150 {
151   //GstGLFilterLaplacian *filter = GST_GL_FILTER_LAPLACIAN (object);
152
153   switch (prop_id) {
154     default:
155       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
156       break;
157   }
158 }
159
160 static void
161 gst_gl_filter_laplacian_init_shader (GstGLFilter * filter)
162 {
163   GstGLFilterLaplacian *laplacian_filter = GST_GL_FILTER_LAPLACIAN (filter);
164
165   //blocking call, wait the opengl thread has compiled the shader
166   gst_gl_display_gen_shader (filter->display, 0, convolution_fragment_source,
167       &laplacian_filter->shader);
168 }
169
170 static gboolean
171 gst_gl_filter_laplacian_filter (GstGLFilter * filter, GstGLBuffer * inbuf,
172     GstGLBuffer * outbuf)
173 {
174   gpointer laplacian_filter = GST_GL_FILTER_LAPLACIAN (filter);
175
176   //blocking call, use a FBO
177   gst_gl_display_use_fbo (filter->display, filter->width, filter->height,
178       filter->fbo, filter->depthbuffer, outbuf->texture,
179       gst_gl_filter_laplacian_callback, inbuf->width, inbuf->height,
180       inbuf->texture, 0, filter->width, 0, filter->height,
181       GST_GL_DISPLAY_PROJECTION_ORTHO2D, laplacian_filter);
182
183   return TRUE;
184 }
185
186 //opengl scene, params: input texture (not the output filter->texture)
187 static void
188 gst_gl_filter_laplacian_callback (gint width, gint height, guint texture,
189     gpointer stuff)
190 {
191   GstGLFilterLaplacian *laplacian_filter = GST_GL_FILTER_LAPLACIAN (stuff);
192
193   gfloat kernel[9] = { 0.0, -1.0, 0.0,
194     -1.0, 4.0, -1.0,
195     0.0, -1.0, 0.0
196   };
197
198   glMatrixMode (GL_PROJECTION);
199   glLoadIdentity ();
200
201   gst_gl_shader_use (laplacian_filter->shader);
202
203   glActiveTexture (GL_TEXTURE0);
204   glEnable (GL_TEXTURE_RECTANGLE_ARB);
205   glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
206
207   gst_gl_shader_set_uniform_1i (laplacian_filter->shader, "tex", 0);
208   gst_gl_shader_set_uniform_1fv (laplacian_filter->shader, "kernel", 9, kernel);
209   gst_gl_shader_set_uniform_1f (laplacian_filter->shader, "norm_const", 1.0);
210   gst_gl_shader_set_uniform_1f (laplacian_filter->shader, "norm_offset", 0.0);  //set to 0.5 to preserve overall greylevel
211
212
213   glBegin (GL_QUADS);
214   glTexCoord2i (0, 0);
215   glVertex2f (-1.0f, -1.0f);
216   glTexCoord2i (width, 0);
217   glVertex2f (1.0f, -1.0f);
218   glTexCoord2i (width, height);
219   glVertex2f (1.0f, 1.0f);
220   glTexCoord2i (0, height);
221   glVertex2f (-1.0f, 1.0f);
222   glEnd ();
223 }