began for maemo
[xscreensaver] / xscreensaver / hacks / grav.c
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 DEFAULTS        "*delay: 10000 \n" \
33                                         "*count: 12 \n" \
34                                         "*ncolors: 64 \n"
35 #define BRIGHT_COLORS
36 # define reshape_grav 0
37 # define grav_handle_event 0
38 # include "xlockmore.h"         /* in xscreensaver distribution */
39 #else /* STANDALONE */
40 # include "xlock.h"             /* in xlockmore distribution */
41 #endif /* STANDALONE */
42
43 #ifdef MODE_grav
44
45 #define DEF_DECAY "True"        /* Damping for decaying orbits */
46 #define DEF_TRAIL "True"        /* For trails (works good in mono only) */
47
48 static Bool decay;
49 static Bool trail;
50
51 static XrmOptionDescRec opts[] =
52 {
53         {"-decay", ".grav.decay", XrmoptionNoArg, "on"},
54         {"+decay", ".grav.decay", XrmoptionNoArg, "off"},
55         {"-trail", ".grav.trail", XrmoptionNoArg, "on"},
56         {"+trail", ".grav.trail", XrmoptionNoArg, "off"}
57 };
58 static argtype vars[] =
59 {
60         {&decay, "decay", "Decay", DEF_DECAY, t_Bool},
61         {&trail, "trail", "Trail", DEF_TRAIL, t_Bool}
62 };
63 static OptionStruct desc[] =
64 {
65         {"-/+decay", "turn on/off decaying orbits"},
66         {"-/+trail", "turn on/off trail dots"}
67 };
68
69 ENTRYPOINT ModeSpecOpt grav_opts =
70 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
71
72 #ifdef USE_MODULES
73 ModStruct   grav_description =
74 {"grav", "init_grav", "draw_grav", "release_grav",
75  "refresh_grav", "init_grav", (char *) NULL, &grav_opts,
76  10000, -12, 1, 1, 64, 1.0, "",
77  "Shows orbiting planets", 0, NULL};
78
79 #endif
80
81 #define GRAV                    -0.02   /* Gravitational constant */
82 #define DIST                    16.0
83 #define COLLIDE                 0.0001
84 #define ALMOST                  15.99
85 #define HALF                    0.5
86 /* #define INTRINSIC_RADIUS     200.0 */
87 #define INTRINSIC_RADIUS        ((float) (gp->height/5))
88 #define STARRADIUS              (unsigned int)(gp->height/(2*DIST))
89 #define AVG_RADIUS              (INTRINSIC_RADIUS/DIST)
90 #define RADIUS                  (unsigned int)(INTRINSIC_RADIUS/(POS(Z)+DIST))
91
92 #define XR                      HALF*ALMOST
93 #define YR                      HALF*ALMOST
94 #define ZR                      HALF*ALMOST
95
96 #define VR                      0.04
97
98 #define DIMENSIONS              3
99 #define X                       0
100 #define Y                       1
101 #define Z                       2
102
103 #define DAMP                    0.999999
104 #define MaxA                    0.1     /* Maximum acceleration (w/ damping) */
105
106 #define POS(c) planet->P[c]
107 #define VEL(c) planet->V[c]
108 #define ACC(c) planet->A[c]
109
110 #define Planet(x,y)\
111   if ((x) >= 0 && (y) >= 0 && (x) <= gp->width && (y) <= gp->height) {\
112     if (planet->ri < 2)\
113      XDrawPoint(display, window, gc, (x), (y));\
114     else\
115      XFillArc(display, window, gc,\
116       (x) - planet->ri / 2, (y) - planet->ri / 2, planet->ri, planet->ri,\
117       0, 23040);\
118    }
119
120 #define FLOATRAND(min,max)      ((min)+(LRAND()/MAXRAND)*((max)-(min)))
121
122 typedef struct {
123         double      P[DIMENSIONS], V[DIMENSIONS], A[DIMENSIONS];
124         int         xi, yi, ri;
125         unsigned long colors;
126 } planetstruct;
127
128 typedef struct {
129         int         width, height;
130         int         x, y, sr, nplanets;
131         unsigned long starcolor;
132         planetstruct *planets;
133 } gravstruct;
134
135 static gravstruct *gravs = (gravstruct *) NULL;
136
137 static void
138 init_planet(ModeInfo * mi, planetstruct * planet)
139 {
140         Display    *display = MI_DISPLAY(mi);
141         Window      window = MI_WINDOW(mi);
142         GC          gc = MI_GC(mi);
143         gravstruct *gp = &gravs[MI_SCREEN(mi)];
144
145 # ifdef HAVE_COCOA
146     jwxyz_XSetAntiAliasing (MI_DISPLAY(mi), MI_GC(mi), False);
147 # endif
148
149         if (MI_NPIXELS(mi) > 2)
150                 planet->colors = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
151         else
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);
157
158         if (POS(Z) > -ALMOST) {
159                 planet->xi = (int)
160                         ((double) gp->width * (HALF + POS(X) / (POS(Z) + DIST)));
161                 planet->yi = (int)
162                         ((double) gp->height * (HALF + POS(Y) / (POS(Z) + DIST)));
163         } else
164                 planet->xi = planet->yi = -1;
165         planet->ri = RADIUS;
166
167         /* Initialize velocities */
168         VEL(X) = FLOATRAND(-VR, VR);
169         VEL(Y) = FLOATRAND(-VR, VR);
170         VEL(Z) = FLOATRAND(-VR, VR);
171
172         /* Draw planets */
173         Planet(planet->xi, planet->yi);
174 }
175
176 static void
177 draw_planet(ModeInfo * mi, planetstruct * planet)
178 {
179         Display    *display = MI_DISPLAY(mi);
180         Window      window = MI_WINDOW(mi);
181         GC          gc = MI_GC(mi);
182         gravstruct *gp = &gravs[MI_SCREEN(mi)];
183         double      D;          /* A distance variable to work with */
184         register unsigned char cmpt;
185
186         D = POS(X) * POS(X) + POS(Y) * POS(Y) + POS(Z) * POS(Z);
187         if (D < COLLIDE)
188                 D = COLLIDE;
189         D = sqrt(D);
190         D = D * D * D;
191         for (cmpt = X; cmpt < DIMENSIONS; cmpt++) {
192                 ACC(cmpt) = POS(cmpt) * GRAV / D;
193                 if (decay) {
194                         if (ACC(cmpt) > MaxA)
195                                 ACC(cmpt) = MaxA;
196                         else if (ACC(cmpt) < -MaxA)
197                                 ACC(cmpt) = -MaxA;
198                         VEL(cmpt) = VEL(cmpt) + ACC(cmpt);
199                         VEL(cmpt) *= DAMP;
200                 } else {
201                         /* update velocity */
202                         VEL(cmpt) = VEL(cmpt) + ACC(cmpt);
203                 }
204                 /* update position */
205                 POS(cmpt) = POS(cmpt) + VEL(cmpt);
206         }
207
208         gp->x = planet->xi;
209         gp->y = planet->yi;
210
211         if (POS(Z) > -ALMOST) {
212                 planet->xi = (int)
213                         ((double) gp->width * (HALF + POS(X) / (POS(Z) + DIST)));
214                 planet->yi = (int)
215                         ((double) gp->height * (HALF + POS(Y) / (POS(Z) + DIST)));
216         } else
217                 planet->xi = planet->yi = -1;
218
219         /* Mask */
220         XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
221         Planet(gp->x, gp->y);
222         if (trail) {
223                 XSetForeground(display, gc, planet->colors);
224                 XDrawPoint(display, MI_WINDOW(mi), gc, gp->x, gp->y);
225         }
226         /* Move */
227         gp->x = planet->xi;
228         gp->y = planet->yi;
229         planet->ri = RADIUS;
230
231         /* Redraw */
232         XSetForeground(display, gc, planet->colors);
233         Planet(gp->x, gp->y);
234 }
235
236 ENTRYPOINT void
237 init_grav(ModeInfo * mi)
238 {
239         Display    *display = MI_DISPLAY(mi);
240         GC          gc = MI_GC(mi);
241         unsigned char ball;
242         gravstruct *gp;
243
244         if (gravs == NULL) {
245                 if ((gravs = (gravstruct *) calloc(MI_NUM_SCREENS(mi),
246                                                sizeof (gravstruct))) == NULL)
247                         return;
248         }
249         gp = &gravs[MI_SCREEN(mi)];
250
251         gp->width = MI_WIDTH(mi);
252         gp->height = MI_HEIGHT(mi);
253
254         gp->sr = STARRADIUS;
255
256         gp->nplanets = MI_COUNT(mi);
257         if (gp->nplanets < 0) {
258                 if (gp->planets) {
259                         (void) free((void *) gp->planets);
260                         gp->planets = (planetstruct *) NULL;
261                 }
262                 gp->nplanets = NRAND(-gp->nplanets) + 1;        /* Add 1 so its not too boring */
263         }
264         if (gp->planets == NULL) {
265                 if ((gp->planets = (planetstruct *) calloc(gp->nplanets,
266                                 sizeof (planetstruct))) == NULL)
267                         return;
268         }
269
270         MI_CLEARWINDOW(mi);
271
272         if (MI_NPIXELS(mi) > 2)
273                 gp->starcolor = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
274         else
275                 gp->starcolor = MI_WHITE_PIXEL(mi);
276         for (ball = 0; ball < (unsigned char) gp->nplanets; ball++)
277                 init_planet(mi, &gp->planets[ball]);
278
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,
282                  0, 23040);
283 }
284
285 ENTRYPOINT void
286 draw_grav(ModeInfo * mi)
287 {
288         Display    *display = MI_DISPLAY(mi);
289         Window      window = MI_WINDOW(mi);
290         GC          gc = MI_GC(mi);
291         register unsigned char ball;
292         gravstruct *gp;
293
294         if (gravs == NULL)
295                         return;
296         gp = &gravs[MI_SCREEN(mi)];
297         if (gp->planets == NULL)
298                 return;
299
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,
305                  0, 23040);
306
307         /* Resize centrepoint */
308         switch (NRAND(4)) {
309                 case 0:
310                         if (gp->sr < (int) STARRADIUS)
311                                 gp->sr++;
312                         break;
313                 case 1:
314                         if (gp->sr > 2)
315                                 gp->sr--;
316         }
317
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,
322                  0, 23040);
323
324         for (ball = 0; ball < (unsigned char) gp->nplanets; ball++)
325                 draw_planet(mi, &gp->planets[ball]);
326 }
327
328 ENTRYPOINT void
329 release_grav(ModeInfo * mi)
330 {
331         if (gravs != NULL) {
332                 int         screen;
333
334                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
335                         gravstruct *gp = &gravs[screen];
336
337                         if (gp->planets)
338                                 (void) free((void *) gp->planets);
339                 }
340                 (void) free((void *) gravs);
341                 gravs = (gravstruct *) NULL;
342         }
343 }
344
345 ENTRYPOINT void
346 refresh_grav(ModeInfo * mi)
347 {
348         MI_CLEARWINDOW(mi);
349 }
350
351 XSCREENSAVER_MODULE ("Grav", grav)
352
353 #endif /* MODE_grav */