clients: Remove a few unused variables
[profile/ivi/weston.git] / clients / simple-egl.c
1 /*
2  * Copyright © 2011 Benjamin Franzke
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdbool.h>
27 #include <math.h>
28 #include <assert.h>
29
30 #include <wayland-client.h>
31 #include <wayland-egl.h>
32
33 #include <GLES2/gl2.h>
34 #include <EGL/egl.h>
35
36 struct display {
37         struct wl_display *display;
38         struct wl_visual *premultiplied_argb_visual;
39         struct wl_compositor *compositor;
40         struct wl_shell *shell;
41         struct {
42                 EGLDisplay dpy;
43                 EGLContext ctx;
44                 EGLConfig conf;
45         } egl;
46         uint32_t mask;
47 };
48
49 struct window {
50         struct display *display;
51         struct {
52                 int width, height;
53         } geometry;
54         struct {
55                 GLuint fbo;
56                 GLuint color_rbo;
57
58                 GLuint program;
59                 GLuint rotation_uniform;
60
61                 GLuint pos;
62                 GLuint col;
63         } gl;
64
65         struct wl_egl_window *native;
66         struct wl_surface *surface;
67         EGLSurface egl_surface;
68 };
69
70 static const char *vert_shader_text =
71         "uniform mat4 rotation;\n"
72         "attribute vec4 pos;\n"
73         "attribute vec4 color;\n"
74         "varying vec4 v_color;\n"
75         "void main() {\n"
76         "  gl_Position = rotation * pos;\n"
77         "  v_color = color;\n"
78         "}\n";
79
80 static const char *frag_shader_text =
81         "precision mediump float;\n"
82         "varying vec4 v_color;\n"
83         "void main() {\n"
84         "  gl_FragColor = v_color;\n"
85         "}\n";
86
87 static void
88 init_egl(struct display *display)
89 {
90         static const EGLint context_attribs[] = {
91                 EGL_CONTEXT_CLIENT_VERSION, 2,
92                 EGL_NONE
93         };
94
95         static const EGLint config_attribs[] = {
96                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
97                 EGL_RED_SIZE, 1,
98                 EGL_GREEN_SIZE, 1,
99                 EGL_BLUE_SIZE, 1,
100                 EGL_ALPHA_SIZE, 1,
101                 EGL_DEPTH_SIZE, 1,
102                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
103                 EGL_NONE
104         };
105
106         EGLint major, minor, n;
107         EGLBoolean ret;
108
109         setenv("EGL_PLATFORM", "wayland", 1);
110         display->egl.dpy = eglGetDisplay(display->display);
111         assert(display->egl.dpy);
112
113         ret = eglInitialize(display->egl.dpy, &major, &minor);
114         assert(ret == EGL_TRUE);
115         ret = eglBindAPI(EGL_OPENGL_ES_API);
116         assert(ret == EGL_TRUE);
117
118         assert(eglChooseConfig(display->egl.dpy, config_attribs,
119                                &display->egl.conf, 1, &n) && n == 1);
120
121         display->egl.ctx = eglCreateContext(display->egl.dpy,
122                                             display->egl.conf,
123                                             EGL_NO_CONTEXT, context_attribs);
124         assert(display->egl.ctx);
125
126 }
127
128 static GLuint
129 create_shader(struct window *window, const char *source, GLenum shader_type)
130 {
131         GLuint shader;
132         GLint status;
133
134         shader = glCreateShader(shader_type);
135         assert(shader != 0);
136
137         glShaderSource(shader, 1, (const char **) &source, NULL);
138         glCompileShader(shader);
139
140         glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
141         if (!status) {
142                 char log[1000];
143                 GLsizei len;
144                 glGetShaderInfoLog(shader, 1000, &len, log);
145                 fprintf(stderr, "Error: compiling %s: %*s\n",
146                         shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
147                         len, log);
148                 exit(1);
149         }
150
151         return shader;
152 }
153
154 static void
155 init_gl(struct window *window)
156 {
157         GLuint frag, vert;
158         GLint status;
159
160         glViewport(0, 0, window->geometry.width, window->geometry.height);
161
162         frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER);
163         vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER);
164
165         window->gl.program = glCreateProgram();
166         glAttachShader(window->gl.program, frag);
167         glAttachShader(window->gl.program, vert);
168         glLinkProgram(window->gl.program);
169
170         glGetProgramiv(window->gl.program, GL_LINK_STATUS, &status);
171         if (!status) {
172                 char log[1000];
173                 GLsizei len;
174                 glGetProgramInfoLog(window->gl.program, 1000, &len, log);
175                 fprintf(stderr, "Error: linking:\n%*s\n", len, log);
176                 exit(1);
177         }
178
179         glUseProgram(window->gl.program);
180         
181         window->gl.pos = 0;
182         window->gl.pos = 1;
183
184         glBindAttribLocation(window->gl.program, window->gl.pos, "pos");
185         glBindAttribLocation(window->gl.program, window->gl.col, "color");
186         glLinkProgram(window->gl.program);
187
188         window->gl.rotation_uniform =
189                 glGetUniformLocation(window->gl.program, "rotation");
190 }
191
192 static void
193 create_surface(struct window *window)
194 {
195         struct display *display = window->display;
196         struct wl_visual *visual;
197         EGLBoolean ret;
198         
199         if (!display->premultiplied_argb_visual)
200                 wl_display_roundtrip(display->display);
201         if (!display->premultiplied_argb_visual) {
202                 fprintf(stderr, "premultiplied argb visual missing\n");
203                 exit(1);
204         }
205
206         window->surface = wl_compositor_create_surface(display->compositor);
207         visual = display->premultiplied_argb_visual;
208         window->native =
209                 wl_egl_window_create(window->surface,
210                                      window->geometry.width,
211                                      window->geometry.height,
212                                      visual);
213         window->egl_surface =
214                 eglCreateWindowSurface(display->egl.dpy,
215                                        display->egl.conf,
216                                        window->native,
217                                        NULL);
218
219         wl_shell_set_toplevel(display->shell, window->surface);
220
221         ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
222                              window->egl_surface, window->display->egl.ctx);
223         assert(ret == EGL_TRUE);
224 }
225
226 static const struct wl_callback_listener frame_listener;
227
228 static void
229 redraw(void *data, struct wl_callback *callback, uint32_t time)
230 {
231         struct window *window = data;
232         static const GLfloat verts[3][2] = {
233                 { -0.5, -0.5 },
234                 {  0.5, -0.5 },
235                 {  0,    0.5 }
236         };
237         static const GLfloat colors[3][3] = {
238                 { 1, 0, 0 },
239                 { 0, 1, 0 },
240                 { 0, 0, 1 }
241         };
242         GLfloat angle;
243         GLfloat rotation[4][4] = {
244                 { 1, 0, 0, 0 },
245                 { 0, 1, 0, 0 },
246                 { 0, 0, 1, 0 },
247                 { 0, 0, 0, 1 }
248         };
249         static const int32_t speed_div = 5;
250         static uint32_t start_time = 0;
251
252         if (start_time == 0)
253                 start_time = time;
254
255         angle = ((time-start_time) / speed_div) % 360 * M_PI / 180.0;
256         rotation[0][0] =  cos(angle);
257         rotation[0][2] =  sin(angle);
258         rotation[2][0] = -sin(angle);
259         rotation[2][2] =  cos(angle);
260
261         glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE,
262                            (GLfloat *) rotation);
263
264         glClearColor(0.0, 0.0, 0.0, 0.5);
265         glClear(GL_COLOR_BUFFER_BIT);
266
267         glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
268         glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors);
269         glEnableVertexAttribArray(window->gl.pos);
270         glEnableVertexAttribArray(window->gl.col);
271
272         glDrawArrays(GL_TRIANGLES, 0, 3);
273
274         glDisableVertexAttribArray(window->gl.pos);
275         glDisableVertexAttribArray(window->gl.col);
276
277         glFlush();
278
279         eglSwapBuffers(window->display->egl.dpy, window->egl_surface);
280         if (callback)
281                 wl_callback_destroy(callback);
282
283         callback = wl_surface_frame(window->surface);
284         wl_callback_add_listener(callback, &frame_listener, window);
285 }
286
287 static const struct wl_callback_listener frame_listener = {
288         redraw
289 };
290
291 static void
292 compositor_handle_visual(void *data,
293                          struct wl_compositor *compositor,
294                          uint32_t id, uint32_t token)
295 {
296         struct display *d = data;
297
298         switch (token) {
299         case WL_COMPOSITOR_VISUAL_PREMULTIPLIED_ARGB32:
300                 d->premultiplied_argb_visual =
301                         wl_display_bind(d->display, id, &wl_visual_interface);
302                 break;
303         }
304 }
305
306 static const struct wl_compositor_listener compositor_listener = {
307         compositor_handle_visual,
308 };
309
310 static void
311 display_handle_global(struct wl_display *display, uint32_t id,
312                       const char *interface, uint32_t version, void *data)
313 {
314         struct display *d = data;
315
316         if (strcmp(interface, "wl_compositor") == 0) {
317                 d->compositor =
318                         wl_display_bind(display, id, &wl_compositor_interface);
319                 wl_compositor_add_listener(d->compositor,
320                                            &compositor_listener, d);
321         } else if (strcmp(interface, "wl_shell") == 0) {
322                 d->shell = wl_display_bind(display, id, &wl_shell_interface);
323         }
324 }
325
326 static int
327 event_mask_update(uint32_t mask, void *data)
328 {
329         struct display *d = data;
330
331         d->mask = mask;
332
333         return 0;
334 }
335
336 int
337 main(int argc, char **argv)
338 {
339         struct display display = { 0 };
340         struct window  window  = { 0 };
341
342         memset(&display, 0, sizeof display);
343         memset(&window,  0, sizeof window);
344
345         window.display = &display;
346         window.geometry.width  = 250;
347         window.geometry.height = 250;
348
349         display.display = wl_display_connect(NULL);
350         assert(display.display);
351
352         wl_display_add_global_listener(display.display,
353                                        display_handle_global, &display);
354
355         wl_display_get_fd(display.display, event_mask_update, &display);
356         wl_display_iterate(display.display, WL_DISPLAY_READABLE);
357
358         init_egl(&display);
359         create_surface(&window);
360         init_gl(&window);
361
362         redraw(&window, NULL, 0);
363
364         while (true)
365                 wl_display_iterate(display.display, display.mask);
366
367         return 0;
368 }