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)