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 HACK_HANDLE_EVENT cube_handle_event
21 #define EVENT_MASK PointerMotionMask
22 #define ccs_opts xlockmore_opts
24 #define DEF_SPIN "XYZ"
25 #define DEF_WANDER "True"
26 #define DEF_TEXTURE "True"
28 #define DEF_WAVE_COUNT "3"
29 #define DEF_WAVE_SPEED "80"
30 #define DEF_WAVE_RADIUS "512"
32 #define DEFAULTS "*delay: 30000 \n" \
34 "*showFPS: False \n" \
35 "*wireframe: False \n" \
36 "*spin: " DEF_SPIN "\n" \
37 "*wander: " DEF_WANDER "\n" \
38 "*texture: " DEF_TEXTURE"\n" \
39 "*waves: " DEF_WAVE_COUNT "\n" \
40 "*waveSpeed: " DEF_WAVE_SPEED "\n" \
41 "*waveRadius: " DEF_WAVE_RADIUS "\n" \
44 #define countof(x) (sizeof((x))/sizeof((*x)))
46 #include "xlockmore.h"
49 #include "gltrackball.h"
52 #ifdef USE_GL /* whole file */
80 GLXContext *glx_context;
82 trackball_state *trackball;
91 int texture_width, texture_height;
92 unsigned char *texture;
96 XColor *texture_colors;
100 static cube_configuration *ccs = NULL;
102 static char *do_spin;
103 static Bool do_wander;
104 static Bool do_texture;
106 static int wave_count;
107 static int wave_speed;
108 static int wave_radius;
109 static int texture_size = 256;
111 static XrmOptionDescRec opts[] = {
112 { "-spin", ".spin", XrmoptionSepArg, 0 },
113 { "+spin", ".spin", XrmoptionNoArg, "" },
114 { "-wander", ".wander", XrmoptionNoArg, "True" },
115 { "+wander", ".wander", XrmoptionNoArg, "False" },
116 {"-texture", ".texture", XrmoptionNoArg, (caddr_t) "true" },
117 {"+texture", ".texture", XrmoptionNoArg, (caddr_t) "false" },
118 {"-waves", ".waves", XrmoptionSepArg, 0 },
119 {"-wave-speed", ".waveSpeed", XrmoptionSepArg, 0 },
120 {"-wave-radius", ".waveRadius", XrmoptionSepArg, 0 },
123 static argtype vars[] = {
124 {(caddr_t *) &do_spin, "spin", "Spin", DEF_SPIN, t_String},
125 {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
126 {(caddr_t *) &do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
127 {(caddr_t *) &wave_count, "waves", "Waves", DEF_WAVE_COUNT, t_Int},
128 {(caddr_t *) &wave_speed, "waveSpeed", "WaveSpeed", DEF_WAVE_SPEED, t_Int},
129 {(caddr_t *) &wave_radius,"waveRadius","WaveRadius", DEF_WAVE_RADIUS,t_Int},
132 ModeSpecOpt ccs_opts = {countof(opts), opts, countof(vars), vars, NULL};
136 unit_cube (Bool wire)
138 glBegin (wire ? GL_LINE_LOOP : GL_QUADS); /* front */
139 glNormal3f (0, 0, 1);
140 glTexCoord2f(1, 0); glVertex3f ( 0.5, -0.5, 0.5);
141 glTexCoord2f(0, 0); glVertex3f ( 0.5, 0.5, 0.5);
142 glTexCoord2f(0, 1); glVertex3f (-0.5, 0.5, 0.5);
143 glTexCoord2f(1, 1); glVertex3f (-0.5, -0.5, 0.5);
146 glBegin (wire ? GL_LINE_LOOP : GL_QUADS); /* back */
147 glNormal3f (0, 0, -1);
148 glTexCoord2f(0, 0); glVertex3f (-0.5, -0.5, -0.5);
149 glTexCoord2f(0, 1); glVertex3f (-0.5, 0.5, -0.5);
150 glTexCoord2f(1, 1); glVertex3f ( 0.5, 0.5, -0.5);
151 glTexCoord2f(1, 0); glVertex3f ( 0.5, -0.5, -0.5);
154 glBegin (wire ? GL_LINE_LOOP : GL_QUADS); /* left */
155 glNormal3f (-1, 0, 0);
156 glTexCoord2f(1, 1); glVertex3f (-0.5, 0.5, 0.5);
157 glTexCoord2f(1, 0); glVertex3f (-0.5, 0.5, -0.5);
158 glTexCoord2f(0, 0); glVertex3f (-0.5, -0.5, -0.5);
159 glTexCoord2f(0, 1); glVertex3f (-0.5, -0.5, 0.5);
162 glBegin (wire ? GL_LINE_LOOP : GL_QUADS); /* right */
163 glNormal3f (1, 0, 0);
164 glTexCoord2f(1, 1); glVertex3f ( 0.5, -0.5, -0.5);
165 glTexCoord2f(1, 0); glVertex3f ( 0.5, 0.5, -0.5);
166 glTexCoord2f(0, 0); glVertex3f ( 0.5, 0.5, 0.5);
167 glTexCoord2f(0, 1); glVertex3f ( 0.5, -0.5, 0.5);
172 glBegin (wire ? GL_LINE_LOOP : GL_QUADS); /* top */
173 glNormal3f (0, 1, 0);
174 glTexCoord2f(0, 0); glVertex3f ( 0.5, 0.5, 0.5);
175 glTexCoord2f(0, 1); glVertex3f ( 0.5, 0.5, -0.5);
176 glTexCoord2f(1, 1); glVertex3f (-0.5, 0.5, -0.5);
177 glTexCoord2f(1, 0); glVertex3f (-0.5, 0.5, 0.5);
180 glBegin (wire ? GL_LINE_LOOP : GL_QUADS); /* bottom */
181 glNormal3f (0, -1, 0);
182 glTexCoord2f(1, 0); glVertex3f (-0.5, -0.5, 0.5);
183 glTexCoord2f(0, 0); glVertex3f (-0.5, -0.5, -0.5);
184 glTexCoord2f(0, 1); glVertex3f ( 0.5, -0.5, -0.5);
185 glTexCoord2f(1, 1); glVertex3f ( 0.5, -0.5, 0.5);
191 /* Window management, etc
194 reshape_cube (ModeInfo *mi, int width, int height)
196 GLfloat h = (GLfloat) height / (GLfloat) width;
198 glViewport (0, 0, (GLint) width, (GLint) height);
200 glMatrixMode(GL_PROJECTION);
203 gluPerspective (30.0, 1/h, 1.0, 100.0);
204 glMatrixMode(GL_MODELVIEW);
206 gluLookAt( 0.0, 0.0, 30.0,
210 glClear(GL_COLOR_BUFFER_BIT);
216 Adapted from ../hacks/interference.c by Hannu Mallat.
220 init_wave (ModeInfo *mi)
222 cube_configuration *cc = &ccs[MI_SCREEN(mi)];
225 cc->waves = ww = (waves *) calloc (sizeof(*cc->waves), 1);
226 ww->nwaves = wave_count;
227 ww->radius = wave_radius;
228 ww->speed = wave_speed;
229 ww->heights = (int *) calloc (sizeof(*ww->heights), ww->radius);
230 ww->srcs = (wave_src *) calloc (sizeof(*ww->srcs), ww->nwaves);
232 for (i = 0; i < ww->radius; i++)
234 float max = (cc->ncolors * (ww->radius - i) / (float) ww->radius);
235 ww->heights[i] = ((max + max * cos(i / 50.0)) / 2.0);
238 for (i = 0; i < ww->nwaves; i++)
240 ww->srcs[i].xth = frand(2.0) * M_PI;
241 ww->srcs[i].yth = frand(2.0) * M_PI;
246 interference (ModeInfo *mi)
248 cube_configuration *cc = &ccs[MI_SCREEN(mi)];
249 waves *ww = cc->waves;
252 /* Move the wave origins around
254 for (i = 0; i < ww->nwaves; i++)
256 ww->srcs[i].xth += (ww->speed / 1000.0);
257 if (ww->srcs[i].xth > 2*M_PI)
258 ww->srcs[i].xth -= 2*M_PI;
259 ww->srcs[i].yth += (ww->speed / 1000.0);
260 if (ww->srcs[i].yth > 2*M_PI)
261 ww->srcs[i].yth -= 2*M_PI;
263 ww->srcs[i].x = (cc->texture_width/2 +
264 (cos (ww->srcs[i].xth) *
265 cc->texture_width / 2));
266 ww->srcs[i].y = (cc->texture_height/2 +
267 (cos (ww->srcs[i].yth) *
268 cc->texture_height / 2));
271 /* Compute the effect of the waves on each pixel,
272 and generate the output map.
274 for (y = 0; y < cc->texture_height; y++)
275 for (x = 0; x < cc->texture_width; x++)
279 for (i = 0; i < ww->nwaves; i++)
281 int dx = x - ww->srcs[i].x;
282 int dy = y - ww->srcs[i].y;
283 int dist = sqrt (dx*dx + dy*dy);
284 result += (dist > ww->radius ? 0 : ww->heights[dist]);
286 result %= cc->ncolors;
288 o = cc->texture + (((y * cc->texture_width) + x) << 2);
289 o[0] = (cc->texture_colors[result].red >> 8);
290 o[1] = (cc->texture_colors[result].green >> 8);
291 o[2] = (cc->texture_colors[result].blue >> 8);
301 init_texture (ModeInfo *mi)
303 cube_configuration *cc = &ccs[MI_SCREEN(mi)];
306 glEnable(GL_TEXTURE_2D);
309 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
310 glGenTextures (1, &cc->texture_id);
311 glBindTexture (GL_TEXTURE_2D, cc->texture_id);
312 check_gl_error("texture binding");
314 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
315 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
316 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
317 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
318 glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
319 glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
320 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
321 check_gl_error("texture initialization");
323 cc->texture_width = texture_size;
324 cc->texture_height = texture_size;
326 i = texture_size * texture_size * 4;
327 cc->texture = (char *) malloc (i);
328 memset (cc->texture, 0xFF, i);
333 shuffle_texture (ModeInfo *mi)
335 cube_configuration *cc = &ccs[MI_SCREEN(mi)];
338 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
339 cc->texture_width, cc->texture_height, 0,
340 GL_RGBA, GL_UNSIGNED_BYTE,
342 check_gl_error("texture");
347 cube_handle_event (ModeInfo *mi, XEvent *event)
349 cube_configuration *cc = &ccs[MI_SCREEN(mi)];
351 if (event->xany.type == ButtonPress &&
352 event->xbutton.button & Button1)
354 cc->button_down_p = True;
355 gltrackball_start (cc->trackball,
356 event->xbutton.x, event->xbutton.y,
357 MI_WIDTH (mi), MI_HEIGHT (mi));
360 else if (event->xany.type == ButtonRelease &&
361 event->xbutton.button & Button1)
363 cc->button_down_p = False;
366 else if (event->xany.type == MotionNotify &&
369 gltrackball_track (cc->trackball,
370 event->xmotion.x, event->xmotion.y,
371 MI_WIDTH (mi), MI_HEIGHT (mi));
380 init_cube (ModeInfo *mi)
383 cube_configuration *cc;
384 int wire = MI_IS_WIREFRAME(mi);
387 ccs = (cube_configuration *)
388 calloc (MI_NUM_SCREENS(mi), sizeof (cube_configuration));
390 fprintf(stderr, "%s: out of memory\n", progname);
395 cc = &ccs[MI_SCREEN(mi)];
397 if ((cc->glx_context = init_GL(mi)) != NULL) {
398 reshape_cube (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
403 static GLfloat pos[4] = {1.0, 0.5, 1.0, 0.0};
404 static GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
405 static GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
407 glLightfv(GL_LIGHT0, GL_POSITION, pos);
408 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
409 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
411 glEnable(GL_LIGHTING);
413 glEnable(GL_DEPTH_TEST);
414 glEnable(GL_CULL_FACE);
419 Bool spinx=False, spiny=False, spinz=False;
420 double spin_speed = 1.0;
421 double wander_speed = 0.05;
426 if (*s == 'x' || *s == 'X') spinx = True;
427 else if (*s == 'y' || *s == 'Y') spiny = True;
428 else if (*s == 'z' || *s == 'Z') spinz = True;
432 "%s: spin must contain only the characters X, Y, or Z (not \"%s\")\n",
439 cc->rot = make_rotator (spinx ? spin_speed : 0,
440 spiny ? spin_speed : 0,
441 spinz ? spin_speed : 0,
443 do_wander ? wander_speed : 0,
444 (spinx && spiny && spinz));
445 cc->trackball = gltrackball_init ();
449 cc->texture_colors = (XColor *) calloc(cc->ncolors, sizeof(XColor));
450 cc->cube_colors = (XColor *) calloc(cc->ncolors, sizeof(XColor));
453 double H[3], S[3], V[3];
456 H[1] = ((H[0] + shift) < 360) ? (H[0]+shift) : (H[0] + shift - 360);
457 H[2] = ((H[1] + shift) < 360) ? (H[1]+shift) : (H[1] + shift - 360);
458 S[0] = S[1] = S[2] = 1.0;
459 V[0] = V[1] = V[2] = 1.0;
460 make_color_loop(0, 0,
464 cc->texture_colors, &cc->ncolors,
467 make_smooth_colormap (0, 0, 0,
468 cc->cube_colors, &cc->ncolors,
472 cc->ncubes = MI_COUNT (mi);
473 cc->cubes = (cube *) calloc (sizeof(cube), cc->ncubes);
474 for (i = 0; i < cc->ncubes; i++)
476 cube *cube = &cc->cubes[i];
477 cube->color = random() % cc->ncolors;
481 cube->dx = frand(0.1);
482 cube->dy = frand(0.1);
483 cube->dz = frand(0.1);
484 cube->dw = frand(0.1);
485 cube->dh = frand(0.1);
486 cube->dd = frand(0.1);
496 shuffle_texture (mi);
499 cc->cube_list = glGenLists (1);
500 glNewList (cc->cube_list, GL_COMPILE);
507 shuffle_cubes (ModeInfo *mi)
509 cube_configuration *cc = &ccs[MI_SCREEN(mi)];
511 for (i = 0; i < cc->ncubes; i++)
513 # define SINOID(SCALE,FRAME,SIZE) \
514 ((((1 + sin((FRAME * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
516 cube *cube = &cc->cubes[i];
517 cube->x = SINOID(cube->dx, cube->frame, 0.5);
518 cube->y = SINOID(cube->dy, cube->frame, 0.5);
519 cube->z = SINOID(cube->dz, cube->frame, 0.5);
520 cube->w = SINOID(cube->dw, cube->frame, 0.9) + 1.0;
521 cube->h = SINOID(cube->dh, cube->frame, 0.9) + 1.0;
522 cube->d = SINOID(cube->dd, cube->frame, 0.9) + 1.0;
530 draw_cube (ModeInfo *mi)
532 cube_configuration *cc = &ccs[MI_SCREEN(mi)];
533 Display *dpy = MI_DISPLAY(mi);
534 Window window = MI_WINDOW(mi);
537 if (!cc->glx_context)
540 glShadeModel(GL_FLAT);
542 glEnable(GL_DEPTH_TEST);
543 glEnable(GL_NORMALIZE);
544 glEnable(GL_CULL_FACE);
546 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
550 glScalef(1.1, 1.1, 1.1);
554 get_position (cc->rot, &x, &y, &z, !cc->button_down_p);
555 glTranslatef((x - 0.5) * 8,
559 gltrackball_rotate (cc->trackball);
561 get_rotation (cc->rot, &x, &y, &z, !cc->button_down_p);
562 glRotatef (x * 360, 1.0, 0.0, 0.0);
563 glRotatef (y * 360, 0.0, 1.0, 0.0);
564 glRotatef (z * 360, 0.0, 0.0, 1.0);
567 glScalef (2.5, 2.5, 2.5);
569 for (i = 0; i < cc->ncubes; i++)
571 cube *cube = &cc->cubes[i];
573 color[0] = cc->cube_colors[cube->color].red / 65536.0;
574 color[1] = cc->cube_colors[cube->color].green / 65536.0;
575 color[2] = cc->cube_colors[cube->color].blue / 65536.0;
578 if (cube->color >= cc->ncolors) cube->color = 0;
581 glTranslatef (cube->x, cube->y, cube->z);
582 glScalef (cube->w, cube->h, cube->d);
583 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
584 glCallList (cc->cube_list);
590 shuffle_texture (mi);
594 if (mi->fps_p) do_fps (mi);
597 glXSwapBuffers(dpy, window);