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 | |
---|
60 | #define DEF_TRACKS "True" |
---|
61 | |
---|
62 | static XrmOptionDescRec opts[] = |
---|
63 | { |
---|
64 | {"-tracks", ".galaxy.tracks", XrmoptionNoArg, (caddr_t) "on"}, |
---|
65 | {"+tracks", ".galaxy.tracks", XrmoptionNoArg, (caddr_t) "off"} |
---|
66 | }; |
---|
67 | |
---|
68 | static argtype vars[] = |
---|
69 | { |
---|
70 | {(caddr_t *) & tracks, "tracks", "Tracks", DEF_TRACKS, t_Bool} |
---|
71 | }; |
---|
72 | |
---|
73 | static OptionStruct desc[] = |
---|
74 | { |
---|
75 | {"-/+tracks", "turn on/off star tracks"} |
---|
76 | }; |
---|
77 | |
---|
78 | ModeSpecOpt galaxy_opts = { 2, opts, 1, vars, desc }; |
---|
79 | |
---|
80 | |
---|
81 | #define FLOATRAND ((double) LRAND() / ((double) MAXRAND)) |
---|
82 | |
---|
83 | #if 0 |
---|
84 | #define WRAP 1 /* Warp around edges */ |
---|
85 | #define BOUNCE 1 /* Bounce from borders */ |
---|
86 | #endif |
---|
87 | |
---|
88 | #define MINSIZE 1 |
---|
89 | #define MINGALAXIES 2 |
---|
90 | #define MAX_STARS 3000 |
---|
91 | #define MAX_IDELTAT 50 |
---|
92 | /* These come originally from the Cluster-version */ |
---|
93 | #define DEFAULT_GALAXIES 3 |
---|
94 | #define DEFAULT_STARS 1000 |
---|
95 | #define DEFAULT_HITITERATIONS 7500 |
---|
96 | #define DEFAULT_IDELTAT 200 /* 0.02 */ |
---|
97 | #define EPSILON 0.00000001 |
---|
98 | |
---|
99 | #define sqrt_EPSILON 0.0001 |
---|
100 | |
---|
101 | #define DELTAT (MAX_IDELTAT * 0.0001) |
---|
102 | |
---|
103 | #define GALAXYRANGESIZE 0.1 |
---|
104 | #define GALAXYMINSIZE 0.15 |
---|
105 | #define QCONS 0.001 |
---|
106 | |
---|
107 | |
---|
108 | #define COLORBASE 16 |
---|
109 | /* Colors for stars start here */ |
---|
110 | #define COLORSTEP (NUMCOLORS/COLORBASE) /* NUMCOLORS / COLORBASE colors |
---|
111 | per galaxy */ |
---|
112 | |
---|
113 | |
---|
114 | typedef struct { |
---|
115 | double pos[3], vel[3]; |
---|
116 | } Star; |
---|
117 | |
---|
118 | |
---|
119 | typedef struct { |
---|
120 | int mass; |
---|
121 | int nstars; |
---|
122 | Star *stars; |
---|
123 | XPoint *oldpoints; |
---|
124 | XPoint *newpoints; |
---|
125 | double pos[3], vel[3]; |
---|
126 | int galcol; |
---|
127 | } Galaxy; |
---|
128 | |
---|
129 | typedef struct { |
---|
130 | double mat[3][3]; /* Movement of stars(?) */ |
---|
131 | double scale; /* Scale */ |
---|
132 | int midx; /* Middle of screen, x */ |
---|
133 | int midy; /* Middle of screen, y */ |
---|
134 | double size; /* */ |
---|
135 | double diff[3]; /* */ |
---|
136 | Galaxy *galaxies; /* the Whole Universe */ |
---|
137 | int ngalaxies; /* # galaxies */ |
---|
138 | int f_hititerations; /* # iterations before restart */ |
---|
139 | int step; /* */ |
---|
140 | double rot_y; /* rotation of eye around center of universe, around |
---|
141 | y-axis*/ |
---|
142 | double rot_x; /* rotation of eye around center of universe, around |
---|
143 | x-axis */ |
---|
144 | } unistruct; |
---|
145 | |
---|
146 | static unistruct *universes = NULL; |
---|
147 | |
---|
148 | static void |
---|
149 | free_galaxies(unistruct * gp) |
---|
150 | { |
---|
151 | if (gp->galaxies != NULL) { |
---|
152 | int i; |
---|
153 | |
---|
154 | for (i = 0; i < gp->ngalaxies; i++) { |
---|
155 | Galaxy *gt = &gp->galaxies[i]; |
---|
156 | |
---|
157 | if (gt->stars != NULL) |
---|
158 | (void) free((void *) gt->stars); |
---|
159 | if (gt->oldpoints != NULL) |
---|
160 | (void) free((void *) gt->oldpoints); |
---|
161 | if (gt->newpoints != NULL) |
---|
162 | (void) free((void *) gt->newpoints); |
---|
163 | } |
---|
164 | (void) free((void *) gp->galaxies); |
---|
165 | gp->galaxies = NULL; |
---|
166 | } |
---|
167 | } |
---|
168 | |
---|
169 | static void |
---|
170 | startover(ModeInfo * mi) |
---|
171 | { |
---|
172 | unistruct *gp = &universes[MI_SCREEN(mi)]; |
---|
173 | int i, j; /* more tmp */ |
---|
174 | double w1, w2; /* more tmp */ |
---|
175 | double d, v, w, h; /* yet more tmp */ |
---|
176 | |
---|
177 | gp->step = 0; |
---|
178 | gp->rot_y = 0; |
---|
179 | gp->rot_x = 0; |
---|
180 | |
---|
181 | if (MI_BATCHCOUNT(mi) < -MINGALAXIES) |
---|
182 | free_galaxies(gp); |
---|
183 | gp->ngalaxies = MI_BATCHCOUNT(mi); |
---|
184 | if (gp->ngalaxies < -MINGALAXIES) |
---|
185 | gp->ngalaxies = NRAND(-gp->ngalaxies - MINGALAXIES + 1) + MINGALAXIES; |
---|
186 | |
---|
187 | else if (gp->ngalaxies < MINGALAXIES) |
---|
188 | gp->ngalaxies = MINGALAXIES; |
---|
189 | if (gp->galaxies == NULL) |
---|
190 | gp->galaxies = (Galaxy *) calloc(gp->ngalaxies, sizeof (Galaxy)); |
---|
191 | |
---|
192 | for (i = 0; i < gp->ngalaxies; ++i) { |
---|
193 | Galaxy *gt = &gp->galaxies[i]; |
---|
194 | double sinw1, sinw2, cosw1, cosw2; |
---|
195 | |
---|
196 | gt->galcol = NRAND(COLORBASE - 2); |
---|
197 | if (gt->galcol > 1) |
---|
198 | gt->galcol += 2; /* Mult 8; 16..31 no green stars */ |
---|
199 | /* Galaxies still may have some green stars but are not all green. */ |
---|
200 | |
---|
201 | if (gt->stars != NULL) { |
---|
202 | (void) free((void *) gt->stars); |
---|
203 | gt->stars = NULL; |
---|
204 | } |
---|
205 | gt->nstars = (NRAND(MAX_STARS / 2)) + MAX_STARS / 2; |
---|
206 | gt->stars = (Star *) malloc(gt->nstars * sizeof (Star)); |
---|
207 | gt->oldpoints = (XPoint *) malloc(gt->nstars * sizeof (XPoint)); |
---|
208 | gt->newpoints = (XPoint *) malloc(gt->nstars * sizeof (XPoint)); |
---|
209 | |
---|
210 | w1 = 2.0 * M_PI * FLOATRAND; |
---|
211 | w2 = 2.0 * M_PI * FLOATRAND; |
---|
212 | sinw1 = SINF(w1); |
---|
213 | sinw2 = SINF(w2); |
---|
214 | cosw1 = COSF(w1); |
---|
215 | cosw2 = COSF(w2); |
---|
216 | |
---|
217 | gp->mat[0][0] = cosw2; |
---|
218 | gp->mat[0][1] = -sinw1 * sinw2; |
---|
219 | gp->mat[0][2] = cosw1 * sinw2; |
---|
220 | gp->mat[1][0] = 0.0; |
---|
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; |
---|
226 | |
---|
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 * gp->f_hititerations + FLOATRAND - |
---|
231 | 0.5; |
---|
232 | gt->pos[1] = -gt->vel[1] * DELTAT * gp->f_hititerations + FLOATRAND - |
---|
233 | 0.5; |
---|
234 | gt->pos[2] = -gt->vel[2] * DELTAT * gp->f_hititerations + FLOATRAND - |
---|
235 | 0.5; |
---|
236 | |
---|
237 | gt->mass = (int) (FLOATRAND * 1000.0) + 1; |
---|
238 | |
---|
239 | gp->size = GALAXYRANGESIZE * FLOATRAND + GALAXYMINSIZE; |
---|
240 | |
---|
241 | for (j = 0; j < gt->nstars; ++j) { |
---|
242 | Star *st = >->stars[j]; |
---|
243 | XPoint *oldp = >->oldpoints[j]; |
---|
244 | XPoint *newp = >->newpoints[j]; |
---|
245 | |
---|
246 | double sinw, cosw; |
---|
247 | |
---|
248 | w = 2.0 * M_PI * FLOATRAND; |
---|
249 | sinw = SINF(w); |
---|
250 | cosw = COSF(w); |
---|
251 | d = FLOATRAND * gp->size; |
---|
252 | h = FLOATRAND * exp(-2.0 * (d / gp->size)) / 5.0 * gp->size; |
---|
253 | if (FLOATRAND < 0.5) |
---|
254 | h = -h; |
---|
255 | st->pos[0] = gp->mat[0][0] * d * cosw + gp->mat[1][0] * d * sinw + |
---|
256 | gp->mat[2][0] * h + gt->pos[0]; |
---|
257 | st->pos[1] = gp->mat[0][1] * d * cosw + gp->mat[1][1] * d * sinw + |
---|
258 | gp->mat[2][1] * h + gt->pos[1]; |
---|
259 | st->pos[2] = gp->mat[0][2] * d * cosw + gp->mat[1][2] * d * sinw + |
---|
260 | gp->mat[2][2] * h + gt->pos[2]; |
---|
261 | |
---|
262 | v = sqrt(gt->mass * QCONS / sqrt(d * d + h * h)); |
---|
263 | st->vel[0] = -gp->mat[0][0] * v * sinw + gp->mat[1][0] * v * cosw + |
---|
264 | gt->vel[0]; |
---|
265 | st->vel[1] = -gp->mat[0][1] * v * sinw + gp->mat[1][1] * v * cosw + |
---|
266 | gt->vel[1]; |
---|
267 | st->vel[2] = -gp->mat[0][2] * v * sinw + gp->mat[1][2] * v * cosw + |
---|
268 | gt->vel[2]; |
---|
269 | |
---|
270 | st->vel[0] *= DELTAT; |
---|
271 | st->vel[1] *= DELTAT; |
---|
272 | st->vel[2] *= DELTAT; |
---|
273 | |
---|
274 | oldp->x = 0; |
---|
275 | oldp->y = 0; |
---|
276 | newp->x = 0; |
---|
277 | newp->y = 0; |
---|
278 | } |
---|
279 | |
---|
280 | } |
---|
281 | |
---|
282 | XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); |
---|
283 | |
---|
284 | #if 0 |
---|
285 | (void) printf("ngalaxies=%d, f_hititerations=%d\n", gp->ngalaxies, |
---|
286 | gp->f_hititerations); |
---|
287 | (void) printf("f_deltat=%g\n", DELTAT); |
---|
288 | (void) printf("Screen: "); |
---|
289 | #endif /*0 */ |
---|
290 | } |
---|
291 | |
---|
292 | void |
---|
293 | init_galaxy(ModeInfo * mi) |
---|
294 | { |
---|
295 | unistruct *gp; |
---|
296 | |
---|
297 | if (universes == NULL) { |
---|
298 | if ((universes = (unistruct *) calloc(MI_NUM_SCREENS(mi), |
---|
299 | sizeof (unistruct))) == NULL) |
---|
300 | return; |
---|
301 | } |
---|
302 | gp = &universes[MI_SCREEN(mi)]; |
---|
303 | |
---|
304 | gp->f_hititerations = MI_CYCLES(mi); |
---|
305 | |
---|
306 | gp->scale = (double) (MI_WIN_WIDTH(mi) + MI_WIN_HEIGHT(mi)) / 8.0; |
---|
307 | gp->midx = MI_WIN_WIDTH(mi) / 2; |
---|
308 | gp->midy = MI_WIN_HEIGHT(mi) / 2; |
---|
309 | startover(mi); |
---|
310 | } |
---|
311 | |
---|
312 | void |
---|
313 | draw_galaxy(ModeInfo * mi) |
---|
314 | { |
---|
315 | Display *display = MI_DISPLAY(mi); |
---|
316 | Window window = MI_WINDOW(mi); |
---|
317 | GC gc = MI_GC(mi); |
---|
318 | unistruct *gp = &universes[MI_SCREEN(mi)]; |
---|
319 | double d, eps, cox, six, cor, sir; /* tmp */ |
---|
320 | int i, j, k; /* more tmp */ |
---|
321 | XPoint *dummy = NULL; |
---|
322 | |
---|
323 | gp->rot_y += 0.01; |
---|
324 | gp->rot_x += 0.004; |
---|
325 | |
---|
326 | cox = COSF(gp->rot_y); |
---|
327 | six = SINF(gp->rot_y); |
---|
328 | cor = COSF(gp->rot_x); |
---|
329 | sir = SINF(gp->rot_x); |
---|
330 | |
---|
331 | eps = 1/(EPSILON * sqrt_EPSILON * DELTAT * DELTAT * QCONS); |
---|
332 | |
---|
333 | for (i = 0; i < gp->ngalaxies; ++i) { |
---|
334 | Galaxy *gt = &gp->galaxies[i]; |
---|
335 | |
---|
336 | for (j = 0; j < gp->galaxies[i].nstars; ++j) { |
---|
337 | Star *st = >->stars[j]; |
---|
338 | XPoint *newp = >->newpoints[j]; |
---|
339 | double v0 = st->vel[0]; |
---|
340 | double v1 = st->vel[1]; |
---|
341 | double v2 = st->vel[2]; |
---|
342 | |
---|
343 | for (k = 0; k < gp->ngalaxies; ++k) { |
---|
344 | Galaxy *gtk = &gp->galaxies[k]; |
---|
345 | double d0 = gtk->pos[0] - st->pos[0]; |
---|
346 | double d1 = gtk->pos[1] - st->pos[1]; |
---|
347 | double d2 = gtk->pos[2] - st->pos[2]; |
---|
348 | |
---|
349 | d = d0 * d0 + d1 * d1 + d2 * d2; |
---|
350 | if (d > EPSILON) |
---|
351 | d = gt->mass / (d * sqrt(d)) * DELTAT * DELTAT * QCONS; |
---|
352 | else |
---|
353 | d = gt->mass * eps; |
---|
354 | v0 += d0 * d; |
---|
355 | v1 += d1 * d; |
---|
356 | v2 += d2 * d; |
---|
357 | } |
---|
358 | |
---|
359 | st->vel[0] = v0; |
---|
360 | st->vel[1] = v1; |
---|
361 | st->vel[2] = v2; |
---|
362 | |
---|
363 | st->pos[0] += v0; |
---|
364 | st->pos[1] += v1; |
---|
365 | st->pos[2] += v2; |
---|
366 | |
---|
367 | newp->x = (short) (((cox * st->pos[0]) - (six * st->pos[2])) * |
---|
368 | gp->scale) + gp->midx; |
---|
369 | newp->y = (short) (((cor * st->pos[1]) - (sir * ((six * st->pos[0]) + |
---|
370 | (cox * st->pos[2])))) * gp->scale) + gp->midy; |
---|
371 | |
---|
372 | } |
---|
373 | |
---|
374 | for (k = i + 1; k < gp->ngalaxies; ++k) { |
---|
375 | Galaxy *gtk = &gp->galaxies[k]; |
---|
376 | double d0 = gtk->pos[0] - gt->pos[0]; |
---|
377 | double d1 = gtk->pos[1] - gt->pos[1]; |
---|
378 | double d2 = gtk->pos[2] - gt->pos[2]; |
---|
379 | |
---|
380 | d = d0 * d0 + d1 * d1 + d2 * d2; |
---|
381 | if (d > EPSILON) |
---|
382 | d = gt->mass * gt->mass / (d * sqrt(d)) * DELTAT * QCONS; |
---|
383 | else |
---|
384 | d = gt->mass * gt->mass / (EPSILON * sqrt_EPSILON) * DELTAT * QCONS; |
---|
385 | |
---|
386 | d0 *= d; |
---|
387 | d1 *= d; |
---|
388 | d2 *= d; |
---|
389 | gt->vel[0] += d0 / gt->mass; |
---|
390 | gt->vel[1] += d1 / gt->mass; |
---|
391 | gt->vel[2] += d2 / gt->mass; |
---|
392 | gtk->vel[0] -= d0 / gtk->mass; |
---|
393 | gtk->vel[1] -= d1 / gtk->mass; |
---|
394 | gtk->vel[2] -= d2 / gtk->mass; |
---|
395 | } |
---|
396 | |
---|
397 | gt->pos[0] += gt->vel[0] * DELTAT; |
---|
398 | gt->pos[1] += gt->vel[1] * DELTAT; |
---|
399 | gt->pos[2] += gt->vel[2] * DELTAT; |
---|
400 | |
---|
401 | XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi)); |
---|
402 | XDrawPoints(display, window, gc, gt->oldpoints, gt->nstars, |
---|
403 | CoordModeOrigin); |
---|
404 | XSetForeground(display, gc, MI_PIXEL(mi, COLORSTEP * gt->galcol)); |
---|
405 | XDrawPoints(display, window, gc, gt->newpoints, gt->nstars, |
---|
406 | CoordModeOrigin); |
---|
407 | |
---|
408 | dummy = gt->oldpoints; |
---|
409 | gt->oldpoints = gt->newpoints; |
---|
410 | gt->newpoints = dummy; |
---|
411 | } |
---|
412 | |
---|
413 | gp->step++; |
---|
414 | if (gp->step > gp->f_hititerations * 4) |
---|
415 | startover(mi); |
---|
416 | } |
---|
417 | |
---|
418 | void |
---|
419 | release_galaxy(ModeInfo * mi) |
---|
420 | { |
---|
421 | if (universes != NULL) { |
---|
422 | int screen; |
---|
423 | |
---|
424 | for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) |
---|
425 | free_galaxies(&universes[screen]); |
---|
426 | (void) free((void *) universes); |
---|
427 | universes = NULL; |
---|
428 | } |
---|
429 | } |
---|
430 | |
---|
431 | void |
---|
432 | refresh_galaxy(ModeInfo * mi) |
---|
433 | { |
---|
434 | /* Do nothing, it will refresh by itself */ |
---|
435 | } |
---|