1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* grav --- planets spinning around a pulsar */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)grav.c 5.00 2000/11/01 xlockmore";
10 * Copyright (c) 1993 by Greg Boewring <gb@pobox.com>
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
18 * This file is provided AS IS with no warranties of any kind. The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof. In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
25 * 01-Nov-2000: Allocation checks
26 * 10-May-1997: Compatible with xscreensaver
27 * 11-Jul-1994: color version
28 * 06-Oct-1993: Written by Greg Bowering <gb@pobox.com>
33 #define PROGCLASS "Grav"
34 #define HACK_INIT init_grav
35 #define HACK_DRAW draw_grav
36 #define grav_opts xlockmore_opts
37 #define DEFAULTS "*delay: 10000 \n" \
41 #include "xlockmore.h" /* in xscreensaver distribution */
42 #else /* STANDALONE */
43 #include "xlock.h" /* in xlockmore distribution */
45 #endif /* STANDALONE */
49 #define DEF_DECAY "False" /* Damping for decaying orbits */
50 #define DEF_TRAIL "False" /* For trails (works good in mono only) */
55 static XrmOptionDescRec opts[] =
57 {(char *) "-decay", (char *) ".grav.decay", XrmoptionNoArg, (caddr_t) "on"},
58 {(char *) "+decay", (char *) ".grav.decay", XrmoptionNoArg, (caddr_t) "off"},
59 {(char *) "-trail", (char *) ".grav.trail", XrmoptionNoArg, (caddr_t) "on"},
60 {(char *) "+trail", (char *) ".grav.trail", XrmoptionNoArg, (caddr_t) "off"}
62 static argtype vars[] =
64 {(caddr_t *) & decay, (char *) "decay", (char *) "Decay", (char *) DEF_DECAY, t_Bool},
65 {(caddr_t *) & trail, (char *) "trail", (char *) "Trail", (char *) DEF_TRAIL, t_Bool}
67 static OptionStruct desc[] =
69 {(char *) "-/+decay", (char *) "turn on/off decaying orbits"},
70 {(char *) "-/+trail", (char *) "turn on/off trail dots"}
73 ModeSpecOpt grav_opts =
74 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
77 ModStruct grav_description =
78 {"grav", "init_grav", "draw_grav", "release_grav",
79 "refresh_grav", "init_grav", (char *) NULL, &grav_opts,
80 10000, -12, 1, 1, 64, 1.0, "",
81 "Shows orbiting planets", 0, NULL};
85 #define GRAV -0.02 /* Gravitational constant */
87 #define COLLIDE 0.0001
90 /* #define INTRINSIC_RADIUS 200.0 */
91 #define INTRINSIC_RADIUS ((float) (gp->height/5))
92 #define STARRADIUS (unsigned int)(gp->height/(2*DIST))
93 #define AVG_RADIUS (INTRINSIC_RADIUS/DIST)
94 #define RADIUS (unsigned int)(INTRINSIC_RADIUS/(POS(Z)+DIST))
96 #define XR HALF*ALMOST
97 #define YR HALF*ALMOST
98 #define ZR HALF*ALMOST
107 #define DAMP 0.999999
108 #define MaxA 0.1 /* Maximum acceleration (w/ damping) */
110 #define POS(c) planet->P[c]
111 #define VEL(c) planet->V[c]
112 #define ACC(c) planet->A[c]
115 if ((x) >= 0 && (y) >= 0 && (x) <= gp->width && (y) <= gp->height) {\
117 XDrawPoint(display, window, gc, (x), (y));\
119 XFillArc(display, window, gc,\
120 (x) - planet->ri / 2, (y) - planet->ri / 2, planet->ri, planet->ri,\
124 #define FLOATRAND(min,max) ((min)+(LRAND()/MAXRAND)*((max)-(min)))
127 double P[DIMENSIONS], V[DIMENSIONS], A[DIMENSIONS];
129 unsigned long colors;
134 int x, y, sr, nplanets;
135 unsigned long starcolor;
136 planetstruct *planets;
139 static gravstruct *gravs = (gravstruct *) NULL;
142 init_planet(ModeInfo * mi, planetstruct * planet)
144 Display *display = MI_DISPLAY(mi);
145 Window window = MI_WINDOW(mi);
147 gravstruct *gp = &gravs[MI_SCREEN(mi)];
149 if (MI_NPIXELS(mi) > 2)
150 planet->colors = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
152 planet->colors = MI_WHITE_PIXEL(mi);
153 /* Initialize positions */
154 POS(X) = FLOATRAND(-XR, XR);
155 POS(Y) = FLOATRAND(-YR, YR);
156 POS(Z) = FLOATRAND(-ZR, ZR);
158 if (POS(Z) > -ALMOST) {
160 ((double) gp->width * (HALF + POS(X) / (POS(Z) + DIST)));
162 ((double) gp->height * (HALF + POS(Y) / (POS(Z) + DIST)));
164 planet->xi = planet->yi = -1;
167 /* Initialize velocities */
168 VEL(X) = FLOATRAND(-VR, VR);
169 VEL(Y) = FLOATRAND(-VR, VR);
170 VEL(Z) = FLOATRAND(-VR, VR);
173 Planet(planet->xi, planet->yi);
177 draw_planet(ModeInfo * mi, planetstruct * planet)
179 Display *display = MI_DISPLAY(mi);
180 Window window = MI_WINDOW(mi);
182 gravstruct *gp = &gravs[MI_SCREEN(mi)];
183 double D; /* A distance variable to work with */
184 register unsigned char cmpt;
186 D = POS(X) * POS(X) + POS(Y) * POS(Y) + POS(Z) * POS(Z);
191 for (cmpt = X; cmpt < DIMENSIONS; cmpt++) {
192 ACC(cmpt) = POS(cmpt) * GRAV / D;
194 if (ACC(cmpt) > MaxA)
196 else if (ACC(cmpt) < -MaxA)
198 VEL(cmpt) = VEL(cmpt) + ACC(cmpt);
201 /* update velocity */
202 VEL(cmpt) = VEL(cmpt) + ACC(cmpt);
204 /* update position */
205 POS(cmpt) = POS(cmpt) + VEL(cmpt);
211 if (POS(Z) > -ALMOST) {
213 ((double) gp->width * (HALF + POS(X) / (POS(Z) + DIST)));
215 ((double) gp->height * (HALF + POS(Y) / (POS(Z) + DIST)));
217 planet->xi = planet->yi = -1;
220 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
221 Planet(gp->x, gp->y);
223 XSetForeground(display, gc, planet->colors);
224 XDrawPoint(display, MI_WINDOW(mi), gc, gp->x, gp->y);
232 XSetForeground(display, gc, planet->colors);
233 Planet(gp->x, gp->y);
237 init_grav(ModeInfo * mi)
239 Display *display = MI_DISPLAY(mi);
245 if ((gravs = (gravstruct *) calloc(MI_NUM_SCREENS(mi),
246 sizeof (gravstruct))) == NULL)
249 gp = &gravs[MI_SCREEN(mi)];
251 gp->width = MI_WIDTH(mi);
252 gp->height = MI_HEIGHT(mi);
256 gp->nplanets = MI_COUNT(mi);
257 if (gp->nplanets < 0) {
259 (void) free((void *) gp->planets);
260 gp->planets = (planetstruct *) NULL;
262 gp->nplanets = NRAND(-gp->nplanets) + 1; /* Add 1 so its not too boring */
264 if (gp->planets == NULL) {
265 if ((gp->planets = (planetstruct *) calloc(gp->nplanets,
266 sizeof (planetstruct))) == NULL)
272 if (MI_NPIXELS(mi) > 2)
273 gp->starcolor = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
275 gp->starcolor = MI_WHITE_PIXEL(mi);
276 for (ball = 0; ball < (unsigned char) gp->nplanets; ball++)
277 init_planet(mi, &gp->planets[ball]);
279 /* Draw centrepoint */
280 XDrawArc(display, MI_WINDOW(mi), gc,
281 gp->width / 2 - gp->sr / 2, gp->height / 2 - gp->sr / 2, gp->sr, gp->sr,
286 draw_grav(ModeInfo * mi)
288 Display *display = MI_DISPLAY(mi);
289 Window window = MI_WINDOW(mi);
291 register unsigned char ball;
296 gp = &gravs[MI_SCREEN(mi)];
297 if (gp->planets == NULL)
300 MI_IS_DRAWN(mi) = True;
301 /* Mask centrepoint */
302 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
303 XDrawArc(display, window, gc,
304 gp->width / 2 - gp->sr / 2, gp->height / 2 - gp->sr / 2, gp->sr, gp->sr,
307 /* Resize centrepoint */
310 if (gp->sr < (int) STARRADIUS)
318 /* Draw centrepoint */
319 XSetForeground(display, gc, gp->starcolor);
320 XDrawArc(display, window, gc,
321 gp->width / 2 - gp->sr / 2, gp->height / 2 - gp->sr / 2, gp->sr, gp->sr,
324 for (ball = 0; ball < (unsigned char) gp->nplanets; ball++)
325 draw_planet(mi, &gp->planets[ball]);
329 release_grav(ModeInfo * mi)
334 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
335 gravstruct *gp = &gravs[screen];
338 (void) free((void *) gp->planets);
340 (void) free((void *) gravs);
341 gravs = (gravstruct *) NULL;
346 refresh_grav(ModeInfo * mi)
351 #endif /* MODE_grav */