1 /* tronbit, Copyright (c) 2011-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"
17 # define refresh_bit 0
18 # define release_bit 0
20 #define countof(x) (sizeof((x))/sizeof((*x)))
22 #include "xlockmore.h"
26 #include "gltrackball.h"
29 #ifdef USE_GL /* whole file */
33 extern const struct gllist *tronbit_idle1, *tronbit_idle2,
34 *tronbit_no, *tronbit_yes;
35 static const struct gllist * const *all_objs[] = {
36 &tronbit_idle1, &tronbit_idle2, &tronbit_no, &tronbit_yes };
39 #define DEF_SPIN "True"
40 #define DEF_WANDER "True"
41 #define DEF_SPEED "1.0"
43 #define HISTORY_LENGTH 512
44 typedef enum { BIT_IDLE1, BIT_IDLE2, BIT_NO, BIT_YES } bit_state;
49 GLXContext *glx_context;
51 trackball_state *trackball;
58 unsigned char history [HISTORY_LENGTH];
59 unsigned char histogram [HISTORY_LENGTH];
60 int history_fp, histogram_fp;
62 GLuint dlists[MODELS], polys[MODELS];
67 static bit_configuration *bps = NULL;
69 static const GLfloat colors[][4] = {
70 { 0.66, 0.85, 1.00, 1.00 },
71 { 0.66, 0.85, 1.00, 1.00 },
72 { 1.00, 0.12, 0.12, 1.00 },
73 { 0.98, 0.85, 0.30, 1.00 }
79 static Bool do_wander;
81 static XrmOptionDescRec opts[] = {
82 { "-spin", ".spin", XrmoptionNoArg, "True" },
83 { "+spin", ".spin", XrmoptionNoArg, "False" },
84 { "-speed", ".speed", XrmoptionSepArg, 0 },
85 { "-wander", ".wander", XrmoptionNoArg, "True" },
86 { "+wander", ".wander", XrmoptionNoArg, "False" }
89 static argtype vars[] = {
90 {&do_spin, "spin", "Spin", DEF_SPIN, t_Bool},
91 {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
92 {&speed, "speed", "Speed", DEF_SPEED, t_Float},
95 ENTRYPOINT ModeSpecOpt bit_opts = {countof(opts), opts, countof(vars), vars, NULL};
98 /* Returns the current time in seconds as a double.
104 # ifdef GETTIMEOFDAY_TWO_ARGS
106 gettimeofday(&now, &tzp);
111 return (now.tv_sec + ((double) now.tv_usec * 0.000001));
116 make_bit (ModeInfo *mi, bit_state which)
118 static const GLfloat spec[4] = {1.0, 1.0, 1.0, 1.0};
119 static const GLfloat shiny = 128.0;
120 const GLfloat *color = colors[which];
121 int wire = MI_IS_WIREFRAME(mi);
124 const struct gllist *gll;
126 glMaterialfv (GL_FRONT, GL_SPECULAR, spec);
127 glMateriali (GL_FRONT, GL_SHININESS, shiny);
128 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
129 glColor4f (color[0], color[1], color[2], color[3]);
135 glRotatef (-44, 0, 1, 0); /* line up the models with each other */
136 glRotatef (-11, 1, 0, 0);
137 glRotatef ( 8, 0, 0, 1);
141 glRotatef ( 16.0, 0, 0, 1);
142 glRotatef (-28.0, 1, 0, 0);
146 glRotatef ( 16.0, 0, 0, 1);
147 glRotatef (-28.0, 1, 0, 0);
151 glRotatef (-44.0, 0, 1, 0);
152 glRotatef (-32.0, 1, 0, 0);
160 gll = *all_objs[which];
161 renderList (gll, wire);
162 polys += gll->points / 3;
170 tick_bit (ModeInfo *mi, double now)
172 bit_configuration *bp = &bps[MI_SCREEN(mi)];
173 double freq = bp->frequency;
174 int n = bp->history[bp->history_fp];
175 int histogram_speed = 3 * speed;
178 if (histogram_speed < 1) histogram_speed = 1;
180 if (n == BIT_YES || n == BIT_NO)
183 if (bp->button_down_p) return;
185 for (i = 0; i < histogram_speed; i++)
187 int nn = (n == BIT_YES ? 240 : n == BIT_NO ? 17 : 128);
188 int on = bp->histogram[(bp->histogram_fp-1) % countof(bp->histogram)];
190 /* smooth out the square wave a little bit */
192 if (!(nn > 100 && nn < 200) !=
193 !(on > 100 && on < 200))
194 nn += (((random() % 48) - 32) *
195 ((on > 100 && on < 200) ? 1 : -1));
197 nn += (random() % 16) - 8;
200 if (bp->histogram_fp >= countof(bp->history))
201 bp->histogram_fp = 0;
202 bp->histogram [bp->histogram_fp] = nn;
206 if (bp->last_time + freq > now && !bp->kbd) return;
211 if (bp->history_fp >= countof(bp->history))
216 n = (bp->kbd == '1' ? BIT_YES :
217 bp->kbd == '0' ? BIT_NO :
218 (random() & 1) ? BIT_YES : BIT_NO);
221 else if (n == BIT_YES ||
223 frand(1.0) >= bp->confidence)
224 n = (n == BIT_IDLE1 ? BIT_IDLE2 : BIT_IDLE1);
226 n = (random() & 1) ? BIT_YES : BIT_NO;
228 bp->history [bp->history_fp] = n;
233 animate_bits (ModeInfo *mi, bit_state omodel, bit_state nmodel, GLfloat ratio)
235 bit_configuration *bp = &bps[MI_SCREEN(mi)];
237 GLfloat scale = sin (ratio * M_PI / 2);
238 GLfloat osize, nsize, small;
239 int wire = MI_IS_WIREFRAME(mi);
241 glShadeModel(GL_SMOOTH);
243 glEnable(GL_DEPTH_TEST);
244 glEnable(GL_NORMALIZE);
245 glEnable(GL_CULL_FACE);
249 glEnable(GL_LIGHTING);
250 glEnable(GL_DEPTH_TEST);
251 glEnable(GL_CULL_FACE);
254 if ((omodel == BIT_IDLE1 || omodel == BIT_IDLE2) &&
255 (nmodel == BIT_IDLE1 || nmodel == BIT_IDLE2))
260 nsize = small + (1 - small) * scale;
261 osize = small + (1 - small) * (1 - scale);
264 glScalef (osize, osize, osize);
265 glCallList (bp->dlists [omodel]);
266 polys += bp->polys [omodel];
270 glScalef (nsize, nsize, nsize);
271 glCallList (bp->dlists [nmodel]);
272 polys += bp->polys [nmodel];
280 draw_histogram (ModeInfo *mi, GLfloat ratio)
282 bit_configuration *bp = &bps[MI_SCREEN(mi)];
283 int samples = countof (bp->histogram);
284 GLfloat scalex = (GLfloat) mi->xgwa.width / samples;
285 GLfloat scaley = mi->xgwa.height / 255.0 / 4; /* about 1/4th of screen */
290 glDisable (GL_TEXTURE_2D);
291 glDisable (GL_LIGHTING);
292 glDisable (GL_BLEND);
293 glDisable (GL_DEPTH_TEST);
294 glDisable (GL_CULL_FACE);
296 glMatrixMode(GL_PROJECTION);
300 glMatrixMode(GL_MODELVIEW);
304 /* glRotatef(current_device_rotation(), 0, 0, 1); */
305 glOrtho (0, mi->xgwa.width, 0, mi->xgwa.height, -1, 1);
307 for (k = 0; k < overlays; k++)
310 GLfloat a = (GLfloat) k / overlays;
312 glColor3f (0.3 * a, 0.7 * a, 1.0 * a);
314 glBegin (GL_LINE_STRIP);
316 j = bp->histogram_fp + 1;
317 for (i = 0; i < samples; i++)
320 if (j >= samples) j = 0;
322 y = bp->histogram[j];
325 y += (int) ((random() % 16) - 8);
326 y += 16; /* margin at bottom of screen */
331 glVertex3f (x, y, z);
340 glMatrixMode(GL_PROJECTION);
343 glMatrixMode(GL_MODELVIEW);
349 /* Window management, etc
352 reshape_bit (ModeInfo *mi, int width, int height)
354 GLfloat h = (GLfloat) height / (GLfloat) width;
356 glViewport (0, 0, (GLint) width, (GLint) height);
358 glMatrixMode(GL_PROJECTION);
360 gluPerspective (30.0, 1/h, 1.0, 100.0);
362 glMatrixMode(GL_MODELVIEW);
364 gluLookAt( 0.0, 0.0, 30.0,
368 glClear(GL_COLOR_BUFFER_BIT);
374 bit_handle_event (ModeInfo *mi, XEvent *event)
376 bit_configuration *bp = &bps[MI_SCREEN(mi)];
378 if (gltrackball_event_handler (event, bp->trackball,
379 MI_WIDTH (mi), MI_HEIGHT (mi),
382 else if (event->xany.type == KeyPress)
386 XLookupString (&event->xkey, &c, 1, &keysym, 0);
388 if (keysym == XK_Up || keysym == XK_Left || keysym == XK_Prior)
390 else if (keysym == XK_Down || keysym == XK_Right || keysym == XK_Next)
393 if (c == ' ' || c == '\t' || c == '\n' || c == '1' || c == '0')
405 init_bit (ModeInfo *mi)
407 bit_configuration *bp;
410 MI_INIT (mi, bps, NULL);
412 bp = &bps[MI_SCREEN(mi)];
414 bp->glx_context = init_GL(mi);
416 reshape_bit (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
419 double spin_speed = 3.0;
420 double wander_speed = 0.03 * speed;
421 double spin_accel = 4.0;
423 bp->rot = make_rotator (do_spin ? spin_speed : 0,
424 do_spin ? spin_speed : 0,
425 do_spin ? spin_speed : 0,
427 do_wander ? wander_speed : 0,
429 bp->trackball = gltrackball_init (False);
432 for (i = 0; i < countof(bp->dlists); i++)
434 bp->dlists[i] = glGenLists (1);
435 glNewList (bp->dlists[i], GL_COMPILE);
436 bp->polys [i] = make_bit (mi, i);
440 bp->frequency = 0.30 / speed; /* parity around 3x/second */
441 bp->confidence = 0.06; /* provide answer 1/15 or so */
443 for (i = 0; i < countof(bp->histogram); i++)
444 bp->histogram[i] = 128 + (random() % 16) - 8;
449 draw_bit (ModeInfo *mi)
451 bit_configuration *bp = &bps[MI_SCREEN(mi)];
452 Display *dpy = MI_DISPLAY(mi);
453 Window window = MI_WINDOW(mi);
454 int wire = MI_IS_WIREFRAME(mi);
456 if (!bp->glx_context)
459 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
461 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
465 GLfloat pos[4] = {1.0, 1.0, 1.0, 0.0};
466 GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};
467 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
468 GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0};
470 glEnable(GL_LIGHTING);
472 glLightfv(GL_LIGHT0, GL_POSITION, pos);
473 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
474 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
475 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
479 glScalef(1.1, 1.1, 1.1);
481 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
483 GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
484 int o = (int) current_device_rotation();
485 if (o != 0 && o != 180 && o != -180)
486 glScalef (1/h, 1/h, 1/h);
487 glRotatef(o, 0, 0, 1);
493 get_position (bp->rot, &x, &y, &z, !bp->button_down_p);
494 glTranslatef((x - 0.5) * 11,
497 gltrackball_rotate (bp->trackball);
499 get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p);
500 glRotatef (x * 360, 1.0, 0.0, 0.0);
501 glRotatef (y * 360, 0.0, 1.0, 0.0);
502 glRotatef (z * 360, 0.0, 0.0, 1.0);
505 mi->polygon_count = 0;
510 int nmodel = bp->history [bp->history_fp];
511 int omodel = bp->history [bp->history_fp > 0
513 : countof(bp->history)-1];
514 double now = double_time();
515 double ratio = 1 - ((bp->last_time + bp->frequency) - now) / bp->frequency;
516 if (ratio > 1) ratio = 1;
517 mi->polygon_count += draw_histogram (mi, ratio);
518 mi->polygon_count += animate_bits (mi, omodel, nmodel, ratio);
523 if (mi->fps_p) do_fps (mi);
526 glXSwapBuffers(dpy, window);
529 XSCREENSAVER_MODULE_2 ("TronBit", tronbit, bit)