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 [] ={
69 static XrmOptionDescRec xrayswarm_options [] = {
70 {"-delay",".delay",XrmoptionSepArg,0},
75 /**********************************************************************
77 * bug structs & variables
79 **********************************************************************/
80 #define MAX_TRAIL_LEN 60
82 #define MAX_TARGETS 10
83 #define sq(x) ((x)*(x))
87 #define DESIRED_DT 0.2
89 typedef struct _sbug {
91 int hist[MAX_TRAIL_LEN][2];
93 struct _sbug *closest;
98 #define COLOR_TRAILS 2
99 #define RANDOM_TRAILS 3
100 #define RANDOM_SCHIZO 4
101 #define COLOR_SCHIZO 5
102 #define NUM_SCHEMES 6 /* too many schizos; don't use last 2 */
110 unsigned char colors[768];
125 float minVelMultiplier;
139 bug targets[MAX_TARGETS];
145 int grayIndex[MAX_TRAIL_LEN];
146 int redIndex[MAX_TRAIL_LEN];
147 int blueIndex[MAX_TRAIL_LEN];
148 int graySIndex[MAX_TRAIL_LEN];
149 int redSIndex[MAX_TRAIL_LEN];
150 int blueSIndex[MAX_TRAIL_LEN];
151 int randomIndex[MAX_TRAIL_LEN];
160 float draw_timePerFrame, draw_elapsed;
161 int *draw_targetColorIndex, *draw_colorIndex;
162 int draw_targetStartColor, draw_targetNumColors;
163 int draw_startColor, draw_numColors;
164 double draw_start, draw_end;
170 struct timeval startupTime;
190 static const bugParams good1 = {
192 0.03, /* targetVel */
193 0.02, /* targetAcc */
201 0.15 /* changeProb */
204 static const bugParams *goodParams[] = {
208 static int numParamSets = 1;
211 static void initCMap(struct state *st)
218 /* color 0 is black */
224 st->colors[n++] = 255;
228 /* color 2 is green */
229 st->colors[n++] = 255;
233 /* color 3 is blue */
234 st->colors[n++] = 255;
238 /* start greyscale colors at 4; 16 levels */
239 for (i = 0; i < 16; i++) {
241 if (temp > 255) temp = 255;
242 st->colors[n++] = 255 - temp;
243 st->colors[n++] = 255 - temp;
244 st->colors[n++] = 255 - temp;
247 /* start red fade at 20; 16 levels */
248 for (i = 0; i < 16; i++) {
250 if (temp > 255) temp = 255;
251 st->colors[n++] = 255 - temp;
252 st->colors[n++] = 255 - pow(i/16.0+0.001, 0.3)*255;
253 st->colors[n++] = 65 - temp/4;
256 /* start blue fade at 36; 16 levels */
257 for (i = 0; i < 16; i++) {
259 if (temp > 255) temp = 255;
260 st->colors[n++] = 32 - temp/8;
261 st->colors[n++] = 180 - pow(i/16.0+0.001, 0.3)*180;
262 st->colors[n++] = 255 - temp;
265 /* random colors start at 52 */
266 st->numRandomColors = MAX_TRAIL_LEN;
268 st->colors[n] = random()&255; n++;
269 st->colors[n] = random()&255; n++;
270 st->colors[n] = st->colors[n-2]/2 + st->colors[n-3]/2; n++;
272 for (i = 0; i < st->numRandomColors; i++) {
273 st->colors[n] = (st->colors[n-3] + (random()&31) - 16)&255; n++;
274 st->colors[n] = (st->colors[n-3] + (random()&31) - 16)&255; n++;
275 st->colors[n] = st->colors[n-2]/(float)(i+2) + st->colors[n-3]/(float)(i+2); n++;
278 st->numColors = n/3 + 1;
281 static int initGraphics(struct state *st)
284 XWindowAttributes xgwa;
285 /* XSetWindowAttributes xswa;*/
292 XGetWindowAttributes(st->dpy,st->win,&xgwa);
294 /* xswa.backing_store=Always;
295 XChangeWindowAttributes(st->dpy,st->win,CWBackingStore,&xswa);*/
296 xgcv.function=GXcopy;
298 st->delay = get_integer_resource(st->dpy, "delay","Integer");
300 xgcv.foreground=get_pixel_resource (st->dpy, cmap, "background", "Background");
301 st->fgc[0]=XCreateGC(st->dpy, st->win, GCForeground|GCFunction,&xgcv);
303 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[0], False);
308 xgcv.foreground=get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
309 st->fgc[1]=XCreateGC(st->dpy,st->win,GCForeground|GCFunction,&xgcv);
311 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[1], False);
313 for (i=0;i<st->numColors;i+=2) st->fgc[i]=st->fgc[0];
314 for (i=1;i<st->numColors;i+=2) st->fgc[i]=st->fgc[1];
316 for (i = 0; i < st->numColors; i++) {
317 color.red=st->colors[n++]<<8;
318 color.green=st->colors[n++]<<8;
319 color.blue=st->colors[n++]<<8;
320 color.flags=DoRed|DoGreen|DoBlue;
321 XAllocColor(st->dpy,cmap,&color);
322 xgcv.foreground=color.pixel;
323 st->fgc[i] = XCreateGC(st->dpy, st->win, GCForeground | GCFunction,&xgcv);
325 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[i], False);
329 st->cgc = XCreateGC(st->dpy,st->win,GCForeground|GCFunction,&xgcv);
330 XSetGraphicsExposures(st->dpy,st->cgc,False);
332 jwxyz_XSetAntiAliasing (st->dpy, st->cgc, False);
335 st->xsize = xgwa.width;
336 st->ysize = xgwa.height;
337 st->xc = st->xsize >> 1;
338 st->yc = st->ysize >> 1;
341 st->maxy = st->ysize/(float)st->xsize;
343 if (st->colorScheme < 0) st->colorScheme = random()%NUM_SCHEMES;
348 static void initBugs(struct state *st)
353 st->head = st->tail = 0;
355 memset((char *)st->bugs, 0,MAX_BUGS*sizeof(bug));
356 memset((char *)st->targets, 0, MAX_TARGETS*sizeof(bug));
358 if (st->ntargets < 0) st->ntargets = (0.25+frand(0.75)*frand(1))*MAX_TARGETS;
359 if (st->ntargets < 1) st->ntargets = 1;
361 if (st->nbugs < 0) st->nbugs = (0.25+frand(0.75)*frand(1))*MAX_BUGS;
362 if (st->nbugs <= st->ntargets) st->nbugs = st->ntargets+1;
364 if (st->trailLen < 0) {
365 st->trailLen = (1.0 - frand(0.6)*frand(1))*MAX_TRAIL_LEN;
368 if (st->nbugs > MAX_BUGS) st->nbugs = MAX_BUGS;
369 if (st->ntargets > MAX_TARGETS) st->ntargets = MAX_TARGETS;
370 if (st->trailLen > MAX_TRAIL_LEN) st->trailLen = MAX_TRAIL_LEN;
373 for (i = 0; i < st->nbugs; i++, b++) {
374 b->pos[0] = frand(st->maxx);
375 b->pos[1] = frand(st->maxy);
376 b->vel[0] = frand(st->maxVel/2);
377 b->vel[1] = frand(st->maxVel/2);
379 b->hist[st->head][0] = b->pos[0]*st->xsize;
380 b->hist[st->head][1] = b->pos[1]*st->xsize;
381 b->closest = &st->targets[random()%st->ntargets];
385 for (i = 0; i < st->ntargets; i++, b++) {
386 b->pos[0] = frand(st->maxx);
387 b->pos[1] = frand(st->maxy);
389 b->vel[0] = frand(st->targetVel/2);
390 b->vel[1] = frand(st->targetVel/2);
392 b->hist[st->head][0] = b->pos[0]*st->xsize;
393 b->hist[st->head][1] = b->pos[1]*st->xsize;
397 static void pickNewTargets(struct state *st)
403 for (i = 0; i < st->nbugs; i++, b++) {
404 b->closest = &st->targets[random()%st->ntargets];
409 static void addBugs(int numToAdd)
414 if (numToAdd + st->nbugs > MAX_BUGS) numToAdd = MAX_BUGS-st->nbugs;
415 else if (numToAdd < 0) numToAdd = 0;
417 for (i = 0; i < numToAdd; i++) {
418 b = &st->bugs[random()%st->nbugs];
419 memcpy((char *)&st->bugs[st->nbugs+i], (char *)b, sizeof(bug));
420 b->closest = &st->targets[random()%st->ntargets];
423 st->nbugs += numToAdd;
426 static void addTargets(int numToAdd)
431 if (numToAdd + st->ntargets > MAX_TARGETS) numToAdd = MAX_TARGETS-st->ntargets;
432 else if (numToAdd < 0) numToAdd = 0;
434 for (i = 0; i < numToAdd; i++) {
435 b = &st->targets[random()%st->ntargets];
436 memcpy((char *)&st->targets[st->ntargets+i], (char *)b, sizeof(bug));
437 b->closest = &st->targets[random()%st->ntargets];
440 st->ntargets += numToAdd;
444 static void computeConstants(struct state *st)
446 st->halfDtSq = st->dt*st->dt*0.5;
447 st->dtInv = 1.0/st->dt;
448 st->targetVelSq = st->targetVel*st->targetVel;
449 st->maxVelSq = st->maxVel*st->maxVel;
450 st->minVel = st->maxVel*st->minVelMultiplier;
451 st->minVelSq = st->minVel*st->minVel;
454 static void computeColorIndices(struct state *st)
459 /* note: colors are used in *reverse* order! */
462 for (i = 0; i < st->trailLen; i++) {
463 st->grayIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5;
464 if (st->grayIndex[st->trailLen-1-i] > 19) st->grayIndex[st->trailLen-1-i] = 19;
468 for (i = 0; i < st->trailLen; i++) {
469 st->redIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5;
470 if (st->redIndex[st->trailLen-1-i] > 35) st->redIndex[st->trailLen-1-i] = 35;
474 for (i = 0; i < st->trailLen; i++) {
475 st->blueIndex[st->trailLen-1-i] = 36 + i*16.0/st->trailLen + 0.5;
476 if (st->blueIndex[st->trailLen-1-i] > 51) st->blueIndex[st->trailLen-1-i] = 51;
479 /* gray schizo - same as gray*/
480 for (i = 0; i < st->trailLen; i++) {
481 st->graySIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5;
482 if (st->graySIndex[st->trailLen-1-i] > 19) st->graySIndex[st->trailLen-1-i] = 19;
485 /*schizoLength = st->trailLen/4;
486 if (schizoLength < 3) schizoLength = 3;*/
488 for (i = 0; i < st->trailLen; i++) {
489 /* redSIndex[trailLen-1-i] =
490 20 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;*/
491 st->redSIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5;
492 if (st->redSIndex[st->trailLen-1-i] > 35) st->redSIndex[st->trailLen-1-i] = 35;
495 schizoLength = st->trailLen/2;
496 if (schizoLength < 3) schizoLength = 3;
497 /* blue schizo is next */
498 for (i = 0; i < st->trailLen; i++) {
499 st->blueSIndex[st->trailLen-1-i] =
500 36 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;
501 if (st->blueSIndex[st->trailLen-1-i] > 51) st->blueSIndex[st->trailLen-1-i] = 51;
505 for (i = 0; i < st->trailLen; i++) {
506 st->randomIndex[i] = 52 + random()%(st->numRandomColors);
511 static void setParams(bugParams *p)
514 st->targetVel = p->targetVel;
515 st->targetAcc = p->targetAcc;
516 st->maxVel = p->maxVel;
517 st->maxAcc = p->maxAcc;
518 st->noise = p->noise;
520 st->nbugs = p->nbugs;
521 st->ntargets = p->ntargets;
522 st->trailLen = p->trailLen;
523 st->colorScheme = p->colorScheme;
524 st->changeProb = p->changeProb;
526 computeColorIndices();
530 static void drawBugs(struct state *st, int *tColorIdx, int tci0, int tnc,
531 int *colorIdx, int ci0, int nc)
537 if (((st->head+1)%st->trailLen) == st->tail) {
538 /* first, erase last segment of bugs if necessary */
539 temp = (st->tail+1) % st->trailLen;
542 for (i = 0; i < st->nbugs; i++, b++) {
543 XDrawLine(st->dpy, st->win, st->fgc[0],
544 b->hist[st->tail][0], b->hist[st->tail][1],
545 b->hist[temp][0], b->hist[temp][1]);
549 for (i = 0; i < st->ntargets; i++, b++) {
550 XDrawLine(st->dpy, st->win, st->fgc[0],
551 b->hist[st->tail][0], b->hist[st->tail][1],
552 b->hist[temp][0], b->hist[temp][1]);
554 st->tail = (st->tail+1)%st->trailLen;
557 for (j = st->tail; j != st->head; j = temp) {
558 temp = (j+1)%st->trailLen;
561 for (i = 0; i < st->nbugs; i++, b++) {
562 XDrawLine(st->dpy, st->win, st->fgc[colorIdx[ci0]],
563 b->hist[j][0], b->hist[j][1],
564 b->hist[temp][0], b->hist[temp][1]);
568 for (i = 0; i < st->ntargets; i++, b++) {
569 XDrawLine(st->dpy, st->win, st->fgc[tColorIdx[tci0]],
570 b->hist[j][0], b->hist[j][1],
571 b->hist[temp][0], b->hist[temp][1]);
578 static void clearBugs(struct state *st)
584 st->tail = st->tail-1;
585 if (st->tail < 0) st->tail = st->trailLen-1;
587 if (((st->head+1)%st->trailLen) == st->tail) {
588 /* first, erase last segment of bugs if necessary */
589 temp = (st->tail+1) % st->trailLen;
592 for (i = 0; i < st->nbugs; i++, b++) {
593 XDrawLine(st->dpy, st->win, st->fgc[0],
594 b->hist[st->tail][0], b->hist[st->tail][1],
595 b->hist[temp][0], b->hist[temp][1]);
599 for (i = 0; i < st->ntargets; i++, b++) {
600 XDrawLine(st->dpy, st->win, st->fgc[0],
601 b->hist[st->tail][0], b->hist[st->tail][1],
602 b->hist[temp][0], b->hist[temp][1]);
604 st->tail = (st->tail+1)%st->trailLen;
607 for (j = st->tail; j != st->head; j = temp) {
608 temp = (j+1)%st->trailLen;
611 for (i = 0; i < st->nbugs; i++, b++) {
612 XDrawLine(st->dpy, st->win, st->fgc[0],
613 b->hist[j][0], b->hist[j][1],
614 b->hist[temp][0], b->hist[temp][1]);
618 for (i = 0; i < st->ntargets; i++, b++) {
619 XDrawLine(st->dpy, st->win, st->fgc[0],
620 b->hist[j][0], b->hist[j][1],
621 b->hist[temp][0], b->hist[temp][1]);
626 static void updateState(struct state *st)
630 register float ax, ay, temp;
635 st->head = (st->head+1)%st->trailLen;
637 for (j = 0; j < 5; j++) {
638 /* update closets bug for the bug indicated by checkIndex */
639 st->checkIndex = (st->checkIndex+1)%st->nbugs;
640 b = &st->bugs[st->checkIndex];
642 ax = b->closest->pos[0] - b->pos[0];
643 ay = b->closest->pos[1] - b->pos[1];
644 temp = ax*ax + ay*ay;
645 for (i = 0; i < st->ntargets; i++) {
646 b2 = &st->targets[i];
647 if (b2 == b->closest) continue;
648 ax = b2->pos[0] - b->pos[0];
649 ay = b2->pos[1] - b->pos[1];
650 theta = ax*ax + ay*ay;
651 if (theta < temp*2) {
658 /* update target state */
661 for (i = 0; i < st->ntargets; i++, b++) {
663 ax = st->targetAcc*cos(theta);
664 ay = st->targetAcc*sin(theta);
666 b->vel[0] += ax*st->dt;
667 b->vel[1] += ay*st->dt;
670 temp = sq(b->vel[0]) + sq(b->vel[1]);
671 if (temp > st->targetVelSq) {
672 temp = st->targetVel/sqrt(temp);
673 /* save old vel for acc computation */
677 /* compute new velocity */
681 /* update acceleration */
682 ax = (b->vel[0]-ax)*st->dtInv;
683 ay = (b->vel[1]-ay)*st->dtInv;
686 /* update position */
687 b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq;
688 b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq;
690 /* check limits on targets */
693 b->pos[0] = -b->pos[0];
694 b->vel[0] = -b->vel[0];
695 } else if (b->pos[0] >= st->maxx) {
697 b->pos[0] = 2*st->maxx-b->pos[0];
698 b->vel[0] = -b->vel[0];
702 b->pos[1] = -b->pos[1];
703 b->vel[1] = -b->vel[1];
704 } else if (b->pos[1] >= st->maxy) {
706 b->pos[1] = 2*st->maxy-b->pos[1];
707 b->vel[1] = -b->vel[1];
710 b->hist[st->head][0] = b->pos[0]*st->xsize;
711 b->hist[st->head][1] = b->pos[1]*st->xsize;
714 /* update bug state */
716 for (i = 0; i < st->nbugs; i++, b++) {
717 theta = atan2(b->closest->pos[1] - b->pos[1] + frand(st->noise),
718 b->closest->pos[0] - b->pos[0] + frand(st->noise));
719 ax = st->maxAcc*cos(theta);
720 ay = st->maxAcc*sin(theta);
722 b->vel[0] += ax*st->dt;
723 b->vel[1] += ay*st->dt;
726 temp = sq(b->vel[0]) + sq(b->vel[1]);
727 if (temp > st->maxVelSq) {
728 temp = st->maxVel/sqrt(temp);
730 /* save old vel for acc computation */
734 /* compute new velocity */
738 /* update acceleration */
739 ax = (b->vel[0]-ax)*st->dtInv;
740 ay = (b->vel[1]-ay)*st->dtInv;
741 } else if (temp < st->minVelSq) {
742 temp = st->minVel/sqrt(temp);
744 /* save old vel for acc computation */
748 /* compute new velocity */
752 /* update acceleration */
753 ax = (b->vel[0]-ax)*st->dtInv;
754 ay = (b->vel[1]-ay)*st->dtInv;
757 /* update position */
758 b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq;
759 b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq;
761 /* check limits on targets */
764 b->pos[0] = -b->pos[0];
765 b->vel[0] = -b->vel[0];
766 } else if (b->pos[0] >= st->maxx) {
768 b->pos[0] = 2*st->maxx-b->pos[0];
769 b->vel[0] = -b->vel[0];
773 b->pos[1] = -b->pos[1];
774 b->vel[1] = -b->vel[1];
775 } else if (b->pos[1] >= st->maxy) {
777 b->pos[1] = 2*st->maxy-b->pos[1];
778 b->vel[1] = -b->vel[1];
781 b->hist[st->head][0] = b->pos[0]*st->xsize;
782 b->hist[st->head][1] = b->pos[1]*st->xsize;
786 static void mutateBug(struct state *st, int which)
791 /* turn bug into target */
792 if (st->ntargets < MAX_TARGETS-1 && st->nbugs > 1) {
793 i = random() % st->nbugs;
794 memcpy((char *)&st->targets[st->ntargets], (char *)&st->bugs[i], sizeof(bug));
795 memcpy((char *)&st->bugs[i], (char *)&st->bugs[st->nbugs-1], sizeof(bug));
796 st->targets[st->ntargets].pos[0] = frand(st->maxx);
797 st->targets[st->ntargets].pos[1] = frand(st->maxy);
801 for (i = 0; i < st->nbugs; i += st->ntargets) {
802 st->bugs[i].closest = &st->targets[st->ntargets-1];
806 /* turn target into bug */
807 if (st->ntargets > 1 && st->nbugs < MAX_BUGS-1) {
809 i = random() % st->ntargets;
811 /* copy state into a new bug */
812 memcpy((char *)&st->bugs[st->nbugs], (char *)&st->targets[i], sizeof(bug));
815 /* pick a target for the new bug */
816 st->bugs[st->nbugs].closest = &st->targets[random()%st->ntargets];
818 for (j = 0; j < st->nbugs; j++) {
819 if (st->bugs[j].closest == &st->targets[st->ntargets]) {
820 st->bugs[j].closest = &st->targets[i];
821 } else if (st->bugs[j].closest == &st->targets[i]) {
822 st->bugs[j].closest = &st->targets[random()%st->ntargets];
827 /* copy the last ntarget into the one we just deleted */
828 memcpy(&st->targets[i], (char *)&st->targets[st->ntargets], sizeof(bug));
833 static void mutateParam(float *param)
835 *param *= 0.75+frand(0.5);
838 static void randomSmallChange(struct state *st)
842 whichCase = random()%11;
844 if (++st->rsc_callDepth > 10) {
852 mutateParam(&st->maxAcc);
856 /* target acceleration */
857 mutateParam(&st->targetAcc);
862 mutateParam(&st->maxVel);
866 /* target velocity */
867 mutateParam(&st->targetVel);
872 mutateParam(&st->noise);
876 /* minVelMultiplier */
877 mutateParam(&st->minVelMultiplier);
883 if (st->ntargets < 2) break;
889 if (st->nbugs < 2) break;
891 if (st->nbugs < 2) break;
897 st->colorScheme = random()%NUM_SCHEMES;
898 if (st->colorScheme == RANDOM_SCHIZO || st->colorScheme == COLOR_SCHIZO) {
899 /* don't use these quite as much */
900 st->colorScheme = random()%NUM_SCHEMES;
905 randomSmallChange(st);
906 randomSmallChange(st);
907 randomSmallChange(st);
908 randomSmallChange(st);
911 if (st->minVelMultiplier < 0.3) st->minVelMultiplier = 0.3;
912 else if (st->minVelMultiplier > 0.9) st->minVelMultiplier = 0.9;
913 if (st->noise < 0.01) st->noise = 0.01;
914 if (st->maxVel < 0.02) st->maxVel = 0.02;
915 if (st->targetVel < 0.02) st->targetVel = 0.02;
916 if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7;
917 if (st->maxAcc > st->maxVel*0.7) st->maxAcc = st->maxVel*0.7;
918 if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7;
919 if (st->maxAcc < 0.01) st->maxAcc = 0.01;
920 if (st->targetAcc < 0.005) st->targetAcc = 0.005;
922 computeConstants(st);
926 static void randomBigChange(struct state *st)
931 whichCase = random()%4;
933 if (++st->rbc_callDepth > 3) {
941 temp = (random()%(MAX_TRAIL_LEN-25)) + 25;
944 computeColorIndices(st);
950 randomSmallChange(st);
951 randomSmallChange(st);
952 randomSmallChange(st);
953 randomSmallChange(st);
954 randomSmallChange(st);
955 randomSmallChange(st);
956 randomSmallChange(st);
957 randomSmallChange(st);
970 temp = random()%st->ntargets;
971 st->targets[temp].pos[0] += frand(st->maxx/4)-st->maxx/8;
972 st->targets[temp].pos[1] += frand(st->maxy/4)-st->maxy/8;
973 /* updateState() will fix bounds */
980 static void updateColorIndex(struct state *st,
981 int **tColorIdx, int *tci0, int *tnc,
982 int **colorIdx, int *ci0, int *nc)
984 switch(st->colorScheme) {
986 *tColorIdx = st->redIndex;
989 *colorIdx = st->blueIndex;
995 *tColorIdx = st->graySIndex;
998 *colorIdx = st->graySIndex;
1004 *tColorIdx = st->redSIndex;
1006 *tnc = st->trailLen;
1007 *colorIdx = st->blueSIndex;
1013 *tColorIdx = st->grayIndex;
1015 *tnc = st->trailLen;
1016 *colorIdx = st->grayIndex;
1022 *tColorIdx = st->redIndex;
1024 *tnc = st->trailLen;
1025 *colorIdx = st->randomIndex;
1031 *tColorIdx = st->redIndex;
1033 *tnc = st->trailLen;
1034 *colorIdx = st->randomIndex;
1041 #if HAVE_GETTIMEOFDAY
1042 static void initTime(struct state *st)
1044 #if GETTIMEOFDAY_TWO_ARGS
1045 gettimeofday(&st->startupTime, NULL);
1047 gettimeofday(&st->startupTime);
1051 static double getTime(struct state *st)
1055 #if GETTIMEOFDAY_TWO_ARGS
1056 gettimeofday(&t, NULL);
1060 t.tv_sec -= st->startupTime.tv_sec;
1061 f = ((double)t.tv_sec) + t.tv_usec*1e-6;
1067 xrayswarm_init (Display *d, Window w)
1069 struct state *st = (struct state *) calloc (1, sizeof(*st));
1076 st->targetVel = 0.03;
1077 st->targetAcc = 0.02;
1081 st->minVelMultiplier = 0.5;
1087 st->colorScheme = /* -1 */ 2;
1088 st->changeProb = 0.08;
1090 if (!initGraphics(st)) abort();
1092 computeConstants(st);
1095 computeColorIndices(st);
1097 if (st->changeProb > 0) {
1098 for (i = random()%5+5; i >= 0; i--) {
1099 randomSmallChange(st);
1106 static unsigned long
1107 xrayswarm_draw (Display *d, Window w, void *closure)
1109 struct state *st = (struct state *) closure;
1110 unsigned long this_delay = st->delay;
1112 #if HAVE_GETTIMEOFDAY
1113 st->draw_start = getTime(st);
1116 if (st->delay > 0) {
1118 st->dt = DESIRED_DT/2;
1121 st->dt = DESIRED_DT;
1124 for (; st->draw_cnt > 0; st->draw_cnt--) {
1126 updateColorIndex(st, &st->draw_targetColorIndex, &st->draw_targetStartColor, &st->draw_targetNumColors,
1127 &st->draw_colorIndex, &st->draw_startColor, &st->draw_numColors);
1128 drawBugs(st, st->draw_targetColorIndex, st->draw_targetStartColor, st->draw_targetNumColors,
1129 st->draw_colorIndex, st->draw_startColor, st->draw_numColors);
1131 #if HAVE_GETTIMEOFDAY
1132 st->draw_end = getTime(st);
1135 if (st->draw_end > st->draw_start+0.5) {
1136 if (frand(1.0) < st->changeProb) randomSmallChange(st);
1137 if (frand(1.0) < st->changeProb*0.3) randomBigChange(st);
1138 st->draw_elapsed = st->draw_end-st->draw_start;
1140 st->draw_timePerFrame = st->draw_elapsed/st->draw_nframes - st->delay*1e-6;
1141 st->draw_fps = st->draw_nframes/st->draw_elapsed;
1143 printf("elapsed: %.3f\n", elapsed);
1144 printf("fps: %.1f secs per frame: %.3f delay: %f\n",
1145 fps, timePerFrame, delay);
1148 if (st->draw_fps > MAX_FPS) {
1149 st->delay = (1.0/MAX_FPS - (st->draw_timePerFrame + st->delay*1e-6))*1e6;
1150 } else if (st->dt*st->draw_fps < MIN_FPS*DESIRED_DT) {
1151 /* need to speed things up somehow */
1152 if (0 && st->nbugs > 10) {
1153 /*printf("reducing bugs to improve speed.\n");*/
1155 st->nbugs *= st->draw_fps/MIN_FPS;
1156 if (st->ntargets >= st->nbugs/2) mutateBug(st, 1);
1157 } else if (0 && st->dt < 0.3) {
1158 /*printf("increasing dt to improve speed.\n");*/
1159 st->dt *= MIN_FPS/st->draw_fps;
1160 computeConstants(st);
1161 } else if (st->trailLen > 10) {
1162 /*printf("reducing trail length to improve speed.\n");*/
1164 st->trailLen = st->trailLen * (st->draw_fps/MIN_FPS);
1165 if (st->trailLen < 10) st->trailLen = 10;
1166 computeColorIndices(st);
1171 st->draw_start = getTime(st);
1172 st->draw_nframes = 0;
1175 if (frand(1) < st->changeProb*2/100.0) randomSmallChange(st);
1176 if (frand(1) < st->changeProb*0.3/100.0) randomBigChange(st);
1179 if (st->delay <= 10000) {
1180 st->draw_delayAccum += st->delay;
1181 if (st->draw_delayAccum > 10000) {
1182 this_delay = st->draw_delayAccum;
1183 st->draw_delayAccum = 0;
1184 st->draw_sleepCount = 0;
1186 if (++st->draw_sleepCount > 2) {
1187 st->draw_sleepCount = 0;
1196 xrayswarm_reshape (Display *dpy, Window window, void *closure,
1197 unsigned int w, unsigned int h)
1199 struct state *st = (struct state *) closure;
1202 st->xc = st->xsize >> 1;
1203 st->yc = st->ysize >> 1;
1204 st->maxy = st->ysize/(float)st->xsize;
1208 xrayswarm_event (Display *dpy, Window window, void *closure, XEvent *event)
1214 xrayswarm_free (Display *dpy, Window window, void *closure)
1216 struct state *st = (struct state *) closure;
1220 XSCREENSAVER_MODULE ("XRaySwarm", xrayswarm)