1 /* tronbit, Copyright (c) 2011 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;
240 if ((omodel == BIT_IDLE1 || omodel == BIT_IDLE2) &&
241 (nmodel == BIT_IDLE1 || nmodel == BIT_IDLE2))
246 nsize = small + (1 - small) * scale;
247 osize = small + (1 - small) * (1 - scale);
250 glScalef (osize, osize, osize);
251 glCallList (bp->dlists [omodel]);
252 polys += bp->polys [omodel];
256 glScalef (nsize, nsize, nsize);
257 glCallList (bp->dlists [nmodel]);
258 polys += bp->polys [nmodel];
266 draw_histogram (ModeInfo *mi, GLfloat ratio)
268 bit_configuration *bp = &bps[MI_SCREEN(mi)];
269 int samples = countof (bp->histogram);
270 GLfloat scalex = (GLfloat) mi->xgwa.width / samples;
271 GLfloat scaley = mi->xgwa.height / 255.0 / 4; /* about 1/4th of screen */
276 glPushAttrib (GL_TRANSFORM_BIT | /* for matrix contents */
277 GL_ENABLE_BIT | /* for various glDisable calls */
278 GL_CURRENT_BIT | /* for glColor3f() */
279 GL_LIST_BIT); /* for glListBase() */
281 glDisable (GL_TEXTURE_2D);
282 glDisable (GL_LIGHTING);
283 glDisable (GL_BLEND);
284 glDisable (GL_DEPTH_TEST);
285 glDisable (GL_CULL_FACE);
287 glMatrixMode(GL_PROJECTION);
291 glMatrixMode(GL_MODELVIEW);
295 gluOrtho2D (0, mi->xgwa.width, 0, mi->xgwa.height);
297 for (k = 0; k < overlays; k++)
300 GLfloat a = (GLfloat) k / overlays;
302 glColor3f (0.3 * a, 0.7 * a, 1.0 * a);
304 glBegin (GL_LINE_STRIP);
306 j = bp->histogram_fp + 1;
307 for (i = 0; i < samples; i++)
310 GLfloat y = bp->histogram[j];
313 y += (int) ((random() % 16) - 8);
314 y += 16; /* margin at bottom of screen */
319 glVertex3f (x, y, z);
320 if (++j >= samples) j = 0;
328 glMatrixMode(GL_PROJECTION);
333 glMatrixMode(GL_MODELVIEW);
339 /* Window management, etc
342 reshape_bit (ModeInfo *mi, int width, int height)
344 GLfloat h = (GLfloat) height / (GLfloat) width;
346 glViewport (0, 0, (GLint) width, (GLint) height);
348 glMatrixMode(GL_PROJECTION);
350 gluPerspective (30.0, 1/h, 1.0, 100.0);
352 glMatrixMode(GL_MODELVIEW);
354 gluLookAt( 0.0, 0.0, 30.0,
358 glClear(GL_COLOR_BUFFER_BIT);
364 bit_handle_event (ModeInfo *mi, XEvent *event)
366 bit_configuration *bp = &bps[MI_SCREEN(mi)];
368 if (event->xany.type == ButtonPress &&
369 event->xbutton.button == Button1)
371 bp->button_down_p = True;
372 gltrackball_start (bp->trackball,
373 event->xbutton.x, event->xbutton.y,
374 MI_WIDTH (mi), MI_HEIGHT (mi));
377 else if (event->xany.type == ButtonRelease &&
378 event->xbutton.button == Button1)
380 bp->button_down_p = False;
383 else if (event->xany.type == ButtonPress &&
384 (event->xbutton.button == Button4 ||
385 event->xbutton.button == Button5 ||
386 event->xbutton.button == Button6 ||
387 event->xbutton.button == Button7))
389 gltrackball_mousewheel (bp->trackball, event->xbutton.button, 3,
390 !!event->xbutton.state);
393 else if (event->xany.type == MotionNotify &&
396 gltrackball_track (bp->trackball,
397 event->xmotion.x, event->xmotion.y,
398 MI_WIDTH (mi), MI_HEIGHT (mi));
401 else if (event->xany.type == KeyPress)
405 XLookupString (&event->xkey, &c, 1, &keysym, 0);
406 if (c == ' ' || c == '1' || c == '0')
418 init_bit (ModeInfo *mi)
420 bit_configuration *bp;
421 int wire = MI_IS_WIREFRAME(mi);
425 bps = (bit_configuration *)
426 calloc (MI_NUM_SCREENS(mi), sizeof (bit_configuration));
428 fprintf(stderr, "%s: out of memory\n", progname);
433 bp = &bps[MI_SCREEN(mi)];
435 bp->glx_context = init_GL(mi);
437 reshape_bit (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
441 GLfloat pos[4] = {1.0, 1.0, 1.0, 0.0};
442 GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};
443 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
444 GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0};
446 glEnable(GL_LIGHTING);
448 glEnable(GL_DEPTH_TEST);
449 glEnable(GL_CULL_FACE);
451 glLightfv(GL_LIGHT0, GL_POSITION, pos);
452 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
453 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
454 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
458 double spin_speed = 3.0;
459 double wander_speed = 0.03 * speed;
460 double spin_accel = 4.0;
462 bp->rot = make_rotator (do_spin ? spin_speed : 0,
463 do_spin ? spin_speed : 0,
464 do_spin ? spin_speed : 0,
466 do_wander ? wander_speed : 0,
468 bp->trackball = gltrackball_init ();
471 for (i = 0; i < countof(bp->dlists); i++)
473 bp->dlists[i] = glGenLists (1);
474 glNewList (bp->dlists[i], GL_COMPILE);
475 bp->polys [i] = make_bit (mi, i);
479 bp->frequency = 0.30 / speed; /* parity around 3x/second */
480 bp->confidence = 0.06; /* provide answer 1/15 or so */
482 for (i = 0; i < countof(bp->histogram); i++)
483 bp->histogram[i] = 128 + (random() % 16) - 8;
488 draw_bit (ModeInfo *mi)
490 bit_configuration *bp = &bps[MI_SCREEN(mi)];
491 Display *dpy = MI_DISPLAY(mi);
492 Window window = MI_WINDOW(mi);
494 if (!bp->glx_context)
497 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
499 glShadeModel(GL_SMOOTH);
501 glEnable(GL_DEPTH_TEST);
502 glEnable(GL_NORMALIZE);
503 glEnable(GL_CULL_FACE);
505 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
509 glScalef(1.1, 1.1, 1.1);
513 get_position (bp->rot, &x, &y, &z, !bp->button_down_p);
514 glTranslatef((x - 0.5) * 11,
518 gltrackball_rotate (bp->trackball);
520 get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p);
521 glRotatef (x * 360, 1.0, 0.0, 0.0);
522 glRotatef (y * 360, 0.0, 1.0, 0.0);
523 glRotatef (z * 360, 0.0, 0.0, 1.0);
526 mi->polygon_count = 0;
532 int nmodel = bp->history [bp->history_fp];
533 int omodel = bp->history [bp->history_fp > 0
535 : countof(bp->history)-1];
536 double now = double_time();
537 double ratio = 1 - ((bp->last_time + bp->frequency) - now) / bp->frequency;
538 if (ratio > 1) ratio = 1;
539 mi->polygon_count += draw_histogram (mi, ratio);
540 mi->polygon_count += animate_bits (mi, omodel, nmodel, ratio);
545 if (mi->fps_p) do_fps (mi);
548 glXSwapBuffers(dpy, window);
551 XSCREENSAVER_MODULE_2 ("TronBit", tronbit, bit)