1 /* cubenetic, Copyright (c) 2002 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 #include <X11/Intrinsic.h>
14 extern XtAppContext app;
16 #define PROGCLASS "Cubenetic"
17 #define HACK_INIT init_cube
18 #define HACK_DRAW draw_cube
19 #define HACK_RESHAPE reshape_cube
20 #define ccs_opts xlockmore_opts
22 #define DEF_SPIN "XYZ"
23 #define DEF_WANDER "True"
24 #define DEF_TEXTURE "True"
26 #define DEF_WAVE_COUNT "3"
27 #define DEF_WAVE_SPEED "80"
28 #define DEF_WAVE_RADIUS "512"
30 #define DEFAULTS "*delay: 30000 \n" \
32 "*showFPS: False \n" \
33 "*wireframe: False \n" \
34 "*spin: " DEF_SPIN "\n" \
35 "*wander: " DEF_WANDER "\n" \
36 "*texture: " DEF_TEXTURE"\n" \
37 "*waves: " DEF_WAVE_COUNT "\n" \
38 "*waveSpeed: " DEF_WAVE_SPEED "\n" \
39 "*waveRadius: " DEF_WAVE_RADIUS "\n" \
42 #define countof(x) (sizeof((x))/sizeof((*x)))
44 #include "xlockmore.h"
48 #ifdef USE_GL /* whole file */
76 GLXContext *glx_context;
78 GLfloat rotx, roty, rotz; /* current object rotation */
79 GLfloat dx, dy, dz; /* current rotational velocity */
80 GLfloat ddx, ddy, ddz; /* current rotational acceleration */
81 GLfloat d_max; /* max velocity */
82 Bool spin_x, spin_y, spin_z;
90 int texture_width, texture_height;
91 unsigned char *texture;
95 XColor *texture_colors;
99 static cube_configuration *ccs = NULL;
101 static char *do_spin;
102 static Bool do_wander;
103 static Bool do_texture;
105 static int wave_count;
106 static int wave_speed;
107 static int wave_radius;
108 static int texture_size = 256;
110 static XrmOptionDescRec opts[] = {
111 { "-spin", ".spin", XrmoptionSepArg, 0 },
112 { "+spin", ".spin", XrmoptionNoArg, "" },
113 { "-wander", ".wander", XrmoptionNoArg, "True" },
114 { "+wander", ".wander", XrmoptionNoArg, "False" },
115 {"-texture", ".texture", XrmoptionNoArg, (caddr_t) "true" },
116 {"+texture", ".texture", XrmoptionNoArg, (caddr_t) "false" },
117 {"-waves", ".waves", XrmoptionSepArg, 0 },
118 {"-wave-speed", ".waveSpeed", XrmoptionSepArg, 0 },
119 {"-wave-radius", ".waveRadius", XrmoptionSepArg, 0 },
122 static argtype vars[] = {
123 {(caddr_t *) &do_spin, "spin", "Spin", DEF_SPIN, t_String},
124 {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
125 {(caddr_t *) &do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
126 {(caddr_t *) &wave_count, "waves", "Waves", DEF_WAVE_COUNT, t_Int},
127 {(caddr_t *) &wave_speed, "waveSpeed", "WaveSpeed", DEF_WAVE_SPEED, t_Int},
128 {(caddr_t *) &wave_radius,"waveRadius","WaveRadius", DEF_WAVE_RADIUS,t_Int},
131 ModeSpecOpt ccs_opts = {countof(opts), opts, countof(vars), vars, NULL};
135 unit_cube (Bool wire)
137 glBegin (wire ? GL_LINE_LOOP : GL_QUADS); /* front */
138 glNormal3f (0, 0, 1);
139 glTexCoord2f(1, 0); glVertex3f ( 0.5, -0.5, 0.5);
140 glTexCoord2f(0, 0); glVertex3f ( 0.5, 0.5, 0.5);
141 glTexCoord2f(0, 1); glVertex3f (-0.5, 0.5, 0.5);
142 glTexCoord2f(1, 1); glVertex3f (-0.5, -0.5, 0.5);
145 glBegin (wire ? GL_LINE_LOOP : GL_QUADS); /* back */
146 glNormal3f (0, 0, -1);
147 glTexCoord2f(0, 0); glVertex3f (-0.5, -0.5, -0.5);
148 glTexCoord2f(0, 1); glVertex3f (-0.5, 0.5, -0.5);
149 glTexCoord2f(1, 1); glVertex3f ( 0.5, 0.5, -0.5);
150 glTexCoord2f(1, 0); glVertex3f ( 0.5, -0.5, -0.5);
153 glBegin (wire ? GL_LINE_LOOP : GL_QUADS); /* left */
154 glNormal3f (-1, 0, 0);
155 glTexCoord2f(1, 1); glVertex3f (-0.5, 0.5, 0.5);
156 glTexCoord2f(1, 0); glVertex3f (-0.5, 0.5, -0.5);
157 glTexCoord2f(0, 0); glVertex3f (-0.5, -0.5, -0.5);
158 glTexCoord2f(0, 1); glVertex3f (-0.5, -0.5, 0.5);
161 glBegin (wire ? GL_LINE_LOOP : GL_QUADS); /* right */
162 glNormal3f (1, 0, 0);
163 glTexCoord2f(1, 1); glVertex3f ( 0.5, -0.5, -0.5);
164 glTexCoord2f(1, 0); glVertex3f ( 0.5, 0.5, -0.5);
165 glTexCoord2f(0, 0); glVertex3f ( 0.5, 0.5, 0.5);
166 glTexCoord2f(0, 1); glVertex3f ( 0.5, -0.5, 0.5);
171 glBegin (wire ? GL_LINE_LOOP : GL_QUADS); /* top */
172 glNormal3f (0, 1, 0);
173 glTexCoord2f(0, 0); glVertex3f ( 0.5, 0.5, 0.5);
174 glTexCoord2f(0, 1); glVertex3f ( 0.5, 0.5, -0.5);
175 glTexCoord2f(1, 1); glVertex3f (-0.5, 0.5, -0.5);
176 glTexCoord2f(1, 0); glVertex3f (-0.5, 0.5, 0.5);
179 glBegin (wire ? GL_LINE_LOOP : GL_QUADS); /* bottom */
180 glNormal3f (0, -1, 0);
181 glTexCoord2f(1, 0); glVertex3f (-0.5, -0.5, 0.5);
182 glTexCoord2f(0, 0); glVertex3f (-0.5, -0.5, -0.5);
183 glTexCoord2f(0, 1); glVertex3f ( 0.5, -0.5, -0.5);
184 glTexCoord2f(1, 1); glVertex3f ( 0.5, -0.5, 0.5);
190 /* Window management, etc
193 reshape_cube (ModeInfo *mi, int width, int height)
195 GLfloat h = (GLfloat) height / (GLfloat) width;
197 glViewport (0, 0, (GLint) width, (GLint) height);
199 glMatrixMode(GL_PROJECTION);
202 gluPerspective( 30.0, 1/h, 1.0, 100.0 );
203 gluLookAt( 0.0, 0.0, 15.0,
206 glMatrixMode(GL_MODELVIEW);
208 glTranslatef(0.0, 0.0, -15.0);
210 glClear(GL_COLOR_BUFFER_BIT);
214 /* lifted from lament.c */
215 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
216 #define RANDSIGN() ((random() & 1) ? 1 : -1)
219 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
234 if (ppos < 0) abort();
235 if (ppos > 1.0) abort();
236 *pos = (*pos > 0 ? ppos : -ppos);
242 if (*v > max_v || *v < -max_v)
246 /* If it stops, start it going in the other direction. */
253 /* keep going in the same direction */
268 /* Alter direction of rotational acceleration randomly. */
269 if (! (random() % 120))
272 /* Change acceleration very occasionally. */
273 if (! (random() % 200))
277 else if (random() & 1)
287 Adapted from ../hacks/interference.c by Hannu Mallat.
291 init_wave (ModeInfo *mi)
293 cube_configuration *cc = &ccs[MI_SCREEN(mi)];
296 cc->waves = ww = (waves *) calloc (sizeof(*cc->waves), 1);
297 ww->nwaves = wave_count;
298 ww->radius = wave_radius;
299 ww->speed = wave_speed;
300 ww->heights = (int *) calloc (sizeof(*ww->heights), ww->radius);
301 ww->srcs = (wave_src *) calloc (sizeof(*ww->srcs), ww->nwaves);
303 for (i = 0; i < ww->radius; i++)
305 float max = (cc->ncolors * (ww->radius - i) / (float) ww->radius);
306 ww->heights[i] = ((max + max * cos(i / 50.0)) / 2.0);
309 for (i = 0; i < ww->nwaves; i++)
311 ww->srcs[i].xth = frand(2.0) * M_PI;
312 ww->srcs[i].yth = frand(2.0) * M_PI;
317 interference (ModeInfo *mi)
319 cube_configuration *cc = &ccs[MI_SCREEN(mi)];
320 waves *ww = cc->waves;
323 /* Move the wave origins around
325 for (i = 0; i < ww->nwaves; i++)
327 ww->srcs[i].xth += (ww->speed / 1000.0);
328 if (ww->srcs[i].xth > 2*M_PI)
329 ww->srcs[i].xth -= 2*M_PI;
330 ww->srcs[i].yth += (ww->speed / 1000.0);
331 if (ww->srcs[i].yth > 2*M_PI)
332 ww->srcs[i].yth -= 2*M_PI;
334 ww->srcs[i].x = (cc->texture_width/2 +
335 (cos (ww->srcs[i].xth) *
336 cc->texture_width / 2));
337 ww->srcs[i].y = (cc->texture_height/2 +
338 (cos (ww->srcs[i].yth) *
339 cc->texture_height / 2));
342 /* Compute the effect of the waves on each pixel,
343 and generate the output map.
345 for (y = 0; y < cc->texture_height; y++)
346 for (x = 0; x < cc->texture_width; x++)
350 for (i = 0; i < ww->nwaves; i++)
352 int dx = x - ww->srcs[i].x;
353 int dy = y - ww->srcs[i].y;
354 int dist = sqrt (dx*dx + dy*dy);
355 result += (dist > ww->radius ? 0 : ww->heights[dist]);
357 result %= cc->ncolors;
359 o = cc->texture + (((y * cc->texture_width) + x) << 2);
360 o[0] = (cc->texture_colors[result].red >> 8);
361 o[1] = (cc->texture_colors[result].green >> 8);
362 o[2] = (cc->texture_colors[result].blue >> 8);
372 init_texture (ModeInfo *mi)
374 cube_configuration *cc = &ccs[MI_SCREEN(mi)];
377 glEnable(GL_TEXTURE_2D);
380 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
381 glGenTextures (1, &cc->texture_id);
382 glBindTexture (GL_TEXTURE_2D, cc->texture_id);
383 check_gl_error("texture binding");
385 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
386 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
387 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
388 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
389 glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
390 glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
391 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
392 check_gl_error("texture initialization");
394 cc->texture_width = texture_size;
395 cc->texture_height = texture_size;
397 i = texture_size * texture_size * 4;
398 cc->texture = (char *) malloc (i);
399 memset (cc->texture, 0xFF, i);
404 shuffle_texture (ModeInfo *mi)
406 cube_configuration *cc = &ccs[MI_SCREEN(mi)];
409 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
410 cc->texture_width, cc->texture_height, 0,
411 GL_RGBA, GL_UNSIGNED_BYTE,
413 check_gl_error("texture");
418 init_cube (ModeInfo *mi)
421 cube_configuration *cc;
422 int wire = MI_IS_WIREFRAME(mi);
425 ccs = (cube_configuration *)
426 calloc (MI_NUM_SCREENS(mi), sizeof (cube_configuration));
428 fprintf(stderr, "%s: out of memory\n", progname);
433 cc = &ccs[MI_SCREEN(mi)];
435 if ((cc->glx_context = init_GL(mi)) != NULL) {
436 reshape_cube (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
441 static GLfloat pos[4] = {1.0, 0.5, 1.0, 0.0};
442 static GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
443 static GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
445 glLightfv(GL_LIGHT0, GL_POSITION, pos);
446 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
447 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
449 glEnable(GL_LIGHTING);
451 glEnable(GL_DEPTH_TEST);
452 glEnable(GL_CULL_FACE);
460 if (*s == 'x' || *s == 'X') cc->spin_x = 1;
461 else if (*s == 'y' || *s == 'Y') cc->spin_y = 1;
462 else if (*s == 'z' || *s == 'Z') cc->spin_z = 1;
466 "%s: spin must contain only the characters X, Y, or Z (not \"%s\")\n",
474 cc->rotx = frand(1.0) * RANDSIGN();
475 cc->roty = frand(1.0) * RANDSIGN();
476 cc->rotz = frand(1.0) * RANDSIGN();
478 /* bell curve from 0-6 degrees, avg 3 */
479 cc->dx = (frand(0.7) + frand(0.7) + frand(0.7)) / (360/2);
480 cc->dy = (frand(0.7) + frand(0.7) + frand(0.7)) / (360/2);
481 cc->dz = (frand(0.7) + frand(0.7) + frand(0.7)) / (360/2);
483 cc->d_max = cc->dx * 2;
485 cc->ddx = 0.00006 + frand(0.00003);
486 cc->ddy = 0.00006 + frand(0.00003);
487 cc->ddz = 0.00006 + frand(0.00003);
490 cc->texture_colors = (XColor *) calloc(cc->ncolors, sizeof(XColor));
491 cc->cube_colors = (XColor *) calloc(cc->ncolors, sizeof(XColor));
494 double H[3], S[3], V[3];
497 H[1] = ((H[0] + shift) < 360) ? (H[0]+shift) : (H[0] + shift - 360);
498 H[2] = ((H[1] + shift) < 360) ? (H[1]+shift) : (H[1] + shift - 360);
499 S[0] = S[1] = S[2] = 1.0;
500 V[0] = V[1] = V[2] = 1.0;
501 make_color_loop(0, 0,
505 cc->texture_colors, &cc->ncolors,
508 make_smooth_colormap (0, 0, 0,
509 cc->cube_colors, &cc->ncolors,
513 cc->ncubes = MI_COUNT (mi);
514 cc->cubes = (cube *) calloc (sizeof(cube), cc->ncubes);
515 for (i = 0; i < cc->ncubes; i++)
517 cube *cube = &cc->cubes[i];
518 cube->color = random() % cc->ncolors;
522 cube->dx = frand(0.1);
523 cube->dy = frand(0.1);
524 cube->dz = frand(0.1);
525 cube->dw = frand(0.1);
526 cube->dh = frand(0.1);
527 cube->dd = frand(0.1);
537 shuffle_texture (mi);
540 cc->cube_list = glGenLists (1);
541 glNewList (cc->cube_list, GL_COMPILE);
548 shuffle_cubes (ModeInfo *mi)
550 cube_configuration *cc = &ccs[MI_SCREEN(mi)];
552 for (i = 0; i < cc->ncubes; i++)
554 # define SINOID(SCALE,FRAME,SIZE) \
555 ((((1 + sin((FRAME * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
557 cube *cube = &cc->cubes[i];
558 cube->x = SINOID(cube->dx, cube->frame, 0.5);
559 cube->y = SINOID(cube->dy, cube->frame, 0.5);
560 cube->z = SINOID(cube->dz, cube->frame, 0.5);
561 cube->w = SINOID(cube->dw, cube->frame, 0.9) + 1.0;
562 cube->h = SINOID(cube->dh, cube->frame, 0.9) + 1.0;
563 cube->d = SINOID(cube->dd, cube->frame, 0.9) + 1.0;
571 draw_cube (ModeInfo *mi)
573 cube_configuration *cc = &ccs[MI_SCREEN(mi)];
574 Display *dpy = MI_DISPLAY(mi);
575 Window window = MI_WINDOW(mi);
578 if (!cc->glx_context)
581 glShadeModel(GL_FLAT);
583 glEnable(GL_DEPTH_TEST);
584 glEnable(GL_NORMALIZE);
585 glEnable(GL_CULL_FACE);
587 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
591 glScalef(1.1, 1.1, 1.1);
598 static int frame = 0;
600 # define SINOID(SCALE,SIZE) \
601 ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
603 x = SINOID(0.0071, 8.0);
604 y = SINOID(0.0053, 6.0);
605 z = SINOID(0.0037, 15.0);
607 glTranslatef(x, y, z);
610 if (cc->spin_x || cc->spin_y || cc->spin_z)
615 if (x < 0) x = 1 - (x + 1);
616 if (y < 0) y = 1 - (y + 1);
617 if (z < 0) z = 1 - (z + 1);
619 if (cc->spin_x) glRotatef(x * 360, 1.0, 0.0, 0.0);
620 if (cc->spin_y) glRotatef(y * 360, 0.0, 1.0, 0.0);
621 if (cc->spin_z) glRotatef(z * 360, 0.0, 0.0, 1.0);
623 rotate(&cc->rotx, &cc->dx, &cc->ddx, cc->d_max);
624 rotate(&cc->roty, &cc->dy, &cc->ddy, cc->d_max);
625 rotate(&cc->rotz, &cc->dz, &cc->ddz, cc->d_max);
629 glScalef (2.5, 2.5, 2.5);
631 for (i = 0; i < cc->ncubes; i++)
633 cube *cube = &cc->cubes[i];
635 color[0] = cc->cube_colors[cube->color].red / 65536.0;
636 color[1] = cc->cube_colors[cube->color].green / 65536.0;
637 color[2] = cc->cube_colors[cube->color].blue / 65536.0;
640 if (cube->color >= cc->ncolors) cube->color = 0;
643 glTranslatef (cube->x, cube->y, cube->z);
644 glScalef (cube->w, cube->h, cube->d);
645 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
646 glCallList (cc->cube_list);
652 shuffle_texture (mi);
656 if (mi->fps_p) do_fps (mi);
659 glXSwapBuffers(dpy, window);