summaryrefslogtreecommitdiffstats
path: root/hacks/xrayswarm.c
diff options
context:
space:
mode:
authorSimon Rettberg2018-10-16 10:08:48 +0200
committerSimon Rettberg2018-10-16 10:08:48 +0200
commitd3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch)
treecbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /hacks/xrayswarm.c
downloadxscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip
Original 5.40
Diffstat (limited to 'hacks/xrayswarm.c')
-rw-r--r--hacks/xrayswarm.c1224
1 files changed, 1224 insertions, 0 deletions
diff --git a/hacks/xrayswarm.c b/hacks/xrayswarm.c
new file mode 100644
index 0000000..678c7b0
--- /dev/null
+++ b/hacks/xrayswarm.c
@@ -0,0 +1,1224 @@
+/*
+ * Copyright (c) 2000 by Chris Leger (xrayjones@users.sourceforge.net)
+ *
+ * xrayswarm - a shameless ripoff of the 'swarm' screensaver on SGI
+ * boxes.
+ *
+ * Version 1.0 - initial release. doesn't read any special command-line
+ * options, and only supports the variable 'delay' via Xresources.
+ * (the delay resouces is most useful on systems w/o gettimeofday, in
+ * which case automagical level-of-detail for FPS maintainance can't
+ * be used.)
+ *
+ * The code isn't commented, but isn't too ugly. It should be pretty
+ * easy to understand, with the exception of the colormap stuff.
+ *
+ */
+/*
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the X Consortium.
+*/
+
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <sys/time.h>
+#include "screenhack.h"
+
+#ifdef HAVE_JWXYZ
+# define HAVE_GETTIMEOFDAY 1
+#endif
+
+/**********************************************************************
+ *
+ * window crap
+ *
+ **********************************************************************/
+
+static const char *xrayswarm_defaults [] ={
+ ".lowrez: true",
+ ".background: black",
+ "*delay: 20000",
+ "*fpsSolid: true",
+#ifdef HAVE_MOBILE
+ "*ignoreRotation: True",
+#endif
+ 0
+};
+
+static XrmOptionDescRec xrayswarm_options [] = {
+ {"-delay",".delay",XrmoptionSepArg,0},
+ {0,0,0,0}
+};
+
+
+/**********************************************************************
+ *
+ * bug structs & variables
+ *
+ **********************************************************************/
+#define MAX_TRAIL_LEN 60
+#define MAX_BUGS 100
+#define MAX_TARGETS 10
+#define sq(x) ((x)*(x))
+
+#define MAX_FPS 150
+#define MIN_FPS 16
+#define DESIRED_DT 0.2
+
+typedef struct _sbug {
+ float pos[3];
+ int hist[MAX_TRAIL_LEN][2];
+ float vel[2];
+ struct _sbug *closest;
+} bug;
+
+#define GRAY_TRAILS 0
+#define GRAY_SCHIZO 1
+#define COLOR_TRAILS 2
+#define RANDOM_TRAILS 3
+#define RANDOM_SCHIZO 4
+#define COLOR_SCHIZO 5
+#define NUM_SCHEMES 6 /* too many schizos; don't use last 2 */
+
+
+
+struct state {
+ Display *dpy;
+ Window win;
+
+ unsigned char colors[768];
+
+ GC fgc[256];
+ GC cgc;
+ int xsize, ysize;
+ int xc, yc;
+ unsigned long delay;
+ float maxx, maxy;
+
+ float dt;
+ float targetVel;
+ float targetAcc;
+ float maxVel;
+ float maxAcc;
+ float noise;
+ float minVelMultiplier;
+
+ int nbugs;
+ int ntargets;
+ int trailLen;
+
+ float dtInv;
+ float halfDtSq;
+ float targetVelSq;
+ float maxVelSq;
+ float minVelSq;
+ float minVel;
+
+ bug bugs[MAX_BUGS];
+ bug targets[MAX_TARGETS];
+ int head;
+ int tail;
+ int colorScheme;
+ float changeProb;
+
+ int grayIndex[MAX_TRAIL_LEN];
+ int redIndex[MAX_TRAIL_LEN];
+ int blueIndex[MAX_TRAIL_LEN];
+ int graySIndex[MAX_TRAIL_LEN];
+ int redSIndex[MAX_TRAIL_LEN];
+ int blueSIndex[MAX_TRAIL_LEN];
+ int randomIndex[MAX_TRAIL_LEN];
+ int numColors;
+ int numRandomColors;
+
+ int checkIndex;
+ int rsc_callDepth;
+ int rbc_callDepth;
+
+ float draw_fps;
+ float draw_timePerFrame, draw_elapsed;
+ int *draw_targetColorIndex, *draw_colorIndex;
+ int draw_targetStartColor, draw_targetNumColors;
+ int draw_startColor, draw_numColors;
+ double draw_start, draw_end;
+ int draw_cnt;
+ int draw_sleepCount;
+ int draw_delayAccum;
+ int draw_nframes;
+
+ struct timeval startupTime;
+};
+
+
+typedef struct {
+ float dt;
+ float targetVel;
+ float targetAcc;
+ float maxVel;
+ float maxAcc;
+ float noise;
+
+ int nbugs;
+ int ntargets;
+ int trailLen;
+ int colorScheme;
+ int changeProb;
+} bugParams;
+
+#if 0
+static const bugParams good1 = {
+ 0.3, /* dt */
+ 0.03, /* targetVel */
+ 0.02, /* targetAcc */
+ 0.05, /* maxVel */
+ 0.03, /* maxAcc */
+ 0.01, /* noise */
+ -1, /* nbugs */
+ -1, /* ntargets */
+ 60, /* trailLen */
+ 2, /* colorScheme */
+ 0.15 /* changeProb */
+};
+
+static const bugParams *goodParams[] = {
+&good1
+};
+
+static int numParamSets = 1;
+#endif
+
+static void initCMap(struct state *st)
+{
+ int i, n;
+ int temp;
+
+ n = 0;
+
+ /* color 0 is black */
+ st->colors[n++] = 0;
+ st->colors[n++] = 0;
+ st->colors[n++] = 0;
+
+ /* color 1 is red */
+ st->colors[n++] = 255;
+ st->colors[n++] = 0;
+ st->colors[n++] = 0;
+
+ /* color 2 is green */
+ st->colors[n++] = 255;
+ st->colors[n++] = 0;
+ st->colors[n++] = 0;
+
+ /* color 3 is blue */
+ st->colors[n++] = 255;
+ st->colors[n++] = 0;
+ st->colors[n++] = 0;
+
+ /* start greyscale colors at 4; 16 levels */
+ for (i = 0; i < 16; i++) {
+ temp = i*16;
+ if (temp > 255) temp = 255;
+ st->colors[n++] = 255 - temp;
+ st->colors[n++] = 255 - temp;
+ st->colors[n++] = 255 - temp;
+ }
+
+ /* start red fade at 20; 16 levels */
+ for (i = 0; i < 16; i++) {
+ temp = i*16;
+ if (temp > 255) temp = 255;
+ st->colors[n++] = 255 - temp;
+ st->colors[n++] = 255 - pow(i/16.0+0.001, 0.3)*255;
+ st->colors[n++] = 65 - temp/4;
+ }
+
+ /* start blue fade at 36; 16 levels */
+ for (i = 0; i < 16; i++) {
+ temp = i*16;
+ if (temp > 255) temp = 255;
+ st->colors[n++] = 32 - temp/8;
+ st->colors[n++] = 180 - pow(i/16.0+0.001, 0.3)*180;
+ st->colors[n++] = 255 - temp;
+ }
+
+ /* random colors start at 52 */
+ st->numRandomColors = MAX_TRAIL_LEN;
+
+ st->colors[n] = random()&255; n++;
+ st->colors[n] = random()&255; n++;
+ st->colors[n] = st->colors[n-2]/2 + st->colors[n-3]/2; n++;
+
+ for (i = 0; i < st->numRandomColors; i++) {
+ st->colors[n] = (st->colors[n-3] + (random()&31) - 16)&255; n++;
+ st->colors[n] = (st->colors[n-3] + (random()&31) - 16)&255; n++;
+ st->colors[n] = st->colors[n-2]/(float)(i+2) + st->colors[n-3]/(float)(i+2); n++;
+ }
+
+ st->numColors = n/3 + 1;
+}
+
+static int initGraphics(struct state *st)
+{
+ XGCValues xgcv;
+ XWindowAttributes xgwa;
+/* XSetWindowAttributes xswa;*/
+ Colormap cmap;
+ XColor color;
+ int n, i;
+
+ initCMap(st);
+
+ XGetWindowAttributes(st->dpy,st->win,&xgwa);
+ cmap=xgwa.colormap;
+/* xswa.backing_store=Always;
+ XChangeWindowAttributes(st->dpy,st->win,CWBackingStore,&xswa);*/
+ xgcv.function=GXcopy;
+
+ st->delay = get_integer_resource(st->dpy, "delay","Integer");
+
+ xgcv.foreground=get_pixel_resource (st->dpy, cmap, "background", "Background");
+ st->fgc[0]=XCreateGC(st->dpy, st->win, GCForeground|GCFunction,&xgcv);
+#ifdef HAVE_JWXYZ
+ jwxyz_XSetAntiAliasing (st->dpy, st->fgc[0], False);
+#endif
+
+ n=0;
+ if (mono_p) {
+ xgcv.foreground=get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
+ st->fgc[1]=XCreateGC(st->dpy,st->win,GCForeground|GCFunction,&xgcv);
+#ifdef HAVE_JWXYZ
+ jwxyz_XSetAntiAliasing (st->dpy, st->fgc[1], False);
+#endif
+ for (i=0;i<st->numColors;i+=2) st->fgc[i]=st->fgc[0];
+ for (i=1;i<st->numColors;i+=2) st->fgc[i]=st->fgc[1];
+ } else {
+ for (i = 0; i < st->numColors; i++) {
+ color.red=st->colors[n++]<<8;
+ color.green=st->colors[n++]<<8;
+ color.blue=st->colors[n++]<<8;
+ color.flags=DoRed|DoGreen|DoBlue;
+ XAllocColor(st->dpy,cmap,&color);
+ xgcv.foreground=color.pixel;
+ st->fgc[i] = XCreateGC(st->dpy, st->win, GCForeground | GCFunction,&xgcv);
+#ifdef HAVE_JWXYZ
+ jwxyz_XSetAntiAliasing (st->dpy, st->fgc[i], False);
+#endif
+ }
+ }
+ st->cgc = XCreateGC(st->dpy,st->win,GCForeground|GCFunction,&xgcv);
+ XSetGraphicsExposures(st->dpy,st->cgc,False);
+#ifdef HAVE_JWXYZ
+ jwxyz_XSetAntiAliasing (st->dpy, st->cgc, False);
+#endif
+
+ st->xsize = xgwa.width;
+ st->ysize = xgwa.height;
+ st->xc = st->xsize >> 1;
+ st->yc = st->ysize >> 1;
+
+ st->maxx = 1.0;
+ st->maxy = st->ysize/(float)st->xsize;
+
+ if (st->colorScheme < 0) st->colorScheme = random()%NUM_SCHEMES;
+
+ return True;
+}
+
+static void initBugs(struct state *st)
+{
+ register bug *b;
+ int i;
+
+ st->head = st->tail = 0;
+
+ memset((char *)st->bugs, 0,MAX_BUGS*sizeof(bug));
+ memset((char *)st->targets, 0, MAX_TARGETS*sizeof(bug));
+
+ if (st->ntargets < 0) st->ntargets = (0.25+frand(0.75)*frand(1))*MAX_TARGETS;
+ if (st->ntargets < 1) st->ntargets = 1;
+
+ if (st->nbugs < 0) st->nbugs = (0.25+frand(0.75)*frand(1))*MAX_BUGS;
+ if (st->nbugs <= st->ntargets) st->nbugs = st->ntargets+1;
+
+ if (st->trailLen < 0) {
+ st->trailLen = (1.0 - frand(0.6)*frand(1))*MAX_TRAIL_LEN;
+ }
+
+ if (st->nbugs > MAX_BUGS) st->nbugs = MAX_BUGS;
+ if (st->ntargets > MAX_TARGETS) st->ntargets = MAX_TARGETS;
+ if (st->trailLen > MAX_TRAIL_LEN) st->trailLen = MAX_TRAIL_LEN;
+
+ b = st->bugs;
+ for (i = 0; i < st->nbugs; i++, b++) {
+ b->pos[0] = frand(st->maxx);
+ b->pos[1] = frand(st->maxy);
+ b->vel[0] = frand(st->maxVel/2);
+ b->vel[1] = frand(st->maxVel/2);
+
+ b->hist[st->head][0] = b->pos[0]*st->xsize;
+ b->hist[st->head][1] = b->pos[1]*st->xsize;
+ b->closest = &st->targets[random()%st->ntargets];
+ }
+
+ b = st->targets;
+ for (i = 0; i < st->ntargets; i++, b++) {
+ b->pos[0] = frand(st->maxx);
+ b->pos[1] = frand(st->maxy);
+
+ b->vel[0] = frand(st->targetVel/2);
+ b->vel[1] = frand(st->targetVel/2);
+
+ b->hist[st->head][0] = b->pos[0]*st->xsize;
+ b->hist[st->head][1] = b->pos[1]*st->xsize;
+ }
+}
+
+static void pickNewTargets(struct state *st)
+{
+ register int i;
+ register bug *b;
+
+ b = st->bugs;
+ for (i = 0; i < st->nbugs; i++, b++) {
+ b->closest = &st->targets[random()%st->ntargets];
+ }
+}
+
+#if 0
+static void addBugs(int numToAdd)
+{
+ register bug *b;
+ int i;
+
+ if (numToAdd + st->nbugs > MAX_BUGS) numToAdd = MAX_BUGS-st->nbugs;
+ else if (numToAdd < 0) numToAdd = 0;
+
+ for (i = 0; i < numToAdd; i++) {
+ b = &st->bugs[random()%st->nbugs];
+ memcpy((char *)&st->bugs[st->nbugs+i], (char *)b, sizeof(bug));
+ b->closest = &st->targets[random()%st->ntargets];
+ }
+
+ st->nbugs += numToAdd;
+}
+
+static void addTargets(int numToAdd)
+{
+ register bug *b;
+ int i;
+
+ if (numToAdd + st->ntargets > MAX_TARGETS) numToAdd = MAX_TARGETS-st->ntargets;
+ else if (numToAdd < 0) numToAdd = 0;
+
+ for (i = 0; i < numToAdd; i++) {
+ b = &st->targets[random()%st->ntargets];
+ memcpy((char *)&st->targets[st->ntargets+i], (char *)b, sizeof(bug));
+ b->closest = &st->targets[random()%st->ntargets];
+ }
+
+ st->ntargets += numToAdd;
+}
+#endif
+
+static void computeConstants(struct state *st)
+{
+ st->halfDtSq = st->dt*st->dt*0.5;
+ st->dtInv = 1.0/st->dt;
+ st->targetVelSq = st->targetVel*st->targetVel;
+ st->maxVelSq = st->maxVel*st->maxVel;
+ st->minVel = st->maxVel*st->minVelMultiplier;
+ st->minVelSq = st->minVel*st->minVel;
+}
+
+static void computeColorIndices(struct state *st)
+{
+ int i;
+ int schizoLength;
+
+ /* note: colors are used in *reverse* order! */
+
+ /* grayscale */
+ for (i = 0; i < st->trailLen; i++) {
+ st->grayIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5;
+ if (st->grayIndex[st->trailLen-1-i] > 19) st->grayIndex[st->trailLen-1-i] = 19;
+ }
+
+ /* red */
+ for (i = 0; i < st->trailLen; i++) {
+ st->redIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5;
+ if (st->redIndex[st->trailLen-1-i] > 35) st->redIndex[st->trailLen-1-i] = 35;
+ }
+
+ /* blue */
+ for (i = 0; i < st->trailLen; i++) {
+ st->blueIndex[st->trailLen-1-i] = 36 + i*16.0/st->trailLen + 0.5;
+ if (st->blueIndex[st->trailLen-1-i] > 51) st->blueIndex[st->trailLen-1-i] = 51;
+ }
+
+ /* gray schizo - same as gray*/
+ for (i = 0; i < st->trailLen; i++) {
+ st->graySIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5;
+ if (st->graySIndex[st->trailLen-1-i] > 19) st->graySIndex[st->trailLen-1-i] = 19;
+ }
+
+ /*schizoLength = st->trailLen/4;
+ if (schizoLength < 3) schizoLength = 3;*/
+ /* red schizo */
+ for (i = 0; i < st->trailLen; i++) {
+ /* redSIndex[trailLen-1-i] =
+ 20 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;*/
+ st->redSIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5;
+ if (st->redSIndex[st->trailLen-1-i] > 35) st->redSIndex[st->trailLen-1-i] = 35;
+ }
+
+ schizoLength = st->trailLen/2;
+ if (schizoLength < 3) schizoLength = 3;
+ /* blue schizo is next */
+ for (i = 0; i < st->trailLen; i++) {
+ st->blueSIndex[st->trailLen-1-i] =
+ 36 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;
+ if (st->blueSIndex[st->trailLen-1-i] > 51) st->blueSIndex[st->trailLen-1-i] = 51;
+ }
+
+ /* random is next */
+ for (i = 0; i < st->trailLen; i++) {
+ st->randomIndex[i] = 52 + random()%(st->numRandomColors);
+ }
+}
+
+#if 0
+static void setParams(bugParams *p)
+{
+ st->dt = p->dt;
+ st->targetVel = p->targetVel;
+ st->targetAcc = p->targetAcc;
+ st->maxVel = p->maxVel;
+ st->maxAcc = p->maxAcc;
+ st->noise = p->noise;
+
+ st->nbugs = p->nbugs;
+ st->ntargets = p->ntargets;
+ st->trailLen = p->trailLen;
+ st->colorScheme = p->colorScheme;
+ st->changeProb = p->changeProb;
+ computeConstants();
+ computeColorIndices();
+}
+#endif
+
+static void drawBugs(struct state *st, int *tColorIdx, int tci0, int tnc,
+ int *colorIdx, int ci0, int nc)
+{
+ register bug *b;
+ register int i, j;
+ int temp;
+
+ if (((st->head+1)%st->trailLen) == st->tail) {
+ /* first, erase last segment of bugs if necessary */
+ temp = (st->tail+1) % st->trailLen;
+
+ b = st->bugs;
+ for (i = 0; i < st->nbugs; i++, b++) {
+ XDrawLine(st->dpy, st->win, st->fgc[0],
+ b->hist[st->tail][0], b->hist[st->tail][1],
+ b->hist[temp][0], b->hist[temp][1]);
+ }
+
+ b = st->targets;
+ for (i = 0; i < st->ntargets; i++, b++) {
+ XDrawLine(st->dpy, st->win, st->fgc[0],
+ b->hist[st->tail][0], b->hist[st->tail][1],
+ b->hist[temp][0], b->hist[temp][1]);
+ }
+ st->tail = (st->tail+1)%st->trailLen;
+ }
+
+ for (j = st->tail; j != st->head; j = temp) {
+ temp = (j+1)%st->trailLen;
+
+ b = st->bugs;
+ for (i = 0; i < st->nbugs; i++, b++) {
+ XDrawLine(st->dpy, st->win, st->fgc[colorIdx[ci0]],
+ b->hist[j][0], b->hist[j][1],
+ b->hist[temp][0], b->hist[temp][1]);
+ }
+
+ b = st->targets;
+ for (i = 0; i < st->ntargets; i++, b++) {
+ XDrawLine(st->dpy, st->win, st->fgc[tColorIdx[tci0]],
+ b->hist[j][0], b->hist[j][1],
+ b->hist[temp][0], b->hist[temp][1]);
+ }
+ ci0 = (ci0+1)%nc;
+ tci0 = (tci0+1)%tnc;
+ }
+}
+
+static void clearBugs(struct state *st)
+{
+ register bug *b;
+ register int i, j;
+ int temp;
+
+ st->tail = st->tail-1;
+ if (st->tail < 0) st->tail = st->trailLen-1;
+
+ if (((st->head+1)%st->trailLen) == st->tail) {
+ /* first, erase last segment of bugs if necessary */
+ temp = (st->tail+1) % st->trailLen;
+
+ b = st->bugs;
+ for (i = 0; i < st->nbugs; i++, b++) {
+ XDrawLine(st->dpy, st->win, st->fgc[0],
+ b->hist[st->tail][0], b->hist[st->tail][1],
+ b->hist[temp][0], b->hist[temp][1]);
+ }
+
+ b = st->targets;
+ for (i = 0; i < st->ntargets; i++, b++) {
+ XDrawLine(st->dpy, st->win, st->fgc[0],
+ b->hist[st->tail][0], b->hist[st->tail][1],
+ b->hist[temp][0], b->hist[temp][1]);
+ }
+ st->tail = (st->tail+1)%st->trailLen;
+ }
+
+ for (j = st->tail; j != st->head; j = temp) {
+ temp = (j+1)%st->trailLen;
+
+ b = st->bugs;
+ for (i = 0; i < st->nbugs; i++, b++) {
+ XDrawLine(st->dpy, st->win, st->fgc[0],
+ b->hist[j][0], b->hist[j][1],
+ b->hist[temp][0], b->hist[temp][1]);
+ }
+
+ b = st->targets;
+ for (i = 0; i < st->ntargets; i++, b++) {
+ XDrawLine(st->dpy, st->win, st->fgc[0],
+ b->hist[j][0], b->hist[j][1],
+ b->hist[temp][0], b->hist[temp][1]);
+ }
+ }
+}
+
+static void updateState(struct state *st)
+{
+ register int i;
+ register bug *b;
+ register float ax, ay, temp;
+ float theta;
+ bug *b2;
+ int j;
+
+ st->head = (st->head+1)%st->trailLen;
+
+ for (j = 0; j < 5; j++) {
+ /* update closets bug for the bug indicated by checkIndex */
+ st->checkIndex = (st->checkIndex+1)%st->nbugs;
+ b = &st->bugs[st->checkIndex];
+
+ ax = b->closest->pos[0] - b->pos[0];
+ ay = b->closest->pos[1] - b->pos[1];
+ temp = ax*ax + ay*ay;
+ for (i = 0; i < st->ntargets; i++) {
+ b2 = &st->targets[i];
+ if (b2 == b->closest) continue;
+ ax = b2->pos[0] - b->pos[0];
+ ay = b2->pos[1] - b->pos[1];
+ theta = ax*ax + ay*ay;
+ if (theta < temp*2) {
+ b->closest = b2;
+ temp = theta;
+ }
+ }
+ }
+
+ /* update target state */
+
+ b = st->targets;
+ for (i = 0; i < st->ntargets; i++, b++) {
+ theta = frand(6.28);
+ ax = st->targetAcc*cos(theta);
+ ay = st->targetAcc*sin(theta);
+
+ b->vel[0] += ax*st->dt;
+ b->vel[1] += ay*st->dt;
+
+ /* check velocity */
+ temp = sq(b->vel[0]) + sq(b->vel[1]);
+ if (temp > st->targetVelSq) {
+ temp = st->targetVel/sqrt(temp);
+ /* save old vel for acc computation */
+ ax = b->vel[0];
+ ay = b->vel[1];
+
+ /* compute new velocity */
+ b->vel[0] *= temp;
+ b->vel[1] *= temp;
+
+ /* update acceleration */
+ ax = (b->vel[0]-ax)*st->dtInv;
+ ay = (b->vel[1]-ay)*st->dtInv;
+ }
+
+ /* update position */
+ b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq;
+ b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq;
+
+ /* check limits on targets */
+ if (b->pos[0] < 0) {
+ /* bounce */
+ b->pos[0] = -b->pos[0];
+ b->vel[0] = -b->vel[0];
+ } else if (b->pos[0] >= st->maxx) {
+ /* bounce */
+ b->pos[0] = 2*st->maxx-b->pos[0];
+ b->vel[0] = -b->vel[0];
+ }
+ if (b->pos[1] < 0) {
+ /* bounce */
+ b->pos[1] = -b->pos[1];
+ b->vel[1] = -b->vel[1];
+ } else if (b->pos[1] >= st->maxy) {
+ /* bounce */
+ b->pos[1] = 2*st->maxy-b->pos[1];
+ b->vel[1] = -b->vel[1];
+ }
+
+ b->hist[st->head][0] = b->pos[0]*st->xsize;
+ b->hist[st->head][1] = b->pos[1]*st->xsize;
+ }
+
+ /* update bug state */
+ b = st->bugs;
+ for (i = 0; i < st->nbugs; i++, b++) {
+ theta = atan2(b->closest->pos[1] - b->pos[1] + frand(st->noise),
+ b->closest->pos[0] - b->pos[0] + frand(st->noise));
+ ax = st->maxAcc*cos(theta);
+ ay = st->maxAcc*sin(theta);
+
+ b->vel[0] += ax*st->dt;
+ b->vel[1] += ay*st->dt;
+
+ /* check velocity */
+ temp = sq(b->vel[0]) + sq(b->vel[1]);
+ if (temp > st->maxVelSq) {
+ temp = st->maxVel/sqrt(temp);
+
+ /* save old vel for acc computation */
+ ax = b->vel[0];
+ ay = b->vel[1];
+
+ /* compute new velocity */
+ b->vel[0] *= temp;
+ b->vel[1] *= temp;
+
+ /* update acceleration */
+ ax = (b->vel[0]-ax)*st->dtInv;
+ ay = (b->vel[1]-ay)*st->dtInv;
+ } else if (temp < st->minVelSq) {
+ temp = st->minVel/sqrt(temp);
+
+ /* save old vel for acc computation */
+ ax = b->vel[0];
+ ay = b->vel[1];
+
+ /* compute new velocity */
+ b->vel[0] *= temp;
+ b->vel[1] *= temp;
+
+ /* update acceleration */
+ ax = (b->vel[0]-ax)*st->dtInv;
+ ay = (b->vel[1]-ay)*st->dtInv;
+ }
+
+ /* update position */
+ b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq;
+ b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq;
+
+ /* check limits on targets */
+ if (b->pos[0] < 0) {
+ /* bounce */
+ b->pos[0] = -b->pos[0];
+ b->vel[0] = -b->vel[0];
+ } else if (b->pos[0] >= st->maxx) {
+ /* bounce */
+ b->pos[0] = 2*st->maxx-b->pos[0];
+ b->vel[0] = -b->vel[0];
+ }
+ if (b->pos[1] < 0) {
+ /* bounce */
+ b->pos[1] = -b->pos[1];
+ b->vel[1] = -b->vel[1];
+ } else if (b->pos[1] >= st->maxy) {
+ /* bounce */
+ b->pos[1] = 2*st->maxy-b->pos[1];
+ b->vel[1] = -b->vel[1];
+ }
+
+ b->hist[st->head][0] = b->pos[0]*st->xsize;
+ b->hist[st->head][1] = b->pos[1]*st->xsize;
+ }
+}
+
+static void mutateBug(struct state *st, int which)
+{
+ int i, j;
+
+ if (which == 0) {
+ /* turn bug into target */
+ if (st->ntargets < MAX_TARGETS-1 && st->nbugs > 1) {
+ i = random() % st->nbugs;
+ memcpy((char *)&st->targets[st->ntargets], (char *)&st->bugs[i], sizeof(bug));
+ memcpy((char *)&st->bugs[i], (char *)&st->bugs[st->nbugs-1], sizeof(bug));
+ st->targets[st->ntargets].pos[0] = frand(st->maxx);
+ st->targets[st->ntargets].pos[1] = frand(st->maxy);
+ st->nbugs--;
+ st->ntargets++;
+
+ for (i = 0; i < st->nbugs; i += st->ntargets) {
+ st->bugs[i].closest = &st->targets[st->ntargets-1];
+ }
+ }
+ } else {
+ /* turn target into bug */
+ if (st->ntargets > 1 && st->nbugs < MAX_BUGS-1) {
+ /* pick a target */
+ i = random() % st->ntargets;
+
+ /* copy state into a new bug */
+ memcpy((char *)&st->bugs[st->nbugs], (char *)&st->targets[i], sizeof(bug));
+ st->ntargets--;
+
+ /* pick a target for the new bug */
+ st->bugs[st->nbugs].closest = &st->targets[random()%st->ntargets];
+
+ for (j = 0; j < st->nbugs; j++) {
+ if (st->bugs[j].closest == &st->targets[st->ntargets]) {
+ st->bugs[j].closest = &st->targets[i];
+ } else if (st->bugs[j].closest == &st->targets[i]) {
+ st->bugs[j].closest = &st->targets[random()%st->ntargets];
+ }
+ }
+ st->nbugs++;
+
+ /* copy the last ntarget into the one we just deleted */
+ memcpy(&st->targets[i], (char *)&st->targets[st->ntargets], sizeof(bug));
+ }
+ }
+}
+
+static void mutateParam(float *param)
+{
+ *param *= 0.75+frand(0.5);
+}
+
+static void randomSmallChange(struct state *st)
+{
+ int whichCase = 0;
+
+ whichCase = random()%11;
+
+ if (++st->rsc_callDepth > 10) {
+ st->rsc_callDepth--;
+ return;
+ }
+
+ switch(whichCase) {
+ case 0:
+ /* acceleration */
+ mutateParam(&st->maxAcc);
+ break;
+
+ case 1:
+ /* target acceleration */
+ mutateParam(&st->targetAcc);
+ break;
+
+ case 2:
+ /* velocity */
+ mutateParam(&st->maxVel);
+ break;
+
+ case 3:
+ /* target velocity */
+ mutateParam(&st->targetVel);
+ break;
+
+ case 4:
+ /* noise */
+ mutateParam(&st->noise);
+ break;
+
+ case 5:
+ /* minVelMultiplier */
+ mutateParam(&st->minVelMultiplier);
+ break;
+
+ case 6:
+ case 7:
+ /* target to bug */
+ if (st->ntargets < 2) break;
+ mutateBug(st, 1);
+ break;
+
+ case 8:
+ /* bug to target */
+ if (st->nbugs < 2) break;
+ mutateBug(st, 0);
+ if (st->nbugs < 2) break;
+ mutateBug(st, 0);
+ break;
+
+ case 9:
+ /* color scheme */
+ st->colorScheme = random()%NUM_SCHEMES;
+ if (st->colorScheme == RANDOM_SCHIZO || st->colorScheme == COLOR_SCHIZO) {
+ /* don't use these quite as much */
+ st->colorScheme = random()%NUM_SCHEMES;
+ }
+ break;
+
+ default:
+ randomSmallChange(st);
+ randomSmallChange(st);
+ randomSmallChange(st);
+ randomSmallChange(st);
+ }
+
+ if (st->minVelMultiplier < 0.3) st->minVelMultiplier = 0.3;
+ else if (st->minVelMultiplier > 0.9) st->minVelMultiplier = 0.9;
+ if (st->noise < 0.01) st->noise = 0.01;
+ if (st->maxVel < 0.02) st->maxVel = 0.02;
+ if (st->targetVel < 0.02) st->targetVel = 0.02;
+ if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7;
+ if (st->maxAcc > st->maxVel*0.7) st->maxAcc = st->maxVel*0.7;
+ if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7;
+ if (st->maxAcc < 0.01) st->maxAcc = 0.01;
+ if (st->targetAcc < 0.005) st->targetAcc = 0.005;
+
+ computeConstants(st);
+ st->rsc_callDepth--;
+}
+
+static void randomBigChange(struct state *st)
+{
+ int whichCase = 0;
+ int temp;
+
+ whichCase = random()%4;
+
+ if (++st->rbc_callDepth > 3) {
+ st->rbc_callDepth--;
+ return;
+ }
+
+ switch(whichCase) {
+ case 0:
+ /* trail length */
+ temp = (random()%(MAX_TRAIL_LEN-25)) + 25;
+ clearBugs(st);
+ st->trailLen = temp;
+ computeColorIndices(st);
+ initBugs(st);
+ break;
+
+ case 1:
+ /* Whee! */
+ randomSmallChange(st);
+ randomSmallChange(st);
+ randomSmallChange(st);
+ randomSmallChange(st);
+ randomSmallChange(st);
+ randomSmallChange(st);
+ randomSmallChange(st);
+ randomSmallChange(st);
+ break;
+
+ case 2:
+ clearBugs(st);
+ initBugs(st);
+ break;
+
+ case 3:
+ pickNewTargets(st);
+ break;
+
+ default:
+ temp = random()%st->ntargets;
+ st->targets[temp].pos[0] += frand(st->maxx/4)-st->maxx/8;
+ st->targets[temp].pos[1] += frand(st->maxy/4)-st->maxy/8;
+ /* updateState() will fix bounds */
+ break;
+ }
+
+ st->rbc_callDepth--;
+}
+
+static void updateColorIndex(struct state *st,
+ int **tColorIdx, int *tci0, int *tnc,
+ int **colorIdx, int *ci0, int *nc)
+{
+ switch(st->colorScheme) {
+ case COLOR_TRAILS:
+ *tColorIdx = st->redIndex;
+ *tci0 = 0;
+ *tnc = st->trailLen;
+ *colorIdx = st->blueIndex;
+ *ci0 = 0;
+ *nc = st->trailLen;
+ break;
+
+ case GRAY_SCHIZO:
+ *tColorIdx = st->graySIndex;
+ *tci0 = st->head;
+ *tnc = st->trailLen;
+ *colorIdx = st->graySIndex;
+ *ci0 = st->head;
+ *nc = st->trailLen;
+ break;
+
+ case COLOR_SCHIZO:
+ *tColorIdx = st->redSIndex;
+ *tci0 = st->head;
+ *tnc = st->trailLen;
+ *colorIdx = st->blueSIndex;
+ *ci0 = st->head;
+ *nc = st->trailLen;
+ break;
+
+ case GRAY_TRAILS:
+ *tColorIdx = st->grayIndex;
+ *tci0 = 0;
+ *tnc = st->trailLen;
+ *colorIdx = st->grayIndex;
+ *ci0 = 0;
+ *nc = st->trailLen;
+ break;
+
+ case RANDOM_TRAILS:
+ *tColorIdx = st->redIndex;
+ *tci0 = 0;
+ *tnc = st->trailLen;
+ *colorIdx = st->randomIndex;
+ *ci0 = 0;
+ *nc = st->trailLen;
+ break;
+
+ case RANDOM_SCHIZO:
+ *tColorIdx = st->redIndex;
+ *tci0 = st->head;
+ *tnc = st->trailLen;
+ *colorIdx = st->randomIndex;
+ *ci0 = st->head;
+ *nc = st->trailLen;
+ break;
+ }
+}
+
+#if HAVE_GETTIMEOFDAY
+static void initTime(struct state *st)
+{
+#if GETTIMEOFDAY_TWO_ARGS
+ gettimeofday(&st->startupTime, NULL);
+#else
+ gettimeofday(&st->startupTime);
+#endif
+}
+
+static double getTime(struct state *st)
+{
+ struct timeval t;
+ float f;
+#if GETTIMEOFDAY_TWO_ARGS
+ gettimeofday(&t, NULL);
+#else
+ gettimeofday(&t);
+#endif
+ t.tv_sec -= st->startupTime.tv_sec;
+ f = ((double)t.tv_sec) + t.tv_usec*1e-6;
+ return f;
+}
+#endif
+
+static void *
+xrayswarm_init (Display *d, Window w)
+{
+ struct state *st = (struct state *) calloc (1, sizeof(*st));
+ int i;
+
+ st->dpy = d;
+ st->win = w;
+
+ st->dt = 0.3;
+ st->targetVel = 0.03;
+ st->targetAcc = 0.02;
+ st->maxVel = 0.05;
+ st->maxAcc = 0.03;
+ st->noise = 0.01;
+ st->minVelMultiplier = 0.5;
+
+ st->nbugs = -1;
+ st->ntargets = -1;
+ st->trailLen = -1;
+
+ st->colorScheme = /* -1 */ 2;
+ st->changeProb = 0.08;
+
+ if (!initGraphics(st)) abort();
+
+ computeConstants(st);
+ initBugs(st);
+ initTime(st);
+ computeColorIndices(st);
+
+ if (st->changeProb > 0) {
+ for (i = random()%5+5; i >= 0; i--) {
+ randomSmallChange(st);
+ }
+ }
+
+ return st;
+}
+
+static unsigned long
+xrayswarm_draw (Display *d, Window w, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ unsigned long this_delay = st->delay;
+
+#if HAVE_GETTIMEOFDAY
+ st->draw_start = getTime(st);
+#endif
+
+ if (st->delay > 0) {
+ st->draw_cnt = 2;
+ st->dt = DESIRED_DT/2;
+ } else {
+ st->draw_cnt = 1;
+ st->dt = DESIRED_DT;
+ }
+
+ for (; st->draw_cnt > 0; st->draw_cnt--) {
+ updateState(st);
+ updateColorIndex(st, &st->draw_targetColorIndex, &st->draw_targetStartColor, &st->draw_targetNumColors,
+ &st->draw_colorIndex, &st->draw_startColor, &st->draw_numColors);
+ drawBugs(st, st->draw_targetColorIndex, st->draw_targetStartColor, st->draw_targetNumColors,
+ st->draw_colorIndex, st->draw_startColor, st->draw_numColors);
+ }
+#if HAVE_GETTIMEOFDAY
+ st->draw_end = getTime(st);
+ st->draw_nframes++;
+
+ if (st->draw_end > st->draw_start+0.5) {
+ if (frand(1.0) < st->changeProb) randomSmallChange(st);
+ if (frand(1.0) < st->changeProb*0.3) randomBigChange(st);
+ st->draw_elapsed = st->draw_end-st->draw_start;
+
+ st->draw_timePerFrame = st->draw_elapsed/st->draw_nframes - st->delay*1e-6;
+ st->draw_fps = st->draw_nframes/st->draw_elapsed;
+ /*
+ printf("elapsed: %.3f\n", elapsed);
+ printf("fps: %.1f secs per frame: %.3f delay: %f\n",
+ fps, timePerFrame, delay);
+ */
+
+ if (st->draw_fps > MAX_FPS) {
+ st->delay = (1.0/MAX_FPS - (st->draw_timePerFrame + st->delay*1e-6))*1e6;
+ } else if (st->dt*st->draw_fps < MIN_FPS*DESIRED_DT) {
+ /* need to speed things up somehow */
+ if (0 && st->nbugs > 10) {
+ /*printf("reducing bugs to improve speed.\n");*/
+ clearBugs(st);
+ st->nbugs *= st->draw_fps/MIN_FPS;
+ if (st->ntargets >= st->nbugs/2) mutateBug(st, 1);
+ } else if (0 && st->dt < 0.3) {
+ /*printf("increasing dt to improve speed.\n");*/
+ st->dt *= MIN_FPS/st->draw_fps;
+ computeConstants(st);
+ } else if (st->trailLen > 10) {
+ /*printf("reducing trail length to improve speed.\n");*/
+ clearBugs(st);
+ st->trailLen = st->trailLen * (st->draw_fps/MIN_FPS);
+ if (st->trailLen < 10) st->trailLen = 10;
+ computeColorIndices(st);
+ initBugs(st);
+ }
+ }
+
+ st->draw_start = getTime(st);
+ st->draw_nframes = 0;
+ }
+#else
+ if (frand(1) < st->changeProb*2/100.0) randomSmallChange(st);
+ if (frand(1) < st->changeProb*0.3/100.0) randomBigChange(st);
+#endif
+
+ if (st->delay <= 10000) {
+ st->draw_delayAccum += st->delay;
+ if (st->draw_delayAccum > 10000) {
+ this_delay = st->draw_delayAccum;
+ st->draw_delayAccum = 0;
+ st->draw_sleepCount = 0;
+ }
+ if (++st->draw_sleepCount > 2) {
+ st->draw_sleepCount = 0;
+ this_delay = 10000;
+ }
+ }
+
+ return this_delay;
+}
+
+static void
+xrayswarm_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
+{
+ struct state *st = (struct state *) closure;
+ st->xsize = w;
+ st->ysize = h;
+ st->xc = st->xsize >> 1;
+ st->yc = st->ysize >> 1;
+ st->maxy = st->ysize/(float)st->xsize;
+}
+
+static Bool
+xrayswarm_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+ return False;
+}
+
+static void
+xrayswarm_free (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ free (st);
+}
+
+XSCREENSAVER_MODULE ("XRaySwarm", xrayswarm)