1 /* nerverot, nervous rotation of random thingies, v1.4
2 * by Dan Bornstein, danfuzz@milk.com
3 * Copyright (c) 2000-2001 Dan Bornstein. All rights reserved.
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation. No representations are made about the suitability of this
10 * software for any purpose. It is provided "as is" without express or
13 * The goal of this screensaver is to be interesting and compelling to
14 * watch, yet induce a state of nervous edginess in the viewer.
16 * See the included man page for more details.
20 #include "screenhack.h"
24 /* random float in the range (-1..1) */
25 #define RAND_FLOAT_PM1 \
26 (((FLOAT) ((random() >> 8) & 0xffff)) / ((FLOAT) 0x10000) * 2 - 1)
28 /* random float in the range (0..1) */
29 #define RAND_FLOAT_01 \
30 (((FLOAT) ((random() >> 8) & 0xffff)) / ((FLOAT) 0x10000))
34 /* parameters that are user configurable */
37 static int requestedBlotCount;
39 /* delay (usec) between iterations */
42 /* max iterations per model */
45 /* variability of xoff/yoff per iteration (0..1) */
46 static FLOAT nervousness;
48 /* max nervousness radius (0..1) */
49 static FLOAT maxNerveRadius;
51 /* chance per iteration that an event will happen */
52 static FLOAT eventChance;
54 /* fraction (0..1) towards rotation target or scale target to move each
58 /* min and max scale for drawing, as fraction of baseScale */
59 static FLOAT minScale;
60 static FLOAT maxScale;
62 /* min and max radius of blot drawing */
66 /* the number of colors to use */
67 static int colorCount;
72 /* whether or not to do double-buffering */
73 static Bool doubleBuffer;
77 /* non-user-modifiable immutable definitions */
79 /* base scale factor for drawing, calculated as
80 * max(screenWidth,screenHeight) */
83 /* width and height of the window */
84 static int windowWidth;
85 static int windowHeight;
87 /* center position of the window */
91 static Display *display; /* the display to draw on */
92 static Window window; /* the window to draw on */
93 static Drawable drawable; /* the thing to directly draw on */
94 static GC *gcs; /* array of gcs, one per color used */
98 /* structure of the model */
100 /* each point-like thingy to draw is represented as a blot */
101 typedef struct blot_s
103 FLOAT x; /* 3d x position (-1..1) */
104 FLOAT y; /* 3d y position (-1..1) */
105 FLOAT z; /* 3d z position (-1..1) */
106 FLOAT xoff[3][3]; /* display x offset per drawn point (-1..1) */
107 FLOAT yoff[3][3]; /* display x offset per drawn point (-1..1) */
110 /* each drawn line is represented as a LineSegment */
111 typedef struct linesegment_s
120 /* array of the blots in the model */
121 static Blot *blots = NULL;
122 static int blotCount;
124 /* each blot draws as a simple 2d shape with each coordinate as an int
125 * in the range (-1..1); this is the base shape */
126 static XPoint blotShape[] = { { 0, 0}, { 1, 0}, { 1, 1},
127 { 0, 1}, {-1, 1}, {-1, 0},
128 {-1,-1}, { 0,-1}, { 1,-1} };
129 static int blotShapeCount = sizeof (blotShape) / sizeof (XPoint);
131 /* two arrays of line segments; one for the ones to erase, and one for the
134 static LineSegment *segsToDraw = NULL;
135 static LineSegment *segsToErase = NULL;
137 /* current rotation values per axis, scale factor, and light position */
141 static FLOAT curScale;
146 /* target rotation values per axis, scale factor, and light position */
147 static FLOAT xRotTarget;
148 static FLOAT yRotTarget;
149 static FLOAT zRotTarget;
150 static FLOAT scaleTarget;
151 static FLOAT lightXTarget;
152 static FLOAT lightYTarget;
153 static FLOAT lightZTarget;
155 /* current absolute offsets from the center */
156 static int centerXOff = 0;
157 static int centerYOff = 0;
159 /* iterations until the model changes */
160 static int itersTillNext;
165 * generic blot setup and manipulation
168 /* initialize a blot with the given coordinates and random display offsets */
169 static void initBlot (Blot *b, FLOAT x, FLOAT y, FLOAT z)
177 for (i = 0; i < 3; i++)
179 for (j = 0; j < 3; j++)
181 b->xoff[i][j] = RAND_FLOAT_PM1;
182 b->yoff[i][j] = RAND_FLOAT_PM1;
187 /* scale the blots to have a max distance of 1 from the center */
188 static void scaleBlotsToRadius1 (void)
193 for (n = 0; n < blotCount; n++)
196 blots[n].x * blots[n].x +
197 blots[n].y * blots[n].y +
198 blots[n].z * blots[n].z;
199 if (distSquare > max)
212 for (n = 0; n < blotCount; n++)
220 /* randomly reorder the blots */
221 static void randomlyReorderBlots (void)
225 for (n = 0; n < blotCount; n++)
227 int m = RAND_FLOAT_01 * (blotCount - n) + n;
228 Blot tmpBlot = blots[n];
234 /* randomly rotate the blots around the origin */
235 static void randomlyRotateBlots (void)
239 /* random amounts to rotate about each axis */
240 FLOAT xRot = RAND_FLOAT_PM1 * M_PI;
241 FLOAT yRot = RAND_FLOAT_PM1 * M_PI;
242 FLOAT zRot = RAND_FLOAT_PM1 * M_PI;
244 /* rotation factors */
245 FLOAT sinX = sin (xRot);
246 FLOAT cosX = cos (xRot);
247 FLOAT sinY = sin (yRot);
248 FLOAT cosY = cos (yRot);
249 FLOAT sinZ = sin (zRot);
250 FLOAT cosZ = cos (zRot);
252 for (n = 0; n < blotCount; n++)
254 FLOAT x1 = blots[n].x;
255 FLOAT y1 = blots[n].y;
256 FLOAT z1 = blots[n].z;
259 /* rotate on z axis */
260 x2 = x1 * cosZ - y1 * sinZ;
261 y2 = x1 * sinZ + y1 * cosZ;
264 /* rotate on x axis */
265 y1 = y2 * cosX - z2 * sinX;
266 z1 = y2 * sinX + z2 * cosX;
269 /* rotate on y axis */
270 z2 = z1 * cosY - x1 * sinY;
271 x2 = z1 * sinY + x1 * cosY;
283 * blot configurations
286 /* set up the initial array of blots to be a at the edge of a sphere */
287 static void setupBlotsSphere (void)
291 blotCount = requestedBlotCount;
292 blots = calloc (sizeof (Blot), blotCount);
294 for (n = 0; n < blotCount; n++)
296 /* pick a spot, but reject if its radius is < 0.2 or > 1 to
297 * avoid scaling problems */
298 FLOAT x, y, z, radius;
306 radius = sqrt (x * x + y * y + z * z);
307 if ((radius >= 0.2) && (radius <= 1.0))
317 initBlot (&blots[n], x, y, z);
321 /* set up the initial array of blots to be a simple cube */
322 static void setupBlotsCube (void)
326 /* derive blotsPerEdge from blotCount, but then do the reverse
327 * since roundoff may have changed blotCount */
328 int blotsPerEdge = ((requestedBlotCount - 8) / 12) + 2;
331 if (blotsPerEdge < 2)
336 distBetween = 2.0 / (blotsPerEdge - 1.0);
338 blotCount = 8 + (blotsPerEdge - 2) * 12;
339 blots = calloc (sizeof (Blot), blotCount);
342 /* define the corners */
343 for (i = -1; i < 2; i += 2)
345 for (j = -1; j < 2; j += 2)
347 for (k = -1; k < 2; k += 2)
349 initBlot (&blots[n], i, j, k);
355 /* define the edges */
356 for (i = 1; i < (blotsPerEdge - 1); i++)
358 FLOAT varEdge = distBetween * i - 1;
359 initBlot (&blots[n++], varEdge, -1, -1);
360 initBlot (&blots[n++], varEdge, 1, -1);
361 initBlot (&blots[n++], varEdge, -1, 1);
362 initBlot (&blots[n++], varEdge, 1, 1);
363 initBlot (&blots[n++], -1, varEdge, -1);
364 initBlot (&blots[n++], 1, varEdge, -1);
365 initBlot (&blots[n++], -1, varEdge, 1);
366 initBlot (&blots[n++], 1, varEdge, 1);
367 initBlot (&blots[n++], -1, -1, varEdge);
368 initBlot (&blots[n++], 1, -1, varEdge);
369 initBlot (&blots[n++], -1, 1, varEdge);
370 initBlot (&blots[n++], 1, 1, varEdge);
373 scaleBlotsToRadius1 ();
374 randomlyReorderBlots ();
375 randomlyRotateBlots ();
378 /* set up the initial array of blots to be a cylinder */
379 static void setupBlotsCylinder (void)
384 /* derive blotsPerEdge and blotsPerRing from blotCount, but then do the
385 * reverse since roundoff may have changed blotCount */
386 FLOAT reqRoot = sqrt ((FLOAT) requestedBlotCount);
387 int blotsPerRing = ceil (RAND_FLOAT_PM1 * reqRoot) / 2 + reqRoot;
388 int blotsPerEdge = requestedBlotCount / blotsPerRing;
390 if (blotsPerRing < 2)
395 if (blotsPerEdge < 2)
400 distBetween = 2.0 / (blotsPerEdge - 1);
402 blotCount = blotsPerEdge * blotsPerRing;
403 blots = calloc (sizeof (Blot), blotCount);
406 /* define the edges */
407 for (i = 0; i < blotsPerRing; i++)
409 FLOAT x = sin (2 * M_PI / blotsPerRing * i);
410 FLOAT y = cos (2 * M_PI / blotsPerRing * i);
411 for (j = 0; j < blotsPerEdge; j++)
413 initBlot (&blots[n], x, y, j * distBetween - 1);
418 scaleBlotsToRadius1 ();
419 randomlyReorderBlots ();
420 randomlyRotateBlots ();
423 /* set up the initial array of blots to be a squiggle */
424 static void setupBlotsSquiggle (void)
426 FLOAT x, y, z, xv, yv, zv, len;
427 int minCoor, maxCoor;
430 blotCount = requestedBlotCount;
431 blots = calloc (sizeof (Blot), blotCount);
433 maxCoor = (int) (RAND_FLOAT_01 * 5) + 1;
443 len = sqrt (xv * xv + yv * yv + zv * zv);
448 for (n = 0; n < blotCount; n++)
450 FLOAT newx, newy, newz;
451 initBlot (&blots[n], x, y, z);
455 xv += RAND_FLOAT_PM1 * 0.1;
456 yv += RAND_FLOAT_PM1 * 0.1;
457 zv += RAND_FLOAT_PM1 * 0.1;
458 len = sqrt (xv * xv + yv * yv + zv * zv);
467 if ( (newx >= minCoor) && (newx <= maxCoor)
468 && (newy >= minCoor) && (newy <= maxCoor)
469 && (newz >= minCoor) && (newz <= maxCoor))
480 scaleBlotsToRadius1 ();
481 randomlyReorderBlots ();
484 /* set up the initial array of blots to be near the corners of a
485 * cube, distributed slightly */
486 static void setupBlotsCubeCorners (void)
490 blotCount = requestedBlotCount;
491 blots = calloc (sizeof (Blot), blotCount);
493 for (n = 0; n < blotCount; n++)
495 FLOAT x = rint (RAND_FLOAT_01) * 2 - 1;
496 FLOAT y = rint (RAND_FLOAT_01) * 2 - 1;
497 FLOAT z = rint (RAND_FLOAT_01) * 2 - 1;
499 x += RAND_FLOAT_PM1 * 0.3;
500 y += RAND_FLOAT_PM1 * 0.3;
501 z += RAND_FLOAT_PM1 * 0.3;
503 initBlot (&blots[n], x, y, z);
506 scaleBlotsToRadius1 ();
507 randomlyRotateBlots ();
510 /* set up the initial array of blots to be randomly distributed
511 * on the surface of a tetrahedron */
512 static void setupBlotsTetrahedron (void)
514 /* table of corners of the tetrahedron */
515 static FLOAT cor[4][3] = { { 0.0, 1.0, 0.0 },
516 { -0.75, -0.5, -0.433013 },
517 { 0.0, -0.5, 0.866025 },
518 { 0.75, -0.5, -0.433013 } };
522 /* derive blotsPerSurface from blotCount, but then do the reverse
523 * since roundoff may have changed blotCount */
524 int blotsPerSurface = requestedBlotCount / 4;
526 blotCount = blotsPerSurface * 4;
527 blots = calloc (sizeof (Blot), blotCount);
529 for (n = 0; n < blotCount; n += 4)
531 /* pick a random point on a unit right triangle */
532 FLOAT rawx = RAND_FLOAT_01;
533 FLOAT rawy = RAND_FLOAT_01;
535 if ((rawx + rawy) > 1)
537 /* swap coords into place */
538 FLOAT t = 1.0 - rawx;
543 /* translate the point to be on each of the surfaces */
544 for (c = 0; c < 4; c++)
548 int c1 = (c + 1) % 4;
549 int c2 = (c + 2) % 4;
551 x = (cor[c1][0] - cor[c][0]) * rawx +
552 (cor[c2][0] - cor[c][0]) * rawy +
555 y = (cor[c1][1] - cor[c][1]) * rawx +
556 (cor[c2][1] - cor[c][1]) * rawy +
559 z = (cor[c1][2] - cor[c][2]) * rawx +
560 (cor[c2][2] - cor[c][2]) * rawy +
563 initBlot (&blots[n + c], x, y, z);
567 randomlyRotateBlots ();
570 /* set up the initial array of blots to be an almost-evenly-distributed
572 static void setupBlotsSheet (void)
576 int blotsPerDimension = floor (sqrt (requestedBlotCount));
579 if (blotsPerDimension < 2)
581 blotsPerDimension = 2;
584 spaceBetween = 2.0 / (blotsPerDimension - 1);
586 blotCount = blotsPerDimension * blotsPerDimension;
587 blots = calloc (sizeof (Blot), blotCount);
589 for (x = 0; x < blotsPerDimension; x++)
591 for (y = 0; y < blotsPerDimension; y++)
593 FLOAT x1 = x * spaceBetween - 1.0;
594 FLOAT y1 = y * spaceBetween - 1.0;
597 x1 += RAND_FLOAT_PM1 * spaceBetween / 3;
598 y1 += RAND_FLOAT_PM1 * spaceBetween / 3;
599 z1 += RAND_FLOAT_PM1 * spaceBetween / 2;
601 initBlot (&blots[x + y * blotsPerDimension], x1, y1, z1);
605 scaleBlotsToRadius1 ();
606 randomlyReorderBlots ();
607 randomlyRotateBlots ();
610 /* set up the initial array of blots to be a swirlycone */
611 static void setupBlotsSwirlyCone (void)
613 FLOAT radSpace = 1.0 / (requestedBlotCount - 1);
614 FLOAT zSpace = radSpace * 2;
615 FLOAT rotAmt = RAND_FLOAT_PM1 * M_PI / 10;
620 blotCount = requestedBlotCount;
621 blots = calloc (sizeof (Blot), blotCount);
623 for (n = 0; n < blotCount; n++)
625 FLOAT radius = n * radSpace;
626 FLOAT x = cos (rot) * radius;
627 FLOAT y = sin (rot) * radius;
628 FLOAT z = n * zSpace - 1.0;
631 initBlot (&blots[n], x, y, z);
634 scaleBlotsToRadius1 ();
635 randomlyReorderBlots ();
636 randomlyRotateBlots ();
639 /* forward declaration for recursive use immediately below */
640 static void setupBlots (void);
642 /* set up the blots to be two of the other choices, placed next to
644 static void setupBlotsDuo (void)
646 int origRequest = requestedBlotCount;
647 FLOAT tx, ty, tz, radius;
648 Blot *blots1, *blots2;
652 if (requestedBlotCount < 15)
654 /* special case bottom-out */
662 radius = sqrt (tx * tx + ty * ty + tz * tz);
667 /* recursive call to setup set 1 */
668 requestedBlotCount = origRequest / 2;
671 if (blotCount >= origRequest)
673 /* return immediately if this satisfies the original count request */
674 requestedBlotCount = origRequest;
683 /* translate to new position */
684 for (n = 0; n < count1; n++)
691 /* recursive call to setup set 2 */
692 requestedBlotCount = origRequest - count1;
697 /* translate to new position */
698 for (n = 0; n < count2; n++)
705 /* combine the two arrays */
706 blotCount = count1 + count2;
707 blots = calloc (sizeof (Blot), blotCount);
708 memcpy (&blots[0], blots1, sizeof (Blot) * count1);
709 memcpy (&blots[count1], blots2, sizeof (Blot) * count2);
713 scaleBlotsToRadius1 ();
714 randomlyReorderBlots ();
716 /* restore the original requested count, for future iterations */
717 requestedBlotCount = origRequest;
726 /* free the blots, in preparation for a new shape */
727 static void freeBlots (void)
735 if (segsToErase != NULL)
741 if (segsToDraw != NULL)
748 /* set up the initial arrays of blots */
749 static void setupBlots (void)
751 int which = RAND_FLOAT_01 * 11;
764 setupBlotsCylinder ();
767 setupBlotsSquiggle ();
770 setupBlotsCubeCorners ();
773 setupBlotsTetrahedron ();
779 setupBlotsSwirlyCone ();
789 /* set up the segments arrays */
790 static void setupSegs (void)
792 /* there are blotShapeCount - 1 line segments per blot */
793 segCount = blotCount * (blotShapeCount - 1);
794 segsToErase = calloc (sizeof (LineSegment), segCount);
795 segsToDraw = calloc (sizeof (LineSegment), segCount);
797 /* erase the world */
798 XFillRectangle (display, drawable, gcs[0], 0, 0,
799 windowWidth, windowHeight);
808 /* set up the colormap */
809 static void setupColormap (XWindowAttributes *xgwa)
813 XColor *colors = (XColor *) calloc (sizeof (XColor), colorCount + 1);
815 unsigned short r, g, b;
817 double s1, s2, v1, v2;
819 r = RAND_FLOAT_01 * 0x10000;
820 g = RAND_FLOAT_01 * 0x10000;
821 b = RAND_FLOAT_01 * 0x10000;
822 rgb_to_hsv (r, g, b, &h1, &s1, &v1);
826 r = RAND_FLOAT_01 * 0x10000;
827 g = RAND_FLOAT_01 * 0x10000;
828 b = RAND_FLOAT_01 * 0x10000;
829 rgb_to_hsv (r, g, b, &h2, &s2, &v2);
833 colors[0].pixel = get_pixel_resource ("background", "Background",
834 display, xgwa->colormap);
836 make_color_ramp (display, xgwa->colormap, h1, s1, v1, h2, s2, v2,
837 colors + 1, &colorCount, False, True, False);
841 fprintf (stderr, "%s: couldn't allocate any colors\n", progname);
845 gcs = (GC *) calloc (sizeof (GC), colorCount + 1);
847 for (n = 0; n <= colorCount; n++)
849 gcv.foreground = colors[n].pixel;
850 gcv.line_width = lineWidth;
851 gcs[n] = XCreateGC (display, window, GCForeground | GCLineWidth, &gcv);
860 * overall setup stuff
863 /* set up the system */
864 static void setup (void)
866 XWindowAttributes xgwa;
868 XGetWindowAttributes (display, window, &xgwa);
870 windowWidth = xgwa.width;
871 windowHeight = xgwa.height;
872 centerX = windowWidth / 2;
873 centerY = windowHeight / 2;
874 baseScale = (xgwa.height < xgwa.width) ? xgwa.height : xgwa.width;
878 drawable = XCreatePixmap (display, window, xgwa.width, xgwa.height,
886 setupColormap (&xgwa);
890 /* set up the initial rotation, scale, and light values as random, but
891 * with the targets equal to where it is */
892 xRot = xRotTarget = RAND_FLOAT_01 * M_PI;
893 yRot = yRotTarget = RAND_FLOAT_01 * M_PI;
894 zRot = zRotTarget = RAND_FLOAT_01 * M_PI;
895 curScale = scaleTarget = RAND_FLOAT_01 * (maxScale - minScale) + minScale;
896 lightX = lightXTarget = RAND_FLOAT_PM1;
897 lightY = lightYTarget = RAND_FLOAT_PM1;
898 lightZ = lightZTarget = RAND_FLOAT_PM1;
900 itersTillNext = RAND_FLOAT_01 * maxIters;
909 /* "render" the blots into segsToDraw, with the current rotation factors */
910 static void renderSegs (void)
915 /* rotation factors */
916 FLOAT sinX = sin (xRot);
917 FLOAT cosX = cos (xRot);
918 FLOAT sinY = sin (yRot);
919 FLOAT cosY = cos (yRot);
920 FLOAT sinZ = sin (zRot);
921 FLOAT cosZ = cos (zRot);
923 for (n = 0; n < blotCount; n++)
933 FLOAT x1 = blots[n].x;
934 FLOAT y1 = blots[n].y;
935 FLOAT z1 = blots[n].z;
938 /* rotate on z axis */
939 x2 = x1 * cosZ - y1 * sinZ;
940 y2 = x1 * sinZ + y1 * cosZ;
943 /* rotate on x axis */
944 y1 = y2 * cosX - z2 * sinX;
945 z1 = y2 * sinX + z2 * cosX;
948 /* rotate on y axis */
949 z2 = z1 * cosY - x1 * sinY;
950 x2 = z1 * sinY + x1 * cosY;
953 /* the color to draw is based on the distance from the light of
954 * the post-rotation blot */
958 color = 1 + (x1 * x1 + y1 * y1 + z1 * z1) / 4 * colorCount;
959 if (color > colorCount)
964 /* set up the base screen coordinates for drawing */
965 baseX = x2 / 2 * baseScale * curScale + centerX + centerXOff;
966 baseY = y2 / 2 * baseScale * curScale + centerY + centerYOff;
968 radius = (z2 + 1) / 2 * (maxRadius - minRadius) + minRadius;
970 for (i = 0; i < 3; i++)
972 for (j = 0; j < 3; j++)
975 ((i - 1) + (b->xoff[i][j] * maxNerveRadius)) * radius;
977 ((j - 1) + (b->yoff[i][j] * maxNerveRadius)) * radius;
981 for (i = 1; i < blotShapeCount; i++)
983 segsToDraw[m].gc = gcs[color];
984 segsToDraw[m].x1 = x[blotShape[i-1].x + 1][blotShape[i-1].y + 1];
985 segsToDraw[m].y1 = y[blotShape[i-1].x + 1][blotShape[i-1].y + 1];
986 segsToDraw[m].x2 = x[blotShape[i].x + 1][blotShape[i].y + 1];
987 segsToDraw[m].y2 = y[blotShape[i].x + 1][blotShape[i].y + 1];
993 /* update blots, adjusting the offsets and rotation factors. */
994 static void updateWithFeeling (void)
998 /* pick a new model if the time is right */
1000 if (itersTillNext < 0)
1002 itersTillNext = RAND_FLOAT_01 * maxIters;
1008 /* update the rotation factors by moving them a bit toward the targets */
1009 xRot = xRot + (xRotTarget - xRot) * iterAmt;
1010 yRot = yRot + (yRotTarget - yRot) * iterAmt;
1011 zRot = zRot + (zRotTarget - zRot) * iterAmt;
1013 /* similarly the scale factor */
1014 curScale = curScale + (scaleTarget - curScale) * iterAmt;
1016 /* and similarly the light position */
1017 lightX = lightX + (lightXTarget - lightX) * iterAmt;
1018 lightY = lightY + (lightYTarget - lightY) * iterAmt;
1019 lightZ = lightZ + (lightZTarget - lightZ) * iterAmt;
1021 /* for each blot... */
1022 for (n = 0; n < blotCount; n++)
1024 /* add a bit of random jitter to xoff/yoff */
1025 for (i = 0; i < 3; i++)
1027 for (j = 0; j < 3; j++)
1031 newOff = blots[n].xoff[i][j] + RAND_FLOAT_PM1 * nervousness;
1032 if (newOff < -1) newOff = -(newOff + 1) - 1;
1033 else if (newOff > 1) newOff = -(newOff - 1) + 1;
1034 blots[n].xoff[i][j] = newOff;
1036 newOff = blots[n].yoff[i][j] + RAND_FLOAT_PM1 * nervousness;
1037 if (newOff < -1) newOff = -(newOff + 1) - 1;
1038 else if (newOff > 1) newOff = -(newOff - 1) + 1;
1039 blots[n].yoff[i][j] = newOff;
1044 /* depending on random chance, update one or more factors */
1045 if (RAND_FLOAT_01 <= eventChance)
1047 int which = RAND_FLOAT_01 * 14;
1052 xRotTarget = RAND_FLOAT_PM1 * M_PI * 2;
1057 yRotTarget = RAND_FLOAT_PM1 * M_PI * 2;
1062 zRotTarget = RAND_FLOAT_PM1 * M_PI * 2;
1067 xRotTarget = RAND_FLOAT_PM1 * M_PI * 2;
1068 yRotTarget = RAND_FLOAT_PM1 * M_PI * 2;
1073 xRotTarget = RAND_FLOAT_PM1 * M_PI * 2;
1074 zRotTarget = RAND_FLOAT_PM1 * M_PI * 2;
1079 yRotTarget = RAND_FLOAT_PM1 * M_PI * 2;
1080 zRotTarget = RAND_FLOAT_PM1 * M_PI * 2;
1085 xRotTarget = RAND_FLOAT_PM1 * M_PI * 2;
1086 yRotTarget = RAND_FLOAT_PM1 * M_PI * 2;
1087 zRotTarget = RAND_FLOAT_PM1 * M_PI * 2;
1092 centerXOff = RAND_FLOAT_PM1 * maxRadius;
1097 centerYOff = RAND_FLOAT_PM1 * maxRadius;
1102 centerXOff = RAND_FLOAT_PM1 * maxRadius;
1103 centerYOff = RAND_FLOAT_PM1 * maxRadius;
1109 RAND_FLOAT_01 * (maxScale - minScale) + minScale;
1115 RAND_FLOAT_01 * (maxScale - minScale) + minScale;
1120 lightX = RAND_FLOAT_PM1;
1121 lightY = RAND_FLOAT_PM1;
1122 lightZ = RAND_FLOAT_PM1;
1127 lightXTarget = RAND_FLOAT_PM1;
1128 lightYTarget = RAND_FLOAT_PM1;
1129 lightZTarget = RAND_FLOAT_PM1;
1136 /* erase segsToErase and draw segsToDraw */
1137 static void eraseAndDraw (void)
1141 for (n = 0; n < segCount; n++)
1143 LineSegment *seg = &segsToErase[n];
1144 XDrawLine (display, drawable, gcs[0],
1145 seg->x1, seg->y1, seg->x2, seg->y2);
1146 seg = &segsToDraw[n];
1147 XDrawLine (display, drawable, seg->gc,
1148 seg->x1, seg->y1, seg->x2, seg->y2);
1153 XCopyArea (display, drawable, window, gcs[0], 0, 0,
1154 windowWidth, windowHeight, 0, 0);
1158 /* do one iteration */
1159 static void oneIteration (void)
1161 /* switch segsToErase and segsToDraw */
1162 LineSegment *temp = segsToDraw;
1163 segsToDraw = segsToErase;
1166 /* update the model */
1167 updateWithFeeling ();
1169 /* render new segments */
1172 /* erase old segments and draw new ones */
1176 char *progclass = "NerveRot";
1178 char *defaults [] = {
1179 ".background: black",
1180 ".foreground: white",
1185 "*doubleBuffer: false",
1186 "*eventChance: 0.2",
1193 "*maxNerveRadius: 0.7",
1194 "*nervousness: 0.3",
1198 XrmOptionDescRec options [] = {
1199 { "-count", ".count", XrmoptionSepArg, 0 },
1200 { "-colors", ".colors", XrmoptionSepArg, 0 },
1201 { "-delay", ".delay", XrmoptionSepArg, 0 },
1202 { "-max-iters", ".maxIters", XrmoptionSepArg, 0 },
1203 { "-db", ".doubleBuffer", XrmoptionNoArg, "true" },
1204 { "-no-db", ".doubleBuffer", XrmoptionNoArg, "false" },
1205 { "-event-chance", ".eventChance", XrmoptionSepArg, 0 },
1206 { "-iter-amt", ".iterAmt", XrmoptionSepArg, 0 },
1207 { "-line-width", ".lineWidth", XrmoptionSepArg, 0 },
1208 { "-min-scale", ".minScale", XrmoptionSepArg, 0 },
1209 { "-max-scale", ".maxScale", XrmoptionSepArg, 0 },
1210 { "-min-radius", ".minRadius", XrmoptionSepArg, 0 },
1211 { "-max-radius", ".maxRadius", XrmoptionSepArg, 0 },
1212 { "-max-nerve-radius", ".maxNerveRadius", XrmoptionSepArg, 0 },
1213 { "-nervousness", ".nervousness", XrmoptionSepArg, 0 },
1217 /* initialize the user-specifiable params */
1218 static void initParams (void)
1222 delay = get_integer_resource ("delay", "Delay");
1225 fprintf (stderr, "error: delay must be at least 0\n");
1229 maxIters = get_integer_resource ("maxIters", "Integer");
1232 fprintf (stderr, "error: maxIters must be at least 0\n");
1236 doubleBuffer = get_boolean_resource ("doubleBuffer", "Boolean");
1238 requestedBlotCount = get_integer_resource ("count", "Count");
1239 if (requestedBlotCount <= 0)
1241 fprintf (stderr, "error: count must be at least 0\n");
1245 colorCount = get_integer_resource ("colors", "Colors");
1246 if (colorCount <= 0)
1248 fprintf (stderr, "error: colors must be at least 1\n");
1252 lineWidth = get_integer_resource ("lineWidth", "LineWidth");
1255 fprintf (stderr, "error: line width must be at least 0\n");
1259 nervousness = get_float_resource ("nervousness", "Float");
1260 if ((nervousness < 0) || (nervousness > 1))
1262 fprintf (stderr, "error: nervousness must be in the range 0..1\n");
1266 maxNerveRadius = get_float_resource ("maxNerveRadius", "Float");
1267 if ((maxNerveRadius < 0) || (maxNerveRadius > 1))
1269 fprintf (stderr, "error: maxNerveRadius must be in the range 0..1\n");
1273 eventChance = get_float_resource ("eventChance", "Float");
1274 if ((eventChance < 0) || (eventChance > 1))
1276 fprintf (stderr, "error: eventChance must be in the range 0..1\n");
1280 iterAmt = get_float_resource ("iterAmt", "Float");
1281 if ((iterAmt < 0) || (iterAmt > 1))
1283 fprintf (stderr, "error: iterAmt must be in the range 0..1\n");
1287 minScale = get_float_resource ("minScale", "Float");
1288 if ((minScale < 0) || (minScale > 10))
1290 fprintf (stderr, "error: minScale must be in the range 0..10\n");
1294 maxScale = get_float_resource ("maxScale", "Float");
1295 if ((maxScale < 0) || (maxScale > 10))
1297 fprintf (stderr, "error: maxScale must be in the range 0..10\n");
1301 if (maxScale < minScale)
1303 fprintf (stderr, "error: maxScale must be >= minScale\n");
1307 minRadius = get_integer_resource ("minRadius", "Integer");
1308 if ((minRadius < 1) || (minRadius > 100))
1310 fprintf (stderr, "error: minRadius must be in the range 1..100\n");
1314 maxRadius = get_integer_resource ("maxRadius", "Integer");
1315 if ((maxRadius < 1) || (maxRadius > 100))
1317 fprintf (stderr, "error: maxRadius must be in the range 1..100\n");
1321 if (maxRadius < minRadius)
1323 fprintf (stderr, "error: maxRadius must be >= minRadius\n");
1334 void screenhack (Display *dpy, Window win)
1342 /* make a valid set to erase at first */
1349 screenhack_handle_events (dpy);