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