X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fnerverot.c;h=16bd267040e822e70fcb58088f1cedab6b3f7451;hb=82c5080773aae5e72ec155327c075775e023d2ee;hp=dcacb5ae097d24ef1c0a2f1c5023f41bee8cd0ce;hpb=93f25dc6827112d98b8b855ea85c8f5eb8123086;p=xscreensaver diff --git a/hacks/nerverot.c b/hacks/nerverot.c index dcacb5ae..16bd2670 100644 --- a/hacks/nerverot.c +++ b/hacks/nerverot.c @@ -1,6 +1,6 @@ -/* nerverot, nervous rotation of random thingies, v1.0 +/* nerverot, nervous rotation of random thingies, v1.3 * by Dan Bornstein, danfuzz@milk.com - * Copyright (c) 2000 Dan Bornstein. + * Copyright (c) 2000-2001 Dan Bornstein. All rights reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -13,28 +13,7 @@ * The goal of this screensaver is to be interesting and compelling to * watch, yet induce a state of nervous edginess in the viewer. * - * Brief description of options/resources: - * - * -fg : foreground color - * -bg : background color - * -delay : delay between frames - * -event-chance : chance, per iteration, that an interesting event - * will happen (range 0..1) - * -iter-amt : amount, per iteration, to move towards rotation and - * scale targets (range 0..1) - * -count : number of blots - * -colors : number of colors to use - * -lineWidth : width of lines (0 means an optimized thin line) - * -nervousness : amount of nervousness (range 0..1) - * -min-scale : minimum scale of drawing as fraction of base scale - * (which is the minumum of the width or height of the screen) (range - * 0..10) - * -max-scale : maximum scale of drawing as fraction of base scale - * (which is the minumum of the width or height of the screen) (range - * 0..10) - * -min-radius : minimum radius for drawing blots (range 1..100) - * -max-radius : maximum radius for drawing blots (range 1..100) - * -max-nerve-radius : maximum nervousness radius (range 0..1) + * See the included man page for more details. */ #include @@ -44,11 +23,11 @@ /* random float in the range (-1..1) */ #define RAND_FLOAT_PM1 \ - (((FLOAT) (random() & 0xffff)) / ((FLOAT) 0x10000) * 2 - 1) + (((FLOAT) ((random() >> 8) & 0xffff)) / ((FLOAT) 0x10000) * 2 - 1) /* random float in the range (0..1) */ #define RAND_FLOAT_01 \ - (((FLOAT) (random() & 0xffff)) / ((FLOAT) 0x10000)) + (((FLOAT) ((random() >> 8) & 0xffff)) / ((FLOAT) 0x10000)) @@ -60,6 +39,9 @@ static int requestedBlotCount; /* delay (usec) between iterations */ int delay; +/* max iterations per model */ +int maxIters; + /* variability of xoff/yoff per iteration (0..1) */ static FLOAT nervousness; @@ -87,6 +69,9 @@ static int colorCount; /* width of lines */ static int lineWidth; +/* whether or not to do double-buffering */ +static Bool doubleBuffer; + /* non-user-modifiable immutable definitions */ @@ -103,9 +88,10 @@ static int windowHeight; static int centerX; static int centerY; -static Display *display; /* the display to draw on */ -static Window window; /* the window to draw on */ -static GC *gcs; /* array of gcs, one per color used */ +static Display *display; /* the display to draw on */ +static Window window; /* the window to draw on */ +static Drawable drawable; /* the thing to directly draw on */ +static GC *gcs; /* array of gcs, one per color used */ @@ -278,9 +264,10 @@ static void setupBlotsSphere (void) initBlot (&blots[n], x, y, z); } - } + + /* set up the initial array of blots to be a simple cube */ static void setupBlotsCube (void) { @@ -338,6 +325,7 @@ static void setupBlotsCube (void) } + /* set up the initial array of blots to be a cylinder */ static void setupBlotsCylinder (void) { @@ -381,11 +369,15 @@ static void setupBlotsCylinder (void) static void setupBlotsSquiggle (void) { FLOAT x, y, z, xv, yv, zv, len; + int minCoor, maxCoor; int n; blotCount = requestedBlotCount; blots = calloc (sizeof (Blot), blotCount); + maxCoor = (int) (RAND_FLOAT_01 * 5) + 1; + minCoor = -maxCoor; + x = RAND_FLOAT_PM1; y = RAND_FLOAT_PM1; z = RAND_FLOAT_PM1; @@ -417,9 +409,9 @@ static void setupBlotsSquiggle (void) newy = y + yv * 0.1; newz = z + zv * 0.1; - if ( (newx >= -1) && (newx <= 1) - && (newy >= -1) && (newy <= 1) - && (newz >= -1) && (newz <= 1)) + if ( (newx >= minCoor) && (newx <= maxCoor) + && (newy >= minCoor) && (newy <= maxCoor) + && (newz >= minCoor) && (newz <= maxCoor)) { break; } @@ -436,6 +428,176 @@ static void setupBlotsSquiggle (void) +/* set up the initial array of blots to be near the corners of a + * cube, distributed slightly */ +static void setupBlotsCubeCorners (void) +{ + int n; + + blotCount = requestedBlotCount; + blots = calloc (sizeof (Blot), blotCount); + + for (n = 0; n < blotCount; n++) + { + FLOAT x = rint (RAND_FLOAT_01) * 2 - 1; + FLOAT y = rint (RAND_FLOAT_01) * 2 - 1; + FLOAT z = rint (RAND_FLOAT_01) * 2 - 1; + + x += RAND_FLOAT_PM1 * 0.3; + y += RAND_FLOAT_PM1 * 0.3; + z += RAND_FLOAT_PM1 * 0.3; + + initBlot (&blots[n], x, y, z); + } + + scaleBlotsToRadius1 (); +} + + + +/* set up the initial array of blots to be randomly distributed + * on the surface of a tetrahedron */ +static void setupBlotsTetrahedron (void) +{ + /* table of corners of the tetrahedron */ + static FLOAT cor[4][3] = { { 0.0, 1.0, 0.0 }, + { -0.75, -0.5, -0.433013 }, + { 0.0, -0.5, 0.866025 }, + { 0.75, -0.5, -0.433013 } }; + + int n, c; + + /* derive blotsPerSurface from blotCount, but then do the reverse + * since roundoff may have changed blotCount */ + int blotsPerSurface = requestedBlotCount / 4; + + blotCount = blotsPerSurface * 4; + blots = calloc (sizeof (Blot), blotCount); + + for (n = 0; n < blotCount; n += 4) + { + /* pick a random point on a unit right triangle */ + FLOAT rawx = RAND_FLOAT_01; + FLOAT rawy = RAND_FLOAT_01; + + if ((rawx + rawy) > 1) + { + /* swap coords into place */ + FLOAT t = 1.0 - rawx; + rawx = 1.0 - rawy; + rawy = t; + } + + /* translate the point to be on each of the surfaces */ + for (c = 0; c < 4; c++) + { + FLOAT x, y, z; + + int c1 = (c + 1) % 4; + int c2 = (c + 2) % 4; + + x = (cor[c1][0] - cor[c][0]) * rawx + + (cor[c2][0] - cor[c][0]) * rawy + + cor[c][0]; + + y = (cor[c1][1] - cor[c][1]) * rawx + + (cor[c2][1] - cor[c][1]) * rawy + + cor[c][1]; + + z = (cor[c1][2] - cor[c][2]) * rawx + + (cor[c2][2] - cor[c][2]) * rawy + + cor[c][2]; + + initBlot (&blots[n + c], x, y, z); + } + } +} + + + +/* forward declaration for recursive use immediately below */ +static void setupBlots (void); + +/* set up the blots to be two of the other choices, placed next to + * each other */ +static void setupBlotsDuo (void) +{ + int origRequest = requestedBlotCount; + FLOAT tx, ty, tz, radius; + Blot *blots1, *blots2; + int count1, count2; + int n; + + if (requestedBlotCount < 15) + { + /* special case bottom-out */ + setupBlotsSphere (); + return; + } + + tx = RAND_FLOAT_PM1; + ty = RAND_FLOAT_PM1; + tz = RAND_FLOAT_PM1; + radius = sqrt (tx * tx + ty * ty + tz * tz); + tx /= radius; + ty /= radius; + tz /= radius; + + /* recursive call to setup set 1 */ + requestedBlotCount = origRequest / 2; + setupBlots (); + + if (blotCount >= origRequest) + { + /* return immediately if this satisfies the original count request */ + requestedBlotCount = origRequest; + return; + } + + blots1 = blots; + count1 = blotCount; + blots = NULL; + blotCount = 0; + + /* translate to new position */ + for (n = 0; n < count1; n++) + { + blots1[n].x += tx; + blots1[n].y += ty; + blots1[n].z += tz; + } + + /* recursive call to setup set 2 */ + requestedBlotCount = origRequest - count1; + setupBlots (); + blots2 = blots; + count2 = blotCount; + + /* translate to new position */ + for (n = 0; n < count2; n++) + { + blots2[n].x -= tx; + blots2[n].y -= ty; + blots2[n].z -= tz; + } + + /* combine the two arrays */ + blotCount = count1 + count2; + blots = calloc (sizeof (Blot), blotCount); + memcpy (&blots[0], blots1, sizeof (Blot) * count1); + memcpy (&blots[count1], blots2, sizeof (Blot) * count2); + free (blots1); + free (blots2); + + scaleBlotsToRadius1 (); + randomlyReorderBlots (); + + /* restore the original requested count, for future iterations */ + requestedBlotCount = origRequest; +} + + + /* free the blots, in preparation for a new shape */ static void freeBlots (void) { @@ -463,7 +625,7 @@ static void freeBlots (void) /* set up the initial arrays of blots */ static void setupBlots (void) { - int which = RAND_FLOAT_01 * 4; + int which = RAND_FLOAT_01 * 8; freeBlots (); @@ -481,15 +643,32 @@ static void setupBlots (void) case 3: setupBlotsSquiggle (); break; + case 4: + setupBlotsCubeCorners (); + break; + case 5: + setupBlotsTetrahedron (); + break; + case 6: + case 7: + setupBlotsDuo (); + break; } +} + + +/* set up the segments arrays */ +static void setupSegs (void) +{ /* there are blotShapeCount - 1 line segments per blot */ segCount = blotCount * (blotShapeCount - 1); segsToErase = calloc (sizeof (LineSegment), segCount); segsToDraw = calloc (sizeof (LineSegment), segCount); /* erase the world */ - XFillRectangle (display, window, gcs[0], 0, 0, windowWidth, windowHeight); + XFillRectangle (display, drawable, gcs[0], 0, 0, + windowWidth, windowHeight); } @@ -566,8 +745,19 @@ static void setup (void) centerY = windowHeight / 2; baseScale = (xgwa.height < xgwa.width) ? xgwa.height : xgwa.width; + if (doubleBuffer) + { + drawable = XCreatePixmap (display, window, xgwa.width, xgwa.height, + xgwa.depth); + } + else + { + drawable = window; + } + setupColormap (&xgwa); setupBlots (); + setupSegs (); /* set up the initial rotation, scale, and light values as random, but * with the targets equal to where it is */ @@ -579,7 +769,7 @@ static void setup (void) lightY = lightYTarget = RAND_FLOAT_PM1; lightZ = lightZTarget = RAND_FLOAT_PM1; - itersTillNext = RAND_FLOAT_01 * 1234; + itersTillNext = RAND_FLOAT_01 * maxIters; } @@ -681,8 +871,9 @@ static void updateWithFeeling (void) itersTillNext--; if (itersTillNext < 0) { - itersTillNext = RAND_FLOAT_01 * 1234; + itersTillNext = RAND_FLOAT_01 * maxIters; setupBlots (); + setupSegs (); renderSegs (); } @@ -770,18 +961,18 @@ static void updateWithFeeling (void) } case 7: { - centerXOff = RAND_FLOAT_PM1 * maxRadius / 2; + centerXOff = RAND_FLOAT_PM1 * maxRadius; break; } case 8: { - centerYOff = RAND_FLOAT_PM1 * maxRadius / 2; + centerYOff = RAND_FLOAT_PM1 * maxRadius; break; } case 9: { - centerXOff = RAND_FLOAT_PM1 * maxRadius / 2; - centerYOff = RAND_FLOAT_PM1 * maxRadius / 2; + centerXOff = RAND_FLOAT_PM1 * maxRadius; + centerYOff = RAND_FLOAT_PM1 * maxRadius; break; } case 10: @@ -822,12 +1013,18 @@ static void eraseAndDraw (void) for (n = 0; n < segCount; n++) { LineSegment *seg = &segsToErase[n]; - XDrawLine (display, window, gcs[0], + XDrawLine (display, drawable, gcs[0], seg->x1, seg->y1, seg->x2, seg->y2); seg = &segsToDraw[n]; - XDrawLine (display, window, seg->gc, + XDrawLine (display, drawable, seg->gc, seg->x1, seg->y1, seg->x2, seg->y2); } + + if (doubleBuffer) + { + XCopyArea (display, drawable, window, gcs[0], 0, 0, + windowWidth, windowHeight, 0, 0); + } } /* do one iteration */ @@ -856,6 +1053,8 @@ char *defaults [] = { "*count: 250", "*colors: 4", "*delay: 10000", + "*maxIters: 1200", + "*doubleBuffer: false", "*eventChance: 0.2", "*iterAmt: 0.01", "*lineWidth: 0", @@ -871,8 +1070,10 @@ char *defaults [] = { XrmOptionDescRec options [] = { { "-count", ".count", XrmoptionSepArg, 0 }, { "-colors", ".colors", XrmoptionSepArg, 0 }, - { "-cube", ".cube", XrmoptionNoArg, "true" }, { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-max-iters", ".maxIters", XrmoptionSepArg, 0 }, + { "-db", ".doubleBuffer", XrmoptionNoArg, "true" }, + { "-no-db", ".doubleBuffer", XrmoptionNoArg, "false" }, { "-event-chance", ".eventChance", XrmoptionSepArg, 0 }, { "-iter-amt", ".iterAmt", XrmoptionSepArg, 0 }, { "-line-width", ".lineWidth", XrmoptionSepArg, 0 }, @@ -896,6 +1097,15 @@ static void initParams (void) fprintf (stderr, "error: delay must be at least 0\n"); problems = 1; } + + maxIters = get_integer_resource ("maxIters", "Integer"); + if (maxIters < 0) + { + fprintf (stderr, "error: maxIters must be at least 0\n"); + problems = 1; + } + + doubleBuffer = get_boolean_resource ("doubleBuffer", "Boolean"); requestedBlotCount = get_integer_resource ("count", "Count"); if (requestedBlotCount <= 0)