http://se.aminet.net/pub/Linux/distributions/slackware/slackware-10.1/source/xap...
[xscreensaver] / hacks / galaxy.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* galaxy --- spinning galaxies */
3 /* #include<math.h>*/
4 #if 0
5 static const char sccsid[] = "@(#)galaxy.c 4.04 97/07/28 xlockmore";
6 #endif
7
8 /* Originally done by Uli Siegmund <uli@wombat.okapi.sub.org> on Amiga
9  *   for EGS in Cluster
10  * Port from Cluster/EGS to C/Intuition by Harald Backert
11  * Port to X11 and incorporation into xlockmore by Hubert Feyrer
12  *   <hubert.feyrer@rz.uni-regensburg.de>
13  *
14  * Permission to use, copy, modify, and distribute this software and its
15  * documentation for any purpose and without fee is hereby granted,
16  * provided that the above copyright notice appear in all copies and that
17  * both that copyright notice and this permission notice appear in
18  * supporting documentation.
19  *
20  * This file is provided AS IS with no warranties of any kind.  The author
21  * shall have no liability with respect to the infringement of copyrights,
22  * trade secrets or any patents by this file or any part thereof.  In no
23  * event will the author be liable for any lost revenue or profits or
24  * other special, indirect and consequential damages.
25  *
26  * Revision History:
27  * 26-Aug-00: robert.nagtegaal@phil.uu.nl and roland@tschai.demon.nl:
28  *            various improvements
29  * 10-May-97: jwz@jwz.org: turned into a standalone program.
30  * 18-Apr-97: Memory leak fixed by Tom Schmidt <tschmidt@micron.com>
31  * 07-Apr-97: Modified by Dave Mitchell <davem@magnet.com>
32  * 23-Oct-94: Modified by David Bagley <bagleyd@bigfoot.com>
33  *  random star sizes
34  *  colors change depending on velocity
35  * 10-Oct-94: Add colors by Hubert Feyer
36  * 30-Sep-94: Initial port by Hubert Feyer
37  * 09-Mar-94: VMS can generate a random number 0.0 which results in a
38  *            division by zero, corrected by Jouk Jansen
39  *            <joukj@crys.chem.uva.nl>
40  */
41
42 #ifdef STANDALONE
43 # define PROGCLASS     "Galaxy"
44 # define HACK_INIT     init_galaxy
45 # define HACK_DRAW     draw_galaxy
46 # define galaxy_opts    xlockmore_opts
47 # define DEFAULTS "*delay:  100  \n"   \
48      "*count:  -5   \n"   \
49      "*cycles:  250  \n"   \
50      "*size:   -3   \n"   \
51      "*ncolors:  64  \n"
52 # define UNIFORM_COLORS
53 # include "xlockmore.h"    /* from the xscreensaver distribution */
54 #else  /* !STANDALONE */
55 # include "xlock.h"     /* from the xlockmore distribution */
56 #endif /* !STANDALONE */
57
58 static Bool tracks;
59 static Bool spin;
60
61 #define DEF_TRACKS "True"
62 #define DEF_SPIN   "True"
63
64 static XrmOptionDescRec opts[] =
65 {
66  {"-tracks", ".galaxy.tracks", XrmoptionNoArg, "on"},
67  {"+tracks", ".galaxy.tracks", XrmoptionNoArg, "off"},
68  {"-spin",   ".galaxy.spin",   XrmoptionNoArg, "on"},
69  {"+spin",   ".galaxy.spin",   XrmoptionNoArg, "off"}
70 };
71
72 static argtype vars[] =
73 {
74  {&tracks, "tracks", "Tracks", DEF_TRACKS, t_Bool},
75  {&spin,   "spin",   "Spin",   DEF_SPIN,   t_Bool}
76 };
77
78 static OptionStruct desc[] =
79 {
80  {"-/+tracks", "turn on/off star tracks"},
81  {"-/+spin",   "do/don't spin viewpoint"}
82 };
83
84 ModeSpecOpt galaxy_opts = { 4, opts, 2, vars, desc };
85
86
87 #define FLOATRAND ((double) LRAND() / ((double) MAXRAND))
88
89 #if 0
90 #define WRAP       1  /* Warp around edges */
91 #define BOUNCE     1  /* Bounce from borders */
92 #endif
93
94 #define MINSIZE       1
95 #define MINGALAXIES    2
96 #define MAX_STARS    3000
97 #define MAX_IDELTAT    50
98 /* These come originally from the Cluster-version */
99 #define DEFAULT_GALAXIES  3
100 #define DEFAULT_STARS    1000
101 #define DEFAULT_HITITERATIONS  7500
102 #define DEFAULT_IDELTAT    200 /* 0.02 */
103 #define EPSILON 0.00000001
104
105 #define sqrt_EPSILON 0.0001
106
107 #define DELTAT (MAX_IDELTAT * 0.0001)
108
109 #define GALAXYRANGESIZE  0.1
110 #define GALAXYMINSIZE  0.15
111 #define QCONS    0.001
112
113
114 #define COLORBASE  16
115   /* Colors for stars start here */
116 #define COLORSTEP  (NUMCOLORS/COLORBASE) /* NUMCOLORS / COLORBASE colors
117 per galaxy */
118
119
120 typedef struct {
121  double      pos[3], vel[3];
122 } Star;
123
124
125 typedef struct {
126  int         mass;
127  int         nstars;
128  Star       *stars;
129  XPoint     *oldpoints;
130  XPoint     *newpoints;
131  double      pos[3], vel[3];
132  int         galcol;
133 } Galaxy;
134
135 typedef struct {
136  double      mat[3][3]; /* Movement of stars(?) */
137  double      scale; /* Scale */
138  int         midx; /* Middle of screen, x */
139  int         midy; /* Middle of screen, y */
140  double      size; /* */
141  double      diff[3]; /* */
142  Galaxy     *galaxies; /* the Whole Universe */
143  int         ngalaxies; /* # galaxies */
144  int         f_hititerations; /* # iterations before restart */
145  int         step; /* */
146  double      rot_y; /* rotation of eye around center of universe, around
147 y-axis*/
148  double      rot_x; /* rotation of eye around center of universe, around
149 x-axis */
150 } unistruct;
151
152 static unistruct *universes = NULL;
153
154 static void
155 free_galaxies(unistruct * gp)
156 {
157  if (gp->galaxies != NULL) {
158   int         i;
159
160   for (i = 0; i < gp->ngalaxies; i++) {
161    Galaxy     *gt = &gp->galaxies[i];
162
163    if (gt->stars != NULL)
164     (void) free((void *) gt->stars);
165    if (gt->oldpoints != NULL)
166        (void) free((void *) gt->oldpoints);
167    if (gt->newpoints != NULL)
168        (void) free((void *) gt->newpoints);
169   }
170   (void) free((void *) gp->galaxies);
171   gp->galaxies = NULL;
172  }
173 }
174
175 static void
176 startover(ModeInfo * mi)
177 {
178  unistruct  *gp = &universes[MI_SCREEN(mi)];
179  int         i, j; /* more tmp */
180  double      w1, w2; /* more tmp */
181  double      d, v, w, h; /* yet more tmp */
182
183  gp->step = 0;
184  gp->rot_y = 0;
185  gp->rot_x = 0;
186
187  if (MI_BATCHCOUNT(mi) < -MINGALAXIES)
188   free_galaxies(gp);
189  gp->ngalaxies = MI_BATCHCOUNT(mi);
190  if (gp->ngalaxies < -MINGALAXIES)
191   gp->ngalaxies = NRAND(-gp->ngalaxies - MINGALAXIES + 1) + MINGALAXIES;
192
193  else if (gp->ngalaxies < MINGALAXIES)
194   gp->ngalaxies = MINGALAXIES;
195  if (gp->galaxies == NULL)
196   gp->galaxies = (Galaxy *) calloc(gp->ngalaxies, sizeof (Galaxy));
197
198  for (i = 0; i < gp->ngalaxies; ++i) {
199   Galaxy     *gt = &gp->galaxies[i];
200   double      sinw1, sinw2, cosw1, cosw2;
201
202   gt->galcol = NRAND(COLORBASE - 2);
203   if (gt->galcol > 1)
204    gt->galcol += 2; /* Mult 8; 16..31 no green stars */
205   /* Galaxies still may have some green stars but are not all green. */
206
207   if (gt->stars != NULL) {
208    (void) free((void *) gt->stars);
209    gt->stars = NULL;
210   }
211   gt->nstars = (NRAND(MAX_STARS / 2)) + MAX_STARS / 2;
212   gt->stars = (Star *) malloc(gt->nstars * sizeof (Star));
213   gt->oldpoints = (XPoint *) malloc(gt->nstars * sizeof (XPoint));
214   gt->newpoints = (XPoint *) malloc(gt->nstars * sizeof (XPoint));
215
216   w1 = 2.0 * M_PI * FLOATRAND;
217   w2 = 2.0 * M_PI * FLOATRAND;
218   sinw1 = SINF(w1);
219   sinw2 = SINF(w2);
220   cosw1 = COSF(w1);
221   cosw2 = COSF(w2);
222
223   gp->mat[0][0] = cosw2;
224   gp->mat[0][1] = -sinw1 * sinw2;
225   gp->mat[0][2] = cosw1 * sinw2;
226   gp->mat[1][0] = 0.0;
227   gp->mat[1][1] = cosw1;
228   gp->mat[1][2] = sinw1;
229   gp->mat[2][0] = -sinw2;
230   gp->mat[2][1] = -sinw1 * cosw2;
231   gp->mat[2][2] = cosw1 * cosw2;
232
233   gt->vel[0] = FLOATRAND * 2.0 - 1.0;
234   gt->vel[1] = FLOATRAND * 2.0 - 1.0;
235   gt->vel[2] = FLOATRAND * 2.0 - 1.0;
236   gt->pos[0] = -gt->vel[0] * DELTAT * gp->f_hititerations + FLOATRAND -
237 0.5;
238   gt->pos[1] = -gt->vel[1] * DELTAT * gp->f_hititerations + FLOATRAND -
239 0.5;
240   gt->pos[2] = -gt->vel[2] * DELTAT * gp->f_hititerations + FLOATRAND -
241 0.5;
242
243   gt->mass = (int) (FLOATRAND * 1000.0) + 1;
244
245   gp->size = GALAXYRANGESIZE * FLOATRAND + GALAXYMINSIZE;
246
247   for (j = 0; j < gt->nstars; ++j) {
248    Star       *st = &gt->stars[j];
249    XPoint     *oldp = &gt->oldpoints[j];
250    XPoint     *newp = &gt->newpoints[j];
251
252    double      sinw, cosw;
253
254    w = 2.0 * M_PI * FLOATRAND;
255    sinw = SINF(w);
256    cosw = COSF(w);
257    d = FLOATRAND * gp->size;
258    h = FLOATRAND * exp(-2.0 * (d / gp->size)) / 5.0 * gp->size;
259    if (FLOATRAND < 0.5)
260     h = -h;
261    st->pos[0] = gp->mat[0][0] * d * cosw + gp->mat[1][0] * d * sinw +
262 gp->mat[2][0] * h + gt->pos[0];
263    st->pos[1] = gp->mat[0][1] * d * cosw + gp->mat[1][1] * d * sinw +
264 gp->mat[2][1] * h + gt->pos[1];
265    st->pos[2] = gp->mat[0][2] * d * cosw + gp->mat[1][2] * d * sinw +
266 gp->mat[2][2] * h + gt->pos[2];
267
268    v = sqrt(gt->mass * QCONS / sqrt(d * d + h * h));
269    st->vel[0] = -gp->mat[0][0] * v * sinw + gp->mat[1][0] * v * cosw +
270 gt->vel[0];
271    st->vel[1] = -gp->mat[0][1] * v * sinw + gp->mat[1][1] * v * cosw +
272 gt->vel[1];
273    st->vel[2] = -gp->mat[0][2] * v * sinw + gp->mat[1][2] * v * cosw +
274 gt->vel[2];
275
276    st->vel[0] *= DELTAT;
277    st->vel[1] *= DELTAT;
278    st->vel[2] *= DELTAT;
279
280    oldp->x = 0;
281    oldp->y = 0;
282    newp->x = 0;
283    newp->y = 0;
284   }
285
286  }
287
288  XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
289
290 #if 0
291  (void) printf("ngalaxies=%d, f_hititerations=%d\n", gp->ngalaxies,
292 gp->f_hititerations);
293  (void) printf("f_deltat=%g\n", DELTAT);
294  (void) printf("Screen: ");
295 #endif /*0 */
296 }
297
298 void
299 init_galaxy(ModeInfo * mi)
300 {
301  unistruct  *gp;
302
303  if (universes == NULL) {
304   if ((universes = (unistruct *) calloc(MI_NUM_SCREENS(mi),
305       sizeof (unistruct))) == NULL)
306    return;
307  }
308  gp = &universes[MI_SCREEN(mi)];
309
310  gp->f_hititerations = MI_CYCLES(mi);
311
312  gp->scale = (double) (MI_WIN_WIDTH(mi) + MI_WIN_HEIGHT(mi)) / 8.0;
313  gp->midx =  MI_WIN_WIDTH(mi)  / 2;
314  gp->midy =  MI_WIN_HEIGHT(mi) / 2;
315  startover(mi);
316 }
317
318 void
319 draw_galaxy(ModeInfo * mi)
320 {
321  Display    *display = MI_DISPLAY(mi);
322  Window      window = MI_WINDOW(mi);
323  GC          gc = MI_GC(mi);
324  unistruct  *gp = &universes[MI_SCREEN(mi)];
325  double      d, eps, cox, six, cor, sir;  /* tmp */
326  int         i, j, k; /* more tmp */
327     XPoint    *dummy = NULL;
328
329  if(spin){
330   gp->rot_y += 0.01;
331   gp->rot_x += 0.004;
332  }
333
334  cox = COSF(gp->rot_y);
335  six = SINF(gp->rot_y);
336     cor = COSF(gp->rot_x);
337     sir = SINF(gp->rot_x);
338
339     eps = 1/(EPSILON * sqrt_EPSILON * DELTAT * DELTAT * QCONS);
340
341  for (i = 0; i < gp->ngalaxies; ++i) {
342   Galaxy     *gt = &gp->galaxies[i];
343
344   for (j = 0; j < gp->galaxies[i].nstars; ++j) {
345    Star       *st = &gt->stars[j];
346    XPoint     *newp = &gt->newpoints[j];
347    double      v0 = st->vel[0];
348    double      v1 = st->vel[1];
349    double      v2 = st->vel[2];
350
351    for (k = 0; k < gp->ngalaxies; ++k) {
352     Galaxy     *gtk = &gp->galaxies[k];
353     double      d0 = gtk->pos[0] - st->pos[0];
354     double      d1 = gtk->pos[1] - st->pos[1];
355     double      d2 = gtk->pos[2] - st->pos[2];
356
357     d = d0 * d0 + d1 * d1 + d2 * d2;
358     if (d > EPSILON)
359      d = gt->mass / (d * sqrt(d)) * DELTAT * DELTAT * QCONS;
360     else
361         d = gt->mass * eps;
362     v0 += d0 * d;
363     v1 += d1 * d;
364     v2 += d2 * d;
365    }
366
367    st->vel[0] = v0;
368    st->vel[1] = v1;
369    st->vel[2] = v2;
370
371    st->pos[0] += v0;
372    st->pos[1] += v1;
373    st->pos[2] += v2;
374
375    newp->x = (short) (((cox * st->pos[0]) - (six * st->pos[2])) *
376 gp->scale) + gp->midx;
377    newp->y = (short) (((cor * st->pos[1]) - (sir * ((six * st->pos[0]) +
378 (cox * st->pos[2])))) * gp->scale) + gp->midy;
379
380   }
381
382   for (k = i + 1; k < gp->ngalaxies; ++k) {
383    Galaxy     *gtk = &gp->galaxies[k];
384    double      d0 = gtk->pos[0] - gt->pos[0];
385    double      d1 = gtk->pos[1] - gt->pos[1];
386    double      d2 = gtk->pos[2] - gt->pos[2];
387
388    d = d0 * d0 + d1 * d1 + d2 * d2;
389    if (d > EPSILON)
390     d = gt->mass * gt->mass / (d * sqrt(d)) * DELTAT * QCONS;
391    else
392     d = gt->mass * gt->mass / (EPSILON * sqrt_EPSILON) * DELTAT * QCONS;
393
394    d0 *= d;
395    d1 *= d;
396    d2 *= d;
397    gt->vel[0] += d0 / gt->mass;
398    gt->vel[1] += d1 / gt->mass;
399    gt->vel[2] += d2 / gt->mass;
400    gtk->vel[0] -= d0 / gtk->mass;
401    gtk->vel[1] -= d1 / gtk->mass;
402    gtk->vel[2] -= d2 / gtk->mass;
403   }
404
405   gt->pos[0] += gt->vel[0] * DELTAT;
406   gt->pos[1] += gt->vel[1] * DELTAT;
407   gt->pos[2] += gt->vel[2] * DELTAT;
408
409          XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
410   XDrawPoints(display, window, gc, gt->oldpoints, gt->nstars,
411 CoordModeOrigin);
412   XSetForeground(display, gc, MI_PIXEL(mi, COLORSTEP * gt->galcol));
413          XDrawPoints(display, window, gc, gt->newpoints, gt->nstars,
414 CoordModeOrigin);
415
416          dummy = gt->oldpoints;
417   gt->oldpoints = gt->newpoints;
418   gt->newpoints = dummy;
419  }
420
421  gp->step++;
422  if (gp->step > gp->f_hititerations * 4)
423   startover(mi);
424 }
425
426 void
427 release_galaxy(ModeInfo * mi)
428 {
429  if (universes != NULL) {
430   int         screen;
431
432   for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
433    free_galaxies(&universes[screen]);
434   (void) free((void *) universes);
435   universes = NULL;
436  }
437 }
438
439 void
440 refresh_galaxy(ModeInfo * mi)
441 {
442  /* Do nothing, it will refresh by itself */
443 }