weston-editor --help works
[profile/ivi/weston-ivi-shell.git] / clients / nested-client.c
1 /*
2  * Copyright © 2013 Intel Corporation
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 "config.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <wayland-egl.h>
30 #include <wayland-cursor.h>
31
32 #include <GLES2/gl2.h>
33 #include <EGL/egl.h>
34
35 struct window;
36 struct seat;
37
38 struct nested_client {
39         struct wl_display *display;
40         struct wl_registry *registry;
41         struct wl_compositor *compositor;
42
43         EGLDisplay egl_display;
44         EGLContext egl_context;
45         EGLConfig egl_config;
46         EGLSurface egl_surface;
47         struct program *color_program;
48
49         GLuint vert, frag, program;
50         GLuint rotation;
51         GLuint pos;
52         GLuint col;
53
54         struct wl_surface *surface;
55         struct wl_egl_window *native;
56         int width, height;
57 };
58
59 #define POS 0
60 #define COL 1
61
62 static GLuint
63 create_shader(const char *source, GLenum shader_type)
64 {
65         GLuint shader;
66         GLint status;
67
68         shader = glCreateShader(shader_type);
69         if (shader == 0)
70                 return 0;
71
72         glShaderSource(shader, 1, (const char **) &source, NULL);
73         glCompileShader(shader);
74
75         glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
76         if (!status) {
77                 char log[1000];
78                 GLsizei len;
79                 glGetShaderInfoLog(shader, 1000, &len, log);
80                 fprintf(stderr, "Error: compiling %s: %*s\n",
81                         shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
82                         len, log);
83                 return 0;
84         }
85
86         return shader;
87 }
88
89 static void
90 create_program(struct nested_client *client,
91                const char *vert, const char *frag)
92 {
93         GLint status;
94
95         client->vert = create_shader(vert, GL_VERTEX_SHADER);
96         client->frag = create_shader(frag, GL_FRAGMENT_SHADER);
97
98         client->program = glCreateProgram();
99         glAttachShader(client->program, client->frag);
100         glAttachShader(client->program, client->vert);
101         glBindAttribLocation(client->program, POS, "pos");
102         glBindAttribLocation(client->program, COL, "color");
103         glLinkProgram(client->program);
104
105         glGetProgramiv(client->program, GL_LINK_STATUS, &status);
106         if (!status) {
107                 char log[1000];
108                 GLsizei len;
109                 glGetProgramInfoLog(client->program, 1000, &len, log);
110                 fprintf(stderr, "Error: linking:\n%*s\n", len, log);
111                 exit(1);
112         }
113
114         client->rotation =
115                 glGetUniformLocation(client->program, "rotation");
116 }
117
118 static const char vertex_shader_text[] =
119         "uniform mat4 rotation;\n"
120         "attribute vec4 pos;\n"
121         "attribute vec4 color;\n"
122         "varying vec4 v_color;\n"
123         "void main() {\n"
124         "  gl_Position = rotation * pos;\n"
125         "  v_color = color;\n"
126         "}\n";
127
128 static const char color_fragment_shader_text[] =
129         "precision mediump float;\n"
130         "varying vec4 v_color;\n"
131         "void main() {\n"
132         "  gl_FragColor = v_color;\n"
133         "}\n";
134
135 static void
136 render_triangle(struct nested_client *client, uint32_t time)
137 {
138         static const GLfloat verts[3][2] = {
139                 { -0.5, -0.5 },
140                 {  0.5, -0.5 },
141                 {  0,    0.5 }
142         };
143         static const GLfloat colors[3][3] = {
144                 { 1, 0, 0 },
145                 { 0, 1, 0 },
146                 { 0, 0, 1 }
147         };
148         GLfloat angle;
149         GLfloat rotation[4][4] = {
150                 { 1, 0, 0, 0 },
151                 { 0, 1, 0, 0 },
152                 { 0, 0, 1, 0 },
153                 { 0, 0, 0, 1 }
154         };
155         static const int32_t speed_div = 5;
156         static uint32_t start_time = 0;
157
158         if (client->program == 0)
159                 create_program(client, vertex_shader_text,
160                                color_fragment_shader_text);
161
162         if (start_time == 0)
163                 start_time = time;
164
165         angle = ((time - start_time) / speed_div) % 360 * M_PI / 180.0;
166         rotation[0][0] =  cos(angle);
167         rotation[0][2] =  sin(angle);
168         rotation[2][0] = -sin(angle);
169         rotation[2][2] =  cos(angle);
170
171         glClearColor(0.4, 0.4, 0.4, 1.0);
172         glClear(GL_COLOR_BUFFER_BIT);
173
174         glUseProgram(client->program);
175
176         glViewport(0, 0, client->width, client->height);
177
178         glUniformMatrix4fv(client->rotation, 1, GL_FALSE,
179                            (GLfloat *) rotation);
180
181         glVertexAttribPointer(POS, 2, GL_FLOAT, GL_FALSE, 0, verts);
182         glVertexAttribPointer(COL, 3, GL_FLOAT, GL_FALSE, 0, colors);
183         glEnableVertexAttribArray(POS);
184         glEnableVertexAttribArray(COL);
185
186         glDrawArrays(GL_TRIANGLES, 0, 3);
187
188         glDisableVertexAttribArray(POS);
189         glDisableVertexAttribArray(COL);
190
191         glFlush();
192 }
193
194 static void
195 frame_callback(void *data, struct wl_callback *callback, uint32_t time);
196
197 static const struct wl_callback_listener frame_listener = {
198         frame_callback
199 };
200
201 static void
202 frame_callback(void *data, struct wl_callback *callback, uint32_t time)
203 {
204         struct nested_client *client = data;
205
206         if (callback)
207                 wl_callback_destroy(callback);
208
209         callback = wl_surface_frame(client->surface);
210         wl_callback_add_listener(callback, &frame_listener, client);
211
212         render_triangle(client, time);
213
214         eglSwapBuffers(client->egl_display, client->egl_surface);
215 }
216
217 static void
218 registry_handle_global(void *data, struct wl_registry *registry,
219                        uint32_t name, const char *interface, uint32_t version)
220 {
221         struct nested_client *client = data;
222
223         if (strcmp(interface, "wl_compositor") == 0) {
224                 client->compositor =
225                         wl_registry_bind(registry, name,
226                                          &wl_compositor_interface, 1);
227         }
228 }
229
230 static void
231 registry_handle_global_remove(void *data, struct wl_registry *registry,
232                               uint32_t name)
233 {
234 }
235
236 static const struct wl_registry_listener registry_listener = {
237         registry_handle_global,
238         registry_handle_global_remove
239 };
240
241 static struct nested_client *
242 nested_client_create(void)
243 {
244         static const EGLint context_attribs[] = {
245                 EGL_CONTEXT_CLIENT_VERSION, 2,
246                 EGL_NONE
247         };
248
249         static const EGLint config_attribs[] = {
250                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
251                 EGL_RED_SIZE, 1,
252                 EGL_GREEN_SIZE, 1,
253                 EGL_BLUE_SIZE, 1,
254                 EGL_ALPHA_SIZE, 1,
255                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
256                 EGL_NONE
257         };
258
259         EGLint major, minor, n;
260         EGLBoolean ret;
261
262         struct nested_client *client;
263
264         client = malloc(sizeof *client);
265         if (client == NULL)
266                 return NULL;
267
268         client->width  = 250;
269         client->height = 250;
270
271         client->display = wl_display_connect(NULL);
272
273         client->registry = wl_display_get_registry(client->display);
274         wl_registry_add_listener(client->registry,
275                                  &registry_listener, client);
276
277         /* get globals */
278         wl_display_roundtrip(client->display);
279
280         client->egl_display = eglGetDisplay(client->display);
281         if (client->egl_display == NULL)
282                 return NULL;
283
284         ret = eglInitialize(client->egl_display, &major, &minor);
285         if (!ret)
286                 return NULL;
287         ret = eglBindAPI(EGL_OPENGL_ES_API);
288         if (!ret)
289                 return NULL;
290
291         ret = eglChooseConfig(client->egl_display, config_attribs,
292                               &client->egl_config, 1, &n);
293         if (!ret || n != 1)
294                 return NULL;
295
296         client->egl_context = eglCreateContext(client->egl_display,
297                                                client->egl_config,
298                                                EGL_NO_CONTEXT,
299                                                context_attribs);
300         if (!client->egl_context)
301                 return NULL;
302
303         client->surface = wl_compositor_create_surface(client->compositor);
304
305         client->native = wl_egl_window_create(client->surface,
306                                               client->width, client->height);
307
308         client->egl_surface =
309                 eglCreateWindowSurface(client->egl_display,
310                                        client->egl_config,
311                                        client->native, NULL);
312
313         eglMakeCurrent(client->egl_display, client->egl_surface,
314                        client->egl_surface, client->egl_context);
315
316         wl_egl_window_resize(client->native,
317                              client->width, client->height, 0, 0);
318
319         frame_callback(client, NULL, 0);
320
321         return client;
322 }
323
324 static void
325 nested_client_destroy(struct nested_client *client)
326 {
327         eglMakeCurrent(client->egl_display,
328                        EGL_NO_SURFACE, EGL_NO_SURFACE,
329                        EGL_NO_CONTEXT);
330
331         wl_egl_window_destroy(client->native);
332
333         wl_surface_destroy(client->surface);
334
335         if (client->compositor)
336                 wl_compositor_destroy(client->compositor);
337
338         wl_registry_destroy(client->registry);
339         wl_display_flush(client->display);
340         wl_display_disconnect(client->display);
341 }
342
343 int
344 main(int argc, char **argv)
345 {
346         struct nested_client *client;
347         int ret = 0;
348
349         if (getenv("WAYLAND_SOCKET") == NULL) {
350                 fprintf(stderr,
351                         "must be run by nested, don't run standalone\n");
352                 return EXIT_FAILURE;
353         }
354
355         client = nested_client_create();
356         if (client == NULL)
357                 return EXIT_FAILURE;
358
359         while (ret != -1)
360                 ret = wl_display_dispatch(client->display);
361
362         nested_client_destroy(client);
363
364         return 0;
365 }