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.
43 #include "screenhack.h"
49 # define HAVE_GETTIMEOFDAY 1
52 /**********************************************************************
56 **********************************************************************/
58 static const char *xrayswarm_defaults [] ={
59 /* ".lowrez: true", */
64 "*ignoreRotation: True",
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");
301 if (xgwa.width > 2560 || xgwa.height > 2560)
302 xgcv.line_width = 3; /* Retina displays */
304 xgcv.foreground=get_pixel_resource (st->dpy, cmap, "background", "Background");
305 st->fgc[0]=XCreateGC(st->dpy, st->win, GCForeground|GCFunction|GCLineWidth,
308 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[0], False);
313 xgcv.foreground=get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
314 st->fgc[1]=XCreateGC(st->dpy,st->win,GCForeground|GCFunction|GCLineWidth,
317 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[1], False);
319 for (i=0;i<st->numColors;i+=2) st->fgc[i]=st->fgc[0];
320 for (i=1;i<st->numColors;i+=2) st->fgc[i]=st->fgc[1];
322 for (i = 0; i < st->numColors; i++) {
323 color.red=st->colors[n++]<<8;
324 color.green=st->colors[n++]<<8;
325 color.blue=st->colors[n++]<<8;
326 color.flags=DoRed|DoGreen|DoBlue;
327 XAllocColor(st->dpy,cmap,&color);
328 xgcv.foreground=color.pixel;
329 if (st->fgc[i]) XFreeGC (st->dpy, st->fgc[i]);
330 st->fgc[i] = XCreateGC(st->dpy, st->win,
331 GCForeground|GCFunction|GCLineWidth, &xgcv);
333 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[i], False);
338 st->cgc = XCreateGC(st->dpy,st->win,GCForeground|GCFunction|GCLineWidth,
340 XSetGraphicsExposures(st->dpy,st->cgc,False);
342 jwxyz_XSetAntiAliasing (st->dpy, st->cgc, False);
345 st->xsize = xgwa.width;
346 st->ysize = xgwa.height;
347 st->xc = st->xsize >> 1;
348 st->yc = st->ysize >> 1;
351 st->maxy = st->ysize/(float)st->xsize;
353 if (st->colorScheme < 0) st->colorScheme = random()%NUM_SCHEMES;
358 static void initBugs(struct state *st)
363 st->head = st->tail = 0;
365 memset((char *)st->bugs, 0,MAX_BUGS*sizeof(bug));
366 memset((char *)st->targets, 0, MAX_TARGETS*sizeof(bug));
368 if (st->ntargets < 0) st->ntargets = (0.25+frand(0.75)*frand(1))*MAX_TARGETS;
369 if (st->ntargets < 1) st->ntargets = 1;
371 if (st->nbugs < 0) st->nbugs = (0.25+frand(0.75)*frand(1))*MAX_BUGS;
372 if (st->nbugs <= st->ntargets) st->nbugs = st->ntargets+1;
374 if (st->trailLen < 0) {
375 st->trailLen = (1.0 - frand(0.6)*frand(1))*MAX_TRAIL_LEN;
378 if (st->nbugs > MAX_BUGS) st->nbugs = MAX_BUGS;
379 if (st->ntargets > MAX_TARGETS) st->ntargets = MAX_TARGETS;
380 if (st->trailLen > MAX_TRAIL_LEN) st->trailLen = MAX_TRAIL_LEN;
383 for (i = 0; i < st->nbugs; i++, b++) {
384 b->pos[0] = frand(st->maxx);
385 b->pos[1] = frand(st->maxy);
386 b->vel[0] = frand(st->maxVel/2);
387 b->vel[1] = frand(st->maxVel/2);
389 b->hist[st->head][0] = b->pos[0]*st->xsize;
390 b->hist[st->head][1] = b->pos[1]*st->xsize;
391 b->closest = &st->targets[random()%st->ntargets];
395 for (i = 0; i < st->ntargets; i++, b++) {
396 b->pos[0] = frand(st->maxx);
397 b->pos[1] = frand(st->maxy);
399 b->vel[0] = frand(st->targetVel/2);
400 b->vel[1] = frand(st->targetVel/2);
402 b->hist[st->head][0] = b->pos[0]*st->xsize;
403 b->hist[st->head][1] = b->pos[1]*st->xsize;
407 static void pickNewTargets(struct state *st)
413 for (i = 0; i < st->nbugs; i++, b++) {
414 b->closest = &st->targets[random()%st->ntargets];
419 static void addBugs(int numToAdd)
424 if (numToAdd + st->nbugs > MAX_BUGS) numToAdd = MAX_BUGS-st->nbugs;
425 else if (numToAdd < 0) numToAdd = 0;
427 for (i = 0; i < numToAdd; i++) {
428 b = &st->bugs[random()%st->nbugs];
429 memcpy((char *)&st->bugs[st->nbugs+i], (char *)b, sizeof(bug));
430 b->closest = &st->targets[random()%st->ntargets];
433 st->nbugs += numToAdd;
436 static void addTargets(int numToAdd)
441 if (numToAdd + st->ntargets > MAX_TARGETS) numToAdd = MAX_TARGETS-st->ntargets;
442 else if (numToAdd < 0) numToAdd = 0;
444 for (i = 0; i < numToAdd; i++) {
445 b = &st->targets[random()%st->ntargets];
446 memcpy((char *)&st->targets[st->ntargets+i], (char *)b, sizeof(bug));
447 b->closest = &st->targets[random()%st->ntargets];
450 st->ntargets += numToAdd;
454 static void computeConstants(struct state *st)
456 st->halfDtSq = st->dt*st->dt*0.5;
457 st->dtInv = 1.0/st->dt;
458 st->targetVelSq = st->targetVel*st->targetVel;
459 st->maxVelSq = st->maxVel*st->maxVel;
460 st->minVel = st->maxVel*st->minVelMultiplier;
461 st->minVelSq = st->minVel*st->minVel;
464 static void computeColorIndices(struct state *st)
469 /* note: colors are used in *reverse* order! */
472 for (i = 0; i < st->trailLen; i++) {
473 st->grayIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5;
474 if (st->grayIndex[st->trailLen-1-i] > 19) st->grayIndex[st->trailLen-1-i] = 19;
478 for (i = 0; i < st->trailLen; i++) {
479 st->redIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5;
480 if (st->redIndex[st->trailLen-1-i] > 35) st->redIndex[st->trailLen-1-i] = 35;
484 for (i = 0; i < st->trailLen; i++) {
485 st->blueIndex[st->trailLen-1-i] = 36 + i*16.0/st->trailLen + 0.5;
486 if (st->blueIndex[st->trailLen-1-i] > 51) st->blueIndex[st->trailLen-1-i] = 51;
489 /* gray schizo - same as gray*/
490 for (i = 0; i < st->trailLen; i++) {
491 st->graySIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5;
492 if (st->graySIndex[st->trailLen-1-i] > 19) st->graySIndex[st->trailLen-1-i] = 19;
495 /*schizoLength = st->trailLen/4;
496 if (schizoLength < 3) schizoLength = 3;*/
498 for (i = 0; i < st->trailLen; i++) {
499 /* redSIndex[trailLen-1-i] =
500 20 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;*/
501 st->redSIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5;
502 if (st->redSIndex[st->trailLen-1-i] > 35) st->redSIndex[st->trailLen-1-i] = 35;
505 schizoLength = st->trailLen/2;
506 if (schizoLength < 3) schizoLength = 3;
507 /* blue schizo is next */
508 for (i = 0; i < st->trailLen; i++) {
509 st->blueSIndex[st->trailLen-1-i] =
510 36 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;
511 if (st->blueSIndex[st->trailLen-1-i] > 51) st->blueSIndex[st->trailLen-1-i] = 51;
515 for (i = 0; i < st->trailLen; i++) {
516 st->randomIndex[i] = 52 + random()%(st->numRandomColors);
521 static void setParams(bugParams *p)
524 st->targetVel = p->targetVel;
525 st->targetAcc = p->targetAcc;
526 st->maxVel = p->maxVel;
527 st->maxAcc = p->maxAcc;
528 st->noise = p->noise;
530 st->nbugs = p->nbugs;
531 st->ntargets = p->ntargets;
532 st->trailLen = p->trailLen;
533 st->colorScheme = p->colorScheme;
534 st->changeProb = p->changeProb;
536 computeColorIndices();
540 static void drawBugs(struct state *st, int *tColorIdx, int tci0, int tnc,
541 int *colorIdx, int ci0, int nc)
547 if (((st->head+1)%st->trailLen) == st->tail) {
548 /* first, erase last segment of bugs if necessary */
549 temp = (st->tail+1) % st->trailLen;
552 for (i = 0; i < st->nbugs; 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]);
559 for (i = 0; i < st->ntargets; i++, b++) {
560 XDrawLine(st->dpy, st->win, st->fgc[0],
561 b->hist[st->tail][0], b->hist[st->tail][1],
562 b->hist[temp][0], b->hist[temp][1]);
564 st->tail = (st->tail+1)%st->trailLen;
567 for (j = st->tail; j != st->head; j = temp) {
568 temp = (j+1)%st->trailLen;
571 for (i = 0; i < st->nbugs; i++, b++) {
572 XDrawLine(st->dpy, st->win, st->fgc[colorIdx[ci0]],
573 b->hist[j][0], b->hist[j][1],
574 b->hist[temp][0], b->hist[temp][1]);
578 for (i = 0; i < st->ntargets; i++, b++) {
579 XDrawLine(st->dpy, st->win, st->fgc[tColorIdx[tci0]],
580 b->hist[j][0], b->hist[j][1],
581 b->hist[temp][0], b->hist[temp][1]);
588 static void clearBugs(struct state *st)
594 st->tail = st->tail-1;
595 if (st->tail < 0) st->tail = st->trailLen-1;
597 if (((st->head+1)%st->trailLen) == st->tail) {
598 /* first, erase last segment of bugs if necessary */
599 temp = (st->tail+1) % st->trailLen;
602 for (i = 0; i < st->nbugs; 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]);
609 for (i = 0; i < st->ntargets; i++, b++) {
610 XDrawLine(st->dpy, st->win, st->fgc[0],
611 b->hist[st->tail][0], b->hist[st->tail][1],
612 b->hist[temp][0], b->hist[temp][1]);
614 st->tail = (st->tail+1)%st->trailLen;
617 for (j = st->tail; j != st->head; j = temp) {
618 temp = (j+1)%st->trailLen;
621 for (i = 0; i < st->nbugs; 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]);
628 for (i = 0; i < st->ntargets; i++, b++) {
629 XDrawLine(st->dpy, st->win, st->fgc[0],
630 b->hist[j][0], b->hist[j][1],
631 b->hist[temp][0], b->hist[temp][1]);
636 static void updateState(struct state *st)
640 register float ax, ay, temp;
645 st->head = (st->head+1)%st->trailLen;
647 for (j = 0; j < 5; j++) {
648 /* update closets bug for the bug indicated by checkIndex */
649 st->checkIndex = (st->checkIndex+1)%st->nbugs;
650 b = &st->bugs[st->checkIndex];
652 ax = b->closest->pos[0] - b->pos[0];
653 ay = b->closest->pos[1] - b->pos[1];
654 temp = ax*ax + ay*ay;
655 for (i = 0; i < st->ntargets; i++) {
656 b2 = &st->targets[i];
657 if (b2 == b->closest) continue;
658 ax = b2->pos[0] - b->pos[0];
659 ay = b2->pos[1] - b->pos[1];
660 theta = ax*ax + ay*ay;
661 if (theta < temp*2) {
668 /* update target state */
671 for (i = 0; i < st->ntargets; i++, b++) {
673 ax = st->targetAcc*cos(theta);
674 ay = st->targetAcc*sin(theta);
676 b->vel[0] += ax*st->dt;
677 b->vel[1] += ay*st->dt;
680 temp = sq(b->vel[0]) + sq(b->vel[1]);
681 if (temp > st->targetVelSq) {
682 temp = st->targetVel/sqrt(temp);
683 /* save old vel for acc computation */
687 /* compute new velocity */
691 /* update acceleration */
692 ax = (b->vel[0]-ax)*st->dtInv;
693 ay = (b->vel[1]-ay)*st->dtInv;
696 /* update position */
697 b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq;
698 b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq;
700 /* check limits on targets */
703 b->pos[0] = -b->pos[0];
704 b->vel[0] = -b->vel[0];
705 } else if (b->pos[0] >= st->maxx) {
707 b->pos[0] = 2*st->maxx-b->pos[0];
708 b->vel[0] = -b->vel[0];
712 b->pos[1] = -b->pos[1];
713 b->vel[1] = -b->vel[1];
714 } else if (b->pos[1] >= st->maxy) {
716 b->pos[1] = 2*st->maxy-b->pos[1];
717 b->vel[1] = -b->vel[1];
720 b->hist[st->head][0] = b->pos[0]*st->xsize;
721 b->hist[st->head][1] = b->pos[1]*st->xsize;
724 /* update bug state */
726 for (i = 0; i < st->nbugs; i++, b++) {
727 theta = atan2(b->closest->pos[1] - b->pos[1] + frand(st->noise),
728 b->closest->pos[0] - b->pos[0] + frand(st->noise));
729 ax = st->maxAcc*cos(theta);
730 ay = st->maxAcc*sin(theta);
732 b->vel[0] += ax*st->dt;
733 b->vel[1] += ay*st->dt;
736 temp = sq(b->vel[0]) + sq(b->vel[1]);
737 if (temp > st->maxVelSq) {
738 temp = st->maxVel/sqrt(temp);
740 /* save old vel for acc computation */
744 /* compute new velocity */
748 /* update acceleration */
749 ax = (b->vel[0]-ax)*st->dtInv;
750 ay = (b->vel[1]-ay)*st->dtInv;
751 } else if (temp < st->minVelSq) {
752 temp = st->minVel/sqrt(temp);
754 /* save old vel for acc computation */
758 /* compute new velocity */
762 /* update acceleration */
763 ax = (b->vel[0]-ax)*st->dtInv;
764 ay = (b->vel[1]-ay)*st->dtInv;
767 /* update position */
768 b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq;
769 b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq;
771 /* check limits on targets */
774 b->pos[0] = -b->pos[0];
775 b->vel[0] = -b->vel[0];
776 } else if (b->pos[0] >= st->maxx) {
778 b->pos[0] = 2*st->maxx-b->pos[0];
779 b->vel[0] = -b->vel[0];
783 b->pos[1] = -b->pos[1];
784 b->vel[1] = -b->vel[1];
785 } else if (b->pos[1] >= st->maxy) {
787 b->pos[1] = 2*st->maxy-b->pos[1];
788 b->vel[1] = -b->vel[1];
791 b->hist[st->head][0] = b->pos[0]*st->xsize;
792 b->hist[st->head][1] = b->pos[1]*st->xsize;
796 static void mutateBug(struct state *st, int which)
801 /* turn bug into target */
802 if (st->ntargets < MAX_TARGETS-1 && st->nbugs > 1) {
803 i = random() % st->nbugs;
804 memcpy((char *)&st->targets[st->ntargets], (char *)&st->bugs[i], sizeof(bug));
805 memcpy((char *)&st->bugs[i], (char *)&st->bugs[st->nbugs-1], sizeof(bug));
806 st->targets[st->ntargets].pos[0] = frand(st->maxx);
807 st->targets[st->ntargets].pos[1] = frand(st->maxy);
811 for (i = 0; i < st->nbugs; i += st->ntargets) {
812 st->bugs[i].closest = &st->targets[st->ntargets-1];
816 /* turn target into bug */
817 if (st->ntargets > 1 && st->nbugs < MAX_BUGS-1) {
819 i = random() % st->ntargets;
821 /* copy state into a new bug */
822 memcpy((char *)&st->bugs[st->nbugs], (char *)&st->targets[i], sizeof(bug));
825 /* pick a target for the new bug */
826 st->bugs[st->nbugs].closest = &st->targets[random()%st->ntargets];
828 for (j = 0; j < st->nbugs; j++) {
829 if (st->bugs[j].closest == &st->targets[st->ntargets]) {
830 st->bugs[j].closest = &st->targets[i];
831 } else if (st->bugs[j].closest == &st->targets[i]) {
832 st->bugs[j].closest = &st->targets[random()%st->ntargets];
837 /* copy the last ntarget into the one we just deleted */
838 memcpy(&st->targets[i], (char *)&st->targets[st->ntargets], sizeof(bug));
843 static void mutateParam(float *param)
845 *param *= 0.75+frand(0.5);
848 static void randomSmallChange(struct state *st)
852 whichCase = random()%11;
854 if (++st->rsc_callDepth > 10) {
862 mutateParam(&st->maxAcc);
866 /* target acceleration */
867 mutateParam(&st->targetAcc);
872 mutateParam(&st->maxVel);
876 /* target velocity */
877 mutateParam(&st->targetVel);
882 mutateParam(&st->noise);
886 /* minVelMultiplier */
887 mutateParam(&st->minVelMultiplier);
893 if (st->ntargets < 2) break;
899 if (st->nbugs < 2) break;
901 if (st->nbugs < 2) break;
907 st->colorScheme = random()%NUM_SCHEMES;
908 if (st->colorScheme == RANDOM_SCHIZO || st->colorScheme == COLOR_SCHIZO) {
909 /* don't use these quite as much */
910 st->colorScheme = random()%NUM_SCHEMES;
915 randomSmallChange(st);
916 randomSmallChange(st);
917 randomSmallChange(st);
918 randomSmallChange(st);
921 if (st->minVelMultiplier < 0.3) st->minVelMultiplier = 0.3;
922 else if (st->minVelMultiplier > 0.9) st->minVelMultiplier = 0.9;
923 if (st->noise < 0.01) st->noise = 0.01;
924 if (st->maxVel < 0.02) st->maxVel = 0.02;
925 if (st->targetVel < 0.02) st->targetVel = 0.02;
926 if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7;
927 if (st->maxAcc > st->maxVel*0.7) st->maxAcc = st->maxVel*0.7;
928 if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7;
929 if (st->maxAcc < 0.01) st->maxAcc = 0.01;
930 if (st->targetAcc < 0.005) st->targetAcc = 0.005;
932 computeConstants(st);
936 static void randomBigChange(struct state *st)
941 whichCase = random()%4;
943 if (++st->rbc_callDepth > 3) {
951 temp = (random()%(MAX_TRAIL_LEN-25)) + 25;
954 computeColorIndices(st);
960 randomSmallChange(st);
961 randomSmallChange(st);
962 randomSmallChange(st);
963 randomSmallChange(st);
964 randomSmallChange(st);
965 randomSmallChange(st);
966 randomSmallChange(st);
967 randomSmallChange(st);
980 temp = random()%st->ntargets;
981 st->targets[temp].pos[0] += frand(st->maxx/4)-st->maxx/8;
982 st->targets[temp].pos[1] += frand(st->maxy/4)-st->maxy/8;
983 /* updateState() will fix bounds */
990 static void updateColorIndex(struct state *st,
991 int **tColorIdx, int *tci0, int *tnc,
992 int **colorIdx, int *ci0, int *nc)
994 switch(st->colorScheme) {
996 *tColorIdx = st->redIndex;
999 *colorIdx = st->blueIndex;
1005 *tColorIdx = st->graySIndex;
1007 *tnc = st->trailLen;
1008 *colorIdx = st->graySIndex;
1014 *tColorIdx = st->redSIndex;
1016 *tnc = st->trailLen;
1017 *colorIdx = st->blueSIndex;
1023 *tColorIdx = st->grayIndex;
1025 *tnc = st->trailLen;
1026 *colorIdx = st->grayIndex;
1032 *tColorIdx = st->redIndex;
1034 *tnc = st->trailLen;
1035 *colorIdx = st->randomIndex;
1041 *tColorIdx = st->redIndex;
1043 *tnc = st->trailLen;
1044 *colorIdx = st->randomIndex;
1051 #if HAVE_GETTIMEOFDAY
1052 static void initTime(struct state *st)
1054 #if GETTIMEOFDAY_TWO_ARGS
1055 gettimeofday(&st->startupTime, NULL);
1057 gettimeofday(&st->startupTime);
1061 static double getTime(struct state *st)
1065 #if GETTIMEOFDAY_TWO_ARGS
1066 gettimeofday(&t, NULL);
1070 t.tv_sec -= st->startupTime.tv_sec;
1071 f = ((double)t.tv_sec) + t.tv_usec*1e-6;
1077 xrayswarm_init (Display *d, Window w)
1079 struct state *st = (struct state *) calloc (1, sizeof(*st));
1086 st->targetVel = 0.03;
1087 st->targetAcc = 0.02;
1091 st->minVelMultiplier = 0.5;
1097 st->colorScheme = /* -1 */ 2;
1098 st->changeProb = 0.08;
1100 if (!initGraphics(st)) abort();
1102 computeConstants(st);
1105 computeColorIndices(st);
1107 if (st->changeProb > 0) {
1108 for (i = random()%5+5; i >= 0; i--) {
1109 randomSmallChange(st);
1116 static unsigned long
1117 xrayswarm_draw (Display *d, Window w, void *closure)
1119 struct state *st = (struct state *) closure;
1120 unsigned long this_delay = st->delay;
1122 #if HAVE_GETTIMEOFDAY
1123 st->draw_start = getTime(st);
1126 if (st->delay > 0) {
1128 st->dt = DESIRED_DT/2;
1131 st->dt = DESIRED_DT;
1134 for (; st->draw_cnt > 0; st->draw_cnt--) {
1136 updateColorIndex(st, &st->draw_targetColorIndex, &st->draw_targetStartColor, &st->draw_targetNumColors,
1137 &st->draw_colorIndex, &st->draw_startColor, &st->draw_numColors);
1138 drawBugs(st, st->draw_targetColorIndex, st->draw_targetStartColor, st->draw_targetNumColors,
1139 st->draw_colorIndex, st->draw_startColor, st->draw_numColors);
1141 #if HAVE_GETTIMEOFDAY
1142 st->draw_end = getTime(st);
1145 if (st->draw_end > st->draw_start+0.5) {
1146 if (frand(1.0) < st->changeProb) randomSmallChange(st);
1147 if (frand(1.0) < st->changeProb*0.3) randomBigChange(st);
1148 st->draw_elapsed = st->draw_end-st->draw_start;
1150 st->draw_timePerFrame = st->draw_elapsed/st->draw_nframes - st->delay*1e-6;
1151 st->draw_fps = st->draw_nframes/st->draw_elapsed;
1153 printf("elapsed: %.3f\n", elapsed);
1154 printf("fps: %.1f secs per frame: %.3f delay: %f\n",
1155 fps, timePerFrame, delay);
1158 if (st->draw_fps > MAX_FPS) {
1159 st->delay = (1.0/MAX_FPS - (st->draw_timePerFrame + st->delay*1e-6))*1e6;
1160 } else if (st->dt*st->draw_fps < MIN_FPS*DESIRED_DT) {
1161 /* need to speed things up somehow */
1162 if (0 && st->nbugs > 10) {
1163 /*printf("reducing bugs to improve speed.\n");*/
1165 st->nbugs *= st->draw_fps/MIN_FPS;
1166 if (st->ntargets >= st->nbugs/2) mutateBug(st, 1);
1167 } else if (0 && st->dt < 0.3) {
1168 /*printf("increasing dt to improve speed.\n");*/
1169 st->dt *= MIN_FPS/st->draw_fps;
1170 computeConstants(st);
1171 } else if (st->trailLen > 10) {
1172 /*printf("reducing trail length to improve speed.\n");*/
1174 st->trailLen = st->trailLen * (st->draw_fps/MIN_FPS);
1175 if (st->trailLen < 10) st->trailLen = 10;
1176 computeColorIndices(st);
1181 st->draw_start = getTime(st);
1182 st->draw_nframes = 0;
1185 if (frand(1) < st->changeProb*2/100.0) randomSmallChange(st);
1186 if (frand(1) < st->changeProb*0.3/100.0) randomBigChange(st);
1189 if (st->delay <= 10000) {
1190 st->draw_delayAccum += st->delay;
1191 if (st->draw_delayAccum > 10000) {
1192 this_delay = st->draw_delayAccum;
1193 st->draw_delayAccum = 0;
1194 st->draw_sleepCount = 0;
1196 if (++st->draw_sleepCount > 2) {
1197 st->draw_sleepCount = 0;
1206 xrayswarm_reshape (Display *dpy, Window window, void *closure,
1207 unsigned int w, unsigned int h)
1209 struct state *st = (struct state *) closure;
1212 st->xc = st->xsize >> 1;
1213 st->yc = st->ysize >> 1;
1214 st->maxy = st->ysize/(float)st->xsize;
1218 xrayswarm_event (Display *dpy, Window window, void *closure, XEvent *event)
1224 xrayswarm_free (Display *dpy, Window window, void *closure)
1226 struct state *st = (struct state *) closure;
1228 for (i = 0; i < 256; i++)
1229 if (st->fgc[i]) XFreeGC (dpy, (st->fgc[i]));
1230 XFreeGC (dpy, st->cgc);
1234 XSCREENSAVER_MODULE ("XRaySwarm", xrayswarm)