1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* galaxy --- spinning galaxies */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)galaxy.c 4.04 97/07/28 xlockmore";
8 /* Originally done by Uli Siegmund <uli@wombat.okapi.sub.org> on Amiga
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>
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.
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.
27 * 10-May-97: jwz@netscape.com: turned into a standalone program.
28 * 18-Apr-97: Memory leak fixed by Tom Schmidt <tschmidt@micron.com>
29 * 07-Apr-97: Modified by Dave Mitchell <davem@magnet.com>
30 * 23-Oct-94: Modified by David Bagley <bagleyd@bigfoot.com>
32 * colors change depending on velocity
33 * 10-Oct-94: Add colors by Hubert Feyer
34 * 30-Sep-94: Initial port by Hubert Feyer
35 * 09-Mar-94: VMS can generate a random number 0.0 which results in a
36 * division by zero, corrected by Jouk Jansen
37 * <joukj@crys.chem.uva.nl>
41 # define PROGCLASS "Galaxy"
42 # define HACK_INIT init_galaxy
43 # define HACK_DRAW draw_galaxy
44 # define galaxy_opts xlockmore_opts
45 # define DEFAULTS "*delay: 100 \n" \
50 # define UNIFORM_COLORS
51 # include "xlockmore.h" /* from the xscreensaver distribution */
52 #else /* !STANDALONE */
53 # include "xlock.h" /* from the xlockmore distribution */
54 #endif /* !STANDALONE */
58 #define DEF_TRACKS "False"
60 static XrmOptionDescRec opts[] =
62 {"-tracks", ".galaxy.tracks", XrmoptionNoArg, (caddr_t) "on"},
63 {"+tracks", ".galaxy.tracks", XrmoptionNoArg, (caddr_t) "off"}
66 static argtype vars[] =
68 {(caddr_t *) & tracks, "tracks", "Tracks", DEF_TRACKS, t_Bool}
71 static OptionStruct desc[] =
73 {"-/+tracks", "turn on/off star tracks"}
76 ModeSpecOpt galaxy_opts = { 2, opts, 1, vars, desc };
79 #define FLOATRAND ((double) LRAND() / ((double) MAXRAND))
82 #define WRAP 1 /* Warp around edges */
83 #define BOUNCE 1 /* Bounce from borders */
89 #define MAX_IDELTAT 50
90 /* These come originally from the Cluster-version */
91 #define DEFAULT_GALAXIES 2
92 #define DEFAULT_STARS 1000
93 #define DEFAULT_HITITERATIONS 7500
94 #define DEFAULT_IDELTAT 200 /* 0.02 */
95 #define EPSILON 0.00000001
97 #define sqrt_EPSILON 0.0001
99 #define DELTAT (MAX_IDELTAT * 0.0001)
101 #define GALAXYRANGESIZE 0.1
102 #define GALAXYMINSIZE 0.1
106 * The following is enabled, it does not look that good for some.
107 * (But it looks great for me.) Maybe velocities should be measured
108 * relative to their galaxy-centers instead of absolute.
111 #undef NO_VELOCITY_COLORING */ /* different colors for different speeds */
115 /* Colors for stars start here */
116 #define COLORSTEP (NUMCOLORS/COLORBASE) /* 8 colors per galaxy */
118 #define drawStar(x,y,size) if(size<=1) XDrawPoint(display,window,gc,x,y);\
119 else XFillArc(display,window,gc,x,y,size,size,0,23040)
122 double pos[3], vel[3];
132 double pos[3], vel[3];
138 int left; /* x minimum */
139 int right; /* x maximum */
140 int top; /* y minimum */
141 int bottom; /* y maximum */
143 double mat[3][3]; /* Movement of stars(?) */
144 double scale; /* Scale */
145 int midx; /* Middle of screen, x */
146 int midy; /* Middle of screen, y */
148 double diff[3]; /* */
149 Galaxy *galaxies; /* the Whole Universe */
150 int ngalaxies; /* # galaxies */
151 int f_hititerations; /* # iterations before restart */
155 static unistruct *universes = NULL;
158 free_galaxies(unistruct * gp)
160 if (gp->galaxies != NULL) {
163 for (i = 0; i < gp->ngalaxies; i++) {
164 Galaxy *gt = &gp->galaxies[i];
166 if (gt->stars != NULL)
167 (void) free((void *) gt->stars);
169 (void) free((void *) gp->galaxies);
175 startover(ModeInfo * mi)
177 unistruct *gp = &universes[MI_SCREEN(mi)];
178 int size = MI_SIZE(mi);
179 int i, j; /* more tmp */
180 double w1, w2; /* more tmp */
181 double d, v, w, h; /* yet more tmp */
185 if (MI_BATCHCOUNT(mi) < -MINGALAXIES)
187 gp->ngalaxies = MI_BATCHCOUNT(mi);
188 if (gp->ngalaxies < -MINGALAXIES)
189 gp->ngalaxies = NRAND(-gp->ngalaxies - MINGALAXIES + 1) + MINGALAXIES;
190 else if (gp->ngalaxies < MINGALAXIES)
191 gp->ngalaxies = MINGALAXIES;
192 if (gp->galaxies == NULL)
193 gp->galaxies = (Galaxy *) calloc(gp->ngalaxies, sizeof (Galaxy));
195 for (i = 0; i < gp->ngalaxies; ++i) {
196 Galaxy *gt = &gp->galaxies[i];
197 double sinw1, sinw2, cosw1, cosw2;
199 gt->galcol = NRAND(COLORBASE - 2);
201 gt->galcol += 2; /* Mult 8; 16..31 no green stars */
202 /* Galaxies still may have some green stars but are not all green. */
204 if (gt->stars != NULL) {
205 (void) free((void *) gt->stars);
208 gt->nstars = (NRAND(MAX_STARS / 2)) + MAX_STARS / 2;
209 gt->stars = (Star *) malloc(gt->nstars * sizeof (Star));
210 w1 = 2.0 * M_PI * FLOATRAND;
211 w2 = 2.0 * M_PI * FLOATRAND;
217 gp->mat[0][0] = cosw2;
218 gp->mat[0][1] = -sinw1 * sinw2;
219 gp->mat[0][2] = cosw1 * sinw2;
221 gp->mat[1][1] = cosw1;
222 gp->mat[1][2] = sinw1;
223 gp->mat[2][0] = -sinw2;
224 gp->mat[2][1] = -sinw1 * cosw2;
225 gp->mat[2][2] = cosw1 * cosw2;
227 gt->vel[0] = FLOATRAND * 2.0 - 1.0;
228 gt->vel[1] = FLOATRAND * 2.0 - 1.0;
229 gt->vel[2] = FLOATRAND * 2.0 - 1.0;
230 gt->pos[0] = -gt->vel[0] * DELTAT *
231 gp->f_hititerations + FLOATRAND - 0.5;
232 gt->pos[1] = -gt->vel[1] * DELTAT *
233 gp->f_hititerations + FLOATRAND - 0.5;
234 gt->pos[2] = -gt->vel[2] * DELTAT *
235 gp->f_hititerations + FLOATRAND - 0.5;
237 gt->mass = (int) (FLOATRAND * 1000.0) + 1;
239 gp->size = GALAXYRANGESIZE * FLOATRAND + GALAXYMINSIZE;
241 for (j = 0; j < gt->nstars; ++j) {
242 Star *st = >->stars[j];
245 w = 2.0 * M_PI * FLOATRAND;
248 d = FLOATRAND * gp->size;
249 h = FLOATRAND * exp(-2.0 * (d / gp->size)) / 5.0 * gp->size;
252 st->pos[0] = gp->mat[0][0] * d * cosw + gp->mat[1][0] * d * sinw +
253 gp->mat[2][0] * h + gt->pos[0];
254 st->pos[1] = gp->mat[0][1] * d * cosw + gp->mat[1][1] * d * sinw +
255 gp->mat[2][1] * h + gt->pos[1];
256 st->pos[2] = gp->mat[0][2] * d * cosw + gp->mat[1][2] * d * sinw +
257 gp->mat[2][2] * h + gt->pos[2];
259 v = sqrt(gt->mass * QCONS / sqrt(d * d + h * h));
260 st->vel[0] = -gp->mat[0][0] * v * sinw + gp->mat[1][0] * v * cosw +
262 st->vel[1] = -gp->mat[0][1] * v * sinw + gp->mat[1][1] * v * cosw +
264 st->vel[2] = -gp->mat[0][2] * v * sinw + gp->mat[1][2] * v * cosw +
267 st->vel[0] *= DELTAT;
268 st->vel[1] *= DELTAT;
269 st->vel[2] *= DELTAT;
275 st->size = NRAND(-size - MINSIZE + 1) + MINSIZE;
276 else if (size < MINSIZE)
283 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
286 (void) printf("ngalaxies=%d, f_hititerations=%d\n",
287 gp->ngalaxies, gp->f_hititerations);
288 (void) printf("f_deltat=%g\n", DELTAT);
289 (void) printf("Screen: ");
290 (void) printf("%dx%d pixel (%d-%d, %d-%d)\n",
291 (gp->clip.right - gp->clip.left), (gp->clip.bottom - gp->clip.top),
292 gp->clip.left, gp->clip.right, gp->clip.top, gp->clip.bottom);
297 init_galaxy(ModeInfo * mi)
301 if (universes == NULL) {
302 if ((universes = (unistruct *) calloc(MI_NUM_SCREENS(mi),
303 sizeof (unistruct))) == NULL)
306 gp = &universes[MI_SCREEN(mi)];
308 gp->f_hititerations = MI_CYCLES(mi);
312 gp->clip.right = MI_WIN_WIDTH(mi);
313 gp->clip.bottom = MI_WIN_HEIGHT(mi);
315 gp->scale = (double) (gp->clip.right + gp->clip.bottom) / 8.0;
316 gp->midx = gp->clip.right / 2;
317 gp->midy = gp->clip.bottom / 2;
322 draw_galaxy(ModeInfo * mi)
324 Display *display = MI_DISPLAY(mi);
325 Window window = MI_WINDOW(mi);
327 unistruct *gp = &universes[MI_SCREEN(mi)];
329 int i, j, k; /* more tmp */
331 for (i = 0; i < gp->ngalaxies; ++i) {
332 Galaxy *gt = &gp->galaxies[i];
334 for (j = 0; j < gp->galaxies[i].nstars; ++j) {
335 Star *st = >->stars[j];
336 double v0 = st->vel[0];
337 double v1 = st->vel[1];
338 double v2 = st->vel[2];
340 for (k = 0; k < gp->ngalaxies; ++k) {
341 Galaxy *gtk = &gp->galaxies[k];
342 double d0 = gtk->pos[0] - st->pos[0];
343 double d1 = gtk->pos[1] - st->pos[1];
344 double d2 = gtk->pos[2] - st->pos[2];
346 d = d0 * d0 + d1 * d1 + d2 * d2;
348 d = gt->mass / (d * sqrt(d)) * DELTAT * DELTAT * QCONS;
350 d = gt->mass / (EPSILON * sqrt_EPSILON) * DELTAT * DELTAT * QCONS;
360 #ifndef NO_VELOCITY_COLORING
361 d = (v0 * v0 + v1 * v1 + v2 * v2) / (3.0 * DELTAT * DELTAT);
362 if (d > (double) COLORSTEP)
363 st->color = COLORSTEP * gt->galcol + COLORSTEP - 1;
365 st->color = COLORSTEP * gt->galcol + ((int) d) % COLORSTEP;
371 if (st->px >= gp->clip.left &&
372 st->px <= gp->clip.right - st->size &&
373 st->py >= gp->clip.top &&
374 st->py <= gp->clip.bottom - st->size) {
375 XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
376 drawStar(st->px, st->py, st->size);
378 st->px = (int) (st->pos[0] * gp->scale) + gp->midx;
379 st->py = (int) (st->pos[1] * gp->scale) + gp->midy;
383 if (st->px < gp->clip.left) {
384 (void) printf("wrap l -> r\n");
385 st->px = gp->clip.right;
387 if (st->px > gp->clip.right) {
388 (void) printf("wrap r -> l\n");
389 st->px = gp->clip.left;
391 if (st->py > gp->clip.bottom) {
392 (void) printf("wrap b -> t\n");
393 st->py = gp->clip.top;
395 if (st->py < gp->clip.top) {
396 (void) printf("wrap t -> b\n");
397 st->py = gp->clip.bottom;
402 if (st->px >= gp->clip.left &&
403 st->px <= gp->clip.right - st->size &&
404 st->py >= gp->clip.top &&
405 st->py <= gp->clip.bottom - st->size) {
406 if (MI_NPIXELS(mi) > 2)
407 #ifdef NO_VELOCITY_COLORING
408 XSetForeground(display, gc, MI_PIXEL(mi, COLORSTEP * gt->galcol));
410 XSetForeground(display, gc, MI_PIXEL(mi, st->color));
413 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
415 drawStar(st->px + 1, st->py, st->size);
417 drawStar(st->px, st->py, st->size);
421 for (k = i + 1; k < gp->ngalaxies; ++k) {
422 Galaxy *gtk = &gp->galaxies[k];
423 double d0 = gtk->pos[0] - gt->pos[0];
424 double d1 = gtk->pos[1] - gt->pos[1];
425 double d2 = gtk->pos[2] - gt->pos[2];
427 d = d0 * d0 + d1 * d1 + d2 * d2;
429 d = gt->mass * gt->mass / (d * sqrt(d)) * DELTAT * QCONS;
431 d = gt->mass * gt->mass / (EPSILON * sqrt_EPSILON) * DELTAT * QCONS;
435 gt->vel[0] += d0 / gt->mass;
436 gt->vel[1] += d1 / gt->mass;
437 gt->vel[2] += d2 / gt->mass;
438 gtk->vel[0] -= d0 / gtk->mass;
439 gtk->vel[1] -= d1 / gtk->mass;
440 gtk->vel[2] -= d2 / gtk->mass;
442 gt->pos[0] += gt->vel[0] * DELTAT;
443 gt->pos[1] += gt->vel[1] * DELTAT;
444 gt->pos[2] += gt->vel[2] * DELTAT;
448 if (gp->step > gp->f_hititerations * 4)
453 release_galaxy(ModeInfo * mi)
455 if (universes != NULL) {
458 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
459 free_galaxies(&universes[screen]);
460 (void) free((void *) universes);
466 refresh_galaxy(ModeInfo * mi)
468 /* Do nothing, it will refresh by itself */