1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* spline --- spline fun */
3
4 #if 0
5 static const char sccsid[] = "@(#)spline.c 5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /*-
10 * Copyright (c) 1992 by Jef Poskanzer
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:
26 * 10-May-1997: Compatible with xscreensaver
27 * 13-Sep-1996: changed FOLLOW to a runtime option "-erase"
28 * 17-Jan-1996: added compile time option, FOLLOW to erase old splines like Qix
29 * thanks to Richard Duran <rduran@cs.utep.edu>
30 * 09-Mar-1995: changed how batchcount is used
31 * 02-Sep-1993: xlock version: David Bagley <bagleyd AT verizon.net>
32 * reminds me of a great "Twilight Zone" episode.
33 * 1992: X11 version Jef Poskanzer <jef@netcom.com>, <jef@well.sf.ca.us>
34 *
35 * spline fun #3
36 */
37
38 /*-
39 * original copyright
40 * xsplinefun.c - X11 version of spline fun #3
41 * Displays colorful moving splines in the X11 root window.
42 * Copyright (C) 1992 by Jef Poskanzer
43 * Permission to use, copy, modify, and distribute this software and its
44 * documentation for any purpose and without fee is hereby granted, provided
45 * that the above copyright notice appear in all copies and that both that
46 * copyright notice and this permission notice appear in supporting
47 * documentation. This software is provided "as is" without express or
48 * implied warranty.
49 */
50
51 #ifdef STANDALONE
52 #define MODE_spline
53 #define DEFAULTS "*delay: 30000 \n" \
54 "*count: -6 \n" \
55 "*cycles: 2048 \n" \
56 "*ncolors: 200 \n" \
57 "*fullrandom: True \n" \
58
59 # define free_spline 0
60 # define reshape_spline 0
61 # define spline_handle_event 0
62 #define UNIFORM_COLORS
63 #define BRIGHT_COLORS
64 #include "xlockmore.h" /* in xscreensaver distribution */
65 #else /* STANDALONE */
66 #include "xlock.h" /* in xlockmore distribution */
67
68 #endif /* STANDALONE */
69
70 #ifdef MODE_spline
71
72 #define DEF_ERASE "False"
73
74 static Bool erase;
75
76 static XrmOptionDescRec opts[] =
77 {
78 {(char *) "-erase", (char *) ".spline.erase", XrmoptionNoArg, (caddr_t) "on"},
79 {(char *) "+erase", (char *) ".spline.erase", XrmoptionNoArg, (caddr_t) "off"}
80 };
81
82 static argtype vars[] =
83 {
84 {(void *) & erase, (char *) "erase", (char *) "Erase", (char *) DEF_ERASE, t_Bool}
85 };
86
87 static OptionStruct desc[] =
88 {
89 {(char *) "-/+erase", (char *) "turn on/off the following erase of splines"}
90 };
91
92 ENTRYPOINT ModeSpecOpt spline_opts =
93 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
94
95 #ifdef USE_MODULES
96 ModStruct spline_description =
97 {"spline", "init_spline", "draw_spline", "release_spline",
98 "refresh_spline", "init_spline", (char *) NULL, &spline_opts,
99 30000, -6, 2048, 1, 64, 0.3, "",
100 "Shows colorful moving splines", 0, NULL};
101
102 #endif
103
104 #define MINPOINTS 3
105
106 /* How many segments to draw per cycle when redrawing */
107 #define REDRAWSTEP 3
108
109 #define SPLINE_THRESH 5
110
111 typedef struct {
112 XPoint pos, delta;
113 } splinepointstruct;
114
115 typedef struct {
116 /* ERASE stuff */
117 int first;
118 int last;
119 int max_delta;
120 XPoint **splineq;
121 int redrawing, redrawpos;
122 Bool erase;
123
124 int width;
125 int height;
126 int color;
127 int points;
128 int nsplines;
129 splinepointstruct *pt;
130 } splinestruct;
131
132 static splinestruct *splines = (splinestruct *) NULL;
133
134 static void XDrawSpline(Display * display, Drawable d, GC gc,
135 int x0, int y0, int x1, int y1, int x2, int y2);
136
137 static void
free_spline_screen(splinestruct * sp)138 free_spline_screen(splinestruct *sp)
139 {
140 if (sp == NULL) {
141 return;
142 }
143 if (sp->pt != NULL) {
144 free(sp->pt);
145 sp->pt = (splinepointstruct *) NULL;
146 }
147 if (sp->splineq != NULL) {
148 int spline;
149
150 for (spline = 0; spline < sp->nsplines; ++spline)
151 if (sp->splineq[spline] != NULL)
152 free(sp->splineq[spline]);
153 free(sp->splineq);
154 sp->splineq = (XPoint **) NULL;
155 }
156 sp = NULL;
157 }
158
159 ENTRYPOINT void
init_spline(ModeInfo * mi)160 init_spline(ModeInfo * mi)
161 {
162 int i;
163 splinestruct *sp;
164
165 MI_INIT(mi, splines);
166 sp = &splines[MI_SCREEN(mi)];
167
168 sp->width = MI_WIDTH(mi);
169 sp->height = MI_HEIGHT(mi);
170 /* batchcount is the upper bound on the number of points */
171 sp->points = MI_COUNT(mi);
172 if (sp->points < -MINPOINTS) {
173 if (sp->pt) {
174 free(sp->pt);
175 sp->pt = (splinepointstruct *) NULL;
176 }
177 if (sp->erase) {
178 if (sp->splineq)
179 for (i = 0; i < sp->nsplines; ++i)
180 if (sp->splineq[i]) {
181 free(sp->splineq[i]);
182 sp->splineq[i] = (XPoint *) NULL;
183 }
184 }
185 sp->points = NRAND(-sp->points - MINPOINTS + 1) + MINPOINTS;
186 } else if (sp->points < MINPOINTS)
187 sp->points = MINPOINTS;
188 if (MI_IS_FULLRANDOM(mi))
189 sp->erase = (Bool) (LRAND() & 1);
190 else
191 sp->erase = erase;
192 if (sp->pt == NULL)
193 if ((sp->pt = (splinepointstruct *) malloc(sp->points *
194 sizeof (splinepointstruct))) == NULL) {
195 free_spline_screen(sp);
196 return;
197 }
198
199 if (sp->erase) {
200 sp->max_delta = 16;
201 sp->redrawing = 0;
202 sp->last = 0;
203 sp->nsplines = MI_CYCLES(mi) / 64 + 1; /* So as to be compatible */
204 if (sp->splineq == NULL)
205 if ((sp->splineq = (XPoint **) calloc(sp->nsplines,
206 sizeof (XPoint *))) == NULL) {
207 free_spline_screen(sp);
208 return;
209 }
210 for (i = 0; i < sp->nsplines; ++i)
211 if (sp->splineq[i] == NULL)
212 if ((sp->splineq[i] = (XPoint *) calloc(sp->points,
213 sizeof (XPoint))) == NULL) {
214 free_spline_screen(sp);
215 return;
216 }
217 } else {
218 sp->max_delta = 3;
219 sp->nsplines = 0;
220 }
221
222 MI_CLEARWINDOW(mi);
223
224 /* Initialize points. */
225 for (i = 0; i < sp->points; ++i) {
226 sp->pt[i].pos.x = NRAND(sp->width);
227 sp->pt[i].pos.y = NRAND(sp->height);
228 sp->pt[i].delta.x = NRAND(sp->max_delta * 2) - sp->max_delta;
229 if (sp->pt[i].delta.x <= 0 && sp->width > 1)
230 --sp->pt[i].delta.x;
231 sp->pt[i].delta.y = NRAND(sp->max_delta * 2) - sp->max_delta;
232 if (sp->pt[i].delta.y <= 0 && sp->height > 1)
233 --sp->pt[i].delta.y;
234 }
235 if (MI_NPIXELS(mi) > 2)
236 sp->color = NRAND(MI_NPIXELS(mi));
237 }
238
239 ENTRYPOINT void
draw_spline(ModeInfo * mi)240 draw_spline(ModeInfo * mi)
241 {
242 Display *display = MI_DISPLAY(mi);
243 Window window = MI_WINDOW(mi);
244 GC gc = MI_GC(mi);
245 int i, t, px, py, zx, zy, nx, ny;
246 splinestruct *sp;
247
248 if (splines == NULL)
249 return;
250 sp = &splines[MI_SCREEN(mi)];
251 if (sp->pt == NULL)
252 return;
253
254 MI_IS_DRAWN(mi) = True;
255 if (sp->erase)
256 sp->first = (sp->last + 2) % sp->nsplines;
257
258 /* Move the points. */
259 for (i = 0; i < sp->points; i++) {
260 for (;;) {
261 t = sp->pt[i].pos.x + sp->pt[i].delta.x;
262 if (t >= 0 && t < sp->width)
263 break;
264 sp->pt[i].delta.x = NRAND(sp->max_delta * 2) - sp->max_delta;
265 if (sp->pt[i].delta.x <= 0 && sp->width > 1)
266 --sp->pt[i].delta.x;
267 }
268 sp->pt[i].pos.x = t;
269 for (;;) {
270 t = sp->pt[i].pos.y + sp->pt[i].delta.y;
271 if (t >= 0 && t < sp->height)
272 break;
273 sp->pt[i].delta.y = NRAND(sp->max_delta * 2) - sp->max_delta;
274 if (sp->pt[i].delta.y <= 0 && sp->height > 1)
275 --sp->pt[i].delta.y;
276 }
277 sp->pt[i].pos.y = t;
278 }
279
280 if (sp->erase) {
281 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
282
283 /* Erase first figure. */
284 px = zx = (sp->splineq[sp->first][0].x +
285 sp->splineq[sp->first][sp->points - 1].x) / 2;
286 py = zy = (sp->splineq[sp->first][0].y +
287 sp->splineq[sp->first][sp->points - 1].y) / 2;
288 for (i = 0; i < sp->points - 1; ++i) {
289 nx = (sp->splineq[sp->first][i + 1].x +
290 sp->splineq[sp->first][i].x) / 2;
291 ny = (sp->splineq[sp->first][i + 1].y +
292 sp->splineq[sp->first][i].y) / 2;
293 XDrawSpline(display, window, gc,
294 px, py, sp->splineq[sp->first][i].x,
295 sp->splineq[sp->first][i].y, nx, ny);
296 px = nx;
297 py = ny;
298 }
299
300 XDrawSpline(display, window, gc,
301 px, py, sp->splineq[sp->first][sp->points - 1].x,
302 sp->splineq[sp->first][sp->points - 1].y, zx, zy);
303 }
304 if (MI_NPIXELS(mi) > 2) {
305 XSetForeground(display, gc, MI_PIXEL(mi, sp->color));
306 if (++sp->color >= MI_NPIXELS(mi))
307 sp->color = 0;
308 } else
309 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
310
311 /* Draw the figure. */
312 px = zx = (sp->pt[0].pos.x + sp->pt[sp->points - 1].pos.x) / 2;
313 py = zy = (sp->pt[0].pos.y + sp->pt[sp->points - 1].pos.y) / 2;
314 for (i = 0; i < sp->points - 1; ++i) {
315 nx = (sp->pt[i + 1].pos.x + sp->pt[i].pos.x) / 2;
316 ny = (sp->pt[i + 1].pos.y + sp->pt[i].pos.y) / 2;
317 XDrawSpline(display, window, gc,
318 px, py, sp->pt[i].pos.x, sp->pt[i].pos.y, nx, ny);
319 px = nx;
320 py = ny;
321 }
322
323 XDrawSpline(display, window, gc, px, py,
324 sp->pt[sp->points - 1].pos.x, sp->pt[sp->points - 1].pos.y, zx, zy);
325
326 if (sp->erase) {
327 for (i = 0; i < sp->points; ++i) {
328 sp->splineq[sp->last][i].x = sp->pt[i].pos.x;
329 sp->splineq[sp->last][i].y = sp->pt[i].pos.y;
330 }
331 sp->last++;
332 if (sp->last >= sp->nsplines)
333 sp->last = 0;
334
335 if (sp->redrawing) {
336 int j, k;
337
338 sp->redrawpos++;
339 /* This compensates for the changed sp->last
340 since last callback */
341
342 for (k = 0; k < REDRAWSTEP; k++) {
343 j = (sp->last - sp->redrawpos + sp->nsplines) %
344 sp->nsplines;
345 #ifdef BACKWARDS
346 /* Draw backwards, probably will not see it,
347 but its the thought ... */
348 px = zx = (sp->splineq[j][0].x +
349 sp->splineq[j][sp->points - 1].x) / 2;
350 py = zy = (sp->splineq[j][0].y +
351 sp->splineq[j][sp->points - 1].y) / 2;
352 for (i = sp->points - 1; i > 0; --i) {
353 nx = (sp->splineq[j][i - 1].x +
354 sp->splineq[j][i].x) / 2;
355 ny = (sp->splineq[j][i - 1].y +
356 sp->splineq[j][i].y) / 2;
357 XDrawSpline(display, window, gc,
358 px, py, sp->splineq[j][i].x,
359 sp->splineq[j][i].y, nx, ny);
360 px = nx;
361 py = ny;
362 }
363
364 XDrawSpline(display, window, gc,
365 px, py, sp->splineq[j][0].x,
366 sp->splineq[j][0].y, zx, zy);
367 #else
368 px = zx = (sp->splineq[j][0].x +
369 sp->splineq[j][sp->points - 1].x) / 2;
370 py = zy = (sp->splineq[j][0].y +
371 sp->splineq[j][sp->points - 1].y) / 2;
372 for (i = 0; i < sp->points - 1; ++i) {
373 nx = (sp->splineq[j][i + 1].x +
374 sp->splineq[j][i].x) / 2;
375 ny = (sp->splineq[j][i + 1].y +
376 sp->splineq[j][i].y) / 2;
377 XDrawSpline(display, window, gc,
378 px, py, sp->splineq[j][i].x,
379 sp->splineq[j][i].y, nx, ny);
380 px = nx;
381 py = ny;
382 }
383
384 XDrawSpline(display, window, gc,
385 px, py, sp->splineq[j][sp->points - 1].x,
386 sp->splineq[j][sp->points - 1].y, zx, zy);
387 #endif
388 if (++(sp->redrawpos) >= sp->nsplines - 1) {
389 sp->redrawing = 0;
390 break;
391 }
392 }
393 }
394 } else if (++sp->nsplines > MI_CYCLES(mi))
395 init_spline(mi);
396 }
397
398 /* X spline routine. */
399
400 static void
XDrawSpline(Display * display,Drawable d,GC gc,int x0,int y0,int x1,int y1,int x2,int y2)401 XDrawSpline(Display * display, Drawable d, GC gc, int x0, int y0, int x1, int y1, int x2, int y2)
402 {
403 register int xa, ya, xb, yb, xc, yc, xp, yp;
404
405 xa = (x0 + x1) / 2;
406 ya = (y0 + y1) / 2;
407 xc = (x1 + x2) / 2;
408 yc = (y1 + y2) / 2;
409 xb = (xa + xc) / 2;
410 yb = (ya + yc) / 2;
411
412 xp = (x0 + xb) / 2;
413 yp = (y0 + yb) / 2;
414 if (ABS(xa - xp) + ABS(ya - yp) > SPLINE_THRESH)
415 XDrawSpline(display, d, gc, x0, y0, xa, ya, xb, yb);
416 else
417 XDrawLine(display, d, gc, x0, y0, xb, yb);
418
419 xp = (x2 + xb) / 2;
420 yp = (y2 + yb) / 2;
421 if (ABS(xc - xp) + ABS(yc - yp) > SPLINE_THRESH)
422 XDrawSpline(display, d, gc, xb, yb, xc, yc, x2, y2);
423 else
424 XDrawLine(display, d, gc, xb, yb, x2, y2);
425 }
426
427 ENTRYPOINT void
release_spline(ModeInfo * mi)428 release_spline(ModeInfo * mi)
429 {
430 if (splines != NULL) {
431 int screen;
432
433 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
434 free_spline_screen(&splines[screen]);
435 free(splines);
436 splines = (splinestruct *) NULL;
437 }
438 }
439
440 #ifndef STANDALONE
441 ENTRYPOINT void
refresh_spline(ModeInfo * mi)442 refresh_spline(ModeInfo * mi)
443 {
444 splinestruct *sp;
445
446 if (splines == NULL)
447 return;
448 sp = &splines[MI_SCREEN(mi)];
449
450 if (sp->erase) {
451 sp->redrawing = 1;
452 sp->redrawpos = 1;
453 } else {
454 MI_CLEARWINDOW(mi);
455 }
456 }
457 #endif
458
459 XSCREENSAVER_MODULE ("Spline", spline)
460
461 #endif /* MODE_spline */
462