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 [] ={
68 static XrmOptionDescRec xrayswarm_options [] = {
69 {"-delay",".delay",XrmoptionSepArg,0},
74 /**********************************************************************
76 * bug structs & variables
78 **********************************************************************/
79 #define MAX_TRAIL_LEN 60
81 #define MAX_TARGETS 10
82 #define sq(x) ((x)*(x))
86 #define DESIRED_DT 0.2
88 typedef struct _sbug {
90 int hist[MAX_TRAIL_LEN][2];
92 struct _sbug *closest;
97 #define COLOR_TRAILS 2
98 #define RANDOM_TRAILS 3
99 #define RANDOM_SCHIZO 4
100 #define COLOR_SCHIZO 5
101 #define NUM_SCHEMES 6 /* too many schizos; don't use last 2 */
109 unsigned char colors[768];
124 float minVelMultiplier;
138 bug targets[MAX_TARGETS];
144 int grayIndex[MAX_TRAIL_LEN];
145 int redIndex[MAX_TRAIL_LEN];
146 int blueIndex[MAX_TRAIL_LEN];
147 int graySIndex[MAX_TRAIL_LEN];
148 int redSIndex[MAX_TRAIL_LEN];
149 int blueSIndex[MAX_TRAIL_LEN];
150 int randomIndex[MAX_TRAIL_LEN];
159 float draw_timePerFrame, draw_elapsed;
160 int *draw_targetColorIndex, *draw_colorIndex;
161 int draw_targetStartColor, draw_targetNumColors;
162 int draw_startColor, draw_numColors;
163 double draw_start, draw_end;
169 struct timeval startupTime;
189 static const bugParams good1 = {
191 0.03, /* targetVel */
192 0.02, /* targetAcc */
200 0.15 /* changeProb */
203 static const bugParams *goodParams[] = {
207 static int numParamSets = 1;
210 static void initCMap(struct state *st)
217 /* color 0 is black */
223 st->colors[n++] = 255;
227 /* color 2 is green */
228 st->colors[n++] = 255;
232 /* color 3 is blue */
233 st->colors[n++] = 255;
237 /* start greyscale colors at 4; 16 levels */
238 for (i = 0; i < 16; i++) {
240 if (temp > 255) temp = 255;
241 st->colors[n++] = 255 - temp;
242 st->colors[n++] = 255 - temp;
243 st->colors[n++] = 255 - temp;
246 /* start red fade at 20; 16 levels */
247 for (i = 0; i < 16; i++) {
249 if (temp > 255) temp = 255;
250 st->colors[n++] = 255 - temp;
251 st->colors[n++] = 255 - pow(i/16.0+0.001, 0.3)*255;
252 st->colors[n++] = 65 - temp/4;
255 /* start blue fade at 36; 16 levels */
256 for (i = 0; i < 16; i++) {
258 if (temp > 255) temp = 255;
259 st->colors[n++] = 32 - temp/8;
260 st->colors[n++] = 180 - pow(i/16.0+0.001, 0.3)*180;
261 st->colors[n++] = 255 - temp;
264 /* random colors start at 52 */
265 st->numRandomColors = MAX_TRAIL_LEN;
267 st->colors[n] = random()&255; n++;
268 st->colors[n] = random()&255; n++;
269 st->colors[n] = st->colors[n-2]/2 + st->colors[n-3]/2; n++;
271 for (i = 0; i < st->numRandomColors; i++) {
272 st->colors[n] = (st->colors[n-3] + (random()&31) - 16)&255; n++;
273 st->colors[n] = (st->colors[n-3] + (random()&31) - 16)&255; n++;
274 st->colors[n] = st->colors[n-2]/(float)(i+2) + st->colors[n-3]/(float)(i+2); n++;
277 st->numColors = n/3 + 1;
280 static int initGraphics(struct state *st)
283 XWindowAttributes xgwa;
284 /* XSetWindowAttributes xswa;*/
291 XGetWindowAttributes(st->dpy,st->win,&xgwa);
293 /* xswa.backing_store=Always;
294 XChangeWindowAttributes(st->dpy,st->win,CWBackingStore,&xswa);*/
295 xgcv.function=GXcopy;
297 st->delay = get_integer_resource(st->dpy, "delay","Integer");
299 xgcv.foreground=get_pixel_resource (st->dpy, cmap, "background", "Background");
300 st->fgc[0]=XCreateGC(st->dpy, st->win, GCForeground|GCFunction,&xgcv);
302 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[0], False);
307 xgcv.foreground=get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
308 st->fgc[1]=XCreateGC(st->dpy,st->win,GCForeground|GCFunction,&xgcv);
310 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[1], False);
312 for (i=0;i<st->numColors;i+=2) st->fgc[i]=st->fgc[0];
313 for (i=1;i<st->numColors;i+=2) st->fgc[i]=st->fgc[1];
315 for (i = 0; i < st->numColors; i++) {
316 color.red=st->colors[n++]<<8;
317 color.green=st->colors[n++]<<8;
318 color.blue=st->colors[n++]<<8;
319 color.flags=DoRed|DoGreen|DoBlue;
320 XAllocColor(st->dpy,cmap,&color);
321 xgcv.foreground=color.pixel;
322 st->fgc[i] = XCreateGC(st->dpy, st->win, GCForeground | GCFunction,&xgcv);
324 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[i], False);
328 st->cgc = XCreateGC(st->dpy,st->win,GCForeground|GCFunction,&xgcv);
329 XSetGraphicsExposures(st->dpy,st->cgc,False);
331 jwxyz_XSetAntiAliasing (st->dpy, st->cgc, False);
334 st->xsize = xgwa.width;
335 st->ysize = xgwa.height;
336 st->xc = st->xsize >> 1;
337 st->yc = st->ysize >> 1;
340 st->maxy = st->ysize/(float)st->xsize;
342 if (st->colorScheme < 0) st->colorScheme = random()%NUM_SCHEMES;
347 static void initBugs(struct state *st)
352 st->head = st->tail = 0;
354 memset((char *)st->bugs, 0,MAX_BUGS*sizeof(bug));
355 memset((char *)st->targets, 0, MAX_TARGETS*sizeof(bug));
357 if (st->ntargets < 0) st->ntargets = (0.25+frand(0.75)*frand(1))*MAX_TARGETS;
358 if (st->ntargets < 1) st->ntargets = 1;
360 if (st->nbugs < 0) st->nbugs = (0.25+frand(0.75)*frand(1))*MAX_BUGS;
361 if (st->nbugs <= st->ntargets) st->nbugs = st->ntargets+1;
363 if (st->trailLen < 0) {
364 st->trailLen = (1.0 - frand(0.6)*frand(1))*MAX_TRAIL_LEN;
367 if (st->nbugs > MAX_BUGS) st->nbugs = MAX_BUGS;
368 if (st->ntargets > MAX_TARGETS) st->ntargets = MAX_TARGETS;
369 if (st->trailLen > MAX_TRAIL_LEN) st->trailLen = MAX_TRAIL_LEN;
372 for (i = 0; i < st->nbugs; i++, b++) {
373 b->pos[0] = frand(st->maxx);
374 b->pos[1] = frand(st->maxy);
375 b->vel[0] = frand(st->maxVel/2);
376 b->vel[1] = frand(st->maxVel/2);
378 b->hist[st->head][0] = b->pos[0]*st->xsize;
379 b->hist[st->head][1] = b->pos[1]*st->xsize;
380 b->closest = &st->targets[random()%st->ntargets];
384 for (i = 0; i < st->ntargets; i++, b++) {
385 b->pos[0] = frand(st->maxx);
386 b->pos[1] = frand(st->maxy);
388 b->vel[0] = frand(st->targetVel/2);
389 b->vel[1] = frand(st->targetVel/2);
391 b->hist[st->head][0] = b->pos[0]*st->xsize;
392 b->hist[st->head][1] = b->pos[1]*st->xsize;
396 static void pickNewTargets(struct state *st)
402 for (i = 0; i < st->nbugs; i++, b++) {
403 b->closest = &st->targets[random()%st->ntargets];
408 static void addBugs(int numToAdd)
413 if (numToAdd + st->nbugs > MAX_BUGS) numToAdd = MAX_BUGS-st->nbugs;
414 else if (numToAdd < 0) numToAdd = 0;
416 for (i = 0; i < numToAdd; i++) {
417 b = &st->bugs[random()%st->nbugs];
418 memcpy((char *)&st->bugs[st->nbugs+i], (char *)b, sizeof(bug));
419 b->closest = &st->targets[random()%st->ntargets];
422 st->nbugs += numToAdd;
425 static void addTargets(int numToAdd)
430 if (numToAdd + st->ntargets > MAX_TARGETS) numToAdd = MAX_TARGETS-st->ntargets;
431 else if (numToAdd < 0) numToAdd = 0;
433 for (i = 0; i < numToAdd; i++) {
434 b = &st->targets[random()%st->ntargets];
435 memcpy((char *)&st->targets[st->ntargets+i], (char *)b, sizeof(bug));
436 b->closest = &st->targets[random()%st->ntargets];
439 st->ntargets += numToAdd;
443 static void computeConstants(struct state *st)
445 st->halfDtSq = st->dt*st->dt*0.5;
446 st->dtInv = 1.0/st->dt;
447 st->targetVelSq = st->targetVel*st->targetVel;
448 st->maxVelSq = st->maxVel*st->maxVel;
449 st->minVel = st->maxVel*st->minVelMultiplier;
450 st->minVelSq = st->minVel*st->minVel;
453 static void computeColorIndices(struct state *st)
458 /* note: colors are used in *reverse* order! */
461 for (i = 0; i < st->trailLen; i++) {
462 st->grayIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5;
463 if (st->grayIndex[st->trailLen-1-i] > 19) st->grayIndex[st->trailLen-1-i] = 19;
467 for (i = 0; i < st->trailLen; i++) {
468 st->redIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5;
469 if (st->redIndex[st->trailLen-1-i] > 35) st->redIndex[st->trailLen-1-i] = 35;
473 for (i = 0; i < st->trailLen; i++) {
474 st->blueIndex[st->trailLen-1-i] = 36 + i*16.0/st->trailLen + 0.5;
475 if (st->blueIndex[st->trailLen-1-i] > 51) st->blueIndex[st->trailLen-1-i] = 51;
478 /* gray schizo - same as gray*/
479 for (i = 0; i < st->trailLen; i++) {
480 st->graySIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5;
481 if (st->graySIndex[st->trailLen-1-i] > 19) st->graySIndex[st->trailLen-1-i] = 19;
484 schizoLength = st->trailLen/4;
485 if (schizoLength < 3) schizoLength = 3;
487 for (i = 0; i < st->trailLen; i++) {
488 /* redSIndex[trailLen-1-i] =
489 20 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;*/
490 st->redSIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5;
491 if (st->redSIndex[st->trailLen-1-i] > 35) st->redSIndex[st->trailLen-1-i] = 35;
494 schizoLength = st->trailLen/2;
495 if (schizoLength < 3) schizoLength = 3;
496 /* blue schizo is next */
497 for (i = 0; i < st->trailLen; i++) {
498 st->blueSIndex[st->trailLen-1-i] =
499 36 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;
500 if (st->blueSIndex[st->trailLen-1-i] > 51) st->blueSIndex[st->trailLen-1-i] = 51;
504 for (i = 0; i < st->trailLen; i++) {
505 st->randomIndex[i] = 52 + random()%(st->numRandomColors);
510 static void setParams(bugParams *p)
513 st->targetVel = p->targetVel;
514 st->targetAcc = p->targetAcc;
515 st->maxVel = p->maxVel;
516 st->maxAcc = p->maxAcc;
517 st->noise = p->noise;
519 st->nbugs = p->nbugs;
520 st->ntargets = p->ntargets;
521 st->trailLen = p->trailLen;
522 st->colorScheme = p->colorScheme;
523 st->changeProb = p->changeProb;
525 computeColorIndices();
529 static void drawBugs(struct state *st, int *tColorIdx, int tci0, int tnc,
530 int *colorIdx, int ci0, int nc)
536 if (((st->head+1)%st->trailLen) == st->tail) {
537 /* first, erase last segment of bugs if necessary */
538 temp = (st->tail+1) % st->trailLen;
541 for (i = 0; i < st->nbugs; i++, b++) {
542 XDrawLine(st->dpy, st->win, st->fgc[0],
543 b->hist[st->tail][0], b->hist[st->tail][1],
544 b->hist[temp][0], b->hist[temp][1]);
548 for (i = 0; i < st->ntargets; i++, b++) {
549 XDrawLine(st->dpy, st->win, st->fgc[0],
550 b->hist[st->tail][0], b->hist[st->tail][1],
551 b->hist[temp][0], b->hist[temp][1]);
553 st->tail = (st->tail+1)%st->trailLen;
556 for (j = st->tail; j != st->head; j = temp) {
557 temp = (j+1)%st->trailLen;
560 for (i = 0; i < st->nbugs; i++, b++) {
561 XDrawLine(st->dpy, st->win, st->fgc[colorIdx[ci0]],
562 b->hist[j][0], b->hist[j][1],
563 b->hist[temp][0], b->hist[temp][1]);
567 for (i = 0; i < st->ntargets; i++, b++) {
568 XDrawLine(st->dpy, st->win, st->fgc[tColorIdx[tci0]],
569 b->hist[j][0], b->hist[j][1],
570 b->hist[temp][0], b->hist[temp][1]);
577 static void clearBugs(struct state *st)
583 st->tail = st->tail-1;
584 if (st->tail < 0) st->tail = st->trailLen-1;
586 if (((st->head+1)%st->trailLen) == st->tail) {
587 /* first, erase last segment of bugs if necessary */
588 temp = (st->tail+1) % st->trailLen;
591 for (i = 0; i < st->nbugs; i++, b++) {
592 XDrawLine(st->dpy, st->win, st->fgc[0],
593 b->hist[st->tail][0], b->hist[st->tail][1],
594 b->hist[temp][0], b->hist[temp][1]);
598 for (i = 0; i < st->ntargets; i++, b++) {
599 XDrawLine(st->dpy, st->win, st->fgc[0],
600 b->hist[st->tail][0], b->hist[st->tail][1],
601 b->hist[temp][0], b->hist[temp][1]);
603 st->tail = (st->tail+1)%st->trailLen;
606 for (j = st->tail; j != st->head; j = temp) {
607 temp = (j+1)%st->trailLen;
610 for (i = 0; i < st->nbugs; i++, b++) {
611 XDrawLine(st->dpy, st->win, st->fgc[0],
612 b->hist[j][0], b->hist[j][1],
613 b->hist[temp][0], b->hist[temp][1]);
617 for (i = 0; i < st->ntargets; i++, b++) {
618 XDrawLine(st->dpy, st->win, st->fgc[0],
619 b->hist[j][0], b->hist[j][1],
620 b->hist[temp][0], b->hist[temp][1]);
625 static void updateState(struct state *st)
629 register float ax, ay, temp;
634 st->head = (st->head+1)%st->trailLen;
636 for (j = 0; j < 5; j++) {
637 /* update closets bug for the bug indicated by checkIndex */
638 st->checkIndex = (st->checkIndex+1)%st->nbugs;
639 b = &st->bugs[st->checkIndex];
641 ax = b->closest->pos[0] - b->pos[0];
642 ay = b->closest->pos[1] - b->pos[1];
643 temp = ax*ax + ay*ay;
644 for (i = 0; i < st->ntargets; i++) {
645 b2 = &st->targets[i];
646 if (b2 == b->closest) continue;
647 ax = b2->pos[0] - b->pos[0];
648 ay = b2->pos[1] - b->pos[1];
649 theta = ax*ax + ay*ay;
650 if (theta < temp*2) {
657 /* update target state */
660 for (i = 0; i < st->ntargets; i++, b++) {
662 ax = st->targetAcc*cos(theta);
663 ay = st->targetAcc*sin(theta);
665 b->vel[0] += ax*st->dt;
666 b->vel[1] += ay*st->dt;
669 temp = sq(b->vel[0]) + sq(b->vel[1]);
670 if (temp > st->targetVelSq) {
671 temp = st->targetVel/sqrt(temp);
672 /* save old vel for acc computation */
676 /* compute new velocity */
680 /* update acceleration */
681 ax = (b->vel[0]-ax)*st->dtInv;
682 ay = (b->vel[1]-ay)*st->dtInv;
685 /* update position */
686 b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq;
687 b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq;
689 /* check limits on targets */
692 b->pos[0] = -b->pos[0];
693 b->vel[0] = -b->vel[0];
694 } else if (b->pos[0] >= st->maxx) {
696 b->pos[0] = 2*st->maxx-b->pos[0];
697 b->vel[0] = -b->vel[0];
701 b->pos[1] = -b->pos[1];
702 b->vel[1] = -b->vel[1];
703 } else if (b->pos[1] >= st->maxy) {
705 b->pos[1] = 2*st->maxy-b->pos[1];
706 b->vel[1] = -b->vel[1];
709 b->hist[st->head][0] = b->pos[0]*st->xsize;
710 b->hist[st->head][1] = b->pos[1]*st->xsize;
713 /* update bug state */
715 for (i = 0; i < st->nbugs; i++, b++) {
716 theta = atan2(b->closest->pos[1] - b->pos[1] + frand(st->noise),
717 b->closest->pos[0] - b->pos[0] + frand(st->noise));
718 ax = st->maxAcc*cos(theta);
719 ay = st->maxAcc*sin(theta);
721 b->vel[0] += ax*st->dt;
722 b->vel[1] += ay*st->dt;
725 temp = sq(b->vel[0]) + sq(b->vel[1]);
726 if (temp > st->maxVelSq) {
727 temp = st->maxVel/sqrt(temp);
729 /* save old vel for acc computation */
733 /* compute new velocity */
737 /* update acceleration */
738 ax = (b->vel[0]-ax)*st->dtInv;
739 ay = (b->vel[1]-ay)*st->dtInv;
740 } else if (temp < st->minVelSq) {
741 temp = st->minVel/sqrt(temp);
743 /* save old vel for acc computation */
747 /* compute new velocity */
751 /* update acceleration */
752 ax = (b->vel[0]-ax)*st->dtInv;
753 ay = (b->vel[1]-ay)*st->dtInv;
756 /* update position */
757 b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq;
758 b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq;
760 /* check limits on targets */
763 b->pos[0] = -b->pos[0];
764 b->vel[0] = -b->vel[0];
765 } else if (b->pos[0] >= st->maxx) {
767 b->pos[0] = 2*st->maxx-b->pos[0];
768 b->vel[0] = -b->vel[0];
772 b->pos[1] = -b->pos[1];
773 b->vel[1] = -b->vel[1];
774 } else if (b->pos[1] >= st->maxy) {
776 b->pos[1] = 2*st->maxy-b->pos[1];
777 b->vel[1] = -b->vel[1];
780 b->hist[st->head][0] = b->pos[0]*st->xsize;
781 b->hist[st->head][1] = b->pos[1]*st->xsize;
785 static void mutateBug(struct state *st, int which)
790 /* turn bug into target */
791 if (st->ntargets < MAX_TARGETS-1 && st->nbugs > 1) {
792 i = random() % st->nbugs;
793 memcpy((char *)&st->targets[st->ntargets], (char *)&st->bugs[i], sizeof(bug));
794 memcpy((char *)&st->bugs[i], (char *)&st->bugs[st->nbugs-1], sizeof(bug));
795 st->targets[st->ntargets].pos[0] = frand(st->maxx);
796 st->targets[st->ntargets].pos[1] = frand(st->maxy);
800 for (i = 0; i < st->nbugs; i += st->ntargets) {
801 st->bugs[i].closest = &st->targets[st->ntargets-1];
805 /* turn target into bug */
806 if (st->ntargets > 1 && st->nbugs < MAX_BUGS-1) {
808 i = random() % st->ntargets;
810 /* copy state into a new bug */
811 memcpy((char *)&st->bugs[st->nbugs], (char *)&st->targets[i], sizeof(bug));
814 /* pick a target for the new bug */
815 st->bugs[st->nbugs].closest = &st->targets[random()%st->ntargets];
817 for (j = 0; j < st->nbugs; j++) {
818 if (st->bugs[j].closest == &st->targets[st->ntargets]) {
819 st->bugs[j].closest = &st->targets[i];
820 } else if (st->bugs[j].closest == &st->targets[i]) {
821 st->bugs[j].closest = &st->targets[random()%st->ntargets];
826 /* copy the last ntarget into the one we just deleted */
827 memcpy(&st->targets[i], (char *)&st->targets[st->ntargets], sizeof(bug));
832 static void mutateParam(float *param)
834 *param *= 0.75+frand(0.5);
837 static void randomSmallChange(struct state *st)
841 whichCase = random()%11;
843 if (++st->rsc_callDepth > 10) {
851 mutateParam(&st->maxAcc);
855 /* target acceleration */
856 mutateParam(&st->targetAcc);
861 mutateParam(&st->maxVel);
865 /* target velocity */
866 mutateParam(&st->targetVel);
871 mutateParam(&st->noise);
875 /* minVelMultiplier */
876 mutateParam(&st->minVelMultiplier);
882 if (st->ntargets < 2) break;
888 if (st->nbugs < 2) break;
890 if (st->nbugs < 2) break;
896 st->colorScheme = random()%NUM_SCHEMES;
897 if (st->colorScheme == RANDOM_SCHIZO || st->colorScheme == COLOR_SCHIZO) {
898 /* don't use these quite as much */
899 st->colorScheme = random()%NUM_SCHEMES;
904 randomSmallChange(st);
905 randomSmallChange(st);
906 randomSmallChange(st);
907 randomSmallChange(st);
910 if (st->minVelMultiplier < 0.3) st->minVelMultiplier = 0.3;
911 else if (st->minVelMultiplier > 0.9) st->minVelMultiplier = 0.9;
912 if (st->noise < 0.01) st->noise = 0.01;
913 if (st->maxVel < 0.02) st->maxVel = 0.02;
914 if (st->targetVel < 0.02) st->targetVel = 0.02;
915 if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7;
916 if (st->maxAcc > st->maxVel*0.7) st->maxAcc = st->maxVel*0.7;
917 if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7;
918 if (st->maxAcc < 0.01) st->maxAcc = 0.01;
919 if (st->targetAcc < 0.005) st->targetAcc = 0.005;
921 computeConstants(st);
925 static void randomBigChange(struct state *st)
930 whichCase = random()%4;
932 if (++st->rbc_callDepth > 3) {
940 temp = (random()%(MAX_TRAIL_LEN-25)) + 25;
943 computeColorIndices(st);
949 randomSmallChange(st);
950 randomSmallChange(st);
951 randomSmallChange(st);
952 randomSmallChange(st);
953 randomSmallChange(st);
954 randomSmallChange(st);
955 randomSmallChange(st);
956 randomSmallChange(st);
969 temp = random()%st->ntargets;
970 st->targets[temp].pos[0] += frand(st->maxx/4)-st->maxx/8;
971 st->targets[temp].pos[1] += frand(st->maxy/4)-st->maxy/8;
972 /* updateState() will fix bounds */
979 static void updateColorIndex(struct state *st,
980 int **tColorIdx, int *tci0, int *tnc,
981 int **colorIdx, int *ci0, int *nc)
983 switch(st->colorScheme) {
985 *tColorIdx = st->redIndex;
988 *colorIdx = st->blueIndex;
994 *tColorIdx = st->graySIndex;
997 *colorIdx = st->graySIndex;
1003 *tColorIdx = st->redSIndex;
1005 *tnc = st->trailLen;
1006 *colorIdx = st->blueSIndex;
1012 *tColorIdx = st->grayIndex;
1014 *tnc = st->trailLen;
1015 *colorIdx = st->grayIndex;
1021 *tColorIdx = st->redIndex;
1023 *tnc = st->trailLen;
1024 *colorIdx = st->randomIndex;
1030 *tColorIdx = st->redIndex;
1032 *tnc = st->trailLen;
1033 *colorIdx = st->randomIndex;
1040 #if HAVE_GETTIMEOFDAY
1041 static void initTime(struct state *st)
1043 #if GETTIMEOFDAY_TWO_ARGS
1044 gettimeofday(&st->startupTime, NULL);
1046 gettimeofday(&st->startupTime);
1050 static double getTime(struct state *st)
1054 #if GETTIMEOFDAY_TWO_ARGS
1055 gettimeofday(&t, NULL);
1059 t.tv_sec -= st->startupTime.tv_sec;
1060 f = ((double)t.tv_sec) + t.tv_usec*1e-6;
1066 xrayswarm_init (Display *d, Window w)
1068 struct state *st = (struct state *) calloc (1, sizeof(*st));
1075 st->targetVel = 0.03;
1076 st->targetAcc = 0.02;
1080 st->minVelMultiplier = 0.5;
1086 st->colorScheme = /* -1 */ 2;
1087 st->changeProb = 0.08;
1089 if (!initGraphics(st)) abort();
1091 computeConstants(st);
1094 computeColorIndices(st);
1096 if (st->changeProb > 0) {
1097 for (i = random()%5+5; i >= 0; i--) {
1098 randomSmallChange(st);
1105 static unsigned long
1106 xrayswarm_draw (Display *d, Window w, void *closure)
1108 struct state *st = (struct state *) closure;
1109 unsigned long this_delay = st->delay;
1111 #if HAVE_GETTIMEOFDAY
1112 st->draw_start = getTime(st);
1115 if (st->delay > 0) {
1117 st->dt = DESIRED_DT/2;
1120 st->dt = DESIRED_DT;
1123 for (; st->draw_cnt > 0; st->draw_cnt--) {
1125 updateColorIndex(st, &st->draw_targetColorIndex, &st->draw_targetStartColor, &st->draw_targetNumColors,
1126 &st->draw_colorIndex, &st->draw_startColor, &st->draw_numColors);
1127 drawBugs(st, st->draw_targetColorIndex, st->draw_targetStartColor, st->draw_targetNumColors,
1128 st->draw_colorIndex, st->draw_startColor, st->draw_numColors);
1130 #if HAVE_GETTIMEOFDAY
1131 st->draw_end = getTime(st);
1134 if (st->draw_end > st->draw_start+0.5) {
1135 if (frand(1.0) < st->changeProb) randomSmallChange(st);
1136 if (frand(1.0) < st->changeProb*0.3) randomBigChange(st);
1137 st->draw_elapsed = st->draw_end-st->draw_start;
1139 st->draw_timePerFrame = st->draw_elapsed/st->draw_nframes - st->delay*1e-6;
1140 st->draw_fps = st->draw_nframes/st->draw_elapsed;
1142 printf("elapsed: %.3f\n", elapsed);
1143 printf("fps: %.1f secs per frame: %.3f delay: %f\n",
1144 fps, timePerFrame, delay);
1147 if (st->draw_fps > MAX_FPS) {
1148 st->delay = (1.0/MAX_FPS - (st->draw_timePerFrame + st->delay*1e-6))*1e6;
1149 } else if (st->dt*st->draw_fps < MIN_FPS*DESIRED_DT) {
1150 /* need to speed things up somehow */
1151 if (0 && st->nbugs > 10) {
1152 /*printf("reducing bugs to improve speed.\n");*/
1154 st->nbugs *= st->draw_fps/MIN_FPS;
1155 if (st->ntargets >= st->nbugs/2) mutateBug(st, 1);
1156 } else if (0 && st->dt < 0.3) {
1157 /*printf("increasing dt to improve speed.\n");*/
1158 st->dt *= MIN_FPS/st->draw_fps;
1159 computeConstants(st);
1160 } else if (st->trailLen > 10) {
1161 /*printf("reducing trail length to improve speed.\n");*/
1163 st->trailLen = st->trailLen * (st->draw_fps/MIN_FPS);
1164 if (st->trailLen < 10) st->trailLen = 10;
1165 computeColorIndices(st);
1170 st->draw_start = getTime(st);
1171 st->draw_nframes = 0;
1174 if (frand(1) < st->changeProb*2/100.0) randomSmallChange(st);
1175 if (frand(1) < st->changeProb*0.3/100.0) randomBigChange(st);
1178 if (st->delay <= 10000) {
1179 st->draw_delayAccum += st->delay;
1180 if (st->draw_delayAccum > 10000) {
1181 this_delay = st->draw_delayAccum;
1182 st->draw_delayAccum = 0;
1183 st->draw_sleepCount = 0;
1185 if (++st->draw_sleepCount > 2) {
1186 st->draw_sleepCount = 0;
1195 xrayswarm_reshape (Display *dpy, Window window, void *closure,
1196 unsigned int w, unsigned int h)
1201 xrayswarm_event (Display *dpy, Window window, void *closure, XEvent *event)
1207 xrayswarm_free (Display *dpy, Window window, void *closure)
1209 struct state *st = (struct state *) closure;
1213 XSCREENSAVER_MODULE ("XRaySwarm", xrayswarm)