1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* galaxy --- spinning galaxies */
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 * 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>
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>
43 # define DEFAULTS "*delay: 20000 \n" \
47 "*fpsSolid: true \n" \
48 "*ignoreRotation: True \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 */
60 #define DEF_TRACKS "True"
61 #define DEF_SPIN "True"
62 #define DEF_DBUF "True"
64 static XrmOptionDescRec opts[] =
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 {"-dbuf", ".galaxy.dbuf", XrmoptionNoArg, "on"},
71 {"+dbuf", ".galaxy.dbuf", XrmoptionNoArg, "off"},
74 static argtype vars[] =
76 {&tracks, "tracks", "Tracks", DEF_TRACKS, t_Bool},
77 {&spin, "spin", "Spin", DEF_SPIN, t_Bool},
78 {&dbufp, "dbuf", "Dbuf", DEF_DBUF, t_Bool},
81 static OptionStruct desc[] =
83 {"-/+tracks", "turn on/off star tracks"},
84 {"-/+spin", "do/don't spin viewpoint"},
85 {"-/+dbuf", "turn on/off double buffering."},
88 ENTRYPOINT ModeSpecOpt galaxy_opts =
89 {sizeof opts / sizeof opts[0], opts,
90 sizeof vars / sizeof vars[0], vars, desc};
93 #define FLOATRAND ((double) LRAND() / ((double) MAXRAND))
96 #define WRAP 1 /* Warp around edges */
97 #define BOUNCE 1 /* Bounce from borders */
101 #define MINGALAXIES 2
102 #define MAX_STARS 3000
103 #define MAX_IDELTAT 50
104 /* These come originally from the Cluster-version */
105 #define DEFAULT_GALAXIES 3
106 #define DEFAULT_STARS 1000
107 #define DEFAULT_HITITERATIONS 7500
108 #define DEFAULT_IDELTAT 200 /* 0.02 */
109 #define EPSILON 0.00000001
111 #define sqrt_EPSILON 0.0001
113 #define DELTAT (MAX_IDELTAT * 0.0001)
115 #define GALAXYRANGESIZE 0.1
116 #define GALAXYMINSIZE 0.15
121 /* colors per galaxy */
122 /* #define COLORSTEP (NUMCOLORS/COLORBASE) */
123 # define COLORSTEP (MI_NCOLORS(mi)/COLORBASE)
127 double pos[3], vel[3];
137 double pos[3], vel[3];
142 double mat[3][3]; /* Movement of stars(?) */
143 double scale; /* Scale */
144 int midx; /* Middle of screen, x */
145 int midy; /* Middle of screen, y */
147 double diff[3]; /* */
148 Galaxy *galaxies; /* the Whole Universe */
149 int ngalaxies; /* # galaxies */
150 int f_hititerations; /* # iterations before restart */
152 double rot_y; /* rotation of eye around center of universe, around
154 double rot_x; /* rotation of eye around center of universe, around
158 static unistruct *universes = NULL;
161 free_galaxies(unistruct * gp)
163 if (gp->galaxies != NULL) {
166 for (i = 0; i < gp->ngalaxies; i++) {
167 Galaxy *gt = &gp->galaxies[i];
169 if (gt->stars != NULL)
170 (void) free((void *) gt->stars);
171 if (gt->oldpoints != NULL)
172 (void) free((void *) gt->oldpoints);
173 if (gt->newpoints != NULL)
174 (void) free((void *) gt->newpoints);
176 (void) free((void *) gp->galaxies);
182 startover(ModeInfo * mi)
184 unistruct *gp = &universes[MI_SCREEN(mi)];
185 int i, j; /* more tmp */
186 double w1, w2; /* more tmp */
187 double d, v, w, h; /* yet more tmp */
193 if (MI_BATCHCOUNT(mi) < -MINGALAXIES)
195 gp->ngalaxies = MI_BATCHCOUNT(mi);
196 if (gp->ngalaxies < -MINGALAXIES)
197 gp->ngalaxies = NRAND(-gp->ngalaxies - MINGALAXIES + 1) + MINGALAXIES;
199 else if (gp->ngalaxies < MINGALAXIES)
200 gp->ngalaxies = MINGALAXIES;
201 if (gp->galaxies == NULL)
202 gp->galaxies = (Galaxy *) calloc(gp->ngalaxies, sizeof (Galaxy));
204 for (i = 0; i < gp->ngalaxies; ++i) {
205 Galaxy *gt = &gp->galaxies[i];
206 double sinw1, sinw2, cosw1, cosw2;
208 gt->galcol = NRAND(COLORBASE - 2);
210 gt->galcol += 2; /* Mult 8; 16..31 no green stars */
211 /* Galaxies still may have some green stars but are not all green. */
213 if (gt->stars != NULL) {
214 (void) free((void *) gt->stars);
217 gt->nstars = (NRAND(MAX_STARS / 2)) + MAX_STARS / 2;
218 gt->stars = (Star *) malloc(gt->nstars * sizeof (Star));
219 gt->oldpoints = (XPoint *) malloc(gt->nstars * sizeof (XPoint));
220 gt->newpoints = (XPoint *) malloc(gt->nstars * sizeof (XPoint));
222 w1 = 2.0 * M_PI * FLOATRAND;
223 w2 = 2.0 * M_PI * FLOATRAND;
229 gp->mat[0][0] = cosw2;
230 gp->mat[0][1] = -sinw1 * sinw2;
231 gp->mat[0][2] = cosw1 * sinw2;
233 gp->mat[1][1] = cosw1;
234 gp->mat[1][2] = sinw1;
235 gp->mat[2][0] = -sinw2;
236 gp->mat[2][1] = -sinw1 * cosw2;
237 gp->mat[2][2] = cosw1 * cosw2;
239 gt->vel[0] = FLOATRAND * 2.0 - 1.0;
240 gt->vel[1] = FLOATRAND * 2.0 - 1.0;
241 gt->vel[2] = FLOATRAND * 2.0 - 1.0;
242 gt->pos[0] = -gt->vel[0] * DELTAT * gp->f_hititerations + FLOATRAND -
244 gt->pos[1] = -gt->vel[1] * DELTAT * gp->f_hititerations + FLOATRAND -
246 gt->pos[2] = -gt->vel[2] * DELTAT * gp->f_hititerations + FLOATRAND -
249 gt->mass = (int) (FLOATRAND * 1000.0) + 1;
251 gp->size = GALAXYRANGESIZE * FLOATRAND + GALAXYMINSIZE;
253 for (j = 0; j < gt->nstars; ++j) {
254 Star *st = >->stars[j];
255 XPoint *oldp = >->oldpoints[j];
256 XPoint *newp = >->newpoints[j];
260 w = 2.0 * M_PI * FLOATRAND;
263 d = FLOATRAND * gp->size;
264 h = FLOATRAND * exp(-2.0 * (d / gp->size)) / 5.0 * gp->size;
267 st->pos[0] = gp->mat[0][0] * d * cosw + gp->mat[1][0] * d * sinw +
268 gp->mat[2][0] * h + gt->pos[0];
269 st->pos[1] = gp->mat[0][1] * d * cosw + gp->mat[1][1] * d * sinw +
270 gp->mat[2][1] * h + gt->pos[1];
271 st->pos[2] = gp->mat[0][2] * d * cosw + gp->mat[1][2] * d * sinw +
272 gp->mat[2][2] * h + gt->pos[2];
274 v = sqrt(gt->mass * QCONS / sqrt(d * d + h * h));
275 st->vel[0] = -gp->mat[0][0] * v * sinw + gp->mat[1][0] * v * cosw +
277 st->vel[1] = -gp->mat[0][1] * v * sinw + gp->mat[1][1] * v * cosw +
279 st->vel[2] = -gp->mat[0][2] * v * sinw + gp->mat[1][2] * v * cosw +
282 st->vel[0] *= DELTAT;
283 st->vel[1] *= DELTAT;
284 st->vel[2] *= DELTAT;
294 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
297 (void) printf("ngalaxies=%d, f_hititerations=%d\n", gp->ngalaxies,
298 gp->f_hititerations);
299 (void) printf("f_deltat=%g\n", DELTAT);
300 (void) printf("Screen: ");
305 init_galaxy(ModeInfo * mi)
309 if (universes == NULL) {
310 if ((universes = (unistruct *) calloc(MI_NUM_SCREENS(mi),
311 sizeof (unistruct))) == NULL)
314 gp = &universes[MI_SCREEN(mi)];
316 # ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */
320 gp->f_hititerations = MI_CYCLES(mi);
322 gp->scale = (double) (MI_WIN_WIDTH(mi) + MI_WIN_HEIGHT(mi)) / 8.0;
323 gp->midx = MI_WIN_WIDTH(mi) / 2;
324 gp->midy = MI_WIN_HEIGHT(mi) / 2;
329 draw_galaxy(ModeInfo * mi)
331 Display *display = MI_DISPLAY(mi);
332 Window window = MI_WINDOW(mi);
334 unistruct *gp = &universes[MI_SCREEN(mi)];
335 double d, eps, cox, six, cor, sir; /* tmp */
336 int i, j, k; /* more tmp */
337 XPoint *dummy = NULL;
340 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
347 cox = COSF(gp->rot_y);
348 six = SINF(gp->rot_y);
349 cor = COSF(gp->rot_x);
350 sir = SINF(gp->rot_x);
352 eps = 1/(EPSILON * sqrt_EPSILON * DELTAT * DELTAT * QCONS);
354 for (i = 0; i < gp->ngalaxies; ++i) {
355 Galaxy *gt = &gp->galaxies[i];
357 for (j = 0; j < gp->galaxies[i].nstars; ++j) {
358 Star *st = >->stars[j];
359 XPoint *newp = >->newpoints[j];
360 double v0 = st->vel[0];
361 double v1 = st->vel[1];
362 double v2 = st->vel[2];
364 for (k = 0; k < gp->ngalaxies; ++k) {
365 Galaxy *gtk = &gp->galaxies[k];
366 double d0 = gtk->pos[0] - st->pos[0];
367 double d1 = gtk->pos[1] - st->pos[1];
368 double d2 = gtk->pos[2] - st->pos[2];
370 d = d0 * d0 + d1 * d1 + d2 * d2;
372 d = gtk->mass / (d * sqrt(d)) * DELTAT * DELTAT * QCONS;
374 d = gtk->mass / (eps * sqrt(eps));
388 newp->x = (short) (((cox * st->pos[0]) - (six * st->pos[2])) *
389 gp->scale) + gp->midx;
390 newp->y = (short) (((cor * st->pos[1]) - (sir * ((six * st->pos[0]) +
391 (cox * st->pos[2]))))
392 * gp->scale) + gp->midy;
396 for (k = i + 1; k < gp->ngalaxies; ++k) {
397 Galaxy *gtk = &gp->galaxies[k];
398 double d0 = gtk->pos[0] - gt->pos[0];
399 double d1 = gtk->pos[1] - gt->pos[1];
400 double d2 = gtk->pos[2] - gt->pos[2];
402 d = d0 * d0 + d1 * d1 + d2 * d2;
404 d = 1 / (d * sqrt(d)) * DELTAT * QCONS;
406 d = 1 / (EPSILON * sqrt_EPSILON) * DELTAT * QCONS;
411 gt->vel[0] += d0 * gtk->mass;
412 gt->vel[1] += d1 * gtk->mass;
413 gt->vel[2] += d2 * gtk->mass;
414 gtk->vel[0] -= d0 * gt->mass;
415 gtk->vel[1] -= d1 * gt->mass;
416 gtk->vel[2] -= d2 * gt->mass;
419 gt->pos[0] += gt->vel[0] * DELTAT;
420 gt->pos[1] += gt->vel[1] * DELTAT;
421 gt->pos[2] += gt->vel[2] * DELTAT;
424 XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
425 XDrawPoints(display, window, gc, gt->oldpoints, gt->nstars,
428 XSetForeground(display, gc, MI_PIXEL(mi, COLORSTEP * gt->galcol));
429 XDrawPoints(display, window, gc, gt->newpoints, gt->nstars,
432 dummy = gt->oldpoints;
433 gt->oldpoints = gt->newpoints;
434 gt->newpoints = dummy;
438 if (gp->step > gp->f_hititerations * 4)
443 reshape_galaxy(ModeInfo * mi, int width, int height)
445 XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi));
450 release_galaxy(ModeInfo * mi)
452 if (universes != NULL) {
455 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
456 free_galaxies(&universes[screen]);
457 (void) free((void *) universes);
463 refresh_galaxy(ModeInfo * mi)
465 /* Do nothing, it will refresh by itself */
469 galaxy_handle_event (ModeInfo *mi, XEvent *event)
471 if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
473 reshape_galaxy (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
480 XSCREENSAVER_MODULE ("Galaxy", galaxy)