http://www.jwz.org/xscreensaver/xscreensaver-5.10.tar.gz
[xscreensaver] / hacks / sphere.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* sphere --- a bunch of shaded spheres */
3
4 #if 0
5 static const char sccsid[] = "@(#)sphere.c      5.00 2000/11/01 xlockmore";
6 #endif
7
8 /*-
9  * Copyright (c) 1988 by Sun Microsystems
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  * 30-May-1997: <jwz@jwz.org> made it go vertically as well as horizontally.
26  * 27-May-1997: <jwz@jwz.org> turned into a standalone program.
27  * 02-Sep-1993: xlock version David Bagley <bagleyd@tux.org>
28  * 1988: Revised to use SunView canvas instead of gfxsw Sun Microsystems
29  * 1982: Orignal Algorithm Tom Duff Lucasfilm Ltd.
30  */
31
32 /*-
33  * original copyright
34  * **************************************************************************
35  * Copyright 1988 by Sun Microsystems, Inc. Mountain View, CA.
36  *
37  * All Rights Reserved
38  *
39  * Permission to use, copy, modify, and distribute this software and its
40  * documentation for any purpose and without fee is hereby granted, provided
41  * that the above copyright notice appear in all copies and that both that
42  * copyright notice and this permission notice appear in supporting
43  * documentation, and that the names of Sun or MIT not be used in advertising
44  * or publicity pertaining to distribution of the software without specific
45  * prior written permission. Sun and M.I.T. make no representations about the
46  * suitability of this software for any purpose. It is provided "as is"
47  * without any express or implied warranty.
48  *
49  * SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
51  * IN NO EVENT SHALL SUN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
52  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
53  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
54  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
55  * SOFTWARE.
56  * ***************************************************************************
57  */
58
59 #ifdef STANDALONE
60 # define MODE_sphere
61 #define DEFAULTS        "*delay: 20000 \n" \
62                                         "*cycles: 20 \n" \
63                                         "*size: 0 \n" \
64                                         "*ncolors: 64 \n" \
65                                         "*fpsSolid: true \n" \
66
67 # define BRIGHT_COLORS
68 # define reshape_sphere 0
69 # define sphere_handle_event 0
70 # include "xlockmore.h"         /* from the xscreensaver distribution */
71 #else /* !STANDALONE */
72 # include "xlock.h"             /* from the xlockmore distribution */
73 #endif /* !STANDALONE */
74
75 #ifdef MODE_sphere
76
77 ENTRYPOINT ModeSpecOpt sphere_opts =
78 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
79
80 #ifdef USE_MODULES
81 ModStruct   sphere_description =
82 {"sphere", "init_sphere", "draw_sphere", "release_sphere",
83  "refresh_sphere", "init_sphere", (char *) NULL, &sphere_opts,
84  5000, 1, 20, 0, 64, 1.0, "",
85  "Shows a bunch of shaded spheres", 0, NULL};
86
87 #endif
88
89 /*-
90  * (NX, NY, NZ) is the light source vector -- length should be 100
91  */
92 #define NX 48
93 #define NY (-36)
94 #define NZ 80
95 #define NR 100
96 #define SQRT(a) ((int)sqrt((double)(a)))
97
98 typedef struct {
99         int         width, height;
100         int         radius;
101         int         x0;         /* x center */
102         int         y0;         /* y center */
103         int         color;
104         int         x, y;
105         int         dirx, diry;
106         int         shadowx, shadowy;
107         int         maxx, maxy;
108         XPoint     *points;
109 } spherestruct;
110
111 static spherestruct *spheres = (spherestruct *) NULL;
112
113 ENTRYPOINT void
114 init_sphere(ModeInfo * mi)
115 {
116         spherestruct *sp;
117
118         if (spheres == NULL) {
119                 if ((spheres = (spherestruct *) calloc(MI_NUM_SCREENS(mi),
120                                              sizeof (spherestruct))) == NULL)
121                         return;
122         }
123         sp = &spheres[MI_SCREEN(mi)];
124
125         if (sp->points != NULL) {
126                 (void) free((void *) sp->points);
127                 sp->points = (XPoint *) NULL;
128         }
129         sp->width = MAX(MI_WIDTH(mi), 4);
130         sp->height = MAX(MI_HEIGHT(mi), 4);
131         if ((sp->points = (XPoint *) malloc(MIN(sp->width, sp->height) *
132                          sizeof (XPoint))) == NULL) {
133                 return;
134         }
135
136         MI_CLEARWINDOW(mi);
137
138         sp->dirx = 1;
139         sp->x = sp->radius;
140         sp->shadowx = (LRAND() & 1) ? 1 : -1;
141         sp->shadowy = (LRAND() & 1) ? 1 : -1;
142 }
143
144 ENTRYPOINT void
145 draw_sphere(ModeInfo * mi)
146 {
147         Display    *display = MI_DISPLAY(mi);
148         GC          gc = MI_GC(mi);
149         int         sqrd, nd;
150         register int minx = 0, maxx = 0, miny = 0, maxy = 0, npts = 0;
151         spherestruct *sp;
152
153         if (spheres == NULL)
154                 return;
155         sp = &spheres[MI_SCREEN(mi)];
156         if (sp->points == NULL)
157                 return;
158
159         MI_IS_DRAWN(mi) = True;
160         if ((sp->dirx && ABS(sp->x) >= sp->radius) ||
161             (sp->diry && ABS(sp->y) >= sp->radius)) {
162                 sp->radius = NRAND(MIN(sp->width / 2, sp->height / 2) - 1) + 1;
163
164                 if (LRAND() & 1) {
165                         sp->dirx = (int) (LRAND() & 1) * 2 - 1;
166                         sp->diry = 0;
167                 } else {
168                         sp->dirx = 0;
169                         sp->diry = (int) (LRAND() & 1) * 2 - 1;
170                 }
171                 sp->x0 = NRAND(sp->width);
172                 sp->y0 = NRAND(sp->height);
173
174                 sp->x = -sp->radius * sp->dirx;
175                 sp->y = -sp->radius * sp->diry;
176
177                 if (MI_NPIXELS(mi) > 2)
178                         sp->color = NRAND(MI_NPIXELS(mi));
179         }
180         if (sp->dirx == 1) {
181                 if (sp->x0 + sp->x < 0)
182                         sp->x = -sp->x0;
183         } else if (sp->dirx == -1) {
184                 if (sp->x0 + sp->x >= sp->width)
185                         sp->x = sp->width - sp->x0 - 1;
186         }
187         if (sp->diry == 1) {
188                 if (sp->y0 + sp->y < 0)
189                         sp->y = -sp->y0;
190         } else if (sp->diry == -1) {
191                 if (sp->y0 + sp->y >= sp->height)
192                         sp->y = sp->height - sp->y0 - 1;
193         }
194         if (sp->dirx) {
195                 sp->maxy = SQRT(sp->radius * sp->radius - sp->x * sp->x);
196                 miny = -sp->maxy;
197                 if (sp->y0 - sp->maxy < 0)
198                         miny = -sp->y0;
199                 maxy = sp->maxy;
200         }
201         if (sp->diry) {
202                 sp->maxx = SQRT(sp->radius * sp->radius - sp->y * sp->y);
203                 minx = -sp->maxx;
204                 if (sp->x0 - sp->maxx < 0)
205                         minx = -sp->x0;
206                 maxx = sp->maxx;
207         }
208         if (sp->dirx) {
209                 if (sp->y0 + sp->maxy >= sp->height)
210                         maxy = sp->height - sp->y0;
211         }
212         if (sp->diry) {
213                 if (sp->x0 + sp->maxx >= sp->width)
214                         maxx = sp->width - sp->x0;
215         }
216         XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
217
218         if (sp->dirx)
219                 XDrawLine(display, MI_WINDOW(mi), gc,
220                 sp->x0 + sp->x, sp->y0 + miny, sp->x0 + sp->x, sp->y0 + maxy);
221         if (sp->diry)
222                 XDrawLine(display, MI_WINDOW(mi), gc,
223                 sp->x0 + minx, sp->y0 + sp->y, sp->x0 + maxx, sp->y0 + sp->y);
224
225         if (MI_NPIXELS(mi) > 2)
226                 XSetForeground(display, gc, MI_PIXEL(mi, sp->color));
227         else
228                 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
229
230         if (sp->dirx) {
231                 sqrd = sp->radius * sp->radius - sp->x * sp->x;
232                 nd = NX * sp->shadowx * sp->x;
233                 for (sp->y = miny; sp->y <= maxy; sp->y++)
234                         if ((NRAND(sp->radius * NR)) <= nd + NY * sp->shadowy * sp->y +
235                             NZ * SQRT(sqrd - sp->y * sp->y)) {
236                                 sp->points[npts].x = sp->x + sp->x0;
237                                 sp->points[npts].y = sp->y + sp->y0;
238                                 npts++;
239                         }
240         }
241         if (sp->diry) {
242                 sqrd = sp->radius * sp->radius - sp->y * sp->y;
243                 nd = NY * sp->shadowy * sp->y;
244                 for (sp->x = minx; sp->x <= maxx; sp->x++)
245                         if ((NRAND(sp->radius * NR)) <= NX * sp->shadowx * sp->x + nd +
246                             NZ * SQRT(sqrd - sp->x * sp->x)) {
247                                 sp->points[npts].x = sp->x + sp->x0;
248                                 sp->points[npts].y = sp->y + sp->y0;
249                                 npts++;
250                         }
251         }
252         XDrawPoints(display, MI_WINDOW(mi), gc, sp->points, npts, CoordModeOrigin);
253         if (sp->dirx == 1) {
254                 sp->x++;
255                 if (sp->x0 + sp->x >= sp->width)
256                         sp->x = sp->radius;
257         } else if (sp->dirx == -1) {
258                 sp->x--;
259                 if (sp->x0 + sp->x < 0)
260                         sp->x = -sp->radius;
261         }
262         if (sp->diry == 1) {
263                 sp->y++;
264                 if (sp->y0 + sp->y >= sp->height)
265                         sp->y = sp->radius;
266         } else if (sp->diry == -1) {
267                 sp->y--;
268                 if (sp->y0 + sp->y < 0)
269                         sp->y = -sp->radius;
270         }
271 }
272
273 ENTRYPOINT void
274 release_sphere(ModeInfo * mi)
275 {
276         if (spheres != NULL) {
277                 int         screen;
278
279                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
280                         spherestruct *sp = &spheres[screen];
281
282                         if (sp->points) {
283                                 (void) free((void *) sp->points);
284                                 /* sp->points = NULL; */
285                         }
286                 }
287                 (void) free((void *) spheres);
288                 spheres = (spherestruct *) NULL;
289         }
290 }
291
292 ENTRYPOINT void
293 refresh_sphere(ModeInfo * mi)
294 {
295         spherestruct *sp;
296
297         if (spheres == NULL)
298                 return;
299         sp = &spheres[MI_SCREEN(mi)];
300
301         MI_CLEARWINDOW(mi);
302
303         sp->x = -sp->radius;
304 }
305
306 XSCREENSAVER_MODULE ("Sphere", sphere)
307
308 #endif /* MODE_sphere */