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.
45 #include "screenhack.h"
49 /**********************************************************************
53 **********************************************************************/
55 char *progclass="xrayswarm";
63 XrmOptionDescRec options [] = {
64 {"-delay",".delay",XrmoptionSepArg,0},
68 static unsigned char colors[768];
74 static int xsize, ysize;
76 static unsigned long delay;
77 static float maxx, maxy;
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 */
108 static float dt = 0.3;
109 static float targetVel = 0.03;
110 static float targetAcc = 0.02;
111 static float maxVel = 0.05;
112 static float maxAcc = 0.03;
113 static float noise = 0.01;
114 static float minVelMultiplier = 0.5;
116 static int nbugs = -1;
117 static int ntargets = -1;
118 static int trailLen = -1;
120 /* vars dependent on those above */
122 static float halfDtSq;
123 static float targetVelSq;
124 static float maxVelSq;
125 static float minVelSq;
128 static bug bugs[MAX_BUGS];
129 static bug targets[MAX_TARGETS];
132 static int colorScheme = -1;
133 static float changeProb = 0.08;
135 static int grayIndex[MAX_TRAIL_LEN];
136 static int redIndex[MAX_TRAIL_LEN];
137 static int blueIndex[MAX_TRAIL_LEN];
138 static int graySIndex[MAX_TRAIL_LEN];
139 static int redSIndex[MAX_TRAIL_LEN];
140 static int blueSIndex[MAX_TRAIL_LEN];
141 static int randomIndex[MAX_TRAIL_LEN];
142 static int numColors;
143 static int numRandomColors;
162 0.03, /* targetVel */
163 0.02, /* targetAcc */
171 0.15 /* changeProb */
174 bugParams *goodParams[] = {
178 int numParamSets = 1;
180 void initCMap(void) {
186 /* color 0 is black */
196 /* color 2 is green */
201 /* color 3 is blue */
206 /* start greyscale colors at 4; 16 levels */
207 for (i = 0; i < 16; i++) {
209 if (temp > 255) temp = 255;
210 colors[n++] = 255 - temp;
211 colors[n++] = 255 - temp;
212 colors[n++] = 255 - temp;
215 /* start red fade at 20; 16 levels */
216 for (i = 0; i < 16; i++) {
218 if (temp > 255) temp = 255;
219 colors[n++] = 255 - temp;
220 colors[n++] = 255 - pow(i/16.0+0.001, 0.3)*255;
221 colors[n++] = 65 - temp/4;
224 /* start blue fade at 36; 16 levels */
225 for (i = 0; i < 16; i++) {
227 if (temp > 255) temp = 255;
228 colors[n++] = 32 - temp/8;
229 colors[n++] = 180 - pow(i/16.0+0.001, 0.3)*180;
230 colors[n++] = 255 - temp;
233 /* random colors start at 52 */
234 numRandomColors = MAX_TRAIL_LEN;
236 colors[n] = random()&255; n++;
237 colors[n] = random()&255; n++;
238 colors[n] = colors[n-2]/2 + colors[n-3]/2; n++;
240 for (i = 0; i < numRandomColors; i++) {
241 colors[n] = (colors[n-3] + (random()&31) - 16)&255; n++;
242 colors[n] = (colors[n-3] + (random()&31) - 16)&255; n++;
243 colors[n] = colors[n-2]/(float)(i+2) + colors[n-3]/(float)(i+2); n++;
249 static int initGraphics(void) {
251 XWindowAttributes xgwa;
252 XSetWindowAttributes xswa;
259 XGetWindowAttributes(dpy,win,&xgwa);
261 xswa.backing_store=Always;
262 XChangeWindowAttributes(dpy,win,CWBackingStore,&xswa);
263 xgcv.function=GXcopy;
265 delay = get_integer_resource("delay","Integer");
267 xgcv.foreground=get_pixel_resource ("background", "Background", dpy, cmap);
268 fgc[0]=XCreateGC(dpy, win, GCForeground|GCFunction,&xgcv);
272 xgcv.foreground=get_pixel_resource ("foreground", "Foreground", dpy, cmap);
273 fgc[1]=XCreateGC(dpy,win,GCForeground|GCFunction,&xgcv);
274 for (i=0;i<numColors;i+=2) fgc[i]=fgc[0];
275 for (i=1;i<numColors;i+=2) fgc[i]=fgc[1];
277 for (i = 0; i < numColors; i++) {
278 color.red=colors[n++]<<8;
279 color.green=colors[n++]<<8;
280 color.blue=colors[n++]<<8;
281 color.flags=DoRed|DoGreen|DoBlue;
282 XAllocColor(dpy,cmap,&color);
283 xgcv.foreground=color.pixel;
284 fgc[i] = XCreateGC(dpy, win, GCForeground | GCFunction,&xgcv);
287 cgc = XCreateGC(dpy,win,GCForeground|GCFunction,&xgcv);
288 XSetGraphicsExposures(dpy,cgc,False);
296 maxy = ysize/(float)xsize;
298 if (colorScheme < 0) colorScheme = random()%NUM_SCHEMES;
303 static void initBugs(void) {
309 memset((char *)bugs, 0,MAX_BUGS*sizeof(bug));
310 memset((char *)targets, 0, MAX_TARGETS*sizeof(bug));
312 if (ntargets < 0) ntargets = (0.25+frand(0.75)*frand(1))*MAX_TARGETS;
313 if (ntargets < 1) ntargets = 1;
315 if (nbugs < 0) nbugs = (0.25+frand(0.75)*frand(1))*MAX_BUGS;
316 if (nbugs <= ntargets) nbugs = ntargets+1;
319 trailLen = (1.0 - frand(0.6)*frand(1))*MAX_TRAIL_LEN;
322 if (nbugs > MAX_BUGS) nbugs = MAX_BUGS;
323 if (ntargets > MAX_TARGETS) ntargets = MAX_TARGETS;
324 if (trailLen > MAX_TRAIL_LEN) trailLen = MAX_TRAIL_LEN;
327 for (i = 0; i < nbugs; i++, b++) {
328 b->pos[0] = frand(maxx);
329 b->pos[1] = frand(maxy);
330 b->vel[0] = frand(maxVel/2);
331 b->vel[1] = frand(maxVel/2);
333 b->hist[head][0] = b->pos[0]*xsize;
334 b->hist[head][1] = b->pos[1]*xsize;
335 b->closest = &targets[random()%ntargets];
339 for (i = 0; i < ntargets; i++, b++) {
340 b->pos[0] = frand(maxx);
341 b->pos[1] = frand(maxy);
343 b->vel[0] = frand(targetVel/2);
344 b->vel[1] = frand(targetVel/2);
346 b->hist[head][0] = b->pos[0]*xsize;
347 b->hist[head][1] = b->pos[1]*xsize;
351 static void pickNewTargets(void) {
356 for (i = 0; i < nbugs; i++, b++) {
357 b->closest = &targets[random()%ntargets];
362 static void addBugs(int numToAdd) {
366 if (numToAdd + nbugs > MAX_BUGS) numToAdd = MAX_BUGS-nbugs;
367 else if (numToAdd < 0) numToAdd = 0;
369 for (i = 0; i < numToAdd; i++) {
370 b = &bugs[random()%nbugs];
371 memcpy((char *)&bugs[nbugs+i], (char *)b, sizeof(bug));
372 b->closest = &targets[random()%ntargets];
378 static void addTargets(int numToAdd) {
382 if (numToAdd + ntargets > MAX_TARGETS) numToAdd = MAX_TARGETS-ntargets;
383 else if (numToAdd < 0) numToAdd = 0;
385 for (i = 0; i < numToAdd; i++) {
386 b = &targets[random()%ntargets];
387 memcpy((char *)&targets[ntargets+i], (char *)b, sizeof(bug));
388 b->closest = &targets[random()%ntargets];
391 ntargets += numToAdd;
395 static void computeConstants(void) {
396 halfDtSq = dt*dt*0.5;
398 targetVelSq = targetVel*targetVel;
399 maxVelSq = maxVel*maxVel;
400 minVel = maxVel*minVelMultiplier;
401 minVelSq = minVel*minVel;
404 void computeColorIndices(void) {
408 /* note: colors are used in *reverse* order! */
411 for (i = 0; i < trailLen; i++) {
412 grayIndex[trailLen-1-i] = 4 + i*16.0/trailLen + 0.5;
413 if (grayIndex[trailLen-1-i] > 19) grayIndex[trailLen-1-i] = 19;
417 for (i = 0; i < trailLen; i++) {
418 redIndex[trailLen-1-i] = 20 + i*16.0/trailLen + 0.5;
419 if (redIndex[trailLen-1-i] > 35) redIndex[trailLen-1-i] = 35;
423 for (i = 0; i < trailLen; i++) {
424 blueIndex[trailLen-1-i] = 36 + i*16.0/trailLen + 0.5;
425 if (blueIndex[trailLen-1-i] > 51) blueIndex[trailLen-1-i] = 51;
428 /* gray schizo - same as gray*/
429 for (i = 0; i < trailLen; i++) {
430 graySIndex[trailLen-1-i] = 4 + i*16.0/trailLen + 0.5;
431 if (graySIndex[trailLen-1-i] > 19) graySIndex[trailLen-1-i] = 19;
434 schizoLength = trailLen/4;
435 if (schizoLength < 3) schizoLength = 3;
437 for (i = 0; i < trailLen; i++) {
438 /* redSIndex[trailLen-1-i] =
439 20 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;*/
440 redSIndex[trailLen-1-i] = 20 + i*16.0/trailLen + 0.5;
441 if (redSIndex[trailLen-1-i] > 35) redSIndex[trailLen-1-i] = 35;
444 schizoLength = trailLen/2;
445 if (schizoLength < 3) schizoLength = 3;
446 /* blue schizo is next */
447 for (i = 0; i < trailLen; i++) {
448 blueSIndex[trailLen-1-i] =
449 36 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;
450 if (blueSIndex[trailLen-1-i] > 51) blueSIndex[trailLen-1-i] = 51;
454 for (i = 0; i < trailLen; i++) {
455 randomIndex[i] = 52 + random()%(numRandomColors);
460 static void setParams(bugParams *p) {
462 targetVel = p->targetVel;
463 targetAcc = p->targetAcc;
469 ntargets = p->ntargets;
470 trailLen = p->trailLen;
471 colorScheme = p->colorScheme;
472 changeProb = p->changeProb;
474 computeColorIndices();
478 static void drawBugs(int *tColorIdx, int tci0, int tnc,
479 int *colorIdx, int ci0, int nc) {
484 if (((head+1)%trailLen) == tail) {
485 /* first, erase last segment of bugs if necessary */
486 temp = (tail+1) % trailLen;
489 for (i = 0; i < nbugs; i++, b++) {
490 XDrawLine(dpy, win, fgc[0],
491 b->hist[tail][0], b->hist[tail][1],
492 b->hist[temp][0], b->hist[temp][1]);
496 for (i = 0; i < ntargets; i++, b++) {
497 XDrawLine(dpy, win, fgc[0],
498 b->hist[tail][0], b->hist[tail][1],
499 b->hist[temp][0], b->hist[temp][1]);
501 tail = (tail+1)%trailLen;
504 for (j = tail; j != head; j = temp) {
505 temp = (j+1)%trailLen;
508 for (i = 0; i < nbugs; i++, b++) {
509 XDrawLine(dpy, win, fgc[colorIdx[ci0]],
510 b->hist[j][0], b->hist[j][1],
511 b->hist[temp][0], b->hist[temp][1]);
515 for (i = 0; i < ntargets; i++, b++) {
516 XDrawLine(dpy, win, fgc[tColorIdx[tci0]],
517 b->hist[j][0], b->hist[j][1],
518 b->hist[temp][0], b->hist[temp][1]);
525 static void clearBugs(void) {
531 if (tail < 0) tail = trailLen-1;
533 if (((head+1)%trailLen) == tail) {
534 /* first, erase last segment of bugs if necessary */
535 temp = (tail+1) % trailLen;
538 for (i = 0; i < nbugs; i++, b++) {
539 XDrawLine(dpy, win, fgc[0],
540 b->hist[tail][0], b->hist[tail][1],
541 b->hist[temp][0], b->hist[temp][1]);
545 for (i = 0; i < ntargets; i++, b++) {
546 XDrawLine(dpy, win, fgc[0],
547 b->hist[tail][0], b->hist[tail][1],
548 b->hist[temp][0], b->hist[temp][1]);
550 tail = (tail+1)%trailLen;
553 for (j = tail; j != head; j = temp) {
554 temp = (j+1)%trailLen;
557 for (i = 0; i < nbugs; i++, b++) {
558 XDrawLine(dpy, win, fgc[0],
559 b->hist[j][0], b->hist[j][1],
560 b->hist[temp][0], b->hist[temp][1]);
564 for (i = 0; i < ntargets; i++, b++) {
565 XDrawLine(dpy, win, fgc[0],
566 b->hist[j][0], b->hist[j][1],
567 b->hist[temp][0], b->hist[temp][1]);
572 void updateState(void) {
575 register float ax, ay, temp;
577 static int checkIndex = 0;
581 head = (head+1)%trailLen;
583 for (j = 0; j < 5; j++) {
584 /* update closets bug for the bug indicated by checkIndex */
585 checkIndex = (checkIndex+1)%nbugs;
586 b = &bugs[checkIndex];
588 ax = b->closest->pos[0] - b->pos[0];
589 ay = b->closest->pos[1] - b->pos[1];
590 temp = ax*ax + ay*ay;
591 for (i = 0; i < ntargets; i++) {
593 if (b2 == b->closest) continue;
594 ax = b2->pos[0] - b->pos[0];
595 ay = b2->pos[1] - b->pos[1];
596 theta = ax*ax + ay*ay;
597 if (theta < temp*2) {
604 /* update target state */
607 for (i = 0; i < ntargets; i++, b++) {
609 ax = targetAcc*cos(theta);
610 ay = targetAcc*sin(theta);
616 temp = sq(b->vel[0]) + sq(b->vel[1]);
617 if (temp > targetVelSq) {
618 temp = targetVel/sqrt(temp);
619 /* save old vel for acc computation */
623 /* compute new velocity */
627 /* update acceleration */
628 ax = (b->vel[0]-ax)*dtInv;
629 ay = (b->vel[1]-ay)*dtInv;
632 /* update position */
633 b->pos[0] += b->vel[0]*dt + ax*halfDtSq;
634 b->pos[1] += b->vel[1]*dt + ay*halfDtSq;
636 /* check limits on targets */
639 b->pos[0] = -b->pos[0];
640 b->vel[0] = -b->vel[0];
641 } else if (b->pos[0] >= maxx) {
643 b->pos[0] = 2*maxx-b->pos[0];
644 b->vel[0] = -b->vel[0];
648 b->pos[1] = -b->pos[1];
649 b->vel[1] = -b->vel[1];
650 } else if (b->pos[1] >= maxy) {
652 b->pos[1] = 2*maxy-b->pos[1];
653 b->vel[1] = -b->vel[1];
656 b->hist[head][0] = b->pos[0]*xsize;
657 b->hist[head][1] = b->pos[1]*xsize;
660 /* update bug state */
662 for (i = 0; i < nbugs; i++, b++) {
663 theta = atan2(b->closest->pos[1] - b->pos[1] + frand(noise),
664 b->closest->pos[0] - b->pos[0] + frand(noise));
665 ax = maxAcc*cos(theta);
666 ay = maxAcc*sin(theta);
672 temp = sq(b->vel[0]) + sq(b->vel[1]);
673 if (temp > maxVelSq) {
674 temp = maxVel/sqrt(temp);
676 /* save old vel for acc computation */
680 /* compute new velocity */
684 /* update acceleration */
685 ax = (b->vel[0]-ax)*dtInv;
686 ay = (b->vel[1]-ay)*dtInv;
687 } else if (temp < minVelSq) {
688 temp = minVel/sqrt(temp);
690 /* save old vel for acc computation */
694 /* compute new velocity */
698 /* update acceleration */
699 ax = (b->vel[0]-ax)*dtInv;
700 ay = (b->vel[1]-ay)*dtInv;
703 /* update position */
704 b->pos[0] += b->vel[0]*dt + ax*halfDtSq;
705 b->pos[1] += b->vel[1]*dt + ay*halfDtSq;
707 /* check limits on targets */
710 b->pos[0] = -b->pos[0];
711 b->vel[0] = -b->vel[0];
712 } else if (b->pos[0] >= maxx) {
714 b->pos[0] = 2*maxx-b->pos[0];
715 b->vel[0] = -b->vel[0];
719 b->pos[1] = -b->pos[1];
720 b->vel[1] = -b->vel[1];
721 } else if (b->pos[1] >= maxy) {
723 b->pos[1] = 2*maxy-b->pos[1];
724 b->vel[1] = -b->vel[1];
727 b->hist[head][0] = b->pos[0]*xsize;
728 b->hist[head][1] = b->pos[1]*xsize;
732 void mutateBug(int which) {
736 /* turn bug into target */
737 if (ntargets < MAX_TARGETS-1 && nbugs > 1) {
738 i = random() % nbugs;
739 memcpy((char *)&targets[ntargets], (char *)&bugs[i], sizeof(bug));
740 memcpy((char *)&bugs[i], (char *)&bugs[nbugs-1], sizeof(bug));
741 targets[ntargets].pos[0] = frand(maxx);
742 targets[ntargets].pos[1] = frand(maxy);
746 for (i = 0; i < nbugs; i += ntargets) {
747 bugs[i].closest = &targets[ntargets-1];
751 /* turn target into bug */
752 if (ntargets > 1 && nbugs < MAX_BUGS-1) {
754 i = random() % ntargets;
756 /* copy state into a new bug */
757 memcpy((char *)&bugs[nbugs], (char *)&targets[i], sizeof(bug));
760 /* pick a target for the new bug */
761 bugs[nbugs].closest = &targets[random()%ntargets];
763 for (j = 0; j < nbugs; j++) {
764 if (bugs[j].closest == &targets[ntargets]) {
765 bugs[j].closest = &targets[i];
766 } else if (bugs[j].closest == &targets[i]) {
767 bugs[j].closest = &targets[random()%ntargets];
772 /* copy the last ntarget into the one we just deleted */
773 memcpy(&targets[i], (char *)&targets[ntargets], sizeof(bug));
778 void mutateParam(float *param) {
779 *param *= 0.75+frand(0.5);
782 void randomSmallChange(void) {
784 static int callDepth = 0;
786 whichCase = random()%11;
788 if (++callDepth > 10) {
796 mutateParam(&maxAcc);
800 /* target acceleration */
801 mutateParam(&targetAcc);
806 mutateParam(&maxVel);
810 /* target velocity */
811 mutateParam(&targetVel);
820 /* minVelMultiplier */
821 mutateParam(&minVelMultiplier);
827 if (ntargets < 2) break;
833 if (nbugs < 2) break;
835 if (nbugs < 2) break;
841 colorScheme = random()%NUM_SCHEMES;
842 if (colorScheme == RANDOM_SCHIZO || colorScheme == COLOR_SCHIZO) {
843 /* don't use these quite as much */
844 colorScheme = random()%NUM_SCHEMES;
855 if (minVelMultiplier < 0.3) minVelMultiplier = 0.3;
856 else if (minVelMultiplier > 0.9) minVelMultiplier = 0.9;
857 if (noise < 0.01) noise = 0.01;
858 if (maxVel < 0.02) maxVel = 0.02;
859 if (targetVel < 0.02) targetVel = 0.02;
860 if (targetAcc > targetVel*0.7) targetAcc = targetVel*0.7;
861 if (maxAcc > maxVel*0.7) maxAcc = maxVel*0.7;
862 if (targetAcc > targetVel*0.7) targetAcc = targetVel*0.7;
863 if (maxAcc < 0.01) maxAcc = 0.01;
864 if (targetAcc < 0.005) targetAcc = 0.005;
870 void randomBigChange(void) {
871 static int whichCase = 0;
872 static int callDepth = 0;
875 whichCase = random()%4;
877 if (++callDepth > 3) {
885 temp = (random()%(MAX_TRAIL_LEN-25)) + 25;
888 computeColorIndices();
914 temp = random()%ntargets;
915 targets[temp].pos[0] += frand(maxx/4)-maxx/8;
916 targets[temp].pos[1] += frand(maxy/4)-maxy/8;
917 /* updateState() will fix bounds */
924 void updateColorIndex(int **tColorIdx, int *tci0, int *tnc,
925 int **colorIdx, int *ci0, int *nc) {
926 switch(colorScheme) {
928 *tColorIdx = redIndex;
931 *colorIdx = blueIndex;
937 *tColorIdx = graySIndex;
940 *colorIdx = graySIndex;
946 *tColorIdx = redSIndex;
949 *colorIdx = blueSIndex;
955 *tColorIdx = grayIndex;
958 *colorIdx = grayIndex;
964 *tColorIdx = redIndex;
967 *colorIdx = randomIndex;
973 *tColorIdx = redIndex;
976 *colorIdx = randomIndex;
983 #if HAVE_GETTIMEOFDAY
984 static struct timeval startupTime;
985 static void initTime(void) {
986 #if GETTIMEOFDAY_TWO_ARGS
987 gettimeofday(&startupTime, NULL);
989 gettimeofday(&startupTime);
993 static double getTime(void) {
996 #if GETTIMEOFDAY_TWO_ARGS
997 gettimeofday(&t, NULL);
1001 t.tv_sec -= startupTime.tv_sec;
1002 f = ((double)t.tv_sec) + t.tv_usec*1e-6;
1007 void screenhack(Display *d, Window w) {
1010 float timePerFrame, elapsed;
1011 int *targetColorIndex, *colorIndex;
1012 int targetStartColor, targetNumColors;
1013 int startColor, numColors;
1022 if (!initGraphics()) return;
1027 computeColorIndices();
1029 if (changeProb > 0) {
1030 for (i = random()%5+5; i >= 0; i--) {
1031 randomSmallChange();
1036 #if HAVE_GETTIMEOFDAY
1049 for (; cnt > 0; cnt--) {
1051 updateColorIndex(&targetColorIndex, &targetStartColor, &targetNumColors,
1052 &colorIndex, &startColor, &numColors);
1053 drawBugs(targetColorIndex, targetStartColor, targetNumColors,
1054 colorIndex, startColor, numColors);
1056 screenhack_handle_events (dpy);
1058 #if HAVE_GETTIMEOFDAY
1062 if (end > start+0.5) {
1063 if (frand(1.0) < changeProb) randomSmallChange();
1064 if (frand(1.0) < changeProb*0.3) randomBigChange();
1065 elapsed = end-start;
1067 timePerFrame = elapsed/nframes - delay*1e-6;
1068 fps = nframes/elapsed;
1070 printf("elapsed: %.3f\n", elapsed);
1071 printf("fps: %.1f secs per frame: %.3f delay: %f\n",
1072 fps, timePerFrame, delay);
1075 if (fps > MAX_FPS) {
1076 delay = (1.0/MAX_FPS - (timePerFrame + delay*1e-6))*1e6;
1077 } else if (dt*fps < MIN_FPS*DESIRED_DT) {
1078 /* need to speed things up somehow */
1079 if (0 && nbugs > 10) {
1080 /*printf("reducing bugs to improve speed.\n");*/
1082 nbugs *= fps/MIN_FPS;
1083 if (ntargets >= nbugs/2) mutateBug(1);
1084 } else if (0 && dt < 0.3) {
1085 /*printf("increasing dt to improve speed.\n");*/
1088 } else if (trailLen > 10) {
1089 /*printf("reducing trail length to improve speed.\n");*/
1091 trailLen = trailLen * (fps/MIN_FPS);
1092 if (trailLen < 10) trailLen = 10;
1093 computeColorIndices();
1102 if (frand(1) < changeProb*2/100.0) randomSmallChange();
1103 if (frand(1) < changeProb*0.3/100.0) randomBigChange();
1106 if (delay > 10000) usleep(delay);
1108 delayAccum += delay;
1109 if (delayAccum > 10000) {
1114 if (++sleepCount > 2) {