Send device name at connect time
[profile/ivi/weston-ivi-shell.git] / clients / gears.c
1 /*
2  * Copyright © 2008 Kristian Høgsberg
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 <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <math.h>
30 #include <time.h>
31 #include <cairo.h>
32 #include <glib.h>
33 #include <cairo-drm.h>
34
35 #define GL_GLEXT_PROTOTYPES
36 #define EGL_EGLEXT_PROTOTYPES
37 #include <GL/gl.h>
38 #include <EGL/egl.h>
39 #include <EGL/eglext.h>
40
41 #include "wayland-util.h"
42 #include "wayland-client.h"
43 #include "wayland-glib.h"
44
45 #include "window.h"
46
47 static const char gem_device[] = "/dev/dri/card0";
48 static const char socket_name[] = "\0wayland";
49
50 struct gears {
51         struct window *window;
52
53         struct display *d;
54         struct rectangle rectangle;
55
56         EGLDisplay display;
57         EGLContext context;
58         EGLImageKHR image;
59         int drm_fd;
60         int resized;
61         GLfloat angle;
62         cairo_surface_t *cairo_surface;
63
64         GLint gear_list[3];
65         GLuint fbo, color_rbo, depth_rbo;
66 };
67
68 struct gear_template {
69         GLfloat material[4];
70         GLfloat inner_radius;
71         GLfloat outer_radius;
72         GLfloat width;
73         GLint teeth;
74         GLfloat tooth_depth;
75 };
76
77 const static struct gear_template gear_templates[] = {
78         { { 0.8, 0.1, 0.0, 1.0 }, 1.0, 4.0, 1.0, 20, 0.7 },
79         { { 0.0, 0.8, 0.2, 1.0 }, 0.5, 2.0, 2.0, 10, 0.7 },
80         { { 0.2, 0.2, 1.0, 1.0 }, 1.3, 2.0, 0.5, 10, 0.7 }, 
81 };
82
83 static GLfloat light_pos[4] = {5.0, 5.0, 10.0, 0.0};
84
85 static void die(const char *msg)
86 {
87         fprintf(stderr, "%s", msg);
88         exit(EXIT_FAILURE);
89 }
90
91 static void
92 make_gear(const struct gear_template *t)
93 {
94         GLint i;
95         GLfloat r0, r1, r2;
96         GLfloat angle, da;
97         GLfloat u, v, len;
98
99         glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, t->material);
100
101         r0 = t->inner_radius;
102         r1 = t->outer_radius - t->tooth_depth / 2.0;
103         r2 = t->outer_radius + t->tooth_depth / 2.0;
104
105         da = 2.0 * M_PI / t->teeth / 4.0;
106
107         glShadeModel(GL_FLAT);
108
109         glNormal3f(0.0, 0.0, 1.0);
110
111         /* draw front face */
112         glBegin(GL_QUAD_STRIP);
113         for (i = 0; i <= t->teeth; i++) {
114                 angle = i * 2.0 * M_PI / t->teeth;
115                 glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
116                 glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
117                 if (i < t->teeth) {
118                         glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
119                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
120                 }
121         }
122         glEnd();
123
124         /* draw front sides of teeth */
125         glBegin(GL_QUADS);
126         da = 2.0 * M_PI / t->teeth / 4.0;
127         for (i = 0; i < t->teeth; i++) {
128                 angle = i * 2.0 * M_PI / t->teeth;
129
130                 glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
131                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5);
132                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5);
133                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
134         }
135         glEnd();
136
137         glNormal3f(0.0, 0.0, -1.0);
138
139         /* draw back face */
140         glBegin(GL_QUAD_STRIP);
141         for (i = 0; i <= t->teeth; i++) {
142                 angle = i * 2.0 * M_PI / t->teeth;
143                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
144                 glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
145                 if (i < t->teeth) {
146                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
147                         glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
148                 }
149         }
150         glEnd();
151
152         /* draw back sides of teeth */
153         glBegin(GL_QUADS);
154         da = 2.0 * M_PI / t->teeth / 4.0;
155         for (i = 0; i < t->teeth; i++) {
156                 angle = i * 2.0 * M_PI / t->teeth;
157
158                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
159                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5);
160                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5);
161                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
162         }
163         glEnd();
164
165         /* draw outward faces of teeth */
166         glBegin(GL_QUAD_STRIP);
167         for (i = 0; i < t->teeth; i++) {
168                 angle = i * 2.0 * M_PI / t->teeth;
169
170                 glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
171                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
172                 u = r2 * cos(angle + da) - r1 * cos(angle);
173                 v = r2 * sin(angle + da) - r1 * sin(angle);
174                 len = sqrt(u * u + v * v);
175                 u /= len;
176                 v /= len;
177                 glNormal3f(v, -u, 0.0);
178                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5);
179                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5);
180                 glNormal3f(cos(angle), sin(angle), 0.0);
181                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5);
182                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5);
183                 u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
184                 v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
185                 glNormal3f(v, -u, 0.0);
186                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
187                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
188                 glNormal3f(cos(angle), sin(angle), 0.0);
189         }
190
191         glVertex3f(r1 * cos(0), r1 * sin(0), t->width * 0.5);
192         glVertex3f(r1 * cos(0), r1 * sin(0), -t->width * 0.5);
193
194         glEnd();
195
196         glShadeModel(GL_SMOOTH);
197
198         /* draw inside radius cylinder */
199         glBegin(GL_QUAD_STRIP);
200         for (i = 0; i <= t->teeth; i++) {
201                 angle = i * 2.0 * M_PI / t->teeth;
202                 glNormal3f(-cos(angle), -sin(angle), 0.0);
203                 glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
204                 glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
205         }
206         glEnd();
207 }
208
209 static void
210 draw_gears(struct gears *gears)
211 {
212         GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
213
214         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
215
216         glPushMatrix();
217
218         glTranslatef(0.0, 0.0, -50);
219
220         glRotatef(view_rotx, 1.0, 0.0, 0.0);
221         glRotatef(view_roty, 0.0, 1.0, 0.0);
222         glRotatef(view_rotz, 0.0, 0.0, 1.0);
223
224         glPushMatrix();
225         glTranslatef(-3.0, -2.0, 0.0);
226         glRotatef(gears->angle, 0.0, 0.0, 1.0);
227         glCallList(gears->gear_list[0]);
228         glPopMatrix();
229
230         glPushMatrix();
231         glTranslatef(3.1, -2.0, 0.0);
232         glRotatef(-2.0 * gears->angle - 9.0, 0.0, 0.0, 1.0);
233         glCallList(gears->gear_list[1]);
234         glPopMatrix();
235
236         glPushMatrix();
237         glTranslatef(-3.1, 4.2, 0.0);
238         glRotatef(-2.0 * gears->angle - 25.0, 0.0, 0.0, 1.0);
239         glCallList(gears->gear_list[2]);
240         glPopMatrix();
241
242         glPopMatrix();
243
244         glFlush();
245 }
246
247 static void
248 resize_window(struct gears *gears)
249 {
250         EGLint attribs[] = {
251                 EGL_WIDTH,              0,
252                 EGL_HEIGHT,             0,
253                 EGL_IMAGE_FORMAT_MESA,  EGL_IMAGE_FORMAT_ARGB8888_MESA,
254                 EGL_IMAGE_USE_MESA,     EGL_IMAGE_USE_SHARE_MESA |
255                                         EGL_IMAGE_USE_SCANOUT_MESA,
256                 EGL_NONE
257         };
258
259         /* Constrain child size to be square and at least 300x300 */
260         window_get_child_rectangle(gears->window, &gears->rectangle);
261         if (gears->rectangle.width > gears->rectangle.height)
262                 gears->rectangle.height = gears->rectangle.width;
263         else
264                 gears->rectangle.width = gears->rectangle.height;
265         if (gears->rectangle.width < 300) {
266                 gears->rectangle.width = 300;
267                 gears->rectangle.height = 300;
268         }
269         window_set_child_size(gears->window, &gears->rectangle);
270
271         window_draw(gears->window);
272
273         if (gears->image)
274                 eglDestroyImageKHR(gears->display, gears->image);
275         attribs[1] = gears->rectangle.width;
276         attribs[3] = gears->rectangle.height;
277         gears->image = eglCreateDRMImageMESA(gears->display, attribs);
278
279         glBindRenderbuffer(GL_RENDERBUFFER_EXT, gears->color_rbo);
280         glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, gears->image);
281
282         glBindRenderbuffer(GL_RENDERBUFFER_EXT, gears->depth_rbo);
283         glRenderbufferStorage(GL_RENDERBUFFER_EXT,
284                               GL_DEPTH_COMPONENT,
285                               gears->rectangle.width,
286                               gears->rectangle.height);
287
288         glViewport(0, 0, gears->rectangle.width, gears->rectangle.height);
289
290         gears->resized = 0;
291 }
292
293 static void
294 resize_handler(struct window *window, void *data)
295 {
296         struct gears *gears = data;
297
298         /* Right now, resizing the window from the per-frame callback
299          * is fine, since the window drawing code is so slow that we
300          * can't draw more than one window per frame anyway.  However,
301          * once we implement faster resizing, this will show lag
302          * between pointer motion and window size even if resizing is
303          * fast.  We need to keep processing motion events and posting
304          * new frames as fast as possible so when the server
305          * composites the next frame it will have the most recent size
306          * possible, like what we do for window moves. */
307
308         gears->resized = 1;
309 }
310
311 static void
312 keyboard_focus_handler(struct window *window,
313                        struct wl_input_device *device, void *data)
314 {
315         struct gears *gears = data;
316
317         gears->resized = 1;
318 }
319
320 static void
321 acknowledge_handler(struct window *window,
322                     uint32_t key, uint32_t frame,
323                     void *data)
324 {
325         struct gears *gears = data;
326
327         if (key == 10) {
328                 if (gears->resized)
329                         resize_window(gears);
330
331                 draw_gears(gears);
332         }
333 }
334
335 static void
336 frame_handler(struct window *window,
337               uint32_t frame, uint32_t timestamp, void *data)
338 {
339         struct gears *gears = data;
340
341         window_copy_image(gears->window, &gears->rectangle, gears->image);
342
343         window_commit(gears->window, 10);
344
345         gears->angle = (GLfloat) (timestamp % 8192) * 360 / 8192.0;
346 }
347
348 static struct gears *
349 gears_create(struct display *display)
350 {
351         const int x = 200, y = 200, width = 450, height = 500;
352         EGLint major, minor, count;
353         EGLConfig config;
354         struct gears *gears;
355         int i;
356
357         static const EGLint config_attribs[] = {
358                 EGL_SURFACE_TYPE,               0,
359                 EGL_NO_SURFACE_CAPABLE_MESA,    EGL_OPENGL_BIT,
360                 EGL_RENDERABLE_TYPE,            EGL_OPENGL_BIT,
361                 EGL_NONE
362         };
363
364         gears = malloc(sizeof *gears);
365         memset(gears, 0, sizeof *gears);
366         gears->d = display;
367         gears->window = window_create(display, "Wayland Gears",
368                                       x, y, width, height);
369
370         gears->display = display_get_egl_display(gears->d);
371         if (gears->display == NULL)
372                 die("failed to create egl display\n");
373
374         if (!eglInitialize(gears->display, &major, &minor))
375                 die("failed to initialize display\n");
376
377         if (!eglChooseConfig(gears->display, config_attribs, &config, 1, &count) ||
378             count == 0)
379                 die("eglChooseConfig() failed\n");
380
381         eglBindAPI(EGL_OPENGL_API);
382
383         gears->context = eglCreateContext(gears->display, config, EGL_NO_CONTEXT, NULL);
384         if (gears->context == NULL)
385                 die("failed to create context\n");
386
387         if (!eglMakeCurrent(gears->display, NULL, NULL, gears->context))
388                 die("faile to make context current\n");
389
390         glGenFramebuffers(1, &gears->fbo);
391         glBindFramebuffer(GL_FRAMEBUFFER_EXT, gears->fbo);
392
393         glGenRenderbuffers(1, &gears->color_rbo);
394         glBindRenderbuffer(GL_RENDERBUFFER_EXT, gears->color_rbo);
395         glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER_EXT,
396                                   GL_COLOR_ATTACHMENT0_EXT,
397                                   GL_RENDERBUFFER_EXT,
398                                   gears->color_rbo);
399
400         glGenRenderbuffers(1, &gears->depth_rbo);
401         glBindRenderbuffer(GL_RENDERBUFFER_EXT, gears->depth_rbo);
402         glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER_EXT,
403                                   GL_DEPTH_ATTACHMENT_EXT,
404                                   GL_RENDERBUFFER_EXT,
405                                   gears->depth_rbo);
406         for (i = 0; i < 3; i++) {
407                 gears->gear_list[i] = glGenLists(1);
408                 glNewList(gears->gear_list[i], GL_COMPILE);
409                 make_gear(&gear_templates[i]);
410                 glEndList();
411         }
412
413         glEnable(GL_NORMALIZE);
414
415         glMatrixMode(GL_PROJECTION);
416         glLoadIdentity();
417         glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 200.0);
418         glMatrixMode(GL_MODELVIEW);
419
420         glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
421         glEnable(GL_CULL_FACE);
422         glEnable(GL_LIGHTING);
423         glEnable(GL_LIGHT0);
424         glEnable(GL_DEPTH_TEST);
425         glClearColor(0, 0, 0, 0.92);
426
427         if (glCheckFramebufferStatus (GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE)
428                 fprintf(stderr, "framebuffer incomplete\n");
429
430         resize_window(gears);
431         draw_gears(gears);
432         frame_handler(gears->window, 0, 0, gears);
433
434         window_set_resize_handler(gears->window, resize_handler, gears);
435         window_set_keyboard_focus_handler(gears->window, keyboard_focus_handler, gears);
436         window_set_acknowledge_handler(gears->window, acknowledge_handler, gears);
437         window_set_frame_handler(gears->window, frame_handler, gears);
438
439         return gears;
440 }
441
442 int main(int argc, char *argv[])
443 {
444         struct display *d;
445         struct gears *gears;
446
447         d = display_create(&argc, &argv, NULL);
448         gears = gears_create(d);
449         display_run(d);
450
451         return 0;
452 }