2 * Copyright © 2011 Benjamin Franzke
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.
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
31 #include <wayland-client.h>
32 #include <wayland-egl.h>
34 #include <GLES2/gl2.h>
41 struct wl_display *display;
42 struct wl_compositor *compositor;
43 struct wl_shell *shell;
45 struct wl_pointer *pointer;
52 struct window *window;
56 struct display *display;
64 GLuint rotation_uniform;
70 struct wl_egl_window *native;
71 struct wl_surface *surface;
72 struct wl_shell_surface *shell_surface;
73 EGLSurface egl_surface;
74 struct wl_callback *callback;
75 int fullscreen, configured;
78 static const char *vert_shader_text =
79 "uniform mat4 rotation;\n"
80 "attribute vec4 pos;\n"
81 "attribute vec4 color;\n"
82 "varying vec4 v_color;\n"
84 " gl_Position = rotation * pos;\n"
88 static const char *frag_shader_text =
89 "precision mediump float;\n"
90 "varying vec4 v_color;\n"
92 " gl_FragColor = v_color;\n"
96 init_egl(struct display *display, EGLint alpha_size)
98 static const EGLint context_attribs[] = {
99 EGL_CONTEXT_CLIENT_VERSION, 2,
103 EGLint config_attribs[] = {
104 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
108 EGL_ALPHA_SIZE, alpha_size,
109 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
113 EGLint major, minor, n;
116 display->egl.dpy = eglGetDisplay(display->display);
117 assert(display->egl.dpy);
119 ret = eglInitialize(display->egl.dpy, &major, &minor);
120 assert(ret == EGL_TRUE);
121 ret = eglBindAPI(EGL_OPENGL_ES_API);
122 assert(ret == EGL_TRUE);
124 ret = eglChooseConfig(display->egl.dpy, config_attribs,
125 &display->egl.conf, 1, &n);
126 assert(ret && n == 1);
128 display->egl.ctx = eglCreateContext(display->egl.dpy,
130 EGL_NO_CONTEXT, context_attribs);
131 assert(display->egl.ctx);
136 fini_egl(struct display *display)
138 /* Required, otherwise segfault in egl_dri2.c: dri2_make_current()
139 * on eglReleaseThread(). */
140 eglMakeCurrent(display->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
143 eglTerminate(display->egl.dpy);
148 create_shader(struct window *window, const char *source, GLenum shader_type)
153 shader = glCreateShader(shader_type);
156 glShaderSource(shader, 1, (const char **) &source, NULL);
157 glCompileShader(shader);
159 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
163 glGetShaderInfoLog(shader, 1000, &len, log);
164 fprintf(stderr, "Error: compiling %s: %*s\n",
165 shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
174 init_gl(struct window *window)
180 glViewport(0, 0, window->geometry.width, window->geometry.height);
182 frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER);
183 vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER);
185 program = glCreateProgram();
186 glAttachShader(program, frag);
187 glAttachShader(program, vert);
188 glLinkProgram(program);
190 glGetProgramiv(program, GL_LINK_STATUS, &status);
194 glGetProgramInfoLog(program, 1000, &len, log);
195 fprintf(stderr, "Error: linking:\n%*s\n", len, log);
199 glUseProgram(program);
204 glBindAttribLocation(program, window->gl.pos, "pos");
205 glBindAttribLocation(program, window->gl.col, "color");
206 glLinkProgram(program);
208 window->gl.rotation_uniform =
209 glGetUniformLocation(program, "rotation");
213 handle_ping(void *data, struct wl_shell_surface *shell_surface,
216 wl_shell_surface_pong(shell_surface, serial);
220 handle_configure(void *data, struct wl_shell_surface *shell_surface,
221 uint32_t edges, int32_t width, int32_t height)
223 struct window *window = data;
225 window->geometry.width = width;
226 window->geometry.height = height;
227 window->configured = 1;
231 handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
235 static const struct wl_shell_surface_listener shell_surface_listener = {
242 create_surface(struct window *window)
244 struct display *display = window->display;
247 window->surface = wl_compositor_create_surface(display->compositor);
248 window->shell_surface = wl_shell_get_shell_surface(display->shell,
251 wl_shell_surface_add_listener(window->shell_surface,
252 &shell_surface_listener, window);
254 if (window->fullscreen) {
255 window->configured = 0;
256 wl_shell_surface_set_fullscreen(window->shell_surface,
257 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
260 while (!window->configured)
261 wl_display_iterate(display->display, display->mask);
264 wl_shell_surface_set_toplevel(window->shell_surface);
267 wl_egl_window_create(window->surface,
268 window->geometry.width,
269 window->geometry.height);
270 window->egl_surface =
271 eglCreateWindowSurface(display->egl.dpy,
273 window->native, NULL);
275 ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
276 window->egl_surface, window->display->egl.ctx);
277 assert(ret == EGL_TRUE);
281 destroy_surface(struct window *window)
283 wl_egl_window_destroy(window->native);
285 wl_shell_surface_destroy(window->shell_surface);
286 wl_surface_destroy(window->surface);
288 if (window->callback)
289 wl_callback_destroy(window->callback);
292 static const struct wl_callback_listener frame_listener;
295 redraw(void *data, struct wl_callback *callback, uint32_t time)
297 struct window *window = data;
298 static const GLfloat verts[3][2] = {
303 static const GLfloat colors[3][3] = {
309 GLfloat rotation[4][4] = {
315 static const int32_t speed_div = 5;
316 static uint32_t start_time = 0;
321 angle = ((time-start_time) / speed_div) % 360 * M_PI / 180.0;
322 rotation[0][0] = cos(angle);
323 rotation[0][2] = sin(angle);
324 rotation[2][0] = -sin(angle);
325 rotation[2][2] = cos(angle);
327 glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE,
328 (GLfloat *) rotation);
330 glClearColor(0.0, 0.0, 0.0, 0.5);
331 glClear(GL_COLOR_BUFFER_BIT);
333 glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
334 glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors);
335 glEnableVertexAttribArray(window->gl.pos);
336 glEnableVertexAttribArray(window->gl.col);
338 glDrawArrays(GL_TRIANGLES, 0, 3);
340 glDisableVertexAttribArray(window->gl.pos);
341 glDisableVertexAttribArray(window->gl.col);
343 eglSwapBuffers(window->display->egl.dpy, window->egl_surface);
345 wl_callback_destroy(callback);
347 window->callback = wl_surface_frame(window->surface);
348 wl_callback_add_listener(window->callback, &frame_listener, window);
351 static const struct wl_callback_listener frame_listener = {
356 pointer_handle_enter(void *data, struct wl_pointer *pointer,
357 uint32_t serial, struct wl_surface *surface,
358 wl_fixed_t sx, wl_fixed_t sy)
360 struct display *display = data;
362 if (display->window->fullscreen)
363 wl_pointer_attach(pointer, serial, NULL, 0, 0);
367 pointer_handle_leave(void *data, struct wl_pointer *pointer,
368 uint32_t serial, struct wl_surface *surface)
373 pointer_handle_motion(void *data, struct wl_pointer *pointer,
374 uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
379 pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
380 uint32_t serial, uint32_t time, uint32_t button,
386 pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
387 uint32_t time, uint32_t axis, wl_fixed_t value)
391 static const struct wl_pointer_listener pointer_listener = {
392 pointer_handle_enter,
393 pointer_handle_leave,
394 pointer_handle_motion,
395 pointer_handle_button,
400 seat_handle_capabilities(void *data, struct wl_seat *seat,
401 enum wl_seat_capability caps)
403 struct display *d = data;
405 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !d->pointer) {
406 d->pointer = wl_seat_get_pointer(seat);
407 wl_pointer_add_listener(d->pointer, &pointer_listener, d);
408 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && d->pointer) {
409 wl_pointer_destroy(d->pointer);
414 static const struct wl_seat_listener seat_listener = {
415 seat_handle_capabilities,
419 display_handle_global(struct wl_display *display, uint32_t id,
420 const char *interface, uint32_t version, void *data)
422 struct display *d = data;
424 if (strcmp(interface, "wl_compositor") == 0) {
426 wl_display_bind(display, id, &wl_compositor_interface);
427 } else if (strcmp(interface, "wl_shell") == 0) {
428 d->shell = wl_display_bind(display, id, &wl_shell_interface);
429 } else if (strcmp(interface, "wl_seat") == 0) {
430 d->seat = wl_display_bind(d->display, id, &wl_seat_interface);
431 wl_seat_add_listener(d->seat, &seat_listener, d);
436 event_mask_update(uint32_t mask, void *data)
438 struct display *d = data;
445 static int running = 1;
448 signal_int(int signum)
454 main(int argc, char **argv)
456 struct sigaction sigint;
457 struct display display = { 0 };
458 struct window window = { 0 };
461 window.display = &display;
462 display.window = &window;
463 window.geometry.width = 250;
464 window.geometry.height = 250;
467 for (i = 1; i < argc; i++) {
468 if (strcmp("-f", argv[i]) == 0)
469 window.fullscreen = 1;
470 if (strcmp("-o", argv[i]) == 0)
474 display.display = wl_display_connect(NULL);
475 assert(display.display);
477 wl_display_add_global_listener(display.display,
478 display_handle_global, &display);
480 wl_display_get_fd(display.display, event_mask_update, &display);
481 wl_display_iterate(display.display, WL_DISPLAY_READABLE);
483 if (window.fullscreen)
486 init_egl(&display, alpha_size);
487 create_surface(&window);
490 sigint.sa_handler = signal_int;
491 sigemptyset(&sigint.sa_mask);
492 sigint.sa_flags = SA_RESETHAND;
493 sigaction(SIGINT, &sigint, NULL);
495 redraw(&window, NULL, 0);
498 wl_display_iterate(display.display, display.mask);
500 fprintf(stderr, "simple-egl exiting\n");
502 destroy_surface(&window);
506 wl_shell_destroy(display.shell);
508 if (display.compositor)
509 wl_compositor_destroy(display.compositor);
511 wl_display_flush(display.display);
512 wl_display_disconnect(display.display);