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