1 /* -*- Mode: C; tab-width: 4 -*-
2 * grav --- simulation of a planetary system.
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)grav.c 4.00 97/01/01 xlockmore";
8 /* Copyright (c) 1993 Greg Bowering <greg@smug.student.adelaide.edu.au>
10 * Permission to use, copy, modify, and distribute this software and its
11 * documentation for any purpose and without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and that
13 * both that copyright notice and this permission notice appear in
14 * supporting documentation.
16 * This file is provided AS IS with no warranties of any kind. The author
17 * shall have no liability with respect to the infringement of copyrights,
18 * trade secrets or any patents by this file or any part thereof. In no
19 * event will the author be liable for any lost revenue or profits or
20 * other special, indirect and consequential damages.
23 * 10-May-97: jwz@jwz.org: turned into a standalone program.
24 * 11-Jul-94: color version
25 * 06-Oct-93: by Greg Bowering <greg@smug.student.adelaide.edu.au>
29 # define PROGCLASS "Grav"
30 # define HACK_INIT init_grav
31 # define HACK_DRAW draw_grav
32 # define grav_opts xlockmore_opts
33 # define DEFAULTS "*count: 12 \n" \
36 # define BRIGHT_COLORS
37 # include "xlockmore.h" /* from the xscreensaver distribution */
38 #else /* !STANDALONE */
39 # include "xlock.h" /* from the xlockmore distribution */
40 #endif /* !STANDALONE */
42 #define GRAV -0.02 /* Gravitational constant */
44 #define COLLIDE 0.0001
47 /* #define INTRINSIC_RADIUS 200.0 */
48 #define INTRINSIC_RADIUS ((float) (gp->height/5))
49 #define STARRADIUS (unsigned int)(gp->height/(2*DIST))
50 #define AVG_RADIUS (INTRINSIC_RADIUS/DIST)
51 #define RADIUS (unsigned int)(INTRINSIC_RADIUS/(POS(Z)+DIST))
53 #define XR HALF*ALMOST
54 #define YR HALF*ALMOST
55 #define ZR HALF*ALMOST
65 #define MaxA 0.1 /* Maximum acceleration (w/ damping) */
67 #define POS(c) planet->P[c]
68 #define VEL(c) planet->V[c]
69 #define ACC(c) planet->A[c]
72 if ((x) >= 0 && (y) >= 0 && (x) <= gp->width && (y) <= gp->height) {\
74 XDrawPoint(display, window, gc, (x), (y));\
76 XFillArc(display, window, gc,\
77 (x) - planet->ri / 2, (y) - planet->ri / 2, planet->ri, planet->ri,\
81 #define FLOATRAND(min,max) ((min)+(LRAND()/MAXRAND)*((max)-(min)))
83 #define DEF_DECAY "False" /* Damping for decaying orbits */
84 #define DEF_TRAIL "False" /* For trails (works good in mono only) */
89 static XrmOptionDescRec opts[] =
91 {"-decay", ".grav.decay", XrmoptionNoArg, (caddr_t) "on"},
92 {"+decay", ".grav.decay", XrmoptionNoArg, (caddr_t) "off"},
93 {"-trail", ".grav.trail", XrmoptionNoArg, (caddr_t) "on"},
94 {"+trail", ".grav.trail", XrmoptionNoArg, (caddr_t) "off"}
96 static argtype vars[] =
98 {(caddr_t *) & decay, "decay", "Decay", DEF_DECAY, t_Bool},
99 {(caddr_t *) & trail, "trail", "Trail", DEF_TRAIL, t_Bool}
101 static OptionStruct desc[] =
103 {"-/+decay", "turn on/off decaying orbits"},
104 {"-/+trail", "turn on/off trail dots"}
107 ModeSpecOpt grav_opts = { 4, opts, 2, vars, desc };
110 double P[DIMENSIONS], V[DIMENSIONS], A[DIMENSIONS];
112 unsigned long colors;
117 int x, y, sr, nplanets;
118 unsigned long starcolor;
119 planetstruct *planets;
122 static gravstruct *gravs = NULL;
125 init_planet(ModeInfo * mi, planetstruct * planet)
127 Display *display = MI_DISPLAY(mi);
128 Window window = MI_WINDOW(mi);
130 gravstruct *gp = &gravs[MI_SCREEN(mi)];
132 if (MI_NPIXELS(mi) > 2)
133 planet->colors = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
135 planet->colors = MI_WIN_WHITE_PIXEL(mi);
136 /* Initialize positions */
137 POS(X) = FLOATRAND(-XR, XR);
138 POS(Y) = FLOATRAND(-YR, YR);
139 POS(Z) = FLOATRAND(-ZR, ZR);
141 if (POS(Z) > -ALMOST) {
143 ((double) gp->width * (HALF + POS(X) / (POS(Z) + DIST)));
145 ((double) gp->height * (HALF + POS(Y) / (POS(Z) + DIST)));
147 planet->xi = planet->yi = -1;
150 /* Initialize velocities */
151 VEL(X) = FLOATRAND(-VR, VR);
152 VEL(Y) = FLOATRAND(-VR, VR);
153 VEL(Z) = FLOATRAND(-VR, VR);
156 Planet(planet->xi, planet->yi);
160 draw_planet(ModeInfo * mi, planetstruct * planet)
162 Display *display = MI_DISPLAY(mi);
163 Window window = MI_WINDOW(mi);
165 gravstruct *gp = &gravs[MI_SCREEN(mi)];
166 double D; /* A distance variable to work with */
167 register unsigned char cmpt;
169 D = POS(X) * POS(X) + POS(Y) * POS(Y) + POS(Z) * POS(Z);
174 for (cmpt = X; cmpt < DIMENSIONS; cmpt++) {
175 ACC(cmpt) = POS(cmpt) * GRAV / D;
177 if (ACC(cmpt) > MaxA)
179 else if (ACC(cmpt) < -MaxA)
181 VEL(cmpt) = VEL(cmpt) + ACC(cmpt);
184 /* update velocity */
185 VEL(cmpt) = VEL(cmpt) + ACC(cmpt);
187 /* update position */
188 POS(cmpt) = POS(cmpt) + VEL(cmpt);
194 if (POS(Z) > -ALMOST) {
196 ((double) gp->width * (HALF + POS(X) / (POS(Z) + DIST)));
198 ((double) gp->height * (HALF + POS(Y) / (POS(Z) + DIST)));
200 planet->xi = planet->yi = -1;
203 XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
204 Planet(gp->x, gp->y);
206 XSetForeground(display, gc, planet->colors);
207 XDrawPoint(display, MI_WINDOW(mi), gc, gp->x, gp->y);
215 XSetForeground(display, gc, planet->colors);
216 Planet(gp->x, gp->y);
220 init_grav(ModeInfo * mi)
222 Display *display = MI_DISPLAY(mi);
228 if ((gravs = (gravstruct *) calloc(MI_NUM_SCREENS(mi),
229 sizeof (gravstruct))) == NULL)
232 gp = &gravs[MI_SCREEN(mi)];
234 gp->width = MI_WIN_WIDTH(mi);
235 gp->height = MI_WIN_HEIGHT(mi);
239 gp->nplanets = MI_BATCHCOUNT(mi);
240 if (gp->nplanets < 0) {
242 (void) free((void *) gp->planets);
245 gp->nplanets = NRAND(-gp->nplanets) + 1; /* Add 1 so its not too boring */
248 gp->planets = (planetstruct *) calloc(gp->nplanets, sizeof (planetstruct));
250 XClearWindow(display, MI_WINDOW(mi));
252 if (MI_NPIXELS(mi) > 2)
253 gp->starcolor = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
255 gp->starcolor = MI_WIN_WHITE_PIXEL(mi);
256 for (ball = 0; ball < (unsigned char) gp->nplanets; ball++)
257 init_planet(mi, &gp->planets[ball]);
259 /* Draw centrepoint */
260 XDrawArc(display, MI_WINDOW(mi), gc,
261 gp->width / 2 - gp->sr / 2, gp->height / 2 - gp->sr / 2, gp->sr, gp->sr,
266 draw_grav(ModeInfo * mi)
268 Display *display = MI_DISPLAY(mi);
269 Window window = MI_WINDOW(mi);
271 gravstruct *gp = &gravs[MI_SCREEN(mi)];
272 register unsigned char ball;
274 /* Mask centrepoint */
275 XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
276 XDrawArc(display, window, gc,
277 gp->width / 2 - gp->sr / 2, gp->height / 2 - gp->sr / 2, gp->sr, gp->sr,
280 /* Resize centrepoint */
283 if (gp->sr < (int) STARRADIUS)
291 /* Draw centrepoint */
292 XSetForeground(display, gc, gp->starcolor);
293 XDrawArc(display, window, gc,
294 gp->width / 2 - gp->sr / 2, gp->height / 2 - gp->sr / 2, gp->sr, gp->sr,
297 for (ball = 0; ball < (unsigned char) gp->nplanets; ball++)
298 draw_planet(mi, &gp->planets[ball]);
302 release_grav(ModeInfo * mi)
307 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
308 gravstruct *gp = &gravs[screen];
311 (void) free((void *) gp->planets);
313 (void) free((void *) gravs);
319 refresh_grav(ModeInfo * mi)
321 /* Do nothing, it will refresh by itself */