2 * Copyright (c) 2000 by Chris Leger (xrayjones@users.sourceforge.net)
4 * xrayswarm - a shameless ripoff of the 'swarm' screensaver on SGI
7 * Version 1.0 - initial release. doesn't read any special command-line
8 * options, and only supports the variable 'delay' via Xresources.
9 * (the delay resouces is most useful on systems w/o gettimeofday, in
10 * which case automagical level-of-detail for FPS maintainance can't
13 * The code isn't commented, but isn't too ugly. It should be pretty
14 * easy to understand, with the exception of the colormap stuff.
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
26 The above copyright notice and this permission notice shall be included
27 in all copies or substantial portions of the Software.
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
30 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32 IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
33 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
34 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35 OTHER DEALINGS IN THE SOFTWARE.
37 Except as contained in this notice, the name of the X Consortium shall
38 not be used in advertising or otherwise to promote the sale, use or
39 other dealings in this Software without prior written authorization
40 from the X Consortium.
50 #include "screenhack.h"
53 # define HAVE_GETTIMEOFDAY 1
56 /**********************************************************************
60 **********************************************************************/
62 static const char *xrayswarm_defaults [] ={
67 "*ignoreRotation: True",
72 static XrmOptionDescRec xrayswarm_options [] = {
73 {"-delay",".delay",XrmoptionSepArg,0},
78 /**********************************************************************
80 * bug structs & variables
82 **********************************************************************/
83 #define MAX_TRAIL_LEN 60
85 #define MAX_TARGETS 10
86 #define sq(x) ((x)*(x))
90 #define DESIRED_DT 0.2
92 typedef struct _sbug {
94 int hist[MAX_TRAIL_LEN][2];
96 struct _sbug *closest;
100 #define GRAY_SCHIZO 1
101 #define COLOR_TRAILS 2
102 #define RANDOM_TRAILS 3
103 #define RANDOM_SCHIZO 4
104 #define COLOR_SCHIZO 5
105 #define NUM_SCHEMES 6 /* too many schizos; don't use last 2 */
113 unsigned char colors[768];
128 float minVelMultiplier;
142 bug targets[MAX_TARGETS];
148 int grayIndex[MAX_TRAIL_LEN];
149 int redIndex[MAX_TRAIL_LEN];
150 int blueIndex[MAX_TRAIL_LEN];
151 int graySIndex[MAX_TRAIL_LEN];
152 int redSIndex[MAX_TRAIL_LEN];
153 int blueSIndex[MAX_TRAIL_LEN];
154 int randomIndex[MAX_TRAIL_LEN];
163 float draw_timePerFrame, draw_elapsed;
164 int *draw_targetColorIndex, *draw_colorIndex;
165 int draw_targetStartColor, draw_targetNumColors;
166 int draw_startColor, draw_numColors;
167 double draw_start, draw_end;
173 struct timeval startupTime;
193 static const bugParams good1 = {
195 0.03, /* targetVel */
196 0.02, /* targetAcc */
204 0.15 /* changeProb */
207 static const bugParams *goodParams[] = {
211 static int numParamSets = 1;
214 static void initCMap(struct state *st)
221 /* color 0 is black */
227 st->colors[n++] = 255;
231 /* color 2 is green */
232 st->colors[n++] = 255;
236 /* color 3 is blue */
237 st->colors[n++] = 255;
241 /* start greyscale colors at 4; 16 levels */
242 for (i = 0; i < 16; i++) {
244 if (temp > 255) temp = 255;
245 st->colors[n++] = 255 - temp;
246 st->colors[n++] = 255 - temp;
247 st->colors[n++] = 255 - temp;
250 /* start red fade at 20; 16 levels */
251 for (i = 0; i < 16; i++) {
253 if (temp > 255) temp = 255;
254 st->colors[n++] = 255 - temp;
255 st->colors[n++] = 255 - pow(i/16.0+0.001, 0.3)*255;
256 st->colors[n++] = 65 - temp/4;
259 /* start blue fade at 36; 16 levels */
260 for (i = 0; i < 16; i++) {
262 if (temp > 255) temp = 255;
263 st->colors[n++] = 32 - temp/8;
264 st->colors[n++] = 180 - pow(i/16.0+0.001, 0.3)*180;
265 st->colors[n++] = 255 - temp;
268 /* random colors start at 52 */
269 st->numRandomColors = MAX_TRAIL_LEN;
271 st->colors[n] = random()&255; n++;
272 st->colors[n] = random()&255; n++;
273 st->colors[n] = st->colors[n-2]/2 + st->colors[n-3]/2; n++;
275 for (i = 0; i < st->numRandomColors; i++) {
276 st->colors[n] = (st->colors[n-3] + (random()&31) - 16)&255; n++;
277 st->colors[n] = (st->colors[n-3] + (random()&31) - 16)&255; n++;
278 st->colors[n] = st->colors[n-2]/(float)(i+2) + st->colors[n-3]/(float)(i+2); n++;
281 st->numColors = n/3 + 1;
284 static int initGraphics(struct state *st)
287 XWindowAttributes xgwa;
288 /* XSetWindowAttributes xswa;*/
295 XGetWindowAttributes(st->dpy,st->win,&xgwa);
297 /* xswa.backing_store=Always;
298 XChangeWindowAttributes(st->dpy,st->win,CWBackingStore,&xswa);*/
299 xgcv.function=GXcopy;
301 st->delay = get_integer_resource(st->dpy, "delay","Integer");
303 xgcv.foreground=get_pixel_resource (st->dpy, cmap, "background", "Background");
304 st->fgc[0]=XCreateGC(st->dpy, st->win, GCForeground|GCFunction,&xgcv);
306 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[0], False);
311 xgcv.foreground=get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
312 st->fgc[1]=XCreateGC(st->dpy,st->win,GCForeground|GCFunction,&xgcv);
314 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[1], False);
316 for (i=0;i<st->numColors;i+=2) st->fgc[i]=st->fgc[0];
317 for (i=1;i<st->numColors;i+=2) st->fgc[i]=st->fgc[1];
319 for (i = 0; i < st->numColors; i++) {
320 color.red=st->colors[n++]<<8;
321 color.green=st->colors[n++]<<8;
322 color.blue=st->colors[n++]<<8;
323 color.flags=DoRed|DoGreen|DoBlue;
324 XAllocColor(st->dpy,cmap,&color);
325 xgcv.foreground=color.pixel;
326 st->fgc[i] = XCreateGC(st->dpy, st->win, GCForeground | GCFunction,&xgcv);
328 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[i], False);
332 st->cgc = XCreateGC(st->dpy,st->win,GCForeground|GCFunction,&xgcv);
333 XSetGraphicsExposures(st->dpy,st->cgc,False);
335 jwxyz_XSetAntiAliasing (st->dpy, st->cgc, False);
338 st->xsize = xgwa.width;
339 st->ysize = xgwa.height;
340 st->xc = st->xsize >> 1;
341 st->yc = st->ysize >> 1;
344 st->maxy = st->ysize/(float)st->xsize;
346 if (st->colorScheme < 0) st->colorScheme = random()%NUM_SCHEMES;
351 static void initBugs(struct state *st)
356 st->head = st->tail = 0;
358 memset((char *)st->bugs, 0,MAX_BUGS*sizeof(bug));
359 memset((char *)st->targets, 0, MAX_TARGETS*sizeof(bug));
361 if (st->ntargets < 0) st->ntargets = (0.25+frand(0.75)*frand(1))*MAX_TARGETS;
362 if (st->ntargets < 1) st->ntargets = 1;
364 if (st->nbugs < 0) st->nbugs = (0.25+frand(0.75)*frand(1))*MAX_BUGS;
365 if (st->nbugs <= st->ntargets) st->nbugs = st->ntargets+1;
367 if (st->trailLen < 0) {
368 st->trailLen = (1.0 - frand(0.6)*frand(1))*MAX_TRAIL_LEN;
371 if (st->nbugs > MAX_BUGS) st->nbugs = MAX_BUGS;
372 if (st->ntargets > MAX_TARGETS) st->ntargets = MAX_TARGETS;
373 if (st->trailLen > MAX_TRAIL_LEN) st->trailLen = MAX_TRAIL_LEN;
376 for (i = 0; i < st->nbugs; i++, b++) {
377 b->pos[0] = frand(st->maxx);
378 b->pos[1] = frand(st->maxy);
379 b->vel[0] = frand(st->maxVel/2);
380 b->vel[1] = frand(st->maxVel/2);
382 b->hist[st->head][0] = b->pos[0]*st->xsize;
383 b->hist[st->head][1] = b->pos[1]*st->xsize;
384 b->closest = &st->targets[random()%st->ntargets];
388 for (i = 0; i < st->ntargets; i++, b++) {
389 b->pos[0] = frand(st->maxx);
390 b->pos[1] = frand(st->maxy);
392 b->vel[0] = frand(st->targetVel/2);
393 b->vel[1] = frand(st->targetVel/2);
395 b->hist[st->head][0] = b->pos[0]*st->xsize;
396 b->hist[st->head][1] = b->pos[1]*st->xsize;
400 static void pickNewTargets(struct state *st)
406 for (i = 0; i < st->nbugs; i++, b++) {
407 b->closest = &st->targets[random()%st->ntargets];
412 static void addBugs(int numToAdd)
417 if (numToAdd + st->nbugs > MAX_BUGS) numToAdd = MAX_BUGS-st->nbugs;
418 else if (numToAdd < 0) numToAdd = 0;
420 for (i = 0; i < numToAdd; i++) {
421 b = &st->bugs[random()%st->nbugs];
422 memcpy((char *)&st->bugs[st->nbugs+i], (char *)b, sizeof(bug));
423 b->closest = &st->targets[random()%st->ntargets];
426 st->nbugs += numToAdd;
429 static void addTargets(int numToAdd)
434 if (numToAdd + st->ntargets > MAX_TARGETS) numToAdd = MAX_TARGETS-st->ntargets;
435 else if (numToAdd < 0) numToAdd = 0;
437 for (i = 0; i < numToAdd; i++) {
438 b = &st->targets[random()%st->ntargets];
439 memcpy((char *)&st->targets[st->ntargets+i], (char *)b, sizeof(bug));
440 b->closest = &st->targets[random()%st->ntargets];
443 st->ntargets += numToAdd;
447 static void computeConstants(struct state *st)
449 st->halfDtSq = st->dt*st->dt*0.5;
450 st->dtInv = 1.0/st->dt;
451 st->targetVelSq = st->targetVel*st->targetVel;
452 st->maxVelSq = st->maxVel*st->maxVel;
453 st->minVel = st->maxVel*st->minVelMultiplier;
454 st->minVelSq = st->minVel*st->minVel;
457 static void computeColorIndices(struct state *st)
462 /* note: colors are used in *reverse* order! */
465 for (i = 0; i < st->trailLen; i++) {
466 st->grayIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5;
467 if (st->grayIndex[st->trailLen-1-i] > 19) st->grayIndex[st->trailLen-1-i] = 19;
471 for (i = 0; i < st->trailLen; i++) {
472 st->redIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5;
473 if (st->redIndex[st->trailLen-1-i] > 35) st->redIndex[st->trailLen-1-i] = 35;
477 for (i = 0; i < st->trailLen; i++) {
478 st->blueIndex[st->trailLen-1-i] = 36 + i*16.0/st->trailLen + 0.5;
479 if (st->blueIndex[st->trailLen-1-i] > 51) st->blueIndex[st->trailLen-1-i] = 51;
482 /* gray schizo - same as gray*/
483 for (i = 0; i < st->trailLen; i++) {
484 st->graySIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5;
485 if (st->graySIndex[st->trailLen-1-i] > 19) st->graySIndex[st->trailLen-1-i] = 19;
488 /*schizoLength = st->trailLen/4;
489 if (schizoLength < 3) schizoLength = 3;*/
491 for (i = 0; i < st->trailLen; i++) {
492 /* redSIndex[trailLen-1-i] =
493 20 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;*/
494 st->redSIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5;
495 if (st->redSIndex[st->trailLen-1-i] > 35) st->redSIndex[st->trailLen-1-i] = 35;
498 schizoLength = st->trailLen/2;
499 if (schizoLength < 3) schizoLength = 3;
500 /* blue schizo is next */
501 for (i = 0; i < st->trailLen; i++) {
502 st->blueSIndex[st->trailLen-1-i] =
503 36 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;
504 if (st->blueSIndex[st->trailLen-1-i] > 51) st->blueSIndex[st->trailLen-1-i] = 51;
508 for (i = 0; i < st->trailLen; i++) {
509 st->randomIndex[i] = 52 + random()%(st->numRandomColors);
514 static void setParams(bugParams *p)
517 st->targetVel = p->targetVel;
518 st->targetAcc = p->targetAcc;
519 st->maxVel = p->maxVel;
520 st->maxAcc = p->maxAcc;
521 st->noise = p->noise;
523 st->nbugs = p->nbugs;
524 st->ntargets = p->ntargets;
525 st->trailLen = p->trailLen;
526 st->colorScheme = p->colorScheme;
527 st->changeProb = p->changeProb;
529 computeColorIndices();
533 static void drawBugs(struct state *st, int *tColorIdx, int tci0, int tnc,
534 int *colorIdx, int ci0, int nc)
540 if (((st->head+1)%st->trailLen) == st->tail) {
541 /* first, erase last segment of bugs if necessary */
542 temp = (st->tail+1) % st->trailLen;
545 for (i = 0; i < st->nbugs; i++, b++) {
546 XDrawLine(st->dpy, st->win, st->fgc[0],
547 b->hist[st->tail][0], b->hist[st->tail][1],
548 b->hist[temp][0], b->hist[temp][1]);
552 for (i = 0; i < st->ntargets; i++, b++) {
553 XDrawLine(st->dpy, st->win, st->fgc[0],
554 b->hist[st->tail][0], b->hist[st->tail][1],
555 b->hist[temp][0], b->hist[temp][1]);
557 st->tail = (st->tail+1)%st->trailLen;
560 for (j = st->tail; j != st->head; j = temp) {
561 temp = (j+1)%st->trailLen;
564 for (i = 0; i < st->nbugs; i++, b++) {
565 XDrawLine(st->dpy, st->win, st->fgc[colorIdx[ci0]],
566 b->hist[j][0], b->hist[j][1],
567 b->hist[temp][0], b->hist[temp][1]);
571 for (i = 0; i < st->ntargets; i++, b++) {
572 XDrawLine(st->dpy, st->win, st->fgc[tColorIdx[tci0]],
573 b->hist[j][0], b->hist[j][1],
574 b->hist[temp][0], b->hist[temp][1]);
581 static void clearBugs(struct state *st)
587 st->tail = st->tail-1;
588 if (st->tail < 0) st->tail = st->trailLen-1;
590 if (((st->head+1)%st->trailLen) == st->tail) {
591 /* first, erase last segment of bugs if necessary */
592 temp = (st->tail+1) % st->trailLen;
595 for (i = 0; i < st->nbugs; i++, b++) {
596 XDrawLine(st->dpy, st->win, st->fgc[0],
597 b->hist[st->tail][0], b->hist[st->tail][1],
598 b->hist[temp][0], b->hist[temp][1]);
602 for (i = 0; i < st->ntargets; i++, b++) {
603 XDrawLine(st->dpy, st->win, st->fgc[0],
604 b->hist[st->tail][0], b->hist[st->tail][1],
605 b->hist[temp][0], b->hist[temp][1]);
607 st->tail = (st->tail+1)%st->trailLen;
610 for (j = st->tail; j != st->head; j = temp) {
611 temp = (j+1)%st->trailLen;
614 for (i = 0; i < st->nbugs; i++, b++) {
615 XDrawLine(st->dpy, st->win, st->fgc[0],
616 b->hist[j][0], b->hist[j][1],
617 b->hist[temp][0], b->hist[temp][1]);
621 for (i = 0; i < st->ntargets; i++, b++) {
622 XDrawLine(st->dpy, st->win, st->fgc[0],
623 b->hist[j][0], b->hist[j][1],
624 b->hist[temp][0], b->hist[temp][1]);
629 static void updateState(struct state *st)
633 register float ax, ay, temp;
638 st->head = (st->head+1)%st->trailLen;
640 for (j = 0; j < 5; j++) {
641 /* update closets bug for the bug indicated by checkIndex */
642 st->checkIndex = (st->checkIndex+1)%st->nbugs;
643 b = &st->bugs[st->checkIndex];
645 ax = b->closest->pos[0] - b->pos[0];
646 ay = b->closest->pos[1] - b->pos[1];
647 temp = ax*ax + ay*ay;
648 for (i = 0; i < st->ntargets; i++) {
649 b2 = &st->targets[i];
650 if (b2 == b->closest) continue;
651 ax = b2->pos[0] - b->pos[0];
652 ay = b2->pos[1] - b->pos[1];
653 theta = ax*ax + ay*ay;
654 if (theta < temp*2) {
661 /* update target state */
664 for (i = 0; i < st->ntargets; i++, b++) {
666 ax = st->targetAcc*cos(theta);
667 ay = st->targetAcc*sin(theta);
669 b->vel[0] += ax*st->dt;
670 b->vel[1] += ay*st->dt;
673 temp = sq(b->vel[0]) + sq(b->vel[1]);
674 if (temp > st->targetVelSq) {
675 temp = st->targetVel/sqrt(temp);
676 /* save old vel for acc computation */
680 /* compute new velocity */
684 /* update acceleration */
685 ax = (b->vel[0]-ax)*st->dtInv;
686 ay = (b->vel[1]-ay)*st->dtInv;
689 /* update position */
690 b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq;
691 b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq;
693 /* check limits on targets */
696 b->pos[0] = -b->pos[0];
697 b->vel[0] = -b->vel[0];
698 } else if (b->pos[0] >= st->maxx) {
700 b->pos[0] = 2*st->maxx-b->pos[0];
701 b->vel[0] = -b->vel[0];
705 b->pos[1] = -b->pos[1];
706 b->vel[1] = -b->vel[1];
707 } else if (b->pos[1] >= st->maxy) {
709 b->pos[1] = 2*st->maxy-b->pos[1];
710 b->vel[1] = -b->vel[1];
713 b->hist[st->head][0] = b->pos[0]*st->xsize;
714 b->hist[st->head][1] = b->pos[1]*st->xsize;
717 /* update bug state */
719 for (i = 0; i < st->nbugs; i++, b++) {
720 theta = atan2(b->closest->pos[1] - b->pos[1] + frand(st->noise),
721 b->closest->pos[0] - b->pos[0] + frand(st->noise));
722 ax = st->maxAcc*cos(theta);
723 ay = st->maxAcc*sin(theta);
725 b->vel[0] += ax*st->dt;
726 b->vel[1] += ay*st->dt;
729 temp = sq(b->vel[0]) + sq(b->vel[1]);
730 if (temp > st->maxVelSq) {
731 temp = st->maxVel/sqrt(temp);
733 /* save old vel for acc computation */
737 /* compute new velocity */
741 /* update acceleration */
742 ax = (b->vel[0]-ax)*st->dtInv;
743 ay = (b->vel[1]-ay)*st->dtInv;
744 } else if (temp < st->minVelSq) {
745 temp = st->minVel/sqrt(temp);
747 /* save old vel for acc computation */
751 /* compute new velocity */
755 /* update acceleration */
756 ax = (b->vel[0]-ax)*st->dtInv;
757 ay = (b->vel[1]-ay)*st->dtInv;
760 /* update position */
761 b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq;
762 b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq;
764 /* check limits on targets */
767 b->pos[0] = -b->pos[0];
768 b->vel[0] = -b->vel[0];
769 } else if (b->pos[0] >= st->maxx) {
771 b->pos[0] = 2*st->maxx-b->pos[0];
772 b->vel[0] = -b->vel[0];
776 b->pos[1] = -b->pos[1];
777 b->vel[1] = -b->vel[1];
778 } else if (b->pos[1] >= st->maxy) {
780 b->pos[1] = 2*st->maxy-b->pos[1];
781 b->vel[1] = -b->vel[1];
784 b->hist[st->head][0] = b->pos[0]*st->xsize;
785 b->hist[st->head][1] = b->pos[1]*st->xsize;
789 static void mutateBug(struct state *st, int which)
794 /* turn bug into target */
795 if (st->ntargets < MAX_TARGETS-1 && st->nbugs > 1) {
796 i = random() % st->nbugs;
797 memcpy((char *)&st->targets[st->ntargets], (char *)&st->bugs[i], sizeof(bug));
798 memcpy((char *)&st->bugs[i], (char *)&st->bugs[st->nbugs-1], sizeof(bug));
799 st->targets[st->ntargets].pos[0] = frand(st->maxx);
800 st->targets[st->ntargets].pos[1] = frand(st->maxy);
804 for (i = 0; i < st->nbugs; i += st->ntargets) {
805 st->bugs[i].closest = &st->targets[st->ntargets-1];
809 /* turn target into bug */
810 if (st->ntargets > 1 && st->nbugs < MAX_BUGS-1) {
812 i = random() % st->ntargets;
814 /* copy state into a new bug */
815 memcpy((char *)&st->bugs[st->nbugs], (char *)&st->targets[i], sizeof(bug));
818 /* pick a target for the new bug */
819 st->bugs[st->nbugs].closest = &st->targets[random()%st->ntargets];
821 for (j = 0; j < st->nbugs; j++) {
822 if (st->bugs[j].closest == &st->targets[st->ntargets]) {
823 st->bugs[j].closest = &st->targets[i];
824 } else if (st->bugs[j].closest == &st->targets[i]) {
825 st->bugs[j].closest = &st->targets[random()%st->ntargets];
830 /* copy the last ntarget into the one we just deleted */
831 memcpy(&st->targets[i], (char *)&st->targets[st->ntargets], sizeof(bug));
836 static void mutateParam(float *param)
838 *param *= 0.75+frand(0.5);
841 static void randomSmallChange(struct state *st)
845 whichCase = random()%11;
847 if (++st->rsc_callDepth > 10) {
855 mutateParam(&st->maxAcc);
859 /* target acceleration */
860 mutateParam(&st->targetAcc);
865 mutateParam(&st->maxVel);
869 /* target velocity */
870 mutateParam(&st->targetVel);
875 mutateParam(&st->noise);
879 /* minVelMultiplier */
880 mutateParam(&st->minVelMultiplier);
886 if (st->ntargets < 2) break;
892 if (st->nbugs < 2) break;
894 if (st->nbugs < 2) break;
900 st->colorScheme = random()%NUM_SCHEMES;
901 if (st->colorScheme == RANDOM_SCHIZO || st->colorScheme == COLOR_SCHIZO) {
902 /* don't use these quite as much */
903 st->colorScheme = random()%NUM_SCHEMES;
908 randomSmallChange(st);
909 randomSmallChange(st);
910 randomSmallChange(st);
911 randomSmallChange(st);
914 if (st->minVelMultiplier < 0.3) st->minVelMultiplier = 0.3;
915 else if (st->minVelMultiplier > 0.9) st->minVelMultiplier = 0.9;
916 if (st->noise < 0.01) st->noise = 0.01;
917 if (st->maxVel < 0.02) st->maxVel = 0.02;
918 if (st->targetVel < 0.02) st->targetVel = 0.02;
919 if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7;
920 if (st->maxAcc > st->maxVel*0.7) st->maxAcc = st->maxVel*0.7;
921 if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7;
922 if (st->maxAcc < 0.01) st->maxAcc = 0.01;
923 if (st->targetAcc < 0.005) st->targetAcc = 0.005;
925 computeConstants(st);
929 static void randomBigChange(struct state *st)
934 whichCase = random()%4;
936 if (++st->rbc_callDepth > 3) {
944 temp = (random()%(MAX_TRAIL_LEN-25)) + 25;
947 computeColorIndices(st);
953 randomSmallChange(st);
954 randomSmallChange(st);
955 randomSmallChange(st);
956 randomSmallChange(st);
957 randomSmallChange(st);
958 randomSmallChange(st);
959 randomSmallChange(st);
960 randomSmallChange(st);
973 temp = random()%st->ntargets;
974 st->targets[temp].pos[0] += frand(st->maxx/4)-st->maxx/8;
975 st->targets[temp].pos[1] += frand(st->maxy/4)-st->maxy/8;
976 /* updateState() will fix bounds */
983 static void updateColorIndex(struct state *st,
984 int **tColorIdx, int *tci0, int *tnc,
985 int **colorIdx, int *ci0, int *nc)
987 switch(st->colorScheme) {
989 *tColorIdx = st->redIndex;
992 *colorIdx = st->blueIndex;
998 *tColorIdx = st->graySIndex;
1000 *tnc = st->trailLen;
1001 *colorIdx = st->graySIndex;
1007 *tColorIdx = st->redSIndex;
1009 *tnc = st->trailLen;
1010 *colorIdx = st->blueSIndex;
1016 *tColorIdx = st->grayIndex;
1018 *tnc = st->trailLen;
1019 *colorIdx = st->grayIndex;
1025 *tColorIdx = st->redIndex;
1027 *tnc = st->trailLen;
1028 *colorIdx = st->randomIndex;
1034 *tColorIdx = st->redIndex;
1036 *tnc = st->trailLen;
1037 *colorIdx = st->randomIndex;
1044 #if HAVE_GETTIMEOFDAY
1045 static void initTime(struct state *st)
1047 #if GETTIMEOFDAY_TWO_ARGS
1048 gettimeofday(&st->startupTime, NULL);
1050 gettimeofday(&st->startupTime);
1054 static double getTime(struct state *st)
1058 #if GETTIMEOFDAY_TWO_ARGS
1059 gettimeofday(&t, NULL);
1063 t.tv_sec -= st->startupTime.tv_sec;
1064 f = ((double)t.tv_sec) + t.tv_usec*1e-6;
1070 xrayswarm_init (Display *d, Window w)
1072 struct state *st = (struct state *) calloc (1, sizeof(*st));
1079 st->targetVel = 0.03;
1080 st->targetAcc = 0.02;
1084 st->minVelMultiplier = 0.5;
1090 st->colorScheme = /* -1 */ 2;
1091 st->changeProb = 0.08;
1093 if (!initGraphics(st)) abort();
1095 computeConstants(st);
1098 computeColorIndices(st);
1100 if (st->changeProb > 0) {
1101 for (i = random()%5+5; i >= 0; i--) {
1102 randomSmallChange(st);
1109 static unsigned long
1110 xrayswarm_draw (Display *d, Window w, void *closure)
1112 struct state *st = (struct state *) closure;
1113 unsigned long this_delay = st->delay;
1115 #if HAVE_GETTIMEOFDAY
1116 st->draw_start = getTime(st);
1119 if (st->delay > 0) {
1121 st->dt = DESIRED_DT/2;
1124 st->dt = DESIRED_DT;
1127 for (; st->draw_cnt > 0; st->draw_cnt--) {
1129 updateColorIndex(st, &st->draw_targetColorIndex, &st->draw_targetStartColor, &st->draw_targetNumColors,
1130 &st->draw_colorIndex, &st->draw_startColor, &st->draw_numColors);
1131 drawBugs(st, st->draw_targetColorIndex, st->draw_targetStartColor, st->draw_targetNumColors,
1132 st->draw_colorIndex, st->draw_startColor, st->draw_numColors);
1134 #if HAVE_GETTIMEOFDAY
1135 st->draw_end = getTime(st);
1138 if (st->draw_end > st->draw_start+0.5) {
1139 if (frand(1.0) < st->changeProb) randomSmallChange(st);
1140 if (frand(1.0) < st->changeProb*0.3) randomBigChange(st);
1141 st->draw_elapsed = st->draw_end-st->draw_start;
1143 st->draw_timePerFrame = st->draw_elapsed/st->draw_nframes - st->delay*1e-6;
1144 st->draw_fps = st->draw_nframes/st->draw_elapsed;
1146 printf("elapsed: %.3f\n", elapsed);
1147 printf("fps: %.1f secs per frame: %.3f delay: %f\n",
1148 fps, timePerFrame, delay);
1151 if (st->draw_fps > MAX_FPS) {
1152 st->delay = (1.0/MAX_FPS - (st->draw_timePerFrame + st->delay*1e-6))*1e6;
1153 } else if (st->dt*st->draw_fps < MIN_FPS*DESIRED_DT) {
1154 /* need to speed things up somehow */
1155 if (0 && st->nbugs > 10) {
1156 /*printf("reducing bugs to improve speed.\n");*/
1158 st->nbugs *= st->draw_fps/MIN_FPS;
1159 if (st->ntargets >= st->nbugs/2) mutateBug(st, 1);
1160 } else if (0 && st->dt < 0.3) {
1161 /*printf("increasing dt to improve speed.\n");*/
1162 st->dt *= MIN_FPS/st->draw_fps;
1163 computeConstants(st);
1164 } else if (st->trailLen > 10) {
1165 /*printf("reducing trail length to improve speed.\n");*/
1167 st->trailLen = st->trailLen * (st->draw_fps/MIN_FPS);
1168 if (st->trailLen < 10) st->trailLen = 10;
1169 computeColorIndices(st);
1174 st->draw_start = getTime(st);
1175 st->draw_nframes = 0;
1178 if (frand(1) < st->changeProb*2/100.0) randomSmallChange(st);
1179 if (frand(1) < st->changeProb*0.3/100.0) randomBigChange(st);
1182 if (st->delay <= 10000) {
1183 st->draw_delayAccum += st->delay;
1184 if (st->draw_delayAccum > 10000) {
1185 this_delay = st->draw_delayAccum;
1186 st->draw_delayAccum = 0;
1187 st->draw_sleepCount = 0;
1189 if (++st->draw_sleepCount > 2) {
1190 st->draw_sleepCount = 0;
1199 xrayswarm_reshape (Display *dpy, Window window, void *closure,
1200 unsigned int w, unsigned int h)
1202 struct state *st = (struct state *) closure;
1205 st->xc = st->xsize >> 1;
1206 st->yc = st->ysize >> 1;
1207 st->maxy = st->ysize/(float)st->xsize;
1211 xrayswarm_event (Display *dpy, Window window, void *closure, XEvent *event)
1217 xrayswarm_free (Display *dpy, Window window, void *closure)
1219 struct state *st = (struct state *) closure;
1223 XSCREENSAVER_MODULE ("XRaySwarm", xrayswarm)