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 "*ignoreRotation: True",
73 static XrmOptionDescRec xrayswarm_options [] = {
74 {"-delay",".delay",XrmoptionSepArg,0},
79 /**********************************************************************
81 * bug structs & variables
83 **********************************************************************/
84 #define MAX_TRAIL_LEN 60
86 #define MAX_TARGETS 10
87 #define sq(x) ((x)*(x))
91 #define DESIRED_DT 0.2
93 typedef struct _sbug {
95 int hist[MAX_TRAIL_LEN][2];
97 struct _sbug *closest;
100 #define GRAY_TRAILS 0
101 #define GRAY_SCHIZO 1
102 #define COLOR_TRAILS 2
103 #define RANDOM_TRAILS 3
104 #define RANDOM_SCHIZO 4
105 #define COLOR_SCHIZO 5
106 #define NUM_SCHEMES 6 /* too many schizos; don't use last 2 */
114 unsigned char colors[768];
129 float minVelMultiplier;
143 bug targets[MAX_TARGETS];
149 int grayIndex[MAX_TRAIL_LEN];
150 int redIndex[MAX_TRAIL_LEN];
151 int blueIndex[MAX_TRAIL_LEN];
152 int graySIndex[MAX_TRAIL_LEN];
153 int redSIndex[MAX_TRAIL_LEN];
154 int blueSIndex[MAX_TRAIL_LEN];
155 int randomIndex[MAX_TRAIL_LEN];
164 float draw_timePerFrame, draw_elapsed;
165 int *draw_targetColorIndex, *draw_colorIndex;
166 int draw_targetStartColor, draw_targetNumColors;
167 int draw_startColor, draw_numColors;
168 double draw_start, draw_end;
174 struct timeval startupTime;
194 static const bugParams good1 = {
196 0.03, /* targetVel */
197 0.02, /* targetAcc */
205 0.15 /* changeProb */
208 static const bugParams *goodParams[] = {
212 static int numParamSets = 1;
215 static void initCMap(struct state *st)
222 /* color 0 is black */
228 st->colors[n++] = 255;
232 /* color 2 is green */
233 st->colors[n++] = 255;
237 /* color 3 is blue */
238 st->colors[n++] = 255;
242 /* start greyscale colors at 4; 16 levels */
243 for (i = 0; i < 16; i++) {
245 if (temp > 255) temp = 255;
246 st->colors[n++] = 255 - temp;
247 st->colors[n++] = 255 - temp;
248 st->colors[n++] = 255 - temp;
251 /* start red fade at 20; 16 levels */
252 for (i = 0; i < 16; i++) {
254 if (temp > 255) temp = 255;
255 st->colors[n++] = 255 - temp;
256 st->colors[n++] = 255 - pow(i/16.0+0.001, 0.3)*255;
257 st->colors[n++] = 65 - temp/4;
260 /* start blue fade at 36; 16 levels */
261 for (i = 0; i < 16; i++) {
263 if (temp > 255) temp = 255;
264 st->colors[n++] = 32 - temp/8;
265 st->colors[n++] = 180 - pow(i/16.0+0.001, 0.3)*180;
266 st->colors[n++] = 255 - temp;
269 /* random colors start at 52 */
270 st->numRandomColors = MAX_TRAIL_LEN;
272 st->colors[n] = random()&255; n++;
273 st->colors[n] = random()&255; n++;
274 st->colors[n] = st->colors[n-2]/2 + st->colors[n-3]/2; n++;
276 for (i = 0; i < st->numRandomColors; i++) {
277 st->colors[n] = (st->colors[n-3] + (random()&31) - 16)&255; n++;
278 st->colors[n] = (st->colors[n-3] + (random()&31) - 16)&255; n++;
279 st->colors[n] = st->colors[n-2]/(float)(i+2) + st->colors[n-3]/(float)(i+2); n++;
282 st->numColors = n/3 + 1;
285 static int initGraphics(struct state *st)
288 XWindowAttributes xgwa;
289 /* XSetWindowAttributes xswa;*/
296 XGetWindowAttributes(st->dpy,st->win,&xgwa);
298 /* xswa.backing_store=Always;
299 XChangeWindowAttributes(st->dpy,st->win,CWBackingStore,&xswa);*/
300 xgcv.function=GXcopy;
302 st->delay = get_integer_resource(st->dpy, "delay","Integer");
304 xgcv.foreground=get_pixel_resource (st->dpy, cmap, "background", "Background");
305 st->fgc[0]=XCreateGC(st->dpy, st->win, GCForeground|GCFunction,&xgcv);
307 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[0], False);
312 xgcv.foreground=get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
313 st->fgc[1]=XCreateGC(st->dpy,st->win,GCForeground|GCFunction,&xgcv);
315 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[1], False);
317 for (i=0;i<st->numColors;i+=2) st->fgc[i]=st->fgc[0];
318 for (i=1;i<st->numColors;i+=2) st->fgc[i]=st->fgc[1];
320 for (i = 0; i < st->numColors; i++) {
321 color.red=st->colors[n++]<<8;
322 color.green=st->colors[n++]<<8;
323 color.blue=st->colors[n++]<<8;
324 color.flags=DoRed|DoGreen|DoBlue;
325 XAllocColor(st->dpy,cmap,&color);
326 xgcv.foreground=color.pixel;
327 st->fgc[i] = XCreateGC(st->dpy, st->win, GCForeground | GCFunction,&xgcv);
329 jwxyz_XSetAntiAliasing (st->dpy, st->fgc[i], False);
333 st->cgc = XCreateGC(st->dpy,st->win,GCForeground|GCFunction,&xgcv);
334 XSetGraphicsExposures(st->dpy,st->cgc,False);
336 jwxyz_XSetAntiAliasing (st->dpy, st->cgc, False);
339 st->xsize = xgwa.width;
340 st->ysize = xgwa.height;
341 st->xc = st->xsize >> 1;
342 st->yc = st->ysize >> 1;
345 st->maxy = st->ysize/(float)st->xsize;
347 if (st->colorScheme < 0) st->colorScheme = random()%NUM_SCHEMES;
352 static void initBugs(struct state *st)
357 st->head = st->tail = 0;
359 memset((char *)st->bugs, 0,MAX_BUGS*sizeof(bug));
360 memset((char *)st->targets, 0, MAX_TARGETS*sizeof(bug));
362 if (st->ntargets < 0) st->ntargets = (0.25+frand(0.75)*frand(1))*MAX_TARGETS;
363 if (st->ntargets < 1) st->ntargets = 1;
365 if (st->nbugs < 0) st->nbugs = (0.25+frand(0.75)*frand(1))*MAX_BUGS;
366 if (st->nbugs <= st->ntargets) st->nbugs = st->ntargets+1;
368 if (st->trailLen < 0) {
369 st->trailLen = (1.0 - frand(0.6)*frand(1))*MAX_TRAIL_LEN;
372 if (st->nbugs > MAX_BUGS) st->nbugs = MAX_BUGS;
373 if (st->ntargets > MAX_TARGETS) st->ntargets = MAX_TARGETS;
374 if (st->trailLen > MAX_TRAIL_LEN) st->trailLen = MAX_TRAIL_LEN;
377 for (i = 0; i < st->nbugs; i++, b++) {
378 b->pos[0] = frand(st->maxx);
379 b->pos[1] = frand(st->maxy);
380 b->vel[0] = frand(st->maxVel/2);
381 b->vel[1] = frand(st->maxVel/2);
383 b->hist[st->head][0] = b->pos[0]*st->xsize;
384 b->hist[st->head][1] = b->pos[1]*st->xsize;
385 b->closest = &st->targets[random()%st->ntargets];
389 for (i = 0; i < st->ntargets; i++, b++) {
390 b->pos[0] = frand(st->maxx);
391 b->pos[1] = frand(st->maxy);
393 b->vel[0] = frand(st->targetVel/2);
394 b->vel[1] = frand(st->targetVel/2);
396 b->hist[st->head][0] = b->pos[0]*st->xsize;
397 b->hist[st->head][1] = b->pos[1]*st->xsize;
401 static void pickNewTargets(struct state *st)
407 for (i = 0; i < st->nbugs; i++, b++) {
408 b->closest = &st->targets[random()%st->ntargets];
413 static void addBugs(int numToAdd)
418 if (numToAdd + st->nbugs > MAX_BUGS) numToAdd = MAX_BUGS-st->nbugs;
419 else if (numToAdd < 0) numToAdd = 0;
421 for (i = 0; i < numToAdd; i++) {
422 b = &st->bugs[random()%st->nbugs];
423 memcpy((char *)&st->bugs[st->nbugs+i], (char *)b, sizeof(bug));
424 b->closest = &st->targets[random()%st->ntargets];
427 st->nbugs += numToAdd;
430 static void addTargets(int numToAdd)
435 if (numToAdd + st->ntargets > MAX_TARGETS) numToAdd = MAX_TARGETS-st->ntargets;
436 else if (numToAdd < 0) numToAdd = 0;
438 for (i = 0; i < numToAdd; i++) {
439 b = &st->targets[random()%st->ntargets];
440 memcpy((char *)&st->targets[st->ntargets+i], (char *)b, sizeof(bug));
441 b->closest = &st->targets[random()%st->ntargets];
444 st->ntargets += numToAdd;
448 static void computeConstants(struct state *st)
450 st->halfDtSq = st->dt*st->dt*0.5;
451 st->dtInv = 1.0/st->dt;
452 st->targetVelSq = st->targetVel*st->targetVel;
453 st->maxVelSq = st->maxVel*st->maxVel;
454 st->minVel = st->maxVel*st->minVelMultiplier;
455 st->minVelSq = st->minVel*st->minVel;
458 static void computeColorIndices(struct state *st)
463 /* note: colors are used in *reverse* order! */
466 for (i = 0; i < st->trailLen; i++) {
467 st->grayIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5;
468 if (st->grayIndex[st->trailLen-1-i] > 19) st->grayIndex[st->trailLen-1-i] = 19;
472 for (i = 0; i < st->trailLen; i++) {
473 st->redIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5;
474 if (st->redIndex[st->trailLen-1-i] > 35) st->redIndex[st->trailLen-1-i] = 35;
478 for (i = 0; i < st->trailLen; i++) {
479 st->blueIndex[st->trailLen-1-i] = 36 + i*16.0/st->trailLen + 0.5;
480 if (st->blueIndex[st->trailLen-1-i] > 51) st->blueIndex[st->trailLen-1-i] = 51;
483 /* gray schizo - same as gray*/
484 for (i = 0; i < st->trailLen; i++) {
485 st->graySIndex[st->trailLen-1-i] = 4 + i*16.0/st->trailLen + 0.5;
486 if (st->graySIndex[st->trailLen-1-i] > 19) st->graySIndex[st->trailLen-1-i] = 19;
489 /*schizoLength = st->trailLen/4;
490 if (schizoLength < 3) schizoLength = 3;*/
492 for (i = 0; i < st->trailLen; i++) {
493 /* redSIndex[trailLen-1-i] =
494 20 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;*/
495 st->redSIndex[st->trailLen-1-i] = 20 + i*16.0/st->trailLen + 0.5;
496 if (st->redSIndex[st->trailLen-1-i] > 35) st->redSIndex[st->trailLen-1-i] = 35;
499 schizoLength = st->trailLen/2;
500 if (schizoLength < 3) schizoLength = 3;
501 /* blue schizo is next */
502 for (i = 0; i < st->trailLen; i++) {
503 st->blueSIndex[st->trailLen-1-i] =
504 36 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;
505 if (st->blueSIndex[st->trailLen-1-i] > 51) st->blueSIndex[st->trailLen-1-i] = 51;
509 for (i = 0; i < st->trailLen; i++) {
510 st->randomIndex[i] = 52 + random()%(st->numRandomColors);
515 static void setParams(bugParams *p)
518 st->targetVel = p->targetVel;
519 st->targetAcc = p->targetAcc;
520 st->maxVel = p->maxVel;
521 st->maxAcc = p->maxAcc;
522 st->noise = p->noise;
524 st->nbugs = p->nbugs;
525 st->ntargets = p->ntargets;
526 st->trailLen = p->trailLen;
527 st->colorScheme = p->colorScheme;
528 st->changeProb = p->changeProb;
530 computeColorIndices();
534 static void drawBugs(struct state *st, int *tColorIdx, int tci0, int tnc,
535 int *colorIdx, int ci0, int nc)
541 if (((st->head+1)%st->trailLen) == st->tail) {
542 /* first, erase last segment of bugs if necessary */
543 temp = (st->tail+1) % st->trailLen;
546 for (i = 0; i < st->nbugs; i++, b++) {
547 XDrawLine(st->dpy, st->win, st->fgc[0],
548 b->hist[st->tail][0], b->hist[st->tail][1],
549 b->hist[temp][0], b->hist[temp][1]);
553 for (i = 0; i < st->ntargets; i++, b++) {
554 XDrawLine(st->dpy, st->win, st->fgc[0],
555 b->hist[st->tail][0], b->hist[st->tail][1],
556 b->hist[temp][0], b->hist[temp][1]);
558 st->tail = (st->tail+1)%st->trailLen;
561 for (j = st->tail; j != st->head; j = temp) {
562 temp = (j+1)%st->trailLen;
565 for (i = 0; i < st->nbugs; i++, b++) {
566 XDrawLine(st->dpy, st->win, st->fgc[colorIdx[ci0]],
567 b->hist[j][0], b->hist[j][1],
568 b->hist[temp][0], b->hist[temp][1]);
572 for (i = 0; i < st->ntargets; i++, b++) {
573 XDrawLine(st->dpy, st->win, st->fgc[tColorIdx[tci0]],
574 b->hist[j][0], b->hist[j][1],
575 b->hist[temp][0], b->hist[temp][1]);
582 static void clearBugs(struct state *st)
588 st->tail = st->tail-1;
589 if (st->tail < 0) st->tail = st->trailLen-1;
591 if (((st->head+1)%st->trailLen) == st->tail) {
592 /* first, erase last segment of bugs if necessary */
593 temp = (st->tail+1) % st->trailLen;
596 for (i = 0; i < st->nbugs; i++, b++) {
597 XDrawLine(st->dpy, st->win, st->fgc[0],
598 b->hist[st->tail][0], b->hist[st->tail][1],
599 b->hist[temp][0], b->hist[temp][1]);
603 for (i = 0; i < st->ntargets; i++, b++) {
604 XDrawLine(st->dpy, st->win, st->fgc[0],
605 b->hist[st->tail][0], b->hist[st->tail][1],
606 b->hist[temp][0], b->hist[temp][1]);
608 st->tail = (st->tail+1)%st->trailLen;
611 for (j = st->tail; j != st->head; j = temp) {
612 temp = (j+1)%st->trailLen;
615 for (i = 0; i < st->nbugs; i++, b++) {
616 XDrawLine(st->dpy, st->win, st->fgc[0],
617 b->hist[j][0], b->hist[j][1],
618 b->hist[temp][0], b->hist[temp][1]);
622 for (i = 0; i < st->ntargets; i++, b++) {
623 XDrawLine(st->dpy, st->win, st->fgc[0],
624 b->hist[j][0], b->hist[j][1],
625 b->hist[temp][0], b->hist[temp][1]);
630 static void updateState(struct state *st)
634 register float ax, ay, temp;
639 st->head = (st->head+1)%st->trailLen;
641 for (j = 0; j < 5; j++) {
642 /* update closets bug for the bug indicated by checkIndex */
643 st->checkIndex = (st->checkIndex+1)%st->nbugs;
644 b = &st->bugs[st->checkIndex];
646 ax = b->closest->pos[0] - b->pos[0];
647 ay = b->closest->pos[1] - b->pos[1];
648 temp = ax*ax + ay*ay;
649 for (i = 0; i < st->ntargets; i++) {
650 b2 = &st->targets[i];
651 if (b2 == b->closest) continue;
652 ax = b2->pos[0] - b->pos[0];
653 ay = b2->pos[1] - b->pos[1];
654 theta = ax*ax + ay*ay;
655 if (theta < temp*2) {
662 /* update target state */
665 for (i = 0; i < st->ntargets; i++, b++) {
667 ax = st->targetAcc*cos(theta);
668 ay = st->targetAcc*sin(theta);
670 b->vel[0] += ax*st->dt;
671 b->vel[1] += ay*st->dt;
674 temp = sq(b->vel[0]) + sq(b->vel[1]);
675 if (temp > st->targetVelSq) {
676 temp = st->targetVel/sqrt(temp);
677 /* save old vel for acc computation */
681 /* compute new velocity */
685 /* update acceleration */
686 ax = (b->vel[0]-ax)*st->dtInv;
687 ay = (b->vel[1]-ay)*st->dtInv;
690 /* update position */
691 b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq;
692 b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq;
694 /* check limits on targets */
697 b->pos[0] = -b->pos[0];
698 b->vel[0] = -b->vel[0];
699 } else if (b->pos[0] >= st->maxx) {
701 b->pos[0] = 2*st->maxx-b->pos[0];
702 b->vel[0] = -b->vel[0];
706 b->pos[1] = -b->pos[1];
707 b->vel[1] = -b->vel[1];
708 } else if (b->pos[1] >= st->maxy) {
710 b->pos[1] = 2*st->maxy-b->pos[1];
711 b->vel[1] = -b->vel[1];
714 b->hist[st->head][0] = b->pos[0]*st->xsize;
715 b->hist[st->head][1] = b->pos[1]*st->xsize;
718 /* update bug state */
720 for (i = 0; i < st->nbugs; i++, b++) {
721 theta = atan2(b->closest->pos[1] - b->pos[1] + frand(st->noise),
722 b->closest->pos[0] - b->pos[0] + frand(st->noise));
723 ax = st->maxAcc*cos(theta);
724 ay = st->maxAcc*sin(theta);
726 b->vel[0] += ax*st->dt;
727 b->vel[1] += ay*st->dt;
730 temp = sq(b->vel[0]) + sq(b->vel[1]);
731 if (temp > st->maxVelSq) {
732 temp = st->maxVel/sqrt(temp);
734 /* save old vel for acc computation */
738 /* compute new velocity */
742 /* update acceleration */
743 ax = (b->vel[0]-ax)*st->dtInv;
744 ay = (b->vel[1]-ay)*st->dtInv;
745 } else if (temp < st->minVelSq) {
746 temp = st->minVel/sqrt(temp);
748 /* save old vel for acc computation */
752 /* compute new velocity */
756 /* update acceleration */
757 ax = (b->vel[0]-ax)*st->dtInv;
758 ay = (b->vel[1]-ay)*st->dtInv;
761 /* update position */
762 b->pos[0] += b->vel[0]*st->dt + ax*st->halfDtSq;
763 b->pos[1] += b->vel[1]*st->dt + ay*st->halfDtSq;
765 /* check limits on targets */
768 b->pos[0] = -b->pos[0];
769 b->vel[0] = -b->vel[0];
770 } else if (b->pos[0] >= st->maxx) {
772 b->pos[0] = 2*st->maxx-b->pos[0];
773 b->vel[0] = -b->vel[0];
777 b->pos[1] = -b->pos[1];
778 b->vel[1] = -b->vel[1];
779 } else if (b->pos[1] >= st->maxy) {
781 b->pos[1] = 2*st->maxy-b->pos[1];
782 b->vel[1] = -b->vel[1];
785 b->hist[st->head][0] = b->pos[0]*st->xsize;
786 b->hist[st->head][1] = b->pos[1]*st->xsize;
790 static void mutateBug(struct state *st, int which)
795 /* turn bug into target */
796 if (st->ntargets < MAX_TARGETS-1 && st->nbugs > 1) {
797 i = random() % st->nbugs;
798 memcpy((char *)&st->targets[st->ntargets], (char *)&st->bugs[i], sizeof(bug));
799 memcpy((char *)&st->bugs[i], (char *)&st->bugs[st->nbugs-1], sizeof(bug));
800 st->targets[st->ntargets].pos[0] = frand(st->maxx);
801 st->targets[st->ntargets].pos[1] = frand(st->maxy);
805 for (i = 0; i < st->nbugs; i += st->ntargets) {
806 st->bugs[i].closest = &st->targets[st->ntargets-1];
810 /* turn target into bug */
811 if (st->ntargets > 1 && st->nbugs < MAX_BUGS-1) {
813 i = random() % st->ntargets;
815 /* copy state into a new bug */
816 memcpy((char *)&st->bugs[st->nbugs], (char *)&st->targets[i], sizeof(bug));
819 /* pick a target for the new bug */
820 st->bugs[st->nbugs].closest = &st->targets[random()%st->ntargets];
822 for (j = 0; j < st->nbugs; j++) {
823 if (st->bugs[j].closest == &st->targets[st->ntargets]) {
824 st->bugs[j].closest = &st->targets[i];
825 } else if (st->bugs[j].closest == &st->targets[i]) {
826 st->bugs[j].closest = &st->targets[random()%st->ntargets];
831 /* copy the last ntarget into the one we just deleted */
832 memcpy(&st->targets[i], (char *)&st->targets[st->ntargets], sizeof(bug));
837 static void mutateParam(float *param)
839 *param *= 0.75+frand(0.5);
842 static void randomSmallChange(struct state *st)
846 whichCase = random()%11;
848 if (++st->rsc_callDepth > 10) {
856 mutateParam(&st->maxAcc);
860 /* target acceleration */
861 mutateParam(&st->targetAcc);
866 mutateParam(&st->maxVel);
870 /* target velocity */
871 mutateParam(&st->targetVel);
876 mutateParam(&st->noise);
880 /* minVelMultiplier */
881 mutateParam(&st->minVelMultiplier);
887 if (st->ntargets < 2) break;
893 if (st->nbugs < 2) break;
895 if (st->nbugs < 2) break;
901 st->colorScheme = random()%NUM_SCHEMES;
902 if (st->colorScheme == RANDOM_SCHIZO || st->colorScheme == COLOR_SCHIZO) {
903 /* don't use these quite as much */
904 st->colorScheme = random()%NUM_SCHEMES;
909 randomSmallChange(st);
910 randomSmallChange(st);
911 randomSmallChange(st);
912 randomSmallChange(st);
915 if (st->minVelMultiplier < 0.3) st->minVelMultiplier = 0.3;
916 else if (st->minVelMultiplier > 0.9) st->minVelMultiplier = 0.9;
917 if (st->noise < 0.01) st->noise = 0.01;
918 if (st->maxVel < 0.02) st->maxVel = 0.02;
919 if (st->targetVel < 0.02) st->targetVel = 0.02;
920 if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7;
921 if (st->maxAcc > st->maxVel*0.7) st->maxAcc = st->maxVel*0.7;
922 if (st->targetAcc > st->targetVel*0.7) st->targetAcc = st->targetVel*0.7;
923 if (st->maxAcc < 0.01) st->maxAcc = 0.01;
924 if (st->targetAcc < 0.005) st->targetAcc = 0.005;
926 computeConstants(st);
930 static void randomBigChange(struct state *st)
935 whichCase = random()%4;
937 if (++st->rbc_callDepth > 3) {
945 temp = (random()%(MAX_TRAIL_LEN-25)) + 25;
948 computeColorIndices(st);
954 randomSmallChange(st);
955 randomSmallChange(st);
956 randomSmallChange(st);
957 randomSmallChange(st);
958 randomSmallChange(st);
959 randomSmallChange(st);
960 randomSmallChange(st);
961 randomSmallChange(st);
974 temp = random()%st->ntargets;
975 st->targets[temp].pos[0] += frand(st->maxx/4)-st->maxx/8;
976 st->targets[temp].pos[1] += frand(st->maxy/4)-st->maxy/8;
977 /* updateState() will fix bounds */
984 static void updateColorIndex(struct state *st,
985 int **tColorIdx, int *tci0, int *tnc,
986 int **colorIdx, int *ci0, int *nc)
988 switch(st->colorScheme) {
990 *tColorIdx = st->redIndex;
993 *colorIdx = st->blueIndex;
999 *tColorIdx = st->graySIndex;
1001 *tnc = st->trailLen;
1002 *colorIdx = st->graySIndex;
1008 *tColorIdx = st->redSIndex;
1010 *tnc = st->trailLen;
1011 *colorIdx = st->blueSIndex;
1017 *tColorIdx = st->grayIndex;
1019 *tnc = st->trailLen;
1020 *colorIdx = st->grayIndex;
1026 *tColorIdx = st->redIndex;
1028 *tnc = st->trailLen;
1029 *colorIdx = st->randomIndex;
1035 *tColorIdx = st->redIndex;
1037 *tnc = st->trailLen;
1038 *colorIdx = st->randomIndex;
1045 #if HAVE_GETTIMEOFDAY
1046 static void initTime(struct state *st)
1048 #if GETTIMEOFDAY_TWO_ARGS
1049 gettimeofday(&st->startupTime, NULL);
1051 gettimeofday(&st->startupTime);
1055 static double getTime(struct state *st)
1059 #if GETTIMEOFDAY_TWO_ARGS
1060 gettimeofday(&t, NULL);
1064 t.tv_sec -= st->startupTime.tv_sec;
1065 f = ((double)t.tv_sec) + t.tv_usec*1e-6;
1071 xrayswarm_init (Display *d, Window w)
1073 struct state *st = (struct state *) calloc (1, sizeof(*st));
1080 st->targetVel = 0.03;
1081 st->targetAcc = 0.02;
1085 st->minVelMultiplier = 0.5;
1091 st->colorScheme = /* -1 */ 2;
1092 st->changeProb = 0.08;
1094 if (!initGraphics(st)) abort();
1096 computeConstants(st);
1099 computeColorIndices(st);
1101 if (st->changeProb > 0) {
1102 for (i = random()%5+5; i >= 0; i--) {
1103 randomSmallChange(st);
1110 static unsigned long
1111 xrayswarm_draw (Display *d, Window w, void *closure)
1113 struct state *st = (struct state *) closure;
1114 unsigned long this_delay = st->delay;
1116 #if HAVE_GETTIMEOFDAY
1117 st->draw_start = getTime(st);
1120 if (st->delay > 0) {
1122 st->dt = DESIRED_DT/2;
1125 st->dt = DESIRED_DT;
1128 for (; st->draw_cnt > 0; st->draw_cnt--) {
1130 updateColorIndex(st, &st->draw_targetColorIndex, &st->draw_targetStartColor, &st->draw_targetNumColors,
1131 &st->draw_colorIndex, &st->draw_startColor, &st->draw_numColors);
1132 drawBugs(st, st->draw_targetColorIndex, st->draw_targetStartColor, st->draw_targetNumColors,
1133 st->draw_colorIndex, st->draw_startColor, st->draw_numColors);
1135 #if HAVE_GETTIMEOFDAY
1136 st->draw_end = getTime(st);
1139 if (st->draw_end > st->draw_start+0.5) {
1140 if (frand(1.0) < st->changeProb) randomSmallChange(st);
1141 if (frand(1.0) < st->changeProb*0.3) randomBigChange(st);
1142 st->draw_elapsed = st->draw_end-st->draw_start;
1144 st->draw_timePerFrame = st->draw_elapsed/st->draw_nframes - st->delay*1e-6;
1145 st->draw_fps = st->draw_nframes/st->draw_elapsed;
1147 printf("elapsed: %.3f\n", elapsed);
1148 printf("fps: %.1f secs per frame: %.3f delay: %f\n",
1149 fps, timePerFrame, delay);
1152 if (st->draw_fps > MAX_FPS) {
1153 st->delay = (1.0/MAX_FPS - (st->draw_timePerFrame + st->delay*1e-6))*1e6;
1154 } else if (st->dt*st->draw_fps < MIN_FPS*DESIRED_DT) {
1155 /* need to speed things up somehow */
1156 if (0 && st->nbugs > 10) {
1157 /*printf("reducing bugs to improve speed.\n");*/
1159 st->nbugs *= st->draw_fps/MIN_FPS;
1160 if (st->ntargets >= st->nbugs/2) mutateBug(st, 1);
1161 } else if (0 && st->dt < 0.3) {
1162 /*printf("increasing dt to improve speed.\n");*/
1163 st->dt *= MIN_FPS/st->draw_fps;
1164 computeConstants(st);
1165 } else if (st->trailLen > 10) {
1166 /*printf("reducing trail length to improve speed.\n");*/
1168 st->trailLen = st->trailLen * (st->draw_fps/MIN_FPS);
1169 if (st->trailLen < 10) st->trailLen = 10;
1170 computeColorIndices(st);
1175 st->draw_start = getTime(st);
1176 st->draw_nframes = 0;
1179 if (frand(1) < st->changeProb*2/100.0) randomSmallChange(st);
1180 if (frand(1) < st->changeProb*0.3/100.0) randomBigChange(st);
1183 if (st->delay <= 10000) {
1184 st->draw_delayAccum += st->delay;
1185 if (st->draw_delayAccum > 10000) {
1186 this_delay = st->draw_delayAccum;
1187 st->draw_delayAccum = 0;
1188 st->draw_sleepCount = 0;
1190 if (++st->draw_sleepCount > 2) {
1191 st->draw_sleepCount = 0;
1200 xrayswarm_reshape (Display *dpy, Window window, void *closure,
1201 unsigned int w, unsigned int h)
1203 struct state *st = (struct state *) closure;
1206 st->xc = st->xsize >> 1;
1207 st->yc = st->ysize >> 1;
1208 st->maxy = st->ysize/(float)st->xsize;
1212 xrayswarm_event (Display *dpy, Window window, void *closure, XEvent *event)
1218 xrayswarm_free (Display *dpy, Window window, void *closure)
1220 struct state *st = (struct state *) closure;
1224 XSCREENSAVER_MODULE ("XRaySwarm", xrayswarm)