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