1 | /* |
2 | Copyright (c) 2013, Broadcom Europe Ltd |
3 | Copyright (c) 2013, Tim Gover |
4 | All rights reserved. |
5 | |
6 | |
7 | Redistribution and use in source and binary forms, with or without |
8 | modification, are permitted provided that the following conditions are met: |
9 | * Redistributions of source code must retain the above copyright |
10 | notice, this list of conditions and the following disclaimer. |
11 | * Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | * Neither the name of the copyright holder nor the |
15 | names of its contributors may be used to endorse or promote products |
16 | derived from this software without specific prior written permission. |
17 | |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
22 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | */ |
29 | |
30 | #include "mirror.h" |
31 | #include "RaspiTex.h" |
32 | #include "RaspiTexUtil.h" |
33 | #include <GLES2/gl2.h> |
34 | #include <EGL/egl.h> |
35 | #include <EGL/eglext.h> |
36 | |
37 | /** |
38 | * Draws an external EGL image and applies a sine wave distortion to create |
39 | * a hall of mirrors effect. |
40 | */ |
41 | static RASPITEXUTIL_SHADER_PROGRAM_T mirror_shader = { |
42 | .vertex_source = |
43 | "attribute vec2 vertex;\n" |
44 | "varying vec2 texcoord;" |
45 | "void main(void) {\n" |
46 | " texcoord = 0.5 * (vertex + 1.0);\n" |
47 | " gl_Position = vec4(vertex, 0.0, 1.0);\n" |
48 | "}\n" , |
49 | |
50 | .fragment_source = |
51 | "#extension GL_OES_EGL_image_external : require\n" |
52 | "uniform samplerExternalOES tex;\n" |
53 | "uniform float offset;\n" |
54 | "const float waves = 2.0;\n" |
55 | "varying vec2 texcoord;\n" |
56 | "void main(void) {\n" |
57 | " float x = texcoord.x + 0.05 * sin(offset + (texcoord.y * waves * 2.0 * 3.141592));\n" |
58 | " float y = texcoord.y + 0.05 * sin(offset + (texcoord.x * waves * 2.0 * 3.141592));\n" |
59 | " if (y < 1.0 && y > 0.0 && x < 1.0 && x > 0.0) {\n" |
60 | " vec2 pos = vec2(x, y);\n" |
61 | " gl_FragColor = texture2D(tex, pos);\n" |
62 | " }\n" |
63 | " else {\n" |
64 | " gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n" |
65 | " }\n" |
66 | "}\n" , |
67 | .uniform_names = {"tex" , "offset" }, |
68 | .attribute_names = {"vertex" }, |
69 | }; |
70 | |
71 | /** |
72 | * Creates the OpenGL ES 2.X context and builds the shaders. |
73 | * @param raspitex_state A pointer to the GL preview state. |
74 | * @return Zero if successful. |
75 | */ |
76 | static int mirror_init(RASPITEX_STATE *state) |
77 | { |
78 | int rc = raspitexutil_gl_init_2_0(state); |
79 | if (rc != 0) |
80 | goto end; |
81 | |
82 | rc = raspitexutil_build_shader_program(&mirror_shader); |
83 | end: |
84 | return rc; |
85 | } |
86 | |
87 | static int mirror_redraw(RASPITEX_STATE *raspitex_state) { |
88 | static float offset = 0.0; |
89 | |
90 | // Start with a clear screen |
91 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
92 | |
93 | // Bind the OES texture which is used to render the camera preview |
94 | glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->texture); |
95 | |
96 | offset += 0.05; |
97 | GLCHK(glUseProgram(mirror_shader.program)); |
98 | GLCHK(glEnableVertexAttribArray(mirror_shader.attribute_locations[0])); |
99 | GLfloat varray[] = { |
100 | -1.0f, -1.0f, |
101 | 1.0f, 1.0f, |
102 | 1.0f, -1.0f, |
103 | |
104 | -1.0f, 1.0f, |
105 | 1.0f, 1.0f, |
106 | -1.0f, -1.0f, |
107 | }; |
108 | GLCHK(glVertexAttribPointer(mirror_shader.attribute_locations[0], 2, GL_FLOAT, GL_FALSE, 0, varray)); |
109 | GLCHK(glUniform1f(mirror_shader.uniform_locations[1], offset)); |
110 | GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6)); |
111 | |
112 | GLCHK(glDisableVertexAttribArray(mirror_shader.attribute_locations[0])); |
113 | GLCHK(glUseProgram(0)); |
114 | return 0; |
115 | } |
116 | |
117 | int mirror_open(RASPITEX_STATE *state) |
118 | { |
119 | state->ops.gl_init = mirror_init; |
120 | state->ops.redraw = mirror_redraw; |
121 | state->ops.update_texture = raspitexutil_update_texture; |
122 | return 0; |
123 | } |
124 | |