compositor-x11: Rename the output make to "weston-X11"
[platform/upstream/weston.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 <stdbool.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <math.h>
31 #include <time.h>
32
33 #include <GL/gl.h>
34 #include <EGL/egl.h>
35 #include <EGL/eglext.h>
36
37 #include <linux/input.h>
38 #include <wayland-client.h>
39
40 #include "window.h"
41
42 struct gears {
43         struct window *window;
44         struct widget *widget;
45
46         struct display *d;
47
48         EGLDisplay display;
49         EGLDisplay config;
50         EGLContext context;
51         GLfloat angle;
52
53         struct {
54                 GLfloat rotx;
55                 GLfloat roty;
56         } view;
57
58         int button_down;
59         int last_x, last_y;
60
61         GLint gear_list[3];
62         int fullscreen;
63         int frames;
64         uint32_t last_fps;
65 };
66
67 struct gear_template {
68         GLfloat material[4];
69         GLfloat inner_radius;
70         GLfloat outer_radius;
71         GLfloat width;
72         GLint teeth;
73         GLfloat tooth_depth;
74 };
75
76 static const struct gear_template gear_templates[] = {
77         { { 0.8, 0.1, 0.0, 1.0 }, 1.0, 4.0, 1.0, 20, 0.7 },
78         { { 0.0, 0.8, 0.2, 1.0 }, 0.5, 2.0, 2.0, 10, 0.7 },
79         { { 0.2, 0.2, 1.0, 1.0 }, 1.3, 2.0, 0.5, 10, 0.7 }, 
80 };
81
82 static GLfloat light_pos[4] = {5.0, 5.0, 10.0, 0.0};
83
84 static void die(const char *msg)
85 {
86         fprintf(stderr, "%s", msg);
87         exit(EXIT_FAILURE);
88 }
89
90 static void
91 make_gear(const struct gear_template *t)
92 {
93         GLint i;
94         GLfloat r0, r1, r2;
95         GLfloat angle, da;
96         GLfloat u, v, len;
97
98         glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, t->material);
99
100         r0 = t->inner_radius;
101         r1 = t->outer_radius - t->tooth_depth / 2.0;
102         r2 = t->outer_radius + t->tooth_depth / 2.0;
103
104         da = 2.0 * M_PI / t->teeth / 4.0;
105
106         glShadeModel(GL_FLAT);
107
108         glNormal3f(0.0, 0.0, 1.0);
109
110         /* draw front face */
111         glBegin(GL_QUAD_STRIP);
112         for (i = 0; i <= t->teeth; i++) {
113                 angle = i * 2.0 * M_PI / t->teeth;
114                 glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
115                 glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
116                 if (i < t->teeth) {
117                         glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
118                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
119                 }
120         }
121         glEnd();
122
123         /* draw front sides of teeth */
124         glBegin(GL_QUADS);
125         da = 2.0 * M_PI / t->teeth / 4.0;
126         for (i = 0; i < t->teeth; i++) {
127                 angle = i * 2.0 * M_PI / t->teeth;
128
129                 glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
130                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5);
131                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5);
132                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
133         }
134         glEnd();
135
136         glNormal3f(0.0, 0.0, -1.0);
137
138         /* draw back face */
139         glBegin(GL_QUAD_STRIP);
140         for (i = 0; i <= t->teeth; i++) {
141                 angle = i * 2.0 * M_PI / t->teeth;
142                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
143                 glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
144                 if (i < t->teeth) {
145                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
146                         glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
147                 }
148         }
149         glEnd();
150
151         /* draw back sides of teeth */
152         glBegin(GL_QUADS);
153         da = 2.0 * M_PI / t->teeth / 4.0;
154         for (i = 0; i < t->teeth; i++) {
155                 angle = i * 2.0 * M_PI / t->teeth;
156
157                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
158                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5);
159                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5);
160                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
161         }
162         glEnd();
163
164         /* draw outward faces of teeth */
165         glBegin(GL_QUAD_STRIP);
166         for (i = 0; i < t->teeth; i++) {
167                 angle = i * 2.0 * M_PI / t->teeth;
168
169                 glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
170                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
171                 u = r2 * cos(angle + da) - r1 * cos(angle);
172                 v = r2 * sin(angle + da) - r1 * sin(angle);
173                 len = sqrt(u * u + v * v);
174                 u /= len;
175                 v /= len;
176                 glNormal3f(v, -u, 0.0);
177                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5);
178                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5);
179                 glNormal3f(cos(angle), sin(angle), 0.0);
180                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5);
181                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5);
182                 u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
183                 v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
184                 glNormal3f(v, -u, 0.0);
185                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
186                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
187                 glNormal3f(cos(angle), sin(angle), 0.0);
188         }
189
190         glVertex3f(r1 * cos(0), r1 * sin(0), t->width * 0.5);
191         glVertex3f(r1 * cos(0), r1 * sin(0), -t->width * 0.5);
192
193         glEnd();
194
195         glShadeModel(GL_SMOOTH);
196
197         /* draw inside radius cylinder */
198         glBegin(GL_QUAD_STRIP);
199         for (i = 0; i <= t->teeth; i++) {
200                 angle = i * 2.0 * M_PI / t->teeth;
201                 glNormal3f(-cos(angle), -sin(angle), 0.0);
202                 glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
203                 glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
204         }
205         glEnd();
206 }
207
208 static void
209 update_fps(struct gears *gears, uint32_t time)
210 {
211         long diff_ms;
212         static bool first_call = true;
213
214         if (first_call) {
215                 gears->last_fps = time;
216                 first_call = false;
217         } else
218                 gears->frames++;
219
220         diff_ms = time - gears->last_fps;
221
222         if (diff_ms > 5000) {
223                 float seconds = diff_ms / 1000.0;
224                 float fps = gears->frames / seconds;
225
226                 printf("%d frames in %6.3f seconds = %6.3f FPS\n", gears->frames, seconds, fps);
227                 fflush(stdout);
228
229                 gears->frames = 0;
230                 gears->last_fps = time;
231         }
232 }
233
234 static void
235 frame_callback(void *data, struct wl_callback *callback, uint32_t time)
236 {
237         struct gears *gears = data;
238
239         update_fps(gears, time);
240
241         gears->angle = (GLfloat) (time % 8192) * 360 / 8192.0;
242
243         window_schedule_redraw(gears->window);
244
245         if (callback)
246                 wl_callback_destroy(callback);
247 }
248
249 static const struct wl_callback_listener listener = {
250         frame_callback
251 };
252
253 static int
254 motion_handler(struct widget *widget, struct input *input,
255                 uint32_t time, float x, float y, void *data)
256 {
257         struct gears *gears = data;
258         int offset_x, offset_y;
259         float step = 0.5;
260
261         if (gears->button_down) {
262                 offset_x = x - gears->last_x;
263                 offset_y = y - gears->last_y;
264                 gears->last_x = x;
265                 gears->last_y = y;
266                 gears->view.roty += offset_x * step;
267                 gears->view.rotx += offset_y * step;
268                 if (gears->view.roty >= 360)
269                         gears->view.roty = gears->view.roty - 360;
270                 if (gears->view.roty <= 0)
271                         gears->view.roty = gears->view.roty + 360;
272                 if (gears->view.rotx >= 360)
273                         gears->view.rotx = gears->view.rotx - 360;
274                 if (gears->view.rotx <= 0)
275                         gears->view.rotx = gears->view.rotx + 360;
276         }
277
278         return CURSOR_LEFT_PTR;
279 }
280
281 static void
282 button_handler(struct widget *widget, struct input *input,
283                 uint32_t time, uint32_t button,
284                 enum wl_pointer_button_state state, void *data)
285 {
286         struct gears *gears = data;
287
288         if (button == BTN_LEFT) {
289                 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
290                         gears->button_down = 1;
291                         input_get_position(input,
292                                         &gears->last_x, &gears->last_y);
293                 } else {
294                         gears->button_down = 0;
295                 }
296         }
297 }
298
299 static void
300 redraw_handler(struct widget *widget, void *data)
301 {
302         struct rectangle window_allocation;
303         struct rectangle allocation;
304         struct wl_callback *callback;
305         struct gears *gears = data;
306
307         widget_get_allocation(gears->widget, &allocation);
308         window_get_allocation(gears->window, &window_allocation);
309
310         if (display_acquire_window_surface(gears->d,
311                                             gears->window,
312                                             gears->context) < 0) {
313                 die("Unable to acquire window surface, "
314                     "compiled without cairo-egl?\n");
315         }
316         
317         glViewport(allocation.x,
318                    window_allocation.height - allocation.height - allocation.y,
319                    allocation.width, allocation.height);
320         glScissor(allocation.x,
321                   window_allocation.height - allocation.height - allocation.y,
322                   allocation.width, allocation.height);
323
324         glEnable(GL_SCISSOR_TEST);
325         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
326
327         glPushMatrix();
328
329         glTranslatef(0.0, 0.0, -50);
330
331         glRotatef(gears->view.rotx, 1.0, 0.0, 0.0);
332         glRotatef(gears->view.roty, 0.0, 1.0, 0.0);
333
334         glPushMatrix();
335         glTranslatef(-3.0, -2.0, 0.0);
336         glRotatef(gears->angle, 0.0, 0.0, 1.0);
337         glCallList(gears->gear_list[0]);
338         glPopMatrix();
339
340         glPushMatrix();
341         glTranslatef(3.1, -2.0, 0.0);
342         glRotatef(-2.0 * gears->angle - 9.0, 0.0, 0.0, 1.0);
343         glCallList(gears->gear_list[1]);
344         glPopMatrix();
345
346         glPushMatrix();
347         glTranslatef(-3.1, 4.2, 0.0);
348         glRotatef(-2.0 * gears->angle - 25.0, 0.0, 0.0, 1.0);
349         glCallList(gears->gear_list[2]);
350         glPopMatrix();
351
352         glPopMatrix();
353
354         glFlush();
355
356         display_release_window_surface(gears->d, gears->window);
357
358         callback = wl_surface_frame(window_get_wl_surface(gears->window));
359         wl_callback_add_listener(callback, &listener, gears);
360 }
361
362 static void
363 resize_handler(struct widget *widget,
364                int32_t width, int32_t height, void *data)
365 {
366         struct gears *gears = data;
367         int32_t size, big, small;
368
369         /* Constrain child size to be square and at least 300x300 */
370         if (width < height) {
371                 small = width;
372                 big = height;
373         } else {
374                 small = height;
375                 big = width;
376         }
377
378         if (gears->fullscreen)
379                 size = small;
380         else
381                 size = big;
382
383         widget_set_size(gears->widget, size, size);
384 }
385
386 static void
387 keyboard_focus_handler(struct window *window,
388                        struct input *device, void *data)
389 {
390         window_schedule_redraw(window);
391 }
392
393 static void
394 fullscreen_handler(struct window *window, void *data)
395 {
396         struct gears *gears = data;
397
398         gears->fullscreen ^= 1;
399         window_set_fullscreen(window, gears->fullscreen);
400 }
401
402 static struct gears *
403 gears_create(struct display *display)
404 {
405         const int width = 450, height = 500;
406         struct gears *gears;
407         int i;
408
409         gears = zalloc(sizeof *gears);
410         gears->d = display;
411         gears->window = window_create(display);
412         gears->widget = window_frame_create(gears->window, gears);
413         window_set_title(gears->window, "Wayland Gears");
414
415         gears->display = display_get_egl_display(gears->d);
416         if (gears->display == NULL)
417                 die("failed to create egl display\n");
418
419         eglBindAPI(EGL_OPENGL_API);
420
421         gears->config = display_get_argb_egl_config(gears->d);
422
423         gears->context = eglCreateContext(gears->display, gears->config,
424                                           EGL_NO_CONTEXT, NULL);
425         if (gears->context == NULL)
426                 die("failed to create context\n");
427
428         if (!eglMakeCurrent(gears->display, NULL, NULL, gears->context))
429                 die("failed to make context current\n");
430
431         for (i = 0; i < 3; i++) {
432                 gears->gear_list[i] = glGenLists(1);
433                 glNewList(gears->gear_list[i], GL_COMPILE);
434                 make_gear(&gear_templates[i]);
435                 glEndList();
436         }
437
438         gears->button_down = 0;
439         gears->last_x = 0;
440         gears->last_y = 0;
441
442         gears->view.rotx = 20.0;
443         gears->view.roty = 30.0;
444
445         printf("Warning: FPS count is limited by the wayland compositor or monitor refresh rate\n");
446
447         glEnable(GL_NORMALIZE);
448
449         glMatrixMode(GL_PROJECTION);
450         glLoadIdentity();
451         glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 200.0);
452         glMatrixMode(GL_MODELVIEW);
453
454         glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
455         glEnable(GL_CULL_FACE);
456         glEnable(GL_LIGHTING);
457         glEnable(GL_LIGHT0);
458         glEnable(GL_DEPTH_TEST);
459         glClearColor(0, 0, 0, 0.92);
460
461         window_set_user_data(gears->window, gears);
462         widget_set_resize_handler(gears->widget, resize_handler);
463         widget_set_redraw_handler(gears->widget, redraw_handler);
464         widget_set_button_handler(gears->widget, button_handler);
465         widget_set_motion_handler(gears->widget, motion_handler);
466         window_set_keyboard_focus_handler(gears->window,
467                                           keyboard_focus_handler);
468         window_set_fullscreen_handler(gears->window, fullscreen_handler);
469
470         window_schedule_resize(gears->window, width, height);
471
472         return gears;
473 }
474
475 static void
476 gears_destroy(struct gears *gears)
477 {
478         widget_destroy(gears->widget);
479         window_destroy(gears->window);
480         free(gears);
481 }
482
483 int main(int argc, char *argv[])
484 {
485         struct display *d;
486         struct gears *gears;
487
488         d = display_create(&argc, argv);
489         if (d == NULL) {
490                 fprintf(stderr, "failed to create display: %m\n");
491                 return -1;
492         }
493         gears = gears_create(d);
494         display_run(d);
495
496         gears_destroy(gears);
497         display_destroy(d);
498
499         return 0;
500 }