1 /* tronbit, Copyright (c) 2011-2012 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 GLfloat y = bp->histogram[j];
323 y += (int) ((random() % 16) - 8);
324 y += 16; /* margin at bottom of screen */
329 glVertex3f (x, y, z);
330 if (++j >= samples) j = 0;
338 glMatrixMode(GL_PROJECTION);
341 glMatrixMode(GL_MODELVIEW);
347 /* Window management, etc
350 reshape_bit (ModeInfo *mi, int width, int height)
352 GLfloat h = (GLfloat) height / (GLfloat) width;
354 glViewport (0, 0, (GLint) width, (GLint) height);
356 glMatrixMode(GL_PROJECTION);
358 gluPerspective (30.0, 1/h, 1.0, 100.0);
360 glMatrixMode(GL_MODELVIEW);
362 gluLookAt( 0.0, 0.0, 30.0,
366 glClear(GL_COLOR_BUFFER_BIT);
372 bit_handle_event (ModeInfo *mi, XEvent *event)
374 bit_configuration *bp = &bps[MI_SCREEN(mi)];
376 if (event->xany.type == ButtonPress &&
377 event->xbutton.button == Button1)
379 bp->button_down_p = True;
380 gltrackball_start (bp->trackball,
381 event->xbutton.x, event->xbutton.y,
382 MI_WIDTH (mi), MI_HEIGHT (mi));
385 else if (event->xany.type == ButtonRelease &&
386 event->xbutton.button == Button1)
388 bp->button_down_p = False;
391 else if (event->xany.type == ButtonPress &&
392 (event->xbutton.button == Button4 ||
393 event->xbutton.button == Button5 ||
394 event->xbutton.button == Button6 ||
395 event->xbutton.button == Button7))
397 gltrackball_mousewheel (bp->trackball, event->xbutton.button, 3,
398 !!event->xbutton.state);
401 else if (event->xany.type == MotionNotify &&
404 gltrackball_track (bp->trackball,
405 event->xmotion.x, event->xmotion.y,
406 MI_WIDTH (mi), MI_HEIGHT (mi));
409 else if (event->xany.type == KeyPress)
413 XLookupString (&event->xkey, &c, 1, &keysym, 0);
414 if (c == ' ' || c == '1' || c == '0')
426 init_bit (ModeInfo *mi)
428 bit_configuration *bp;
432 bps = (bit_configuration *)
433 calloc (MI_NUM_SCREENS(mi), sizeof (bit_configuration));
435 fprintf(stderr, "%s: out of memory\n", progname);
440 bp = &bps[MI_SCREEN(mi)];
442 bp->glx_context = init_GL(mi);
444 reshape_bit (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
447 double spin_speed = 3.0;
448 double wander_speed = 0.03 * speed;
449 double spin_accel = 4.0;
451 bp->rot = make_rotator (do_spin ? spin_speed : 0,
452 do_spin ? spin_speed : 0,
453 do_spin ? spin_speed : 0,
455 do_wander ? wander_speed : 0,
457 bp->trackball = gltrackball_init ();
460 for (i = 0; i < countof(bp->dlists); i++)
462 bp->dlists[i] = glGenLists (1);
463 glNewList (bp->dlists[i], GL_COMPILE);
464 bp->polys [i] = make_bit (mi, i);
468 bp->frequency = 0.30 / speed; /* parity around 3x/second */
469 bp->confidence = 0.06; /* provide answer 1/15 or so */
471 for (i = 0; i < countof(bp->histogram); i++)
472 bp->histogram[i] = 128 + (random() % 16) - 8;
477 draw_bit (ModeInfo *mi)
479 bit_configuration *bp = &bps[MI_SCREEN(mi)];
480 Display *dpy = MI_DISPLAY(mi);
481 Window window = MI_WINDOW(mi);
482 int wire = MI_IS_WIREFRAME(mi);
484 if (!bp->glx_context)
487 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
489 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
493 GLfloat pos[4] = {1.0, 1.0, 1.0, 0.0};
494 GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};
495 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
496 GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0};
498 glEnable(GL_LIGHTING);
500 glLightfv(GL_LIGHT0, GL_POSITION, pos);
501 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
502 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
503 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
507 glRotatef(current_device_rotation(), 0, 0, 1);
508 glScalef(1.1, 1.1, 1.1);
512 get_position (bp->rot, &x, &y, &z, !bp->button_down_p);
513 glTranslatef((x - 0.5) * 11,
516 gltrackball_rotate (bp->trackball);
518 get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p);
519 glRotatef (x * 360, 1.0, 0.0, 0.0);
520 glRotatef (y * 360, 0.0, 1.0, 0.0);
521 glRotatef (z * 360, 0.0, 0.0, 1.0);
524 mi->polygon_count = 0;
529 int nmodel = bp->history [bp->history_fp];
530 int omodel = bp->history [bp->history_fp > 0
532 : countof(bp->history)-1];
533 double now = double_time();
534 double ratio = 1 - ((bp->last_time + bp->frequency) - now) / bp->frequency;
535 if (ratio > 1) ratio = 1;
536 mi->polygon_count += draw_histogram (mi, ratio);
537 mi->polygon_count += animate_bits (mi, omodel, nmodel, ratio);
542 if (mi->fps_p) do_fps (mi);
545 glXSwapBuffers(dpy, window);
548 XSCREENSAVER_MODULE_2 ("TronBit", tronbit, bit)