gldownloadelement: fix build with msvc
[platform/upstream/gst-plugins-base.git] / ext / gl / gltestsrc.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2016> Matthew Waters <matthew@centricular.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., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <gst/gl/gstglfuncs.h>
26
27 #include "gltestsrc.h"
28
29 #define MAX_ATTRIBUTES 4
30
31 struct vts_color_struct
32 {
33   gfloat R, G, B;
34 };
35
36 struct XYZWRGB
37 {
38   gfloat X, Y, Z, W, R, G, B;
39 };
40
41 enum
42 {
43   COLOR_WHITE = 0,
44   COLOR_YELLOW,
45   COLOR_CYAN,
46   COLOR_GREEN,
47   COLOR_MAGENTA,
48   COLOR_RED,
49   COLOR_BLUE,
50   COLOR_BLACK,
51   COLOR_NEG_I,
52   COLOR_POS_Q,
53   COLOR_SUPER_BLACK,
54   COLOR_DARK_GREY
55 };
56
57 static const struct vts_color_struct vts_colors[] = {
58   /* 100% white */
59   {1.0f, 1.0f, 1.0f},
60   /* yellow */
61   {1.0f, 1.0f, 0.0f},
62   /* cyan */
63   {0.0f, 1.0f, 1.0f},
64   /* green */
65   {0.0f, 1.0f, 0.0f},
66   /* magenta */
67   {1.0f, 0.0f, 1.0f},
68   /* red */
69   {1.0f, 0.0f, 0.0f},
70   /* blue */
71   {0.0f, 0.0f, 1.0f},
72   /* black */
73   {0.0f, 0.0f, 0.0f},
74   /* -I */
75   {0.0, 0.0f, 0.5f},
76   /* +Q */
77   {0.0f, 0.5, 1.0f},
78   /* superblack */
79   {0.0f, 0.0f, 0.0f},
80   /* 7.421875% grey */
81   {19. / 256.0f, 19. / 256.0f, 19. / 256.0},
82 };
83
84 /* *INDENT-OFF* */
85 static const GLfloat positions[] = {
86      -1.0,  1.0,  0.0, 1.0,
87       1.0,  1.0,  0.0, 1.0,
88       1.0, -1.0,  0.0, 1.0,
89      -1.0, -1.0,  0.0, 1.0,
90 };
91
92 static const GLushort indices_quad[] = { 0, 1, 2, 0, 2, 3 };
93 /* *INDENT-ON* */
94
95 struct attribute
96 {
97   const gchar *name;
98   gint location;
99   guint n_elements;
100   GLenum element_type;
101   guint offset;                 /* in bytes */
102   guint stride;                 /* in bytes */
103 };
104
105 struct SrcShader
106 {
107   struct BaseSrcImpl base;
108
109   GstGLShader *shader;
110
111   guint vao;
112   guint vbo;
113   guint vbo_indices;
114
115   guint n_attributes;
116   struct attribute attributes[MAX_ATTRIBUTES];
117
118   gconstpointer vertices;
119   gsize vertices_size;
120   const gushort *indices;
121   guint index_offset;
122   guint n_indices;
123 };
124
125 static void
126 _bind_buffer (struct SrcShader *src)
127 {
128   GstGLContext *context = src->base.context;
129   const GstGLFuncs *gl = context->gl_vtable;
130   gint i;
131
132   gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, src->vbo_indices);
133   gl->BindBuffer (GL_ARRAY_BUFFER, src->vbo);
134
135   /* Load the vertex position */
136   for (i = 0; i < src->n_attributes; i++) {
137     struct attribute *attr = &src->attributes[i];
138
139     if (attr->location == -1)
140       attr->location =
141           gst_gl_shader_get_attribute_location (src->shader, attr->name);
142
143     gl->VertexAttribPointer (attr->location, attr->n_elements,
144         attr->element_type, GL_FALSE, attr->stride,
145         (void *) (gintptr) attr->offset);
146
147     gl->EnableVertexAttribArray (attr->location);
148   }
149 }
150
151 static void
152 _unbind_buffer (struct SrcShader *src)
153 {
154   GstGLContext *context = src->base.context;
155   const GstGLFuncs *gl = context->gl_vtable;
156   gint i;
157
158   gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
159   gl->BindBuffer (GL_ARRAY_BUFFER, 0);
160
161   for (i = 0; i < src->n_attributes; i++) {
162     struct attribute *attr = &src->attributes[i];
163
164     gl->DisableVertexAttribArray (attr->location);
165   }
166 }
167
168 static gboolean
169 _src_shader_init (gpointer impl, GstGLContext * context, GstVideoInfo * v_info)
170 {
171   struct SrcShader *src = impl;
172   const GstGLFuncs *gl = context->gl_vtable;
173
174   src->base.context = context;
175
176   if (!src->vbo) {
177     if (gl->GenVertexArrays) {
178       gl->GenVertexArrays (1, &src->vao);
179       gl->BindVertexArray (src->vao);
180     }
181
182     gl->GenBuffers (1, &src->vbo);
183     gl->BindBuffer (GL_ARRAY_BUFFER, src->vbo);
184     gl->BufferData (GL_ARRAY_BUFFER, src->vertices_size,
185         src->vertices, GL_STATIC_DRAW);
186
187     gl->GenBuffers (1, &src->vbo_indices);
188     gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, src->vbo_indices);
189     gl->BufferData (GL_ELEMENT_ARRAY_BUFFER, src->n_indices * sizeof (gushort),
190         src->indices, GL_STATIC_DRAW);
191
192     if (gl->GenVertexArrays) {
193       _bind_buffer (src);
194       gl->BindVertexArray (0);
195     }
196
197     gl->BindBuffer (GL_ARRAY_BUFFER, 0);
198     gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
199   }
200
201   return TRUE;
202 }
203
204 static gboolean
205 _src_shader_fill_bound_fbo (gpointer impl)
206 {
207   struct SrcShader *src = impl;
208   const GstGLFuncs *gl;
209
210   g_return_val_if_fail (src->base.context, FALSE);
211   g_return_val_if_fail (src->shader, FALSE);
212   gl = src->base.context->gl_vtable;
213
214   gst_gl_shader_use (src->shader);
215
216   if (gl->GenVertexArrays)
217     gl->BindVertexArray (src->vao);
218   _bind_buffer (src);
219
220   gl->DrawElements (GL_TRIANGLES, src->n_indices, GL_UNSIGNED_SHORT,
221       (gpointer) (gintptr) src->index_offset);
222
223   if (gl->GenVertexArrays)
224     gl->BindVertexArray (0);
225   _unbind_buffer (src);
226
227   gst_gl_context_clear_shader (src->base.context);
228
229   return TRUE;
230 }
231
232 static void
233 _src_shader_deinit (gpointer impl)
234 {
235   struct SrcShader *src = impl;
236   const GstGLFuncs *gl = src->base.context->gl_vtable;
237
238   if (src->shader)
239     gst_object_unref (src->shader);
240   src->shader = NULL;
241
242   if (src->vao)
243     gl->DeleteVertexArrays (1, &src->vao);
244   src->vao = 0;
245
246   if (src->vbo)
247     gl->DeleteBuffers (1, &src->vbo);
248   src->vbo = 0;
249
250   if (src->vbo_indices)
251     gl->DeleteBuffers (1, &src->vbo_indices);
252   src->vbo_indices = 0;
253 }
254
255 /* *INDENT-OFF* */
256 static const gchar *smpte_vertex_src =
257     "attribute vec4 position;\n"
258     "attribute vec4 a_color;\n"
259     "varying vec4 color;\n"
260     "void main()\n"
261     "{\n"
262     "  gl_Position = position;\n"
263     "  color = a_color;\n"
264     "}";
265
266 static const gchar *smpte_fragment_src =
267     "#ifdef GL_ES\n"
268     "precision mediump float;\n"
269     "#endif\n"
270     "varying vec4 color;\n"
271     "void main()\n"
272     "{\n"
273     "  gl_FragColor = color;\n"
274     "}";
275
276 static const gchar *snow_vertex_src =
277     "attribute vec4 position;\n"
278     "varying vec2 out_uv;\n"
279     "void main()\n"
280     "{\n"
281     "   gl_Position = position;\n"
282     "   out_uv = position.xy;\n"
283     "}";
284
285 static const gchar *snow_fragment_src = 
286     "#ifdef GL_ES\n"
287     "precision mediump float;\n"
288     "#endif\n"
289     "uniform float time;\n"
290     "varying vec2 out_uv;\n"
291     "\n"
292     "float rand(vec2 co){\n"
293     "    return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453);\n"
294     "}\n"
295     "void main()\n"
296     "{\n"
297     "  gl_FragColor = vec4(rand(time * out_uv));\n"
298     "}";
299 /* *INDENT-ON* */
300
301 #define N_QUADS 21
302 struct SrcSMPTE
303 {
304   struct SrcShader base;
305
306   GstGLShader *snow_shader;
307   GstGLShader *color_shader;
308   gint attr_snow_position;
309 };
310
311 static gpointer
312 _src_smpte_new (GstGLTestSrc * test)
313 {
314   struct SrcSMPTE *src = g_new0 (struct SrcSMPTE, 1);
315
316   src->base.base.src = test;
317
318   return src;
319 }
320
321 static gboolean
322 _src_smpte_init (gpointer impl, GstGLContext * context, GstVideoInfo * v_info)
323 {
324   struct SrcSMPTE *src = impl;
325   struct XYZWRGB *coord;
326   gushort *plane_indices;
327   GError *error = NULL;
328   int color_idx = 0;
329   int i;
330
331   src->base.base.context = context;
332
333   coord = g_new0 (struct XYZWRGB, N_QUADS * 4);
334   plane_indices = g_new0 (gushort, N_QUADS * 6);
335
336   /* top row */
337   for (i = 0; i < 7; i++) {
338     coord[color_idx * 4 + 0].X = -1.0f + i * (2.0f / 7.0f);
339     coord[color_idx * 4 + 0].Y = 1.0f / 3.0f;
340     coord[color_idx * 4 + 1].X = -1.0f + (i + 1) * (2.0f / 7.0f);
341     coord[color_idx * 4 + 1].Y = 1.0f / 3.0f;
342     coord[color_idx * 4 + 2].X = -1.0f + (i + 1) * (2.0f / 7.0f);
343     coord[color_idx * 4 + 2].Y = -1.0f;
344     coord[color_idx * 4 + 3].X = -1.0f + i * (2.0f / 7.0f);
345     coord[color_idx * 4 + 3].Y = -1.0f;
346     color_idx++;
347   }
348
349   /* middle row */
350   for (i = 0; i < 7; i++) {
351     coord[color_idx * 4 + 0].X = -1.0f + i * (2.0f / 7.0f);
352     coord[color_idx * 4 + 0].Y = 0.5f;
353     coord[color_idx * 4 + 1].X = -1.0f + (i + 1) * (2.0f / 7.0f);
354     coord[color_idx * 4 + 1].Y = 0.5f;
355     coord[color_idx * 4 + 2].X = -1.0f + (i + 1) * (2.0f / 7.0f);
356     coord[color_idx * 4 + 2].Y = 1.0f / 3.0f;
357     coord[color_idx * 4 + 3].X = -1.0f + i * (2.0f / 7.0f);
358     coord[color_idx * 4 + 3].Y = 1.0f / 3.0f;
359     color_idx++;
360   }
361
362   /* bottom row, left three */
363   for (i = 0; i < 3; i++) {
364     coord[color_idx * 4 + 0].X = -1.0f + i / 3.0f;
365     coord[color_idx * 4 + 0].Y = 1.0f;
366     coord[color_idx * 4 + 1].X = -1.0f + (i + 1) / 3.0f;
367     coord[color_idx * 4 + 1].Y = 1.0f;
368     coord[color_idx * 4 + 2].X = -1.0f + (i + 1) / 3.0f;
369     coord[color_idx * 4 + 2].Y = 0.5f;
370     coord[color_idx * 4 + 3].X = -1.0f + i / 3.0f;
371     coord[color_idx * 4 + 3].Y = 0.5f;
372     color_idx++;
373   }
374
375   /* bottom row, middle three (the blacks) */
376   for (i = 0; i < 3; i++) {
377     coord[color_idx * 4 + 0].X = i / 6.0f;
378     coord[color_idx * 4 + 0].Y = 1.0f;
379     coord[color_idx * 4 + 1].X = (i + 1) / 6.0f;
380     coord[color_idx * 4 + 1].Y = 1.0f;
381     coord[color_idx * 4 + 2].X = (i + 1) / 6.0f;
382     coord[color_idx * 4 + 2].Y = 0.5f;
383     coord[color_idx * 4 + 3].X = i / 6.0f;
384     coord[color_idx * 4 + 3].Y = 0.5f;
385     color_idx++;
386   }
387
388   g_assert (color_idx < N_QUADS);
389
390   for (i = 0; i < N_QUADS - 1; i++) {
391     int j, k;
392     if (i < 7) {
393       k = i;
394     } else if ((i - 7) & 1) {
395       k = COLOR_BLACK;
396     } else {
397       k = 13 - i;
398     }
399
400     if (i == 14) {
401       k = COLOR_NEG_I;
402     } else if (i == 15) {
403       k = COLOR_WHITE;
404     } else if (i == 16) {
405       k = COLOR_POS_Q;
406     } else if (i == 17) {
407       k = COLOR_SUPER_BLACK;
408     } else if (i == 18) {
409       k = COLOR_BLACK;
410     } else if (i == 19) {
411       k = COLOR_DARK_GREY;
412     }
413
414     for (j = 0; j < 4; j++) {
415       coord[i * 4 + j].Z = 0.0f;
416       coord[i * 4 + j].W = 1.0f;
417       coord[i * 4 + j].R = vts_colors[k].R;
418       coord[i * 4 + j].G = vts_colors[k].G;
419       coord[i * 4 + j].B = vts_colors[k].B;
420     }
421
422     for (j = 0; j < 6; j++)
423       plane_indices[i * 6 + j] = i * 4 + indices_quad[j];
424   }
425
426   /* snow */
427   coord[color_idx * 4 + 0].X = 0.5f;
428   coord[color_idx * 4 + 0].Y = 1.0f;
429   coord[color_idx * 4 + 0].Z = 0.0f;
430   coord[color_idx * 4 + 0].W = 1.0f;
431   coord[color_idx * 4 + 1].X = 1.0f;
432   coord[color_idx * 4 + 1].Y = 1.0f;
433   coord[color_idx * 4 + 1].Z = 0.0f;
434   coord[color_idx * 4 + 1].W = 1.0f;
435   coord[color_idx * 4 + 2].X = 1.0f;
436   coord[color_idx * 4 + 2].Y = 0.5f;
437   coord[color_idx * 4 + 2].Z = 0.0f;
438   coord[color_idx * 4 + 2].W = 1.0f;
439   coord[color_idx * 4 + 3].X = 0.5f;
440   coord[color_idx * 4 + 3].Y = 0.5f;
441   coord[color_idx * 4 + 3].Z = 0.0f;
442   coord[color_idx * 4 + 3].W = 1.0f;
443   for (i = 0; i < 6; i++)
444     plane_indices[color_idx * 6 + i] = color_idx * 4 + indices_quad[i];
445   color_idx++;
446
447   if (src->color_shader)
448     gst_object_unref (src->color_shader);
449   src->color_shader = gst_gl_shader_new_link_with_stages (context, &error,
450       gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
451           GST_GLSL_VERSION_NONE,
452           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
453           smpte_vertex_src),
454       gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
455           GST_GLSL_VERSION_NONE,
456           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
457           smpte_fragment_src), NULL);
458   if (!src->color_shader) {
459     GST_ERROR_OBJECT (src->base.base.src, "%s", error->message);
460     return FALSE;
461   }
462
463   if (src->snow_shader)
464     gst_object_unref (src->snow_shader);
465   src->snow_shader = gst_gl_shader_new_link_with_stages (context, &error,
466       gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
467           GST_GLSL_VERSION_NONE,
468           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
469           snow_vertex_src),
470       gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
471           GST_GLSL_VERSION_NONE,
472           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
473           snow_fragment_src), NULL);
474   if (!src->snow_shader) {
475     GST_ERROR_OBJECT (src->base.base.src, "%s", error->message);
476     return FALSE;
477   }
478
479   src->attr_snow_position = -1;
480
481   src->base.n_attributes = 2;
482
483   src->base.attributes[0].name = "position";
484   src->base.attributes[0].location = -1;
485   src->base.attributes[0].n_elements = 4;
486   src->base.attributes[0].element_type = GL_FLOAT;
487   src->base.attributes[0].offset = 0;
488   src->base.attributes[0].stride = sizeof (struct XYZWRGB);
489
490   src->base.attributes[1].name = "a_color";
491   src->base.attributes[1].location = -1;
492   src->base.attributes[1].n_elements = 3;
493   src->base.attributes[1].element_type = GL_FLOAT;
494   src->base.attributes[1].offset = 4 * sizeof (gfloat);
495   src->base.attributes[1].stride = sizeof (struct XYZWRGB);
496
497   if (src->base.shader)
498     gst_object_unref (src->base.shader);
499   src->base.shader = gst_object_ref (src->color_shader);
500   src->base.vertices = (gfloat *) coord;
501   src->base.vertices_size = sizeof (struct XYZWRGB) * N_QUADS * 4;
502   src->base.indices = plane_indices;
503   src->base.n_indices = N_QUADS * 6;
504
505   return _src_shader_init (impl, context, v_info);
506 }
507
508 static gboolean
509 _src_smpte_fill_bound_fbo (gpointer impl)
510 {
511   struct SrcSMPTE *src = impl;
512   gint attr_color_position = -1;
513
514   src->base.n_attributes = 2;
515   if (src->base.shader)
516     gst_object_unref (src->base.shader);
517   src->base.shader = gst_object_ref (src->color_shader);
518   src->base.n_indices = (N_QUADS - 1) * 6;
519   src->base.index_offset = 0;
520   if (!_src_shader_fill_bound_fbo (impl))
521     return FALSE;
522   attr_color_position = src->base.attributes[0].location;
523
524   src->base.attributes[0].location = src->attr_snow_position;
525   src->base.n_attributes = 1;
526   if (src->base.shader)
527     gst_object_unref (src->base.shader);
528   src->base.shader = gst_object_ref (src->snow_shader);
529   src->base.n_indices = 6;
530   src->base.index_offset = (N_QUADS - 1) * 6 * sizeof (gushort);
531   gst_gl_shader_use (src->snow_shader);
532   gst_gl_shader_set_uniform_1f (src->snow_shader, "time",
533       (gfloat) src->base.base.src->running_time / GST_SECOND);
534   if (!_src_shader_fill_bound_fbo (impl))
535     return FALSE;
536   src->attr_snow_position = src->base.attributes[0].location;
537   src->base.attributes[0].location = attr_color_position;
538
539   return TRUE;
540 }
541
542 static void
543 _src_smpte_free (gpointer impl)
544 {
545   struct SrcSMPTE *src = impl;
546
547   if (!impl)
548     return;
549
550   _src_shader_deinit (impl);
551
552   g_free ((gpointer) src->base.vertices);
553   g_free ((gpointer) src->base.indices);
554
555   if (src->snow_shader)
556     gst_object_unref (src->snow_shader);
557   if (src->color_shader)
558     gst_object_unref (src->color_shader);
559
560   g_free (impl);
561 }
562
563 static const struct SrcFuncs src_smpte = {
564   GST_GL_TEST_SRC_SMPTE,
565   _src_smpte_new,
566   _src_smpte_init,
567   _src_smpte_fill_bound_fbo,
568   _src_smpte_free,
569 };
570
571 #undef N_QUADS
572
573 struct SrcUniColor
574 {
575   struct BaseSrcImpl base;
576
577   struct vts_color_struct color;
578 };
579
580 static gpointer
581 _src_uni_color_new (GstGLTestSrc * test)
582 {
583   struct SrcUniColor *src = g_new0 (struct SrcUniColor, 1);
584
585   src->base.src = test;
586
587   return src;
588 }
589
590 static gboolean
591 _src_uni_color_init (gpointer impl, GstGLContext * context,
592     GstVideoInfo * v_info)
593 {
594   struct SrcUniColor *src = impl;
595
596   src->base.context = context;
597   src->base.v_info = *v_info;
598
599   return TRUE;
600 }
601
602 static gboolean
603 _src_uni_color_fill_bound_fbo (gpointer impl)
604 {
605   struct SrcUniColor *src = impl;
606   const GstGLFuncs *gl = src->base.context->gl_vtable;
607
608   gl->ClearColor (src->color.R, src->color.G, src->color.B, 1.0f);
609   gl->Clear (GL_COLOR_BUFFER_BIT);
610
611   return TRUE;
612 }
613
614 static void
615 _src_uni_color_free (gpointer impl)
616 {
617   g_free (impl);
618 }
619
620 #define SRC_UNICOLOR(name, cap_name) \
621 static gpointer \
622 G_PASTE(G_PASTE(_src_unicolor_,name),_new) (GstGLTestSrc * test) \
623 { \
624   struct SrcUniColor *src = _src_uni_color_new (test); \
625   src->color = vts_colors[G_PASTE(COLOR_,cap_name)]; \
626   return src; \
627 } \
628 static const struct SrcFuncs G_PASTE (src_,name) = { \
629   G_PASTE(GST_GL_TEST_SRC_,cap_name), \
630   G_PASTE(G_PASTE(_src_unicolor_,name),_new), \
631   _src_uni_color_init, \
632   _src_uni_color_fill_bound_fbo, \
633   _src_uni_color_free, \
634 }
635
636 SRC_UNICOLOR (white, WHITE);
637 SRC_UNICOLOR (black, BLACK);
638 SRC_UNICOLOR (red, RED);
639 SRC_UNICOLOR (green, GREEN);
640 SRC_UNICOLOR (blue, BLUE);
641
642 static gpointer
643 _src_blink_new (GstGLTestSrc * test)
644 {
645   struct SrcUniColor *src = _src_uni_color_new (test);
646
647   src->color = vts_colors[COLOR_WHITE];
648
649   return src;
650 }
651
652 static gboolean
653 _src_blink_fill_bound_fbo (gpointer impl)
654 {
655   struct SrcUniColor *src = impl;
656
657   if (src->color.R > 0.5) {
658     src->color = vts_colors[COLOR_BLACK];
659   } else {
660     src->color = vts_colors[COLOR_WHITE];
661   }
662
663   return _src_uni_color_fill_bound_fbo (impl);
664 }
665
666 static const struct SrcFuncs src_blink = {
667   GST_GL_TEST_SRC_BLINK,
668   _src_blink_new,
669   _src_uni_color_init,
670   _src_blink_fill_bound_fbo,
671   _src_uni_color_free,
672 };
673
674 /* *INDENT-OFF* */
675 static const gchar *checkers_vertex_src = "attribute vec4 position;\n"
676     "varying vec2 uv;\n"
677     "void main()\n"
678     "{\n"
679     "  gl_Position = position;\n"
680     /* RPi gives incorrect results for positive uv (plus it makes us start on
681      * the right pixel color i.e. red) */
682     "  uv = position.xy - 1.0;\n"
683     "}";
684
685 static const gchar *checkers_fragment_src =
686     "#ifdef GL_ES\n"
687     "precision mediump float;\n"
688     "#endif\n"
689     "uniform float checker_width;\n"
690     "uniform float width;\n"
691     "uniform float height;\n"
692     "varying vec2 uv;\n"
693     "void main()\n"
694     "{\n"
695     "  vec2 xy_mod = floor (0.5 * uv * vec2(width, height) / (checker_width));\n"
696     "  float result = mod (xy_mod.x + xy_mod.y, 2.0);\n"
697     "  gl_FragColor.r = step (result, 0.5);\n"
698     "  gl_FragColor.g = 1.0 - gl_FragColor.r;\n"
699     "  gl_FragColor.ba = vec2(0.0, 1.0);\n"
700     "}";
701 /* *INDENT-ON* */
702
703 struct SrcCheckers
704 {
705   struct SrcShader base;
706
707   guint checker_width;
708 };
709
710 static gboolean
711 _src_checkers_init (gpointer impl, GstGLContext * context,
712     GstVideoInfo * v_info)
713 {
714   struct SrcCheckers *src = impl;
715   GError *error = NULL;
716
717   src->base.base.context = context;
718
719   if (src->base.shader)
720     gst_object_unref (src->base.shader);
721   src->base.shader = gst_gl_shader_new_link_with_stages (context, &error,
722       gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
723           GST_GLSL_VERSION_NONE,
724           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
725           checkers_vertex_src),
726       gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
727           GST_GLSL_VERSION_NONE,
728           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
729           checkers_fragment_src), NULL);
730   if (!src->base.shader) {
731     GST_ERROR_OBJECT (src->base.base.src, "%s", error->message);
732     return FALSE;
733   }
734
735   src->base.n_attributes = 1;
736
737   src->base.attributes[0].name = "position";
738   src->base.attributes[0].location = -1;
739   src->base.attributes[0].n_elements = 4;
740   src->base.attributes[0].element_type = GL_FLOAT;
741   src->base.attributes[0].offset = 0;
742   src->base.attributes[0].stride = 4 * sizeof (gfloat);
743
744   src->base.vertices = positions;
745   src->base.vertices_size = sizeof (positions);
746   src->base.indices = indices_quad;
747   src->base.n_indices = 6;
748
749   gst_gl_shader_use (src->base.shader);
750   gst_gl_shader_set_uniform_1f (src->base.shader, "checker_width",
751       src->checker_width);
752   gst_gl_shader_set_uniform_1f (src->base.shader, "width",
753       (gfloat) GST_VIDEO_INFO_WIDTH (v_info));
754   gst_gl_shader_set_uniform_1f (src->base.shader, "height",
755       (gfloat) GST_VIDEO_INFO_HEIGHT (v_info));
756   gst_gl_context_clear_shader (src->base.base.context);
757
758   return _src_shader_init (impl, context, v_info);
759 }
760
761 static void
762 _src_checkers_free (gpointer impl)
763 {
764   struct SrcCheckers *src = impl;
765
766   if (!src)
767     return;
768
769   _src_shader_deinit (impl);
770
771   g_free (impl);
772 }
773
774 static gpointer
775 _src_checkers_new (GstGLTestSrc * test)
776 {
777   struct SrcCheckers *src = g_new0 (struct SrcCheckers, 1);
778
779   src->base.base.src = test;
780
781   return src;
782 }
783
784 #define SRC_CHECKERS(spacing) \
785 static gpointer \
786 G_PASTE(G_PASTE(_src_checkers,spacing),_new) (GstGLTestSrc * test) \
787 { \
788   struct SrcCheckers *src = _src_checkers_new (test); \
789   src->checker_width = spacing; \
790   return src; \
791 } \
792 static const struct SrcFuncs G_PASTE(src_checkers,spacing) = { \
793   G_PASTE(GST_GL_TEST_SRC_CHECKERS,spacing), \
794   G_PASTE(G_PASTE(_src_checkers,spacing),_new), \
795   _src_checkers_init, \
796   _src_shader_fill_bound_fbo, \
797   _src_checkers_free, \
798 }
799
800 SRC_CHECKERS (1);
801 SRC_CHECKERS (2);
802 SRC_CHECKERS (4);
803 SRC_CHECKERS (8);
804
805 static gboolean
806 _src_snow_init (gpointer impl, GstGLContext * context, GstVideoInfo * v_info)
807 {
808   struct SrcShader *src = impl;
809   GError *error = NULL;
810
811   src->base.context = context;
812
813   if (src->shader)
814     gst_object_unref (src->shader);
815   src->shader = gst_gl_shader_new_link_with_stages (context, &error,
816       gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
817           GST_GLSL_VERSION_NONE,
818           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
819           snow_vertex_src),
820       gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
821           GST_GLSL_VERSION_NONE,
822           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
823           snow_fragment_src), NULL);
824   if (!src->shader) {
825     GST_ERROR_OBJECT (src->base.src, "%s", error->message);
826     return FALSE;
827   }
828
829   src->n_attributes = 1;
830
831   src->attributes[0].name = "position";
832   src->attributes[0].location = -1;
833   src->attributes[0].n_elements = 4;
834   src->attributes[0].element_type = GL_FLOAT;
835   src->attributes[0].offset = 0;
836   src->attributes[0].stride = 4 * sizeof (gfloat);
837
838   src->vertices = positions;
839   src->vertices_size = sizeof (positions);
840   src->indices = indices_quad;
841   src->n_indices = 6;
842
843   return _src_shader_init (impl, context, v_info);
844 }
845
846 static gboolean
847 _src_snow_fill_bound_fbo (gpointer impl)
848 {
849   struct SrcShader *src = impl;
850
851   g_return_val_if_fail (src->base.context, FALSE);
852   g_return_val_if_fail (src->shader, FALSE);
853
854   gst_gl_shader_use (src->shader);
855   gst_gl_shader_set_uniform_1f (src->shader, "time",
856       (gfloat) src->base.src->running_time / GST_SECOND);
857
858   return _src_shader_fill_bound_fbo (impl);
859 }
860
861 static void
862 _src_snow_free (gpointer impl)
863 {
864   struct SrcShader *src = impl;
865
866   if (!src)
867     return;
868
869   _src_shader_deinit (impl);
870
871   g_free (impl);
872 }
873
874 static gpointer
875 _src_snow_new (GstGLTestSrc * test)
876 {
877   struct SrcShader *src = g_new0 (struct SrcShader, 1);
878
879   src->base.src = test;
880
881   return src;
882 }
883
884 static const struct SrcFuncs src_snow = {
885   GST_GL_TEST_SRC_SNOW,
886   _src_snow_new,
887   _src_snow_init,
888   _src_snow_fill_bound_fbo,
889   _src_snow_free,
890 };
891
892 /* *INDENT-OFF* */
893 static const gchar *mandelbrot_vertex_src = "attribute vec4 position;\n"
894     "uniform float aspect_ratio;\n"
895     "varying vec2 fractal_position;\n"
896     "void main()\n"
897     "{\n"
898     "  gl_Position = position;\n"
899     "  fractal_position = vec2(position.y * 0.5 - 0.3, aspect_ratio * position.x * 0.5);\n"
900     "  fractal_position *= 2.5;\n"
901     "}";
902
903 static const gchar *mandelbrot_fragment_src = 
904     "#ifdef GL_ES\n"
905     "precision mediump float;\n"
906     "#endif\n"
907     "uniform float time;\n"
908     "varying vec2 fractal_position;\n"
909     "const vec4 K = vec4(1.0, 0.66, 0.33, 3.0);\n"
910     "vec4 hsv_to_rgb(float hue, float saturation, float value) {\n"
911     "  vec4 p = abs(fract(vec4(hue) + K) * 6.0 - K.wwww);\n"
912     "  return value * mix(K.xxxx, clamp(p - K.xxxx, 0.0, 1.0), saturation);\n"
913     "}\n"
914     "vec4 i_to_rgb(int i) {\n"
915     "  float hue = float(i) / 100.0 + sin(time);\n"
916     "  return hsv_to_rgb(hue, 0.5, 0.8);\n"
917     "}\n"
918     "vec2 pow_2_complex(vec2 c) {\n"
919     "  return vec2(c.x*c.x - c.y*c.y, 2.0 * c.x * c.y);\n"
920     "}\n"
921     "vec2 mandelbrot(vec2 c, vec2 c0) {\n"
922     "  return pow_2_complex(c) + c0;\n"
923     "}\n"
924     "vec4 iterate_pixel(vec2 position) {\n"
925     "  vec2 c = vec2(0);\n"
926     "  for (int i=0; i < 20; i++) {\n"
927     "    if (c.x*c.x + c.y*c.y > 2.0*2.0)\n"
928     "      return i_to_rgb(i);\n"
929     "    c = mandelbrot(c, position);\n"
930     "  }\n"
931     "  return vec4(0, 0, 0, 1);\n"
932     "}\n"
933     "void main() {\n"
934     "  gl_FragColor = iterate_pixel(fractal_position);\n"
935     "}";
936 /* *INDENT-ON* */
937
938 static gboolean
939 _src_mandelbrot_init (gpointer impl, GstGLContext * context,
940     GstVideoInfo * v_info)
941 {
942   struct SrcShader *src = impl;
943   GError *error = NULL;
944
945   src->base.context = context;
946
947   if (src->shader)
948     gst_object_unref (src->shader);
949   src->shader = gst_gl_shader_new_link_with_stages (context, &error,
950       gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
951           GST_GLSL_VERSION_NONE,
952           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
953           mandelbrot_vertex_src),
954       gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
955           GST_GLSL_VERSION_NONE,
956           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
957           mandelbrot_fragment_src), NULL);
958   if (!src->shader) {
959     GST_ERROR_OBJECT (src->base.src, "%s", error->message);
960     return FALSE;
961   }
962
963   src->n_attributes = 1;
964
965   src->attributes[0].name = "position";
966   src->attributes[0].location = -1;
967   src->attributes[0].n_elements = 4;
968   src->attributes[0].element_type = GL_FLOAT;
969   src->attributes[0].offset = 0;
970   src->attributes[0].stride = 4 * sizeof (gfloat);
971
972   src->vertices = positions;
973   src->vertices_size = sizeof (positions);
974   src->indices = indices_quad;
975   src->n_indices = 6;
976
977   gst_gl_shader_use (src->shader);
978   gst_gl_shader_set_uniform_1f (src->shader, "aspect_ratio",
979       (gfloat) GST_VIDEO_INFO_WIDTH (v_info) /
980       (gfloat) GST_VIDEO_INFO_HEIGHT (v_info));
981   gst_gl_context_clear_shader (src->base.context);
982
983   return _src_shader_init (impl, context, v_info);
984 }
985
986 static gboolean
987 _src_mandelbrot_fill_bound_fbo (gpointer impl)
988 {
989   struct SrcShader *src = impl;
990
991   g_return_val_if_fail (src->base.context, FALSE);
992   g_return_val_if_fail (src->shader, FALSE);
993
994   gst_gl_shader_use (src->shader);
995   gst_gl_shader_set_uniform_1f (src->shader, "time",
996       (gfloat) src->base.src->running_time / GST_SECOND);
997
998   return _src_shader_fill_bound_fbo (impl);
999 }
1000
1001 static void
1002 _src_mandelbrot_free (gpointer impl)
1003 {
1004   struct SrcShader *src = impl;
1005
1006   if (!src)
1007     return;
1008
1009   _src_shader_deinit (impl);
1010
1011   g_free (impl);
1012 }
1013
1014 static gpointer
1015 _src_mandelbrot_new (GstGLTestSrc * test)
1016 {
1017   struct SrcShader *src = g_new0 (struct SrcShader, 1);
1018
1019   src->base.src = test;
1020
1021   return src;
1022 }
1023
1024 static const struct SrcFuncs src_mandelbrot = {
1025   GST_GL_TEST_SRC_MANDELBROT,
1026   _src_mandelbrot_new,
1027   _src_mandelbrot_init,
1028   _src_mandelbrot_fill_bound_fbo,
1029   _src_mandelbrot_free,
1030 };
1031
1032 /* *INDENT-OFF* */
1033 static const gchar *circular_vertex_src =
1034     "attribute vec4 position;\n"
1035     "varying vec2 uv;\n"
1036     "void main()\n"
1037     "{\n"
1038     "  gl_Position = position;\n"
1039     "  uv = position.xy;\n"
1040     "}";
1041
1042 static const gchar *circular_fragment_src =
1043     "#ifdef GL_ES\n"
1044     "precision mediump float;\n"
1045     "#endif\n"
1046     "uniform float aspect_ratio;\n"
1047     "varying vec2 uv;\n"
1048     "#define PI 3.14159265\n"
1049     "void main() {\n"
1050     "  float dist = 0.5 * sqrt(uv.x * uv.x + uv.y / aspect_ratio * uv.y / aspect_ratio);\n"
1051     "  float seg = floor(dist * 16.0);\n"
1052     "  if (seg <= 0.0 || seg >= 8.0) {\n"
1053     "    gl_FragColor = vec4(vec3(0.0), 1.0);\n"
1054     "  } else {\n"
1055     "    float d = floor (256.0 * dist * 200.0 * pow (2.0, - (seg - 1.0) / 4.0) + 0.5) / 128.0;\n"
1056     "    gl_FragColor = vec4 (vec3(sin (d * PI) * 0.5 + 0.5), 1.0);\n"
1057     "  }\n"
1058     "}";
1059 /* *INDENT-ON* */
1060
1061 static gboolean
1062 _src_circular_init (gpointer impl, GstGLContext * context,
1063     GstVideoInfo * v_info)
1064 {
1065   struct SrcShader *src = impl;
1066   GError *error = NULL;
1067
1068   src->base.context = context;
1069
1070   if (src->shader)
1071     gst_object_unref (src->shader);
1072   src->shader = gst_gl_shader_new_link_with_stages (context, &error,
1073       gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
1074           GST_GLSL_VERSION_NONE,
1075           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
1076           circular_vertex_src),
1077       gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
1078           GST_GLSL_VERSION_NONE,
1079           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
1080           circular_fragment_src), NULL);
1081   if (!src->shader) {
1082     GST_ERROR_OBJECT (src->base.src, "%s", error->message);
1083     return FALSE;
1084   }
1085
1086   src->n_attributes = 1;
1087
1088   src->attributes[0].name = "position";
1089   src->attributes[0].location = -1;
1090   src->attributes[0].n_elements = 4;
1091   src->attributes[0].element_type = GL_FLOAT;
1092   src->attributes[0].offset = 0;
1093   src->attributes[0].stride = 4 * sizeof (gfloat);
1094
1095   src->vertices = positions;
1096   src->vertices_size = sizeof (positions);
1097   src->indices = indices_quad;
1098   src->n_indices = 6;
1099
1100   gst_gl_shader_use (src->shader);
1101   gst_gl_shader_set_uniform_1f (src->shader, "aspect_ratio",
1102       (gfloat) GST_VIDEO_INFO_WIDTH (v_info) /
1103       (gfloat) GST_VIDEO_INFO_HEIGHT (v_info));
1104   gst_gl_context_clear_shader (src->base.context);
1105
1106   return _src_shader_init (impl, context, v_info);
1107 }
1108
1109 static void
1110 _src_circular_free (gpointer impl)
1111 {
1112   struct SrcShader *src = impl;
1113
1114   if (!src)
1115     return;
1116
1117   _src_shader_deinit (impl);
1118
1119   g_free (impl);
1120 }
1121
1122 static gpointer
1123 _src_circular_new (GstGLTestSrc * test)
1124 {
1125   struct SrcShader *src = g_new0 (struct SrcShader, 1);
1126
1127   src->base.src = test;
1128
1129   return src;
1130 }
1131
1132 static const struct SrcFuncs src_circular = {
1133   GST_GL_TEST_SRC_CIRCULAR,
1134   _src_circular_new,
1135   _src_circular_init,
1136   _src_mandelbrot_fill_bound_fbo,
1137   _src_circular_free,
1138 };
1139
1140 static const struct SrcFuncs *src_impls[] = {
1141   &src_smpte,
1142   &src_snow,
1143   &src_black,
1144   &src_white,
1145   &src_red,
1146   &src_green,
1147   &src_blue,
1148   &src_checkers1,
1149   &src_checkers2,
1150   &src_checkers4,
1151   &src_checkers8,
1152   &src_circular,
1153   &src_blink,
1154   &src_mandelbrot,
1155 };
1156
1157 const struct SrcFuncs *
1158 gst_gl_test_src_get_src_funcs_for_pattern (GstGLTestSrcPattern pattern)
1159 {
1160   gint i;
1161
1162   for (i = 0; i < G_N_ELEMENTS (src_impls); i++) {
1163     if (src_impls[i]->pattern == pattern)
1164       return src_impls[i];
1165   }
1166
1167   return NULL;
1168 }