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