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