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;
321 GLfloat y = bp->histogram[j];
324 y += (int) ((random() % 16) - 8);
325 y += 16; /* margin at bottom of screen */
330 glVertex3f (x, y, z);
339 glMatrixMode(GL_PROJECTION);
342 glMatrixMode(GL_MODELVIEW);
348 /* Window management, etc
351 reshape_bit (ModeInfo *mi, int width, int height)
353 GLfloat h = (GLfloat) height / (GLfloat) width;
355 glViewport (0, 0, (GLint) width, (GLint) height);
357 glMatrixMode(GL_PROJECTION);
359 gluPerspective (30.0, 1/h, 1.0, 100.0);
361 glMatrixMode(GL_MODELVIEW);
363 gluLookAt( 0.0, 0.0, 30.0,
367 glClear(GL_COLOR_BUFFER_BIT);
373 bit_handle_event (ModeInfo *mi, XEvent *event)
375 bit_configuration *bp = &bps[MI_SCREEN(mi)];
377 if (gltrackball_event_handler (event, bp->trackball,
378 MI_WIDTH (mi), MI_HEIGHT (mi),
381 else if (event->xany.type == KeyPress)
385 XLookupString (&event->xkey, &c, 1, &keysym, 0);
387 if (keysym == XK_Up || keysym == XK_Left || keysym == XK_Prior)
389 else if (keysym == XK_Down || keysym == XK_Right || keysym == XK_Next)
392 if (c == ' ' || c == '\t' || c == '\n' || c == '1' || c == '0')
404 init_bit (ModeInfo *mi)
406 bit_configuration *bp;
410 bps = (bit_configuration *)
411 calloc (MI_NUM_SCREENS(mi), sizeof (bit_configuration));
413 fprintf(stderr, "%s: out of memory\n", progname);
418 bp = &bps[MI_SCREEN(mi)];
420 bp->glx_context = init_GL(mi);
422 reshape_bit (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
425 double spin_speed = 3.0;
426 double wander_speed = 0.03 * speed;
427 double spin_accel = 4.0;
429 bp->rot = make_rotator (do_spin ? spin_speed : 0,
430 do_spin ? spin_speed : 0,
431 do_spin ? spin_speed : 0,
433 do_wander ? wander_speed : 0,
435 bp->trackball = gltrackball_init (False);
438 for (i = 0; i < countof(bp->dlists); i++)
440 bp->dlists[i] = glGenLists (1);
441 glNewList (bp->dlists[i], GL_COMPILE);
442 bp->polys [i] = make_bit (mi, i);
446 bp->frequency = 0.30 / speed; /* parity around 3x/second */
447 bp->confidence = 0.06; /* provide answer 1/15 or so */
449 for (i = 0; i < countof(bp->histogram); i++)
450 bp->histogram[i] = 128 + (random() % 16) - 8;
455 draw_bit (ModeInfo *mi)
457 bit_configuration *bp = &bps[MI_SCREEN(mi)];
458 Display *dpy = MI_DISPLAY(mi);
459 Window window = MI_WINDOW(mi);
460 int wire = MI_IS_WIREFRAME(mi);
462 if (!bp->glx_context)
465 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
467 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
471 GLfloat pos[4] = {1.0, 1.0, 1.0, 0.0};
472 GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};
473 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
474 GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0};
476 glEnable(GL_LIGHTING);
478 glLightfv(GL_LIGHT0, GL_POSITION, pos);
479 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
480 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
481 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
485 glRotatef(current_device_rotation(), 0, 0, 1);
486 glScalef(1.1, 1.1, 1.1);
490 get_position (bp->rot, &x, &y, &z, !bp->button_down_p);
491 glTranslatef((x - 0.5) * 11,
494 gltrackball_rotate (bp->trackball);
496 get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p);
497 glRotatef (x * 360, 1.0, 0.0, 0.0);
498 glRotatef (y * 360, 0.0, 1.0, 0.0);
499 glRotatef (z * 360, 0.0, 0.0, 1.0);
502 mi->polygon_count = 0;
507 int nmodel = bp->history [bp->history_fp];
508 int omodel = bp->history [bp->history_fp > 0
510 : countof(bp->history)-1];
511 double now = double_time();
512 double ratio = 1 - ((bp->last_time + bp->frequency) - now) / bp->frequency;
513 if (ratio > 1) ratio = 1;
514 mi->polygon_count += draw_histogram (mi, ratio);
515 mi->polygon_count += animate_bits (mi, omodel, nmodel, ratio);
520 if (mi->fps_p) do_fps (mi);
523 glXSwapBuffers(dpy, window);
526 XSCREENSAVER_MODULE_2 ("TronBit", tronbit, bit)