1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* roll --- rolling ball of points */
3
4 #if 0
5 static const char sccsid[] = "@(#)roll.c 5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /*-
10 * Copyright (c) 1995 by Charles Vidal <cvidal AT ivsweb.com>
11 * http://www.chez.com/vidalc
12 *
13 * Permission to use, copy, modify, and distribute this software and its
14 * documentation for any purpose and without fee is hereby granted,
15 * provided that the above copyright notice appear in all copies and that
16 * both that copyright notice and this permission notice appear in
17 * supporting documentation.
18 *
19 * This file is provided AS IS with no warranties of any kind. The author
20 * shall have no liability with respect to the infringement of copyrights,
21 * trade secrets or any patents by this file or any part thereof. In no
22 * event will the author be liable for any lost revenue or profits or
23 * other special, indirect and consequential damages.
24 *
25 * Revision History:
26 * 01-Nov-2000: Allocation checks
27 * 10-May-1997: Compatible with xscreensaver
28 * 1995: Written.
29 */
30
31 #ifdef STANDALONE
32 #define MODE_roll
33 #define DEFAULTS "*delay: 100000 \n" \
34 "*count: 25 \n" \
35 "*size: -64 \n" \
36 "*ncolors: 200 \n" \
37
38 # define free_roll 0
39 # define reshape_roll 0
40 # define roll_handle_event 0
41 #define BRIGHT_COLORS
42 #define SMOOTH_COLORS
43 #include "xlockmore.h" /* in xscreensaver distribution */
44 #else /* STANDALONE */
45 #include "xlock.h" /* in xlockmore distribution */
46 #endif /* STANDALONE */
47
48 #ifdef MODE_roll
49
50 ENTRYPOINT ModeSpecOpt roll_opts =
51 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
52
53 #ifdef USE_MODULES
54 ModStruct roll_description =
55 {"roll", "init_roll", "draw_roll", "release_roll",
56 "refresh_roll", "init_roll", (char *) NULL, &roll_opts,
57 100000, 25, 1, -64, 64, 0.6, "",
58 "Shows a rolling ball", 0, NULL};
59
60 #endif
61
62 #define MINPTS 1
63 #define MINSIZE 8
64 #define FACTOR 8.0
65 #define SPEED 25.0
66
67 typedef struct {
68 float t, u, v;
69 float t1, u1, v1;
70 } ptsstruct;
71 typedef struct {
72 ptsstruct *pts;
73 XPoint *p;
74 int maxpts, npts;
75 float alpha, theta, phi, r;
76 XPoint sphere, direction;
77 int color;
78 int width, height;
79 } rollstruct;
80
81 static rollstruct *rolls = (rollstruct *) NULL;
82
83 static void
createsphere(rollstruct * rp,int n1,int n2)84 createsphere(rollstruct * rp, int n1, int n2)
85 {
86 double i, j;
87 int n = 0;
88
89 for (i = 0.0; i < FACTOR * M_PI; i += (FACTOR * M_PI) / n1)
90 for (j = 0.0; j < FACTOR * M_PI; j += (FACTOR * M_PI) / n2) {
91 rp->pts[n].t1 = rp->r * COSF(i) * COSF(j);
92 rp->pts[n].u1 = rp->r * COSF(i) * SINF(j);
93 rp->pts[n].v1 = rp->r * SINF(i);
94 n++;
95 }
96 }
97
98 static void
rotation3d(rollstruct * rp)99 rotation3d(rollstruct * rp)
100 {
101 float c1, c2, c3, c4, c5, c6, c7, c8, c9, x, y, z;
102 float sintheta, costheta;
103 float sinphi, cosphi;
104 float sinalpha, cosalpha;
105 int i;
106
107 sintheta = SINF(rp->theta);
108 costheta = COSF(rp->theta);
109 sinphi = SINF(rp->phi);
110 cosphi = COSF(rp->phi);
111 sinalpha = SINF(rp->alpha);
112 cosalpha = COSF(rp->alpha);
113
114 c1 = cosphi * costheta;
115 c2 = sinphi * costheta;
116 c3 = -sintheta;
117
118 c4 = cosphi * sintheta * sinalpha - sinphi * cosalpha;
119 c5 = sinphi * sintheta * sinalpha + cosphi * cosalpha;
120 c6 = costheta * sinalpha;
121
122 c7 = cosphi * sintheta * cosalpha + sinphi * sinalpha;
123 c8 = sinphi * sintheta * cosalpha - cosphi * sinalpha;
124 c9 = costheta * cosalpha;
125 for (i = 0; i < rp->maxpts; i++) {
126 x = rp->pts[i].t;
127 y = rp->pts[i].u;
128 z = rp->pts[i].v;
129 rp->pts[i].t = c1 * x + c2 * y + c3 * z;
130 rp->pts[i].u = c4 * x + c5 * y + c6 * z;
131 rp->pts[i].v = c7 * x + c8 * y + c9 * z;
132 }
133 }
134
135 static void
project(rollstruct * rp)136 project(rollstruct * rp)
137 {
138 int i;
139
140 for (i = 0; i < rp->maxpts; i++) {
141 rp->p[i].x = (short) (2 * rp->pts[i].t);
142 rp->p[i].y = (short) (2 * rp->pts[i].u);
143 }
144 }
145
146 static void
free_roll_screen(rollstruct * rp)147 free_roll_screen(rollstruct *rp)
148 {
149 if (rp == NULL) {
150 return;
151 }
152 if (rp->pts != NULL) {
153 free(rp->pts);
154 rp->pts = (ptsstruct *) NULL;
155 }
156 if (rp->p != NULL) {
157 free(rp->p);
158 rp->p = (XPoint *) NULL;
159 }
160 rp = NULL;
161 }
162
163 ENTRYPOINT void
init_roll(ModeInfo * mi)164 init_roll(ModeInfo * mi)
165 {
166 int i;
167 int size = MI_SIZE(mi);
168 double ang;
169 rollstruct *rp;
170
171 MI_INIT(mi, rolls);
172 rp = &rolls[MI_SCREEN(mi)];
173
174 ang = (double) NRAND(75) + 7.5;
175 rp->direction.x = (short) ((2 * (LRAND() & 1)) - 1) * (int)
176 (SPEED * SINF(ang * M_PI / 180.0));
177 rp->direction.y = (short) ((2 * (LRAND() & 1)) - 1) * (int)
178 (SPEED * COSF(ang * M_PI / 180.0));
179 rp->width = MI_WIDTH(mi);
180 rp->height = MI_HEIGHT(mi);
181 if (size < -MINSIZE)
182 rp->r = NRAND(MIN(-size, MAX(MINSIZE,
183 MIN(rp->width, rp->height) / 4)) - MINSIZE + 1) + MINSIZE;
184 else if (size < MINSIZE) {
185 if (!size)
186 rp->r = MAX(MINSIZE, MIN(rp->width, rp->height) / 4);
187 else
188 rp->r = MINSIZE;
189 } else
190 rp->r = MIN(size, MAX(MINSIZE,
191 MIN(rp->width, rp->height) / 4));
192 rp->sphere.x = NRAND(MAX(1, rp->width - 4 * (int) rp->r)) +
193 2 * (int) rp->r;
194 rp->sphere.y = NRAND(MAX(1, rp->height - 4 * (int) rp->r)) +
195 2 * (int) rp->r;
196 rp->alpha = 0;
197 rp->theta = 0;
198 rp->phi = 0;
199 rp->maxpts = MI_COUNT(mi);
200 if (rp->maxpts < -MINPTS) {
201 /* if rp->maxpts is random ... the size can change */
202 if (rp->pts != NULL) {
203 free(rp->pts);
204 rp->pts = (ptsstruct *) NULL;
205 }
206 rp->maxpts = NRAND(-rp->maxpts - MINPTS + 1) + MINPTS;
207 } else if (rp->maxpts < MINPTS)
208 rp->maxpts = MINPTS;
209 i = rp->maxpts;
210 rp->maxpts *= rp->maxpts;
211 rp->npts = 0;
212 if (rp->pts == NULL)
213 if ((rp->pts = (ptsstruct *) malloc(rp->maxpts *
214 sizeof (ptsstruct))) ==NULL) {
215 free_roll_screen(rp);
216 return;
217 }
218 if (rp->p != NULL) {
219 free(rp->p);
220 rp->p = (XPoint *) NULL;
221 }
222 if (MI_NPIXELS(mi) > 2)
223 rp->color = NRAND(MI_NPIXELS(mi));
224 createsphere(rp, i, i);
225
226 MI_CLEARWINDOW(mi);
227 }
228
229 ENTRYPOINT void
draw_roll(ModeInfo * mi)230 draw_roll(ModeInfo * mi)
231 {
232 Display *display = MI_DISPLAY(mi);
233 Window window = MI_WINDOW(mi);
234 GC gc = MI_GC(mi);
235 int i;
236 rollstruct *rp;
237
238 if (rolls == NULL)
239 return;
240 rp = &rolls[MI_SCREEN(mi)];
241 if (rp->pts == NULL)
242 return;
243
244 MI_IS_DRAWN(mi) = True;
245 for (i = 0; i < rp->maxpts; i++) {
246 rp->pts[i].t = rp->pts[i].t1;
247 rp->pts[i].u = rp->pts[i].u1;
248 rp->pts[i].v = rp->pts[i].v1;
249 }
250 rp->alpha += ((FACTOR * M_PI) / 200.0);
251 rp->theta += ((FACTOR * M_PI) / 200.0);
252 rp->phi += ((FACTOR * M_PI) / 200.0);
253 if (rp->alpha > (FACTOR * M_PI))
254 rp->alpha -= (FACTOR * M_PI);
255 if (rp->theta > (FACTOR * M_PI))
256 rp->theta -= (FACTOR * M_PI);
257 if (rp->phi > (FACTOR * M_PI))
258 rp->phi -= (FACTOR * M_PI);
259
260 if (rp->npts) {
261 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
262 XDrawPoints(display, window, gc, rp->p, rp->npts, CoordModeOrigin);
263 } else {
264 if (rp->p)
265 free(rp->p);
266 if ((rp->p = (XPoint *) malloc(rp->maxpts *
267 sizeof (XPoint))) == NULL) {
268 free_roll_screen(rp);
269 return;
270 }
271 }
272 rotation3d(rp);
273 project(rp);
274 rp->npts = 0;
275 for (i = 0; i < rp->maxpts; i++) {
276 if (rp->pts[i].v > 0.0) {
277 rp->p[rp->npts].x += rp->sphere.x;
278 rp->p[rp->npts].y += rp->sphere.y;
279 rp->npts++;
280 }
281 }
282 if (MI_NPIXELS(mi) <= 2)
283 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
284 else {
285 rp->color = (rp->color + 1) % MI_NPIXELS(mi);
286 XSetForeground(display, gc, MI_PIXEL(mi, rp->color));
287 }
288 XDrawPoints(display, window, gc, rp->p, rp->npts, CoordModeOrigin);
289 if (rp->sphere.x >= rp->width - (int) rp->r && rp->direction.x > 0)
290 rp->direction.x = -rp->direction.x;
291 else if (rp->sphere.x <= (int) rp->r && rp->direction.x < 0)
292 rp->direction.x = -rp->direction.x;
293 else if (rp->sphere.x < rp->width - 2 * (int) rp->r ||
294 rp->sphere.x > 2 * (int) rp->r) {
295 if (rp->sphere.x >= rp->width - 2 * (int) rp->r && rp->direction.x > 0)
296 rp->direction.x = -rp->direction.x;
297 else if (rp->sphere.x <= 2 * (int) rp->r && rp->direction.x < 0)
298 rp->direction.x = -rp->direction.x;
299 }
300 if (rp->sphere.y >= rp->height - (int) rp->r && rp->direction.y > 0)
301 rp->direction.y = -rp->direction.y;
302 else if (rp->sphere.y <= (int) rp->r && rp->direction.y < 0)
303 rp->direction.y = -rp->direction.y;
304 else if (rp->sphere.y < rp->height - 2 * (int) rp->r ||
305 rp->sphere.y > 2 * (int) rp->r) {
306 if (rp->sphere.y >= rp->height - 2 * (int) rp->r && rp->direction.y > 0)
307 rp->direction.y = -rp->direction.y;
308 else if (rp->sphere.y <= 2 * (int) rp->r && rp->direction.y < 0)
309 rp->direction.y = -rp->direction.y;
310 }
311 rp->sphere.x += rp->direction.x;
312 rp->sphere.y += rp->direction.y;
313 }
314
315 ENTRYPOINT void
release_roll(ModeInfo * mi)316 release_roll(ModeInfo * mi)
317 {
318 if (rolls != NULL) {
319 int screen;
320
321 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
322 free_roll_screen(&rolls[screen]);
323 free(rolls);
324 rolls = (rollstruct *) NULL;
325 }
326 }
327
328 #ifndef STANDALONE
329 ENTRYPOINT void
refresh_roll(ModeInfo * mi)330 refresh_roll(ModeInfo * mi)
331 {
332 MI_CLEARWINDOW(mi);
333 }
334 #endif
335
336 XSCREENSAVER_MODULE ("Roll", roll)
337
338 #endif /* MODE_roll */
339