1 | /* -*- Mode: C; tab-width: 4 -*- */ |
---|
2 | /* grav --- planets spinning around a pulsar */ |
---|
3 | |
---|
4 | #if 0 |
---|
5 | static const char sccsid[] = "@(#)grav.c 5.00 2000/11/01 xlockmore"; |
---|
6 | #endif |
---|
7 | |
---|
8 | /*- |
---|
9 | * Copyright (c) 1993 by Greg Boewring <gb@pobox.com> |
---|
10 | * |
---|
11 | * Permission to use, copy, modify, and distribute this software and its |
---|
12 | * documentation for any purpose and without fee is hereby granted, |
---|
13 | * provided that the above copyright notice appear in all copies and that |
---|
14 | * both that copyright notice and this permission notice appear in |
---|
15 | * supporting documentation. |
---|
16 | * |
---|
17 | * This file is provided AS IS with no warranties of any kind. The author |
---|
18 | * shall have no liability with respect to the infringement of copyrights, |
---|
19 | * trade secrets or any patents by this file or any part thereof. In no |
---|
20 | * event will the author be liable for any lost revenue or profits or |
---|
21 | * other special, indirect and consequential damages. |
---|
22 | * |
---|
23 | * Revision History: |
---|
24 | * 01-Nov-2000: Allocation checks |
---|
25 | * 10-May-1997: Compatible with xscreensaver |
---|
26 | * 11-Jul-1994: color version |
---|
27 | * 06-Oct-1993: Written by Greg Bowering <gb@pobox.com> |
---|
28 | */ |
---|
29 | |
---|
30 | #ifdef STANDALONE |
---|
31 | #define MODE_grav |
---|
32 | #define PROGCLASS "Grav" |
---|
33 | #define HACK_INIT init_grav |
---|
34 | #define HACK_DRAW draw_grav |
---|
35 | #define grav_opts xlockmore_opts |
---|
36 | #define DEFAULTS "*delay: 10000 \n" \ |
---|
37 | "*count: 12 \n" \ |
---|
38 | "*ncolors: 64 \n" |
---|
39 | #define BRIGHT_COLORS |
---|
40 | #include "xlockmore.h" /* in xscreensaver distribution */ |
---|
41 | #else /* STANDALONE */ |
---|
42 | #include "xlock.h" /* in xlockmore distribution */ |
---|
43 | |
---|
44 | #endif /* STANDALONE */ |
---|
45 | |
---|
46 | #ifdef MODE_grav |
---|
47 | |
---|
48 | #define DEF_DECAY "False" /* Damping for decaying orbits */ |
---|
49 | #define DEF_TRAIL "False" /* For trails (works good in mono only) */ |
---|
50 | |
---|
51 | static Bool decay; |
---|
52 | static Bool trail; |
---|
53 | |
---|
54 | static XrmOptionDescRec opts[] = |
---|
55 | { |
---|
56 | {(char *) "-decay", (char *) ".grav.decay", XrmoptionNoArg, (caddr_t) "on"}, |
---|
57 | {(char *) "+decay", (char *) ".grav.decay", XrmoptionNoArg, (caddr_t) "off"}, |
---|
58 | {(char *) "-trail", (char *) ".grav.trail", XrmoptionNoArg, (caddr_t) "on"}, |
---|
59 | {(char *) "+trail", (char *) ".grav.trail", XrmoptionNoArg, (caddr_t) "off"} |
---|
60 | }; |
---|
61 | static argtype vars[] = |
---|
62 | { |
---|
63 | {(caddr_t *) & decay, (char *) "decay", (char *) "Decay", (char *) DEF_DECAY, t_Bool}, |
---|
64 | {(caddr_t *) & trail, (char *) "trail", (char *) "Trail", (char *) DEF_TRAIL, t_Bool} |
---|
65 | }; |
---|
66 | static OptionStruct desc[] = |
---|
67 | { |
---|
68 | {(char *) "-/+decay", (char *) "turn on/off decaying orbits"}, |
---|
69 | {(char *) "-/+trail", (char *) "turn on/off trail dots"} |
---|
70 | }; |
---|
71 | |
---|
72 | ModeSpecOpt grav_opts = |
---|
73 | {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; |
---|
74 | |
---|
75 | #ifdef USE_MODULES |
---|
76 | ModStruct grav_description = |
---|
77 | {"grav", "init_grav", "draw_grav", "release_grav", |
---|
78 | "refresh_grav", "init_grav", (char *) NULL, &grav_opts, |
---|
79 | 10000, -12, 1, 1, 64, 1.0, "", |
---|
80 | "Shows orbiting planets", 0, NULL}; |
---|
81 | |
---|
82 | #endif |
---|
83 | |
---|
84 | #define GRAV -0.02 /* Gravitational constant */ |
---|
85 | #define DIST 16.0 |
---|
86 | #define COLLIDE 0.0001 |
---|
87 | #define ALMOST 15.99 |
---|
88 | #define HALF 0.5 |
---|
89 | /* #define INTRINSIC_RADIUS 200.0 */ |
---|
90 | #define INTRINSIC_RADIUS ((float) (gp->height/5)) |
---|
91 | #define STARRADIUS (unsigned int)(gp->height/(2*DIST)) |
---|
92 | #define AVG_RADIUS (INTRINSIC_RADIUS/DIST) |
---|
93 | #define RADIUS (unsigned int)(INTRINSIC_RADIUS/(POS(Z)+DIST)) |
---|
94 | |
---|
95 | #define XR HALF*ALMOST |
---|
96 | #define YR HALF*ALMOST |
---|
97 | #define ZR HALF*ALMOST |
---|
98 | |
---|
99 | #define VR 0.04 |
---|
100 | |
---|
101 | #define DIMENSIONS 3 |
---|
102 | #define X 0 |
---|
103 | #define Y 1 |
---|
104 | #define Z 2 |
---|
105 | |
---|
106 | #define DAMP 0.999999 |
---|
107 | #define MaxA 0.1 /* Maximum acceleration (w/ damping) */ |
---|
108 | |
---|
109 | #define POS(c) planet->P[c] |
---|
110 | #define VEL(c) planet->V[c] |
---|
111 | #define ACC(c) planet->A[c] |
---|
112 | |
---|
113 | #define Planet(x,y)\ |
---|
114 | if ((x) >= 0 && (y) >= 0 && (x) <= gp->width && (y) <= gp->height) {\ |
---|
115 | if (planet->ri < 2)\ |
---|
116 | XDrawPoint(display, window, gc, (x), (y));\ |
---|
117 | else\ |
---|
118 | XFillArc(display, window, gc,\ |
---|
119 | (x) - planet->ri / 2, (y) - planet->ri / 2, planet->ri, planet->ri,\ |
---|
120 | 0, 23040);\ |
---|
121 | } |
---|
122 | |
---|
123 | #define FLOATRAND(min,max) ((min)+(LRAND()/MAXRAND)*((max)-(min))) |
---|
124 | |
---|
125 | typedef struct { |
---|
126 | double P[DIMENSIONS], V[DIMENSIONS], A[DIMENSIONS]; |
---|
127 | int xi, yi, ri; |
---|
128 | unsigned long colors; |
---|
129 | } planetstruct; |
---|
130 | |
---|
131 | typedef struct { |
---|
132 | int width, height; |
---|
133 | int x, y, sr, nplanets; |
---|
134 | unsigned long starcolor; |
---|
135 | planetstruct *planets; |
---|
136 | } gravstruct; |
---|
137 | |
---|
138 | static gravstruct *gravs = (gravstruct *) NULL; |
---|
139 | |
---|
140 | static void |
---|
141 | init_planet(ModeInfo * mi, planetstruct * planet) |
---|
142 | { |
---|
143 | Display *display = MI_DISPLAY(mi); |
---|
144 | Window window = MI_WINDOW(mi); |
---|
145 | GC gc = MI_GC(mi); |
---|
146 | gravstruct *gp = &gravs[MI_SCREEN(mi)]; |
---|
147 | |
---|
148 | if (MI_NPIXELS(mi) > 2) |
---|
149 | planet->colors = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))); |
---|
150 | else |
---|
151 | planet->colors = MI_WHITE_PIXEL(mi); |
---|
152 | /* Initialize positions */ |
---|
153 | POS(X) = FLOATRAND(-XR, XR); |
---|
154 | POS(Y) = FLOATRAND(-YR, YR); |
---|
155 | POS(Z) = FLOATRAND(-ZR, ZR); |
---|
156 | |
---|
157 | if (POS(Z) > -ALMOST) { |
---|
158 | planet->xi = (int) |
---|
159 | ((double) gp->width * (HALF + POS(X) / (POS(Z) + DIST))); |
---|
160 | planet->yi = (int) |
---|
161 | ((double) gp->height * (HALF + POS(Y) / (POS(Z) + DIST))); |
---|
162 | } else |
---|
163 | planet->xi = planet->yi = -1; |
---|
164 | planet->ri = RADIUS; |
---|
165 | |
---|
166 | /* Initialize velocities */ |
---|
167 | VEL(X) = FLOATRAND(-VR, VR); |
---|
168 | VEL(Y) = FLOATRAND(-VR, VR); |
---|
169 | VEL(Z) = FLOATRAND(-VR, VR); |
---|
170 | |
---|
171 | /* Draw planets */ |
---|
172 | Planet(planet->xi, planet->yi); |
---|
173 | } |
---|
174 | |
---|
175 | static void |
---|
176 | draw_planet(ModeInfo * mi, planetstruct * planet) |
---|
177 | { |
---|
178 | Display *display = MI_DISPLAY(mi); |
---|
179 | Window window = MI_WINDOW(mi); |
---|
180 | GC gc = MI_GC(mi); |
---|
181 | gravstruct *gp = &gravs[MI_SCREEN(mi)]; |
---|
182 | double D; /* A distance variable to work with */ |
---|
183 | register unsigned char cmpt; |
---|
184 | |
---|
185 | D = POS(X) * POS(X) + POS(Y) * POS(Y) + POS(Z) * POS(Z); |
---|
186 | if (D < COLLIDE) |
---|
187 | D = COLLIDE; |
---|
188 | D = sqrt(D); |
---|
189 | D = D * D * D; |
---|
190 | for (cmpt = X; cmpt < DIMENSIONS; cmpt++) { |
---|
191 | ACC(cmpt) = POS(cmpt) * GRAV / D; |
---|
192 | if (decay) { |
---|
193 | if (ACC(cmpt) > MaxA) |
---|
194 | ACC(cmpt) = MaxA; |
---|
195 | else if (ACC(cmpt) < -MaxA) |
---|
196 | ACC(cmpt) = -MaxA; |
---|
197 | VEL(cmpt) = VEL(cmpt) + ACC(cmpt); |
---|
198 | VEL(cmpt) *= DAMP; |
---|
199 | } else { |
---|
200 | /* update velocity */ |
---|
201 | VEL(cmpt) = VEL(cmpt) + ACC(cmpt); |
---|
202 | } |
---|
203 | /* update position */ |
---|
204 | POS(cmpt) = POS(cmpt) + VEL(cmpt); |
---|
205 | } |
---|
206 | |
---|
207 | gp->x = planet->xi; |
---|
208 | gp->y = planet->yi; |
---|
209 | |
---|
210 | if (POS(Z) > -ALMOST) { |
---|
211 | planet->xi = (int) |
---|
212 | ((double) gp->width * (HALF + POS(X) / (POS(Z) + DIST))); |
---|
213 | planet->yi = (int) |
---|
214 | ((double) gp->height * (HALF + POS(Y) / (POS(Z) + DIST))); |
---|
215 | } else |
---|
216 | planet->xi = planet->yi = -1; |
---|
217 | |
---|
218 | /* Mask */ |
---|
219 | XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); |
---|
220 | Planet(gp->x, gp->y); |
---|
221 | if (trail) { |
---|
222 | XSetForeground(display, gc, planet->colors); |
---|
223 | XDrawPoint(display, MI_WINDOW(mi), gc, gp->x, gp->y); |
---|
224 | } |
---|
225 | /* Move */ |
---|
226 | gp->x = planet->xi; |
---|
227 | gp->y = planet->yi; |
---|
228 | planet->ri = RADIUS; |
---|
229 | |
---|
230 | /* Redraw */ |
---|
231 | XSetForeground(display, gc, planet->colors); |
---|
232 | Planet(gp->x, gp->y); |
---|
233 | } |
---|
234 | |
---|
235 | void |
---|
236 | init_grav(ModeInfo * mi) |
---|
237 | { |
---|
238 | Display *display = MI_DISPLAY(mi); |
---|
239 | GC gc = MI_GC(mi); |
---|
240 | unsigned char ball; |
---|
241 | gravstruct *gp; |
---|
242 | |
---|
243 | if (gravs == NULL) { |
---|
244 | if ((gravs = (gravstruct *) calloc(MI_NUM_SCREENS(mi), |
---|
245 | sizeof (gravstruct))) == NULL) |
---|
246 | return; |
---|
247 | } |
---|
248 | gp = &gravs[MI_SCREEN(mi)]; |
---|
249 | |
---|
250 | gp->width = MI_WIDTH(mi); |
---|
251 | gp->height = MI_HEIGHT(mi); |
---|
252 | |
---|
253 | gp->sr = STARRADIUS; |
---|
254 | |
---|
255 | gp->nplanets = MI_COUNT(mi); |
---|
256 | if (gp->nplanets < 0) { |
---|
257 | if (gp->planets) { |
---|
258 | (void) free((void *) gp->planets); |
---|
259 | gp->planets = (planetstruct *) NULL; |
---|
260 | } |
---|
261 | gp->nplanets = NRAND(-gp->nplanets) + 1; /* Add 1 so its not too boring */ |
---|
262 | } |
---|
263 | if (gp->planets == NULL) { |
---|
264 | if ((gp->planets = (planetstruct *) calloc(gp->nplanets, |
---|
265 | sizeof (planetstruct))) == NULL) |
---|
266 | return; |
---|
267 | } |
---|
268 | |
---|
269 | MI_CLEARWINDOW(mi); |
---|
270 | |
---|
271 | if (MI_NPIXELS(mi) > 2) |
---|
272 | gp->starcolor = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))); |
---|
273 | else |
---|
274 | gp->starcolor = MI_WHITE_PIXEL(mi); |
---|
275 | for (ball = 0; ball < (unsigned char) gp->nplanets; ball++) |
---|
276 | init_planet(mi, &gp->planets[ball]); |
---|
277 | |
---|
278 | /* Draw centrepoint */ |
---|
279 | XDrawArc(display, MI_WINDOW(mi), gc, |
---|
280 | gp->width / 2 - gp->sr / 2, gp->height / 2 - gp->sr / 2, gp->sr, gp->sr, |
---|
281 | 0, 23040); |
---|
282 | } |
---|
283 | |
---|
284 | void |
---|
285 | draw_grav(ModeInfo * mi) |
---|
286 | { |
---|
287 | Display *display = MI_DISPLAY(mi); |
---|
288 | Window window = MI_WINDOW(mi); |
---|
289 | GC gc = MI_GC(mi); |
---|
290 | register unsigned char ball; |
---|
291 | gravstruct *gp; |
---|
292 | |
---|
293 | if (gravs == NULL) |
---|
294 | return; |
---|
295 | gp = &gravs[MI_SCREEN(mi)]; |
---|
296 | if (gp->planets == NULL) |
---|
297 | return; |
---|
298 | |
---|
299 | MI_IS_DRAWN(mi) = True; |
---|
300 | /* Mask centrepoint */ |
---|
301 | XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); |
---|
302 | XDrawArc(display, window, gc, |
---|
303 | gp->width / 2 - gp->sr / 2, gp->height / 2 - gp->sr / 2, gp->sr, gp->sr, |
---|
304 | 0, 23040); |
---|
305 | |
---|
306 | /* Resize centrepoint */ |
---|
307 | switch (NRAND(4)) { |
---|
308 | case 0: |
---|
309 | if (gp->sr < (int) STARRADIUS) |
---|
310 | gp->sr++; |
---|
311 | break; |
---|
312 | case 1: |
---|
313 | if (gp->sr > 2) |
---|
314 | gp->sr--; |
---|
315 | } |
---|
316 | |
---|
317 | /* Draw centrepoint */ |
---|
318 | XSetForeground(display, gc, gp->starcolor); |
---|
319 | XDrawArc(display, window, gc, |
---|
320 | gp->width / 2 - gp->sr / 2, gp->height / 2 - gp->sr / 2, gp->sr, gp->sr, |
---|
321 | 0, 23040); |
---|
322 | |
---|
323 | for (ball = 0; ball < (unsigned char) gp->nplanets; ball++) |
---|
324 | draw_planet(mi, &gp->planets[ball]); |
---|
325 | } |
---|
326 | |
---|
327 | void |
---|
328 | release_grav(ModeInfo * mi) |
---|
329 | { |
---|
330 | if (gravs != NULL) { |
---|
331 | int screen; |
---|
332 | |
---|
333 | for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { |
---|
334 | gravstruct *gp = &gravs[screen]; |
---|
335 | |
---|
336 | if (gp->planets) |
---|
337 | (void) free((void *) gp->planets); |
---|
338 | } |
---|
339 | (void) free((void *) gravs); |
---|
340 | gravs = (gravstruct *) NULL; |
---|
341 | } |
---|
342 | } |
---|
343 | |
---|
344 | void |
---|
345 | refresh_grav(ModeInfo * mi) |
---|
346 | { |
---|
347 | MI_CLEARWINDOW(mi); |
---|
348 | } |
---|
349 | |
---|
350 | #endif /* MODE_grav */ |
---|