source: trunk/third/xscreensaver/hacks/xrayswarm.c @ 20158

Revision 20158, 25.8 KB checked in by ghudson, 21 years ago (diff)
Merge with xscreensaver 4.14.
Line 
1/*
2 * Copyright (c) 2000 by Chris Leger (xrayjones@users.sourceforge.net)
3 *
4 * xrayswarm - a shameless ripoff of the 'swarm' screensaver on SGI
5 *   boxes.
6 *
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
11 *   be used.)
12 *
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.
15 *
16 */
17/*
18Permission is hereby granted, free of charge, to any person obtaining
19a copy of this software and associated documentation files (the
20"Software"), to deal in the Software without restriction, including
21without limitation the rights to use, copy, modify, merge, publish,
22distribute, sublicense, and/or sell copies of the Software, and to
23permit persons to whom the Software is furnished to do so, subject to
24the following conditions:
25
26The above copyright notice and this permission notice shall be included
27in all copies or substantial portions of the Software.
28
29THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
30OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
33OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
34ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35OTHER DEALINGS IN THE SOFTWARE.
36
37Except as contained in this notice, the name of the X Consortium shall
38not be used in advertising or otherwise to promote the sale, use or
39other dealings in this Software without prior written authorization
40from the X Consortium.
41*/
42
43#include <math.h>
44#include <sys/time.h>
45#include "screenhack.h"
46#include "config.h"
47
48
49/**********************************************************************
50 *                                                                     
51 * window crap
52 *
53 **********************************************************************/
54
55char *progclass="xrayswarm";
56
57char *defaults [] ={
58        ".background:           black",
59        "*delay:                0",
60        0
61};
62
63XrmOptionDescRec options [] = {
64        {"-delay",".delay",XrmoptionSepArg,0},
65        {0,0,0,0}
66};
67
68static unsigned char colors[768];
69
70static Display *dpy;
71static Window win;
72static GC fgc[256];
73static GC cgc;
74static int xsize, ysize;
75static int xc, yc;
76static unsigned long delay;
77static float maxx, maxy;
78
79/**********************************************************************
80 *                                                                     
81 * bug structs & variables
82 *
83 **********************************************************************/
84#define MAX_TRAIL_LEN 60
85#define MAX_BUGS 100
86#define MAX_TARGETS 10
87#define sq(x) ((x)*(x))
88
89#define MAX_FPS 150
90#define MIN_FPS 16
91#define DESIRED_DT 0.2
92
93typedef struct _sbug {
94  float pos[3];
95  int hist[MAX_TRAIL_LEN][2];
96  float vel[2];
97  struct _sbug *closest;
98} bug;
99
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 */ 
107
108static float dt = 0.3;
109static float targetVel = 0.03;
110static float targetAcc = 0.02;
111static float maxVel = 0.05;
112static float maxAcc = 0.03;
113static float noise = 0.01;
114static float minVelMultiplier = 0.5;
115
116static int nbugs = -1;
117static int ntargets = -1;
118static int trailLen = -1;
119
120/* vars dependent on those above */
121static float dtInv;
122static float halfDtSq;
123static float targetVelSq;
124static float maxVelSq;
125static float minVelSq;
126static float minVel;
127
128static bug bugs[MAX_BUGS];
129static bug targets[MAX_TARGETS];
130static int head = 0;
131static int tail = 0;
132static int colorScheme = -1;
133static float changeProb = 0.08;
134
135static int grayIndex[MAX_TRAIL_LEN];
136static int redIndex[MAX_TRAIL_LEN];
137static int blueIndex[MAX_TRAIL_LEN];
138static int graySIndex[MAX_TRAIL_LEN];
139static int redSIndex[MAX_TRAIL_LEN];
140static int blueSIndex[MAX_TRAIL_LEN];
141static int randomIndex[MAX_TRAIL_LEN];
142static int numColors;
143static int numRandomColors;
144
145typedef struct {
146  float dt;
147  float targetVel;
148  float targetAcc;
149  float maxVel;
150  float maxAcc;
151  float noise;
152
153  int nbugs;
154  int ntargets;
155  int trailLen;
156  int colorScheme;
157  int changeProb;
158} bugParams;
159
160bugParams good1 = {
161  0.3,  /* dt */
162  0.03,  /* targetVel */
163  0.02,  /* targetAcc */
164  0.05,  /* maxVel */
165  0.03,  /* maxAcc */
166  0.01,  /* noise */
167  -1,    /* nbugs */
168  -1,     /* ntargets */
169  60,    /* trailLen */
170  2,     /* colorScheme */
171  0.15  /* changeProb */
172};
173
174bugParams *goodParams[] = {
175&good1
176};
177
178int numParamSets = 1;
179
180void initCMap(void) {
181  int i, n;
182  int temp;
183
184  n = 0;
185
186  /* color 0 is black */
187  colors[n++] = 0;
188  colors[n++] = 0;
189  colors[n++] = 0;
190
191  /* color 1 is red */
192  colors[n++] = 255;
193  colors[n++] = 0;
194  colors[n++] = 0;
195
196  /* color 2 is green */
197  colors[n++] = 255;
198  colors[n++] = 0;
199  colors[n++] = 0;
200
201  /* color 3 is blue */
202  colors[n++] = 255;
203  colors[n++] = 0;
204  colors[n++] = 0;
205
206  /* start greyscale colors at 4; 16 levels */
207  for (i = 0; i < 16; i++) {
208    temp = i*16;
209    if (temp > 255) temp = 255;
210    colors[n++] = 255 - temp;
211    colors[n++] = 255 - temp;
212    colors[n++] = 255 - temp;
213  }
214
215  /* start red fade at 20; 16 levels */
216  for (i = 0; i < 16; i++) {
217    temp = i*16;
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;
222  }
223
224  /* start blue fade at 36; 16 levels */
225  for (i = 0; i < 16; i++) {
226    temp = i*16;
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;
231  }
232
233  /* random colors start at 52 */
234  numRandomColors = MAX_TRAIL_LEN;
235
236  colors[n] = random()&255; n++;
237  colors[n] = random()&255; n++;
238  colors[n] = colors[n-2]/2 + colors[n-3]/2; n++;
239
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++;
244  }
245 
246  numColors = n/3 + 1;
247}
248
249static int initGraphics(void) {
250  XGCValues xgcv;
251  XWindowAttributes xgwa;
252  XSetWindowAttributes xswa;
253  Colormap cmap;
254  XColor color;
255  int n, i;
256 
257  initCMap();
258
259  XGetWindowAttributes(dpy,win,&xgwa);
260  cmap=xgwa.colormap;
261  xswa.backing_store=Always;
262  XChangeWindowAttributes(dpy,win,CWBackingStore,&xswa);
263  xgcv.function=GXcopy;
264
265  delay = get_integer_resource("delay","Integer");
266 
267  xgcv.foreground=get_pixel_resource ("background", "Background", dpy, cmap);
268  fgc[0]=XCreateGC(dpy, win, GCForeground|GCFunction,&xgcv);
269 
270  n=0;
271  if (mono_p) {
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];
276  } else {
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      if (XAllocColor(dpy,cmap,&color)) {
283        xgcv.foreground=color.pixel;
284        fgc[i] = XCreateGC(dpy, win, GCForeground | GCFunction,&xgcv);
285      } else {
286        fgc[i] = fgc[i%2];
287      }
288    }
289  }
290  cgc = XCreateGC(dpy,win,GCForeground|GCFunction,&xgcv);
291  XSetGraphicsExposures(dpy,cgc,False);
292
293  xsize = xgwa.width;
294  ysize = xgwa.height;
295  xc = xsize >> 1;
296  yc = ysize >> 1;
297
298  maxx = 1.0;
299  maxy = ysize/(float)xsize;
300
301  if (colorScheme < 0) colorScheme = random()%NUM_SCHEMES;
302
303  return True;
304}
305
306static void initBugs(void) {
307  register bug *b;
308  int i;
309
310  head = tail = 0;
311
312  memset((char *)bugs, 0,MAX_BUGS*sizeof(bug));
313  memset((char *)targets, 0, MAX_TARGETS*sizeof(bug));
314
315  if (ntargets < 0) ntargets = (0.25+frand(0.75)*frand(1))*MAX_TARGETS;
316  if (ntargets < 1) ntargets = 1;
317
318  if (nbugs < 0) nbugs = (0.25+frand(0.75)*frand(1))*MAX_BUGS;
319  if (nbugs <= ntargets) nbugs = ntargets+1;
320
321  if (trailLen < 0) {
322    trailLen = (1.0 - frand(0.6)*frand(1))*MAX_TRAIL_LEN;
323  }
324
325  if (nbugs > MAX_BUGS) nbugs = MAX_BUGS;
326  if (ntargets > MAX_TARGETS) ntargets = MAX_TARGETS;
327  if (trailLen > MAX_TRAIL_LEN) trailLen = MAX_TRAIL_LEN;
328
329  b = bugs;
330  for (i = 0; i < nbugs; i++, b++) {
331    b->pos[0] = frand(maxx);
332    b->pos[1] = frand(maxy);
333    b->vel[0] = frand(maxVel/2);
334    b->vel[1] = frand(maxVel/2);
335
336    b->hist[head][0] = b->pos[0]*xsize;
337    b->hist[head][1] = b->pos[1]*xsize;
338    b->closest = &targets[random()%ntargets];
339  }
340
341  b = targets;
342  for (i = 0; i < ntargets; i++, b++) {
343    b->pos[0] = frand(maxx);
344    b->pos[1] = frand(maxy);
345
346    b->vel[0] = frand(targetVel/2);
347    b->vel[1] = frand(targetVel/2);
348
349    b->hist[head][0] = b->pos[0]*xsize;
350    b->hist[head][1] = b->pos[1]*xsize;
351  }
352}
353
354static void pickNewTargets(void) {
355  register int i;
356  register bug *b;
357
358  b = bugs;
359  for (i = 0; i < nbugs; i++, b++) {
360    b->closest = &targets[random()%ntargets];
361  }
362}
363
364#if 0
365static void addBugs(int numToAdd) {
366  register bug *b;
367  int i;
368
369  if (numToAdd + nbugs > MAX_BUGS) numToAdd = MAX_BUGS-nbugs;
370  else if (numToAdd < 0) numToAdd = 0;
371
372  for (i = 0; i < numToAdd; i++) {
373    b = &bugs[random()%nbugs];
374    memcpy((char *)&bugs[nbugs+i], (char *)b, sizeof(bug));
375    b->closest = &targets[random()%ntargets];
376  }
377
378  nbugs += numToAdd;
379}
380
381static void addTargets(int numToAdd) {
382  register bug *b;
383  int i;
384
385  if (numToAdd + ntargets > MAX_TARGETS) numToAdd = MAX_TARGETS-ntargets;
386  else if (numToAdd < 0) numToAdd = 0;
387
388  for (i = 0; i < numToAdd; i++) {
389    b = &targets[random()%ntargets];
390    memcpy((char *)&targets[ntargets+i], (char *)b, sizeof(bug));
391    b->closest = &targets[random()%ntargets];
392  }
393
394  ntargets += numToAdd;
395}
396#endif
397
398static void computeConstants(void) {
399  halfDtSq = dt*dt*0.5;
400  dtInv = 1.0/dt;
401  targetVelSq = targetVel*targetVel;
402  maxVelSq = maxVel*maxVel;
403  minVel = maxVel*minVelMultiplier;
404  minVelSq = minVel*minVel;
405}
406
407void computeColorIndices(void) {
408  int i;
409  int schizoLength;
410
411  /* note: colors are used in *reverse* order! */
412
413  /* grayscale */
414  for (i = 0; i < trailLen; i++) {
415    grayIndex[trailLen-1-i] = 4 + i*16.0/trailLen + 0.5;
416    if (grayIndex[trailLen-1-i] > 19) grayIndex[trailLen-1-i] = 19;
417  }
418
419  /* red */
420  for (i = 0; i < trailLen; i++) {
421    redIndex[trailLen-1-i] = 20 + i*16.0/trailLen + 0.5;
422    if (redIndex[trailLen-1-i] > 35) redIndex[trailLen-1-i] = 35;
423  }
424
425  /* blue */
426  for (i = 0; i < trailLen; i++) {
427    blueIndex[trailLen-1-i] = 36 + i*16.0/trailLen + 0.5;
428    if (blueIndex[trailLen-1-i] > 51) blueIndex[trailLen-1-i] = 51;
429  }
430
431  /* gray schizo - same as gray*/
432  for (i = 0; i < trailLen; i++) {
433    graySIndex[trailLen-1-i] = 4 + i*16.0/trailLen + 0.5;
434    if (graySIndex[trailLen-1-i] > 19) graySIndex[trailLen-1-i] = 19;
435  }
436
437  schizoLength = trailLen/4;
438  if (schizoLength < 3) schizoLength = 3;
439  /* red schizo */
440  for (i = 0; i < trailLen; i++) {
441    /*    redSIndex[trailLen-1-i] =
442          20 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;*/
443    redSIndex[trailLen-1-i] = 20 + i*16.0/trailLen + 0.5;
444    if (redSIndex[trailLen-1-i] > 35) redSIndex[trailLen-1-i] = 35;
445  }
446
447  schizoLength = trailLen/2;
448  if (schizoLength < 3) schizoLength = 3;
449  /* blue schizo is next */
450  for (i = 0; i < trailLen; i++) {
451    blueSIndex[trailLen-1-i] =
452      36 + 16.0*(i%schizoLength)/(schizoLength-1.0) + 0.5;
453    if (blueSIndex[trailLen-1-i] > 51) blueSIndex[trailLen-1-i] = 51;
454  }
455
456  /* random is next */
457  for (i = 0; i < trailLen; i++) {
458    randomIndex[i] = 52 + random()%(numRandomColors);
459  }
460}
461
462#if 0
463static void setParams(bugParams *p) {
464  dt = p->dt;
465  targetVel = p->targetVel;
466  targetAcc = p->targetAcc;
467  maxVel = p->maxVel;
468  maxAcc = p->maxAcc;
469  noise = p->noise;
470
471  nbugs = p->nbugs;
472  ntargets = p->ntargets;
473  trailLen = p->trailLen;
474  colorScheme = p->colorScheme;
475  changeProb = p->changeProb;
476  computeConstants();
477  computeColorIndices();
478}
479#endif
480
481static void drawBugs(int *tColorIdx, int tci0, int tnc,
482                     int *colorIdx, int ci0, int nc) {
483  register bug *b;
484  register int i, j;
485  int temp;
486
487  if (((head+1)%trailLen) == tail) {
488    /* first, erase last segment of bugs if necessary */
489    temp = (tail+1) % trailLen;
490   
491    b = bugs;
492    for (i = 0; i < nbugs; i++, b++) {
493      XDrawLine(dpy, win, fgc[0],
494                b->hist[tail][0], b->hist[tail][1],
495                b->hist[temp][0], b->hist[temp][1]);
496    }
497 
498    b = targets;
499    for (i = 0; i < ntargets; i++, b++) {
500      XDrawLine(dpy, win, fgc[0],
501                b->hist[tail][0], b->hist[tail][1],
502                b->hist[temp][0], b->hist[temp][1]);
503    }
504    tail = (tail+1)%trailLen;
505  }
506 
507  for (j = tail; j != head; j = temp) {
508    temp = (j+1)%trailLen;
509
510    b = bugs;
511    for (i = 0; i < nbugs; i++, b++) {
512      XDrawLine(dpy, win, fgc[colorIdx[ci0]],
513                b->hist[j][0], b->hist[j][1],
514                b->hist[temp][0], b->hist[temp][1]);
515    }
516   
517    b = targets;
518    for (i = 0; i < ntargets; i++, b++) {
519      XDrawLine(dpy, win, fgc[tColorIdx[tci0]],
520                b->hist[j][0], b->hist[j][1],
521                b->hist[temp][0], b->hist[temp][1]);
522    }
523    ci0 = (ci0+1)%nc; 
524    tci0 = (tci0+1)%tnc; 
525  }
526}
527
528static void clearBugs(void) {
529  register bug *b;
530  register int i, j;
531  int temp;
532
533  tail = tail-1;
534  if (tail < 0) tail = trailLen-1;
535
536  if (((head+1)%trailLen) == tail) {
537    /* first, erase last segment of bugs if necessary */
538    temp = (tail+1) % trailLen;
539   
540    b = bugs;
541    for (i = 0; i < nbugs; i++, b++) {
542      XDrawLine(dpy, win, fgc[0],
543                b->hist[tail][0], b->hist[tail][1],
544                b->hist[temp][0], b->hist[temp][1]);
545    }
546 
547    b = targets;
548    for (i = 0; i < ntargets; i++, b++) {
549      XDrawLine(dpy, win, fgc[0],
550                b->hist[tail][0], b->hist[tail][1],
551                b->hist[temp][0], b->hist[temp][1]);
552    }
553    tail = (tail+1)%trailLen;
554  }
555 
556  for (j = tail; j != head; j = temp) {
557    temp = (j+1)%trailLen;
558
559    b = bugs;
560    for (i = 0; i < nbugs; i++, b++) {
561      XDrawLine(dpy, win, fgc[0],
562                b->hist[j][0], b->hist[j][1],
563                b->hist[temp][0], b->hist[temp][1]);
564    }
565   
566    b = targets;
567    for (i = 0; i < ntargets; i++, b++) {
568      XDrawLine(dpy, win, fgc[0],
569                b->hist[j][0], b->hist[j][1],
570                b->hist[temp][0], b->hist[temp][1]);
571    }
572  }
573}
574
575void updateState(void) {
576  register int i;
577  register bug *b;
578  register float ax, ay, temp;
579  float theta;
580  static int checkIndex = 0;
581  bug *b2;
582  int j;
583
584  head = (head+1)%trailLen;
585 
586  for (j = 0; j < 5; j++) {
587    /* update closets bug for the bug indicated by checkIndex */
588    checkIndex = (checkIndex+1)%nbugs;
589    b = &bugs[checkIndex];
590
591    ax = b->closest->pos[0] - b->pos[0];
592    ay = b->closest->pos[1] - b->pos[1];
593    temp = ax*ax + ay*ay;
594    for (i = 0; i < ntargets; i++) {
595      b2 = &targets[i];
596      if (b2 == b->closest) continue;
597      ax = b2->pos[0] - b->pos[0];
598      ay = b2->pos[1] - b->pos[1];
599      theta = ax*ax + ay*ay;
600      if (theta < temp*2) {
601        b->closest = b2;
602        temp = theta;
603      }
604    }
605  }
606 
607  /* update target state */
608
609  b = targets;
610  for (i = 0; i < ntargets; i++, b++) {
611    theta = frand(6.28);
612    ax = targetAcc*cos(theta);
613    ay = targetAcc*sin(theta);
614
615    b->vel[0] += ax*dt;
616    b->vel[1] += ay*dt;
617
618    /* check velocity */
619    temp = sq(b->vel[0]) + sq(b->vel[1]);
620    if (temp > targetVelSq) {
621      temp = targetVel/sqrt(temp);
622      /* save old vel for acc computation */
623      ax = b->vel[0];
624      ay = b->vel[1];
625
626      /* compute new velocity */
627      b->vel[0] *= temp;
628      b->vel[1] *= temp;
629     
630      /* update acceleration */
631      ax = (b->vel[0]-ax)*dtInv;
632      ay = (b->vel[1]-ay)*dtInv;
633    }
634
635    /* update position */
636    b->pos[0] += b->vel[0]*dt + ax*halfDtSq;
637    b->pos[1] += b->vel[1]*dt + ay*halfDtSq;
638
639    /* check limits on targets */
640    if (b->pos[0] < 0) {
641      /* bounce */
642      b->pos[0] = -b->pos[0];
643      b->vel[0] = -b->vel[0];
644    } else if (b->pos[0] >= maxx) {
645      /* bounce */
646      b->pos[0] = 2*maxx-b->pos[0];
647      b->vel[0] = -b->vel[0];
648    }
649    if (b->pos[1] < 0) {
650      /* bounce */
651      b->pos[1] = -b->pos[1];
652      b->vel[1] = -b->vel[1];
653    } else if (b->pos[1] >= maxy) {
654      /* bounce */
655      b->pos[1] = 2*maxy-b->pos[1];
656      b->vel[1] = -b->vel[1];
657    }
658
659    b->hist[head][0] = b->pos[0]*xsize;
660    b->hist[head][1] = b->pos[1]*xsize;
661  }
662
663  /* update bug state */
664  b = bugs;
665  for (i = 0; i < nbugs; i++, b++) {
666    theta = atan2(b->closest->pos[1] - b->pos[1] + frand(noise),
667                  b->closest->pos[0] - b->pos[0] + frand(noise));
668    ax = maxAcc*cos(theta);
669    ay = maxAcc*sin(theta);
670
671    b->vel[0] += ax*dt;
672    b->vel[1] += ay*dt;
673
674    /* check velocity */
675    temp = sq(b->vel[0]) + sq(b->vel[1]);
676    if (temp > maxVelSq) {
677      temp = maxVel/sqrt(temp);
678
679      /* save old vel for acc computation */
680      ax = b->vel[0];
681      ay = b->vel[1];
682
683      /* compute new velocity */
684      b->vel[0] *= temp;
685      b->vel[1] *= temp;
686     
687      /* update acceleration */
688      ax = (b->vel[0]-ax)*dtInv;
689      ay = (b->vel[1]-ay)*dtInv;
690    } else if (temp < minVelSq) {
691      temp = minVel/sqrt(temp);
692
693      /* save old vel for acc computation */
694      ax = b->vel[0];
695      ay = b->vel[1];
696
697      /* compute new velocity */
698      b->vel[0] *= temp;
699      b->vel[1] *= temp;
700     
701      /* update acceleration */
702      ax = (b->vel[0]-ax)*dtInv;
703      ay = (b->vel[1]-ay)*dtInv;
704    }
705
706    /* update position */
707    b->pos[0] += b->vel[0]*dt + ax*halfDtSq;
708    b->pos[1] += b->vel[1]*dt + ay*halfDtSq;
709
710    /* check limits on targets */
711    if (b->pos[0] < 0) {
712      /* bounce */
713      b->pos[0] = -b->pos[0];
714      b->vel[0] = -b->vel[0];
715    } else if (b->pos[0] >= maxx) {
716      /* bounce */
717      b->pos[0] = 2*maxx-b->pos[0];
718      b->vel[0] = -b->vel[0];
719    }
720    if (b->pos[1] < 0) {
721      /* bounce */
722      b->pos[1] = -b->pos[1];
723      b->vel[1] = -b->vel[1];
724    } else if (b->pos[1] >= maxy) {
725      /* bounce */
726      b->pos[1] = 2*maxy-b->pos[1];
727      b->vel[1] = -b->vel[1];
728    }
729
730    b->hist[head][0] = b->pos[0]*xsize;
731    b->hist[head][1] = b->pos[1]*xsize;
732  }
733}
734
735void mutateBug(int which) {
736  int i, j;
737
738  if (which == 0) {
739    /* turn bug into target */
740    if (ntargets < MAX_TARGETS-1 && nbugs > 1) {
741      i = random() % nbugs;
742      memcpy((char *)&targets[ntargets], (char *)&bugs[i], sizeof(bug));
743      memcpy((char *)&bugs[i], (char *)&bugs[nbugs-1], sizeof(bug));
744      targets[ntargets].pos[0] = frand(maxx);
745      targets[ntargets].pos[1] = frand(maxy);
746      nbugs--;
747      ntargets++;
748
749      for (i = 0; i < nbugs; i += ntargets) {
750        bugs[i].closest = &targets[ntargets-1];
751      }
752    }
753  } else {
754    /* turn target into bug */
755    if (ntargets > 1 && nbugs < MAX_BUGS-1) {
756      /* pick a target */
757      i = random() % ntargets;
758
759      /* copy state into a new bug */
760      memcpy((char *)&bugs[nbugs], (char *)&targets[i], sizeof(bug));
761      ntargets--;
762
763      /* pick a target for the new bug */
764      bugs[nbugs].closest = &targets[random()%ntargets];
765
766      for (j = 0; j < nbugs; j++) {
767        if (bugs[j].closest == &targets[ntargets]) {
768          bugs[j].closest = &targets[i];
769        } else if (bugs[j].closest == &targets[i]) {
770          bugs[j].closest = &targets[random()%ntargets];
771        }
772      }
773      nbugs++;
774     
775      /* copy the last ntarget into the one we just deleted */
776      memcpy(&targets[i], (char *)&targets[ntargets], sizeof(bug));
777    }
778  }
779}
780
781void mutateParam(float *param) {
782  *param *= 0.75+frand(0.5);
783}
784
785void randomSmallChange(void) {
786  int whichCase = 0;
787  static int callDepth = 0;
788
789  whichCase = random()%11;
790
791  if (++callDepth > 10) {
792    callDepth--;
793    return;
794  }
795 
796  switch(whichCase) {
797  case 0:
798    /* acceleration */
799    mutateParam(&maxAcc);
800    break;
801
802  case 1:
803    /* target acceleration */
804    mutateParam(&targetAcc);
805    break;
806
807  case 2:
808    /* velocity */
809    mutateParam(&maxVel);
810    break;
811
812  case 3:
813    /* target velocity */
814    mutateParam(&targetVel);
815    break;
816
817  case 4:
818    /* noise */
819    mutateParam(&noise);
820    break;
821
822  case 5:
823    /* minVelMultiplier */
824    mutateParam(&minVelMultiplier);
825    break;
826   
827  case 6:
828  case 7:
829    /* target to bug */
830    if (ntargets < 2) break;
831    mutateBug(1);
832    break;
833
834  case 8:
835    /* bug to target */
836    if (nbugs < 2) break;
837    mutateBug(0);
838    if (nbugs < 2) break;
839    mutateBug(0);
840    break;
841
842  case 9:
843    /* color scheme */
844    colorScheme = random()%NUM_SCHEMES;
845    if (colorScheme == RANDOM_SCHIZO || colorScheme == COLOR_SCHIZO) {
846      /* don't use these quite as much */
847      colorScheme = random()%NUM_SCHEMES;
848    }
849    break;
850
851  default:
852    randomSmallChange();
853    randomSmallChange();
854    randomSmallChange();
855    randomSmallChange();
856  }
857
858  if (minVelMultiplier < 0.3) minVelMultiplier = 0.3;
859  else if (minVelMultiplier > 0.9) minVelMultiplier = 0.9;
860  if (noise < 0.01) noise = 0.01;
861  if (maxVel < 0.02) maxVel = 0.02;
862  if (targetVel < 0.02) targetVel = 0.02;
863  if (targetAcc > targetVel*0.7) targetAcc = targetVel*0.7;
864  if (maxAcc > maxVel*0.7) maxAcc = maxVel*0.7;
865  if (targetAcc > targetVel*0.7) targetAcc = targetVel*0.7;
866  if (maxAcc < 0.01) maxAcc = 0.01;
867  if (targetAcc < 0.005) targetAcc = 0.005;
868
869  computeConstants();
870  callDepth--;
871}
872
873void randomBigChange(void) {
874  static int whichCase = 0;
875  static int callDepth = 0;
876  int temp;
877
878  whichCase = random()%4;
879 
880  if (++callDepth > 3) {
881    callDepth--;
882    return;
883  }
884
885  switch(whichCase) {
886  case 0:
887    /* trail length */
888    temp = (random()%(MAX_TRAIL_LEN-25)) + 25;
889    clearBugs();
890    trailLen = temp;
891    computeColorIndices();
892    initBugs();
893    break;
894
895  case 1: 
896    /* Whee! */
897    randomSmallChange();
898    randomSmallChange();
899    randomSmallChange();
900    randomSmallChange();
901    randomSmallChange();
902    randomSmallChange();
903    randomSmallChange();
904    randomSmallChange();
905    break;
906
907  case 2:
908    clearBugs();
909    initBugs();
910    break;
911   
912  case 3:
913    pickNewTargets();
914    break;
915   
916  default:
917    temp = random()%ntargets;
918    targets[temp].pos[0] += frand(maxx/4)-maxx/8;
919    targets[temp].pos[1] += frand(maxy/4)-maxy/8;
920    /* updateState() will fix bounds */
921    break;
922  }
923
924  callDepth--;
925}
926
927void updateColorIndex(int **tColorIdx, int *tci0, int *tnc,
928                      int **colorIdx, int *ci0, int *nc) {
929  switch(colorScheme) {
930  case COLOR_TRAILS:
931    *tColorIdx = redIndex;
932    *tci0 = 0;
933    *tnc = trailLen;
934    *colorIdx = blueIndex;
935    *ci0 = 0;
936    *nc = trailLen;
937    break;
938
939  case GRAY_SCHIZO:
940    *tColorIdx = graySIndex;
941    *tci0 = head;
942    *tnc = trailLen;
943    *colorIdx = graySIndex;
944    *ci0 = head;
945    *nc = trailLen;
946    break;
947
948  case COLOR_SCHIZO:
949    *tColorIdx = redSIndex;
950    *tci0 = head;
951    *tnc = trailLen;
952    *colorIdx = blueSIndex;
953    *ci0 = head;
954    *nc = trailLen;
955    break;
956
957  case GRAY_TRAILS:
958    *tColorIdx = grayIndex;
959    *tci0 = 0;
960    *tnc = trailLen;
961    *colorIdx = grayIndex;
962    *ci0 = 0;
963    *nc = trailLen;
964    break;
965
966  case RANDOM_TRAILS:
967    *tColorIdx = redIndex;
968    *tci0 = 0;
969    *tnc = trailLen;
970    *colorIdx = randomIndex;
971    *ci0 = 0;
972    *nc = trailLen;
973    break;
974
975  case RANDOM_SCHIZO:
976    *tColorIdx = redIndex;
977    *tci0 = head;
978    *tnc = trailLen;
979    *colorIdx = randomIndex;
980    *ci0 = head;
981    *nc = trailLen;
982    break;
983  }
984}
985
986#if HAVE_GETTIMEOFDAY
987static struct timeval startupTime;
988static void initTime(void) {
989#if GETTIMEOFDAY_TWO_ARGS
990  gettimeofday(&startupTime, NULL);
991#else
992  gettimeofday(&startupTime);
993#endif
994}
995
996static double getTime(void) {
997  struct timeval t;
998  float f;
999#if GETTIMEOFDAY_TWO_ARGS
1000  gettimeofday(&t, NULL);
1001#else
1002  gettimeofday(&t);
1003#endif
1004  t.tv_sec -= startupTime.tv_sec;
1005  f = ((double)t.tv_sec) + t.tv_usec*1e-6;
1006  return f;
1007}
1008#endif
1009
1010void screenhack(Display *d, Window w) {
1011  int nframes, i;
1012  float fps;
1013  float timePerFrame, elapsed;
1014  int *targetColorIndex, *colorIndex;
1015  int targetStartColor, targetNumColors;
1016  int startColor, numColors;
1017  double start, end;
1018  int cnt;
1019  int sleepCount = 0;
1020  int delayAccum = 0;
1021
1022  dpy = d;
1023  win = w;
1024
1025  if (!initGraphics()) return;
1026
1027  computeConstants();
1028  initBugs();
1029  initTime();
1030  computeColorIndices();
1031
1032  if (changeProb > 0) {
1033    for (i = random()%5+5; i >= 0; i--) {
1034      randomSmallChange();
1035    }
1036  }
1037
1038  nframes = 0;
1039#if HAVE_GETTIMEOFDAY
1040  start = getTime();
1041#endif
1042
1043  while (1) {
1044    if (delay > 0) {
1045      cnt = 2;
1046      dt = DESIRED_DT/2;
1047    } else {
1048      cnt = 1;
1049      dt = DESIRED_DT;
1050    }
1051
1052    for (; cnt > 0; cnt--) {
1053      updateState();
1054      updateColorIndex(&targetColorIndex, &targetStartColor, &targetNumColors,
1055                       &colorIndex, &startColor, &numColors);
1056      drawBugs(targetColorIndex, targetStartColor, targetNumColors,
1057               colorIndex, startColor, numColors);
1058      XSync(dpy, False);
1059      screenhack_handle_events (dpy);
1060    }
1061#if HAVE_GETTIMEOFDAY
1062    end = getTime();
1063    nframes++;
1064
1065    if (end > start+0.5) {
1066      if (frand(1.0) < changeProb) randomSmallChange();
1067      if (frand(1.0) < changeProb*0.3) randomBigChange();
1068      elapsed = end-start;
1069       
1070      timePerFrame = elapsed/nframes - delay*1e-6;
1071      fps = nframes/elapsed;
1072      /*
1073      printf("elapsed: %.3f\n", elapsed);
1074      printf("fps: %.1f  secs per frame: %.3f  delay: %f\n",
1075             fps, timePerFrame, delay);
1076      */
1077
1078      if (fps > MAX_FPS) {
1079        delay = (1.0/MAX_FPS - (timePerFrame + delay*1e-6))*1e6;
1080      } else if (dt*fps < MIN_FPS*DESIRED_DT) {
1081        /* need to speed things up somehow */
1082        if (0 && nbugs > 10) {
1083          /*printf("reducing bugs to improve speed.\n");*/
1084          clearBugs();
1085          nbugs *= fps/MIN_FPS;
1086          if (ntargets >= nbugs/2) mutateBug(1);
1087        } else if (0 && dt < 0.3) {
1088          /*printf("increasing dt to improve speed.\n");*/
1089          dt *= MIN_FPS/fps;
1090          computeConstants();
1091        } else if (trailLen > 10) {
1092          /*printf("reducing trail length to improve speed.\n");*/
1093          clearBugs();
1094          trailLen = trailLen * (fps/MIN_FPS);
1095          if (trailLen < 10) trailLen = 10;
1096          computeColorIndices();
1097          initBugs();
1098        }
1099      }
1100
1101      start = getTime();
1102      nframes = 0;
1103    }
1104#else
1105    if (frand(1) < changeProb*2/100.0) randomSmallChange();
1106    if (frand(1) < changeProb*0.3/100.0) randomBigChange();
1107#endif
1108   
1109    if (delay > 10000) usleep(delay);
1110    else {
1111      delayAccum += delay;
1112      if (delayAccum > 10000) {
1113        usleep(delayAccum);
1114        delayAccum = 0;
1115        sleepCount = 0;
1116      }
1117      if (++sleepCount > 2) {
1118        sleepCount = 0;
1119        usleep(10000);
1120      }
1121    }
1122  }
1123}
Note: See TracBrowser for help on using the repository browser.