Fix new gcc 4.6 warnings
[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 "config.h"
24
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <math.h>
32 #include <time.h>
33 #include <cairo.h>
34 #include <glib.h>
35
36 #define GL_GLEXT_PROTOTYPES
37 #define EGL_EGLEXT_PROTOTYPES
38 #include <GL/gl.h>
39 #include <EGL/egl.h>
40 #include <EGL/eglext.h>
41
42 #include "wayland-util.h"
43 #include "wayland-client.h"
44 #include "wayland-glib.h"
45
46 #include "window.h"
47
48 struct gears {
49         struct window *window;
50
51         struct display *d;
52
53         EGLDisplay display;
54         EGLContext context;
55         int drm_fd;
56         GLfloat angle;
57         cairo_surface_t *cairo_surface;
58
59         GLint gear_list[3];
60         GLuint fbo, color_rbo[2], depth_rbo;
61         cairo_surface_t *surface[2];
62         int current;
63 };
64
65 struct gear_template {
66         GLfloat material[4];
67         GLfloat inner_radius;
68         GLfloat outer_radius;
69         GLfloat width;
70         GLint teeth;
71         GLfloat tooth_depth;
72 };
73
74 const static struct gear_template gear_templates[] = {
75         { { 0.8, 0.1, 0.0, 1.0 }, 1.0, 4.0, 1.0, 20, 0.7 },
76         { { 0.0, 0.8, 0.2, 1.0 }, 0.5, 2.0, 2.0, 10, 0.7 },
77         { { 0.2, 0.2, 1.0, 1.0 }, 1.3, 2.0, 0.5, 10, 0.7 }, 
78 };
79
80 static GLfloat light_pos[4] = {5.0, 5.0, 10.0, 0.0};
81
82 static void die(const char *msg)
83 {
84         fprintf(stderr, "%s", msg);
85         exit(EXIT_FAILURE);
86 }
87
88 static void
89 make_gear(const struct gear_template *t)
90 {
91         GLint i;
92         GLfloat r0, r1, r2;
93         GLfloat angle, da;
94         GLfloat u, v, len;
95
96         glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, t->material);
97
98         r0 = t->inner_radius;
99         r1 = t->outer_radius - t->tooth_depth / 2.0;
100         r2 = t->outer_radius + t->tooth_depth / 2.0;
101
102         da = 2.0 * M_PI / t->teeth / 4.0;
103
104         glShadeModel(GL_FLAT);
105
106         glNormal3f(0.0, 0.0, 1.0);
107
108         /* draw front face */
109         glBegin(GL_QUAD_STRIP);
110         for (i = 0; i <= t->teeth; i++) {
111                 angle = i * 2.0 * M_PI / t->teeth;
112                 glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
113                 glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
114                 if (i < t->teeth) {
115                         glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
116                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
117                 }
118         }
119         glEnd();
120
121         /* draw front sides of teeth */
122         glBegin(GL_QUADS);
123         da = 2.0 * M_PI / t->teeth / 4.0;
124         for (i = 0; i < t->teeth; i++) {
125                 angle = i * 2.0 * M_PI / t->teeth;
126
127                 glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
128                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5);
129                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5);
130                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
131         }
132         glEnd();
133
134         glNormal3f(0.0, 0.0, -1.0);
135
136         /* draw back face */
137         glBegin(GL_QUAD_STRIP);
138         for (i = 0; i <= t->teeth; i++) {
139                 angle = i * 2.0 * M_PI / t->teeth;
140                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
141                 glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
142                 if (i < t->teeth) {
143                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
144                         glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
145                 }
146         }
147         glEnd();
148
149         /* draw back sides of teeth */
150         glBegin(GL_QUADS);
151         da = 2.0 * M_PI / t->teeth / 4.0;
152         for (i = 0; i < t->teeth; i++) {
153                 angle = i * 2.0 * M_PI / t->teeth;
154
155                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
156                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5);
157                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5);
158                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
159         }
160         glEnd();
161
162         /* draw outward faces of teeth */
163         glBegin(GL_QUAD_STRIP);
164         for (i = 0; i < t->teeth; i++) {
165                 angle = i * 2.0 * M_PI / t->teeth;
166
167                 glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
168                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
169                 u = r2 * cos(angle + da) - r1 * cos(angle);
170                 v = r2 * sin(angle + da) - r1 * sin(angle);
171                 len = sqrt(u * u + v * v);
172                 u /= len;
173                 v /= len;
174                 glNormal3f(v, -u, 0.0);
175                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5);
176                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5);
177                 glNormal3f(cos(angle), sin(angle), 0.0);
178                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5);
179                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5);
180                 u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
181                 v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
182                 glNormal3f(v, -u, 0.0);
183                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
184                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
185                 glNormal3f(cos(angle), sin(angle), 0.0);
186         }
187
188         glVertex3f(r1 * cos(0), r1 * sin(0), t->width * 0.5);
189         glVertex3f(r1 * cos(0), r1 * sin(0), -t->width * 0.5);
190
191         glEnd();
192
193         glShadeModel(GL_SMOOTH);
194
195         /* draw inside radius cylinder */
196         glBegin(GL_QUAD_STRIP);
197         for (i = 0; i <= t->teeth; i++) {
198                 angle = i * 2.0 * M_PI / t->teeth;
199                 glNormal3f(-cos(angle), -sin(angle), 0.0);
200                 glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
201                 glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
202         }
203         glEnd();
204 }
205
206 static void
207 allocate_buffer(struct gears *gears)
208 {
209         EGLImageKHR image;
210         struct rectangle allocation;
211
212         window_draw(gears->window);
213
214         gears->surface[gears->current] = window_get_surface(gears->window);
215 #ifdef HAVE_CAIRO_EGL
216         image = display_get_image_for_drm_surface(gears->display,
217                                                   gears->surface[gears->current]);
218 #else /* XXX: hack to make Wayland compile, even if this example doesn't run */
219         die("gears cannot allocate buffer: it was compiled without cairo-gl\n");
220         return;
221 #endif
222         if (!eglMakeCurrent(gears->display, NULL, NULL, gears->context))
223                 die("faile to make context current\n");
224
225         glBindRenderbuffer(GL_RENDERBUFFER_EXT,
226                            gears->color_rbo[gears->current]);
227         glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, image);
228
229         glBindRenderbuffer(GL_RENDERBUFFER_EXT, gears->depth_rbo);
230         window_get_child_allocation(gears->window, &allocation);
231         glRenderbufferStorage(GL_RENDERBUFFER_EXT,
232                               GL_DEPTH_COMPONENT,
233                               allocation.width + 20 + 32,
234                               allocation.height + 60 + 32);
235 }
236
237 static void
238 draw_gears(struct gears *gears)
239 {
240         GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
241         struct rectangle allocation;
242
243         if (gears->surface[gears->current] == NULL)
244                 allocate_buffer(gears);
245
246         glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER_EXT,
247                                   GL_COLOR_ATTACHMENT0_EXT,
248                                   GL_RENDERBUFFER_EXT,
249                                   gears->color_rbo[gears->current]);
250
251         window_get_child_allocation(gears->window, &allocation);
252         glViewport(allocation.x, allocation.y,
253                    allocation.width, allocation.height);
254         glScissor(allocation.x, allocation.y,
255                    allocation.width, allocation.height);
256
257         glEnable(GL_SCISSOR_TEST);
258         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
259
260         glPushMatrix();
261
262         glTranslatef(0.0, 0.0, -50);
263
264         glRotatef(view_rotx, 1.0, 0.0, 0.0);
265         glRotatef(view_roty, 0.0, 1.0, 0.0);
266         glRotatef(view_rotz, 0.0, 0.0, 1.0);
267
268         glPushMatrix();
269         glTranslatef(-3.0, -2.0, 0.0);
270         glRotatef(gears->angle, 0.0, 0.0, 1.0);
271         glCallList(gears->gear_list[0]);
272         glPopMatrix();
273
274         glPushMatrix();
275         glTranslatef(3.1, -2.0, 0.0);
276         glRotatef(-2.0 * gears->angle - 9.0, 0.0, 0.0, 1.0);
277         glCallList(gears->gear_list[1]);
278         glPopMatrix();
279
280         glPushMatrix();
281         glTranslatef(-3.1, 4.2, 0.0);
282         glRotatef(-2.0 * gears->angle - 25.0, 0.0, 0.0, 1.0);
283         glCallList(gears->gear_list[2]);
284         glPopMatrix();
285
286         glPopMatrix();
287
288         glFlush();
289
290         window_set_surface(gears->window, gears->surface[gears->current]);
291         window_flush(gears->window);
292 }
293
294 static void
295 resize_handler(struct window *window,
296                int32_t width, int32_t height, void *data)
297 {
298         struct gears *gears = data;
299
300         cairo_surface_destroy(gears->surface[0]);
301         gears->surface[0] = NULL;
302         cairo_surface_destroy(gears->surface[1]);
303         gears->surface[1] = NULL;
304
305         /* Constrain child size to be square and at least 300x300 */
306         if (width > height)
307                 height = width;
308         else
309                 width = height;
310         if (width < 300) {
311                 width = 300;
312                 height = 300;
313         }
314
315         window_set_child_size(gears->window, width, height);
316 }
317
318 static void
319 keyboard_focus_handler(struct window *window,
320                        struct input *device, void *data)
321 {
322         struct gears *gears = data;
323         struct rectangle allocation;
324
325         window_get_child_allocation(gears->window, &allocation);
326         resize_handler(window, allocation.width, allocation.height, gears);
327 }
328
329 static void
330 redraw_handler(struct window *window, void *data)
331 {
332         struct gears *gears = data;
333
334         draw_gears(gears);
335 }
336
337 static void
338 frame_callback(void *data, uint32_t time)
339 {
340         struct gears *gears = data;
341
342         gears->current = 1 - gears->current;
343
344         gears->angle = (GLfloat) (time % 8192) * 360 / 8192.0;
345
346         window_schedule_redraw(gears->window);
347         wl_display_frame_callback(display_get_display(gears->d),
348                                   frame_callback, gears);
349 }
350
351 static struct gears *
352 gears_create(struct display *display)
353 {
354         const int width = 450, height = 500;
355         struct gears *gears;
356         int i;
357
358         gears = malloc(sizeof *gears);
359         memset(gears, 0, sizeof *gears);
360         gears->d = display;
361         gears->window = window_create(display, width, height);
362         window_set_title(gears->window, "Wayland Gears");
363
364         gears->display = display_get_egl_display(gears->d);
365         if (gears->display == NULL)
366                 die("failed to create egl display\n");
367
368         eglBindAPI(EGL_OPENGL_API);
369
370         gears->context = eglCreateContext(gears->display,
371                                           NULL, EGL_NO_CONTEXT, NULL);
372         if (gears->context == NULL)
373                 die("failed to create context\n");
374
375         if (!eglMakeCurrent(gears->display, NULL, NULL, gears->context))
376                 die("faile to make context current\n");
377
378         glGenFramebuffers(1, &gears->fbo);
379         glBindFramebuffer(GL_FRAMEBUFFER_EXT, gears->fbo);
380
381         glGenRenderbuffers(2, gears->color_rbo);
382         glGenRenderbuffers(1, &gears->depth_rbo);
383         glBindRenderbuffer(GL_RENDERBUFFER_EXT, gears->depth_rbo);
384         glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER_EXT,
385                                   GL_DEPTH_ATTACHMENT_EXT,
386                                   GL_RENDERBUFFER_EXT,
387                                   gears->depth_rbo);
388         for (i = 0; i < 3; i++) {
389                 gears->gear_list[i] = glGenLists(1);
390                 glNewList(gears->gear_list[i], GL_COMPILE);
391                 make_gear(&gear_templates[i]);
392                 glEndList();
393         }
394
395         glEnable(GL_NORMALIZE);
396
397         glMatrixMode(GL_PROJECTION);
398         glLoadIdentity();
399         glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 200.0);
400         glMatrixMode(GL_MODELVIEW);
401
402         glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
403         glEnable(GL_CULL_FACE);
404         glEnable(GL_LIGHTING);
405         glEnable(GL_LIGHT0);
406         glEnable(GL_DEPTH_TEST);
407         glClearColor(0, 0, 0, 0.92);
408
409         window_set_user_data(gears->window, gears);
410         window_set_resize_handler(gears->window, resize_handler);
411         window_set_keyboard_focus_handler(gears->window, keyboard_focus_handler);
412         window_set_redraw_handler(gears->window, redraw_handler);
413
414         draw_gears(gears);
415         wl_display_frame_callback(display_get_display(gears->d),
416                                   frame_callback, gears);
417
418         return gears;
419 }
420
421 int main(int argc, char *argv[])
422 {
423         struct display *d;
424
425         d = display_create(&argc, &argv, NULL);
426         if (d == NULL) {
427                 fprintf(stderr, "failed to create display: %m\n");
428                 return -1;
429         }
430         gears_create(d);
431         display_run(d);
432
433         return 0;
434 }