1 /* moebiusgears, Copyright (c) 2007-2014 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
12 #define DEFAULTS "*delay: 30000 \n" \
14 "*showFPS: False \n" \
15 "*wireframe: False \n" \
16 "*suppressRotationAnimation: True\n" \
18 # define refresh_mgears 0
19 # define release_mgears 0
21 #define countof(x) (sizeof((x))/sizeof((*x)))
23 #include "xlockmore.h"
27 #include "gltrackball.h"
30 #ifdef USE_GL /* whole file */
33 #define DEF_SPIN "True"
34 #define DEF_WANDER "True"
35 #define DEF_ROLL "True"
36 #define DEF_SPEED "1.0"
37 #define DEF_TEETH "15"
42 GLfloat pos_th; /* position on ring of gear system */
43 GLfloat pos_thz; /* rotation out of plane of gear system */
47 GLXContext *glx_context;
49 trackball_state *trackball;
54 GLfloat ring_r; /* radius of gear system */
57 } mgears_configuration;
59 static mgears_configuration *bps = NULL;
63 static Bool do_wander;
67 static XrmOptionDescRec opts[] = {
68 { "-spin", ".spin", XrmoptionNoArg, "True" },
69 { "+spin", ".spin", XrmoptionNoArg, "False" },
70 { "-speed", ".speed", XrmoptionSepArg, 0 },
71 { "-wander", ".wander", XrmoptionNoArg, "True" },
72 { "+wander", ".wander", XrmoptionNoArg, "False" },
73 { "-roll", ".roll", XrmoptionNoArg, "True" },
74 { "+roll", ".roll", XrmoptionNoArg, "False" },
75 { "-teeth", ".teeth", XrmoptionSepArg, 0 },
78 static argtype vars[] = {
79 {&do_spin, "spin", "Spin", DEF_SPIN, t_Bool},
80 {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
81 {&do_roll, "roll", "Roll", DEF_ROLL, t_Bool},
82 {&speed, "speed", "Speed", DEF_SPEED, t_Float},
83 {&teeth_arg, "teeth", "Teeth", DEF_TEETH, t_Int},
86 ENTRYPOINT ModeSpecOpt mgears_opts = {countof(opts), opts, countof(vars), vars, NULL};
89 /* Window management, etc
92 reshape_mgears (ModeInfo *mi, int width, int height)
94 GLfloat h = (GLfloat) height / (GLfloat) width;
96 glViewport (0, 0, (GLint) width, (GLint) height);
98 glMatrixMode(GL_PROJECTION);
100 gluPerspective (30.0, 1/h, 1.0, 100.0);
102 glMatrixMode(GL_MODELVIEW);
104 gluLookAt( 0.0, 0.0, 30.0,
108 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
110 int o = (int) current_device_rotation();
111 if (o != 0 && o != 180 && o != -180)
112 glScalef (1/h, 1/h, 1/h);
116 glClear(GL_COLOR_BUFFER_BIT);
121 reset_mgears (ModeInfo *mi)
123 mgears_configuration *bp = &bps[MI_SCREEN(mi)];
124 int wire = MI_IS_WIREFRAME(mi);
125 int total_gears = MI_COUNT(mi);
126 double gears_per_turn;
127 double gear_r, tw, th, thick, slope;
130 if (! (total_gears & 1))
131 total_gears++; /* must be odd or gears intersect */
133 /* Number of teeth must be odd if number of gears is odd, or teeth don't
134 mesh when the loop closes. And since number of gears must be odd...
136 if (! (teeth_arg & 1)) teeth_arg++;
137 if (teeth_arg < 7) teeth_arg = 7;
139 if (total_gears < 13) /* gear mesh angle is too steep with less */
143 nubs = (random() & 3) ? 0 : (random() % teeth_arg) / 2;
147 /* Sloping gears are incompatible with "-roll" ... */
148 /* slope= -M_PI * 2 / total_gears; */
150 gears_per_turn = total_gears / 2.0;
153 gear_r = M_PI * bp->ring_r / gears_per_turn;
155 th = gear_r * 2.5 / teeth_arg;
157 /* If the gears are small, use a lower density mesh. */
158 size = (gear_r > 0.60 ? INVOLUTE_HUGE :
159 gear_r > 0.32 ? INVOLUTE_LARGE :
160 gear_r > 0.13 ? INVOLUTE_MEDIUM :
163 /* If there are lots of teeth, use a lower density mesh. */
165 size = INVOLUTE_SMALL;
166 if (teeth_arg > 45 && size >= INVOLUTE_HUGE)
167 size = INVOLUTE_MEDIUM;
171 for (i = 0; i < bp->ngears; i++)
172 glDeleteLists (bp->gears[i].g.dlist, 1);
177 bp->ngears = total_gears;
179 bp->gears = (mogear *) calloc (bp->ngears, sizeof(*bp->gears));
180 for (i = 0; i < bp->ngears; i++)
182 mogear *mg = &bp->gears[i];
187 g->nteeth = teeth_arg;
190 g->tooth_slope = slope;
191 g->thickness = g->r * thick;
192 g->thickness2 = g->thickness * 0.1;
193 g->thickness3 = g->thickness;
194 g->inner_r = g->r * 0.80;
195 g->inner_r2 = g->r * 0.60;
196 g->inner_r3 = g->r * 0.55;
198 mg->pos_th = (M_PI * 2 / gears_per_turn) * i;
199 mg->pos_thz = (M_PI / 2 / gears_per_turn) * i;
202 ? (M_PI * 2 / g->nteeth)
207 g->color[0] = 0.7 + frand(0.3);
208 g->color[1] = 0.7 + frand(0.3);
209 g->color[2] = 0.7 + frand(0.3);
212 g->color2[0] = g->color[0] * 0.85;
213 g->color2[1] = g->color[1] * 0.85;
214 g->color2[2] = g->color[2] * 0.85;
215 g->color2[3] = g->color[3];
217 /* Now render the gear into its display list.
219 g->dlist = glGenLists (1);
222 check_gl_error ("glGenLists");
226 glNewList (g->dlist, GL_COMPILE);
227 g->polygons += draw_involute_gear (g, wire);
234 init_mgears (ModeInfo *mi)
236 mgears_configuration *bp;
237 int wire = MI_IS_WIREFRAME(mi);
239 MI_INIT (mi, bps, NULL);
241 bp = &bps[MI_SCREEN(mi)];
243 bp->glx_context = init_GL(mi);
245 reshape_mgears (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
249 GLfloat pos[4] = {1.0, 1.0, 1.0, 0.0};
250 GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};
251 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
252 GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0};
254 glEnable(GL_LIGHTING);
256 glEnable(GL_DEPTH_TEST);
257 glEnable(GL_CULL_FACE);
259 glLightfv(GL_LIGHT0, GL_POSITION, pos);
260 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
261 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
262 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
266 double spin_speed = 0.5;
267 double wander_speed = 0.01;
268 double spin_accel = 2.0;
270 bp->rot = make_rotator (do_spin ? spin_speed : 0,
271 do_spin ? spin_speed : 0,
272 do_spin ? spin_speed : 0,
274 do_wander ? wander_speed : 0,
275 False /* don't randomize */
277 bp->trackball = gltrackball_init (True);
285 mgears_handle_event (ModeInfo *mi, XEvent *event)
287 mgears_configuration *bp = &bps[MI_SCREEN(mi)];
289 if (gltrackball_event_handler (event, bp->trackball,
290 MI_WIDTH (mi), MI_HEIGHT (mi),
293 else if (event->xany.type == KeyPress)
297 XLookupString (&event->xkey, &c, 1, &keysym, 0);
298 if (c == '+' || c == '=' ||
299 keysym == XK_Up || keysym == XK_Right || keysym == XK_Next)
305 else if (c == '-' || c == '_' ||
306 keysym == XK_Down || keysym == XK_Left || keysym == XK_Prior)
308 if (MI_COUNT(mi) <= 13)
314 else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
317 else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
320 MI_COUNT(mi) = 13 + (2 * (random() % 10));
330 draw_mgears (ModeInfo *mi)
332 mgears_configuration *bp = &bps[MI_SCREEN(mi)];
333 Display *dpy = MI_DISPLAY(mi);
334 Window window = MI_WINDOW(mi);
337 if (!bp->glx_context)
340 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
342 glShadeModel(GL_SMOOTH);
344 glEnable(GL_DEPTH_TEST);
345 glEnable(GL_NORMALIZE);
346 glEnable(GL_CULL_FACE);
348 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
352 glScalef(1.1, 1.1, 1.1);
356 get_position (bp->rot, &x, &y, &z, !bp->button_down_p);
357 glTranslatef ((x - 0.5) * 4,
361 gltrackball_rotate (bp->trackball);
363 get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p);
365 /* add a little rotation for -no-spin mode */
369 glRotatef (x * 360, 1.0, 0.0, 0.0);
370 glRotatef (y * 360, 0.0, 1.0, 0.0);
371 glRotatef (z * 360, 0.0, 0.0, 1.0);
374 mi->polygon_count = 0;
376 glScalef (1.5, 1.5, 1.5);
381 glScalef (.5, .5, .5);
382 glTranslatef (0, -bp->gears[0].g.r * bp->ngears, 0);
385 for (i = 0; i < bp->ngears; i++)
387 mogear *mg = &bp->gears[i];
392 glRotatef (mg->pos_th * 180 / M_PI, 0, 0, 1); /* rotation on ring */
393 glTranslatef (bp->ring_r, 0, 0); /* position on ring */
394 glRotatef (mg->pos_thz * 180 / M_PI, 0, 1, 0); /* twist a bit */
398 glRotatef (bp->roll_th * 180 / M_PI, 0, 1, 0);
399 bp->roll_th += speed * 0.0005;
402 glTranslatef (0, i * 2 * g->r, 0);
404 glRotatef (g->th * 180 / M_PI, 0, 0, 1);
406 glCallList (g->dlist);
407 mi->polygon_count += g->polygons;
415 for (i = 0; i < bp->ngears; i++)
417 mogear *mg = &bp->gears[i];
418 mg->g.th += speed * (M_PI / 100) * (i & 1 ? 1 : -1);
422 if (mi->fps_p) do_fps (mi);
425 glXSwapBuffers(dpy, window);
428 XSCREENSAVER_MODULE_2 ("MoebiusGears", moebiusgears, mgears)