2 /**************************************************************************
5 * MODULE OF xscreensaver
7 * DESCRIPTION Bilinear interpolation for morphing line shapes.
9 * WRITTEN BY Sverre H. Huseby Glenn T. Lines
10 * Kurvn. 30 Østgaardsgt. 5
11 * N-0495 Oslo N-0474 Oslo
14 * Phone: +47 901 63 579 Phone: +47 22 04 67 28
15 * E-mail: sverrehu@online.no E-mail: gtl@si.sintef.no
16 * URL: http://home.sol.no/~sverrehu/
18 * The original idea, and the bilinear interpolation
19 * mathematics used, emerged in the head of the wise
22 * MODIFICATIONS june 1998 (shh)
23 * * Minor code cleanup.
26 * * Added -mailfile option to allow checking for
27 * new mail while the screensaver is active.
30 * * Some code reformatting.
31 * * Added possibility to use float arithmetic.
32 * * Added -figtype option.
33 * * Made color blue default.
36 * * Function headers converted from ANSI to K&R.
37 * * Added posibility for random number of steps, and
38 * made this the default.
41 * * Converted from an MS-Windows program to X Window.
43 **************************************************************************/
49 #include "screenhack.h"
51 /**************************************************************************
53 * P R I V A T E D A T A *
55 **************************************************************************/
57 /* define MARGINS to make some space around the figure. */
60 /* define USE_FLOAT to avoid using integer calculations in
61 createPoints. integer calculation is supposed to be faster, but it
62 won't work for displays larger than 2048x2048 or so pixels. */
66 #define TWO_PI (2.0 * M_PI)
67 #define RND(x) (random() % (x))
71 #define FT_ALL (FT_OPEN | FT_CLOSED)
74 numFigs = 0, /* number of figure arrays. */
75 numPoints, /* number of points in each array. */
76 nWork, /* current work array number. */
77 nFrom, /* current from array number. */
78 nTo, /* current to array number. */
80 static long delay; /* usecs to wait between updates. */
82 *aWork[2], /* working arrays. */
83 *a[MAXFIGS], /* the figure arrays. */
84 *aTmp, /* used as source when interrupting morph */
85 *aPrev, /* previous points displayed. */
86 *aCurr, /* the current points displayed. */
87 *aFrom, /* figure converting from. */
88 *aTo; /* figure converting to. */
89 static int scrWidth, scrHeight;
90 static double currGamma, maxGamma = 1.0, deltaGamma;
91 static GC gcDraw, gcClear;
97 /**************************************************************************
99 * P U B L I C D A T A *
101 **************************************************************************/
103 char *progclass = "LMorph";
105 char *defaults [] = {
106 ".background: black",
115 XrmOptionDescRec options [] = {
116 { "-points", ".points", XrmoptionSepArg, 0 },
117 { "-steps", ".steps", XrmoptionSepArg, 0 },
118 { "-delay", ".delay", XrmoptionSepArg, 0 },
119 { "-figtype", ".figtype", XrmoptionSepArg, 0 },
122 int options_size = (sizeof (options) / sizeof (options[0]));
126 /**************************************************************************
128 * P R I V A T E F U N C T I O N S *
130 **************************************************************************/
137 if ((ret = malloc(size)) == NULL) {
138 fprintf(stderr, "lmorph: out of memory\n");
145 initPointArrays(void)
148 mx, my, /* max screen coordinates. */
149 mp, /* max point number. */
152 double scalex, scaley;
158 aWork[0] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
159 aWork[1] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
160 aTmp = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
162 if (figType & FT_CLOSED) {
164 a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
166 for (q = 0; q < s; q++) {
167 a[numFigs][q].x = ((double) q / s) * mx;
169 a[numFigs][s + q].x = mx;
170 a[numFigs][s + q].y = ((double) q / s) * my;
171 a[numFigs][2 * s + q].x = mx - ((double) q / s) * mx;
172 a[numFigs][2 * s + q].y = my;
173 a[numFigs][3 * s + q].x = 0;
174 a[numFigs][3 * s + q].y = my - ((double) q / s) * my;
176 for (q = 4 * s; q < numPoints; q++)
177 a[numFigs][q].x = a[numFigs][q].y = 0;
178 a[numFigs][mp].x = a[numFigs][0].x;
179 a[numFigs][mp].y = a[numFigs][0].y;
183 a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
186 for (q = 0; q < numPoints; q++) {
187 a[numFigs][q].x = mx / 2 + rx * sin(1 * TWO_PI * (double) q / mp);
188 a[numFigs][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp);
190 a[numFigs][mp].x = a[numFigs][0].x;
191 a[numFigs][mp].y = a[numFigs][0].y;
195 a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
198 for (q = 0; q < numPoints; q++) {
199 a[numFigs][q].x = mx / 2 + ry * sin(3 * TWO_PI * (double) q / mp);
200 a[numFigs][q].y = my / 2 + ry * cos(1 * TWO_PI * (double) q / mp);
202 a[numFigs][mp].x = a[numFigs][0].x;
203 a[numFigs][mp].y = a[numFigs][0].y;
207 a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
210 for (q = 0; q < numPoints; q++) {
211 a[numFigs][q].x = mx / 2 + ry
212 * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp))
213 * sin(TWO_PI * (double) q / mp);
214 a[numFigs][q].y = my / 2 + ry
215 * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp))
216 * cos(TWO_PI * (double) q / mp);
218 a[numFigs][mp].x = a[numFigs][0].x;
219 a[numFigs][mp].y = a[numFigs][0].y;
223 a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
226 for (q = 0; q < numPoints; q++) {
227 a[numFigs][q].x = mx / 2 + ry * sin(TWO_PI * (double) q / mp);
228 a[numFigs][q].y = my / 2 + ry * cos(TWO_PI * (double) q / mp);
230 a[numFigs][mp].x = a[numFigs][0].x;
231 a[numFigs][mp].y = a[numFigs][0].y;
235 a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
238 for (q = 0; q < numPoints; q++) {
239 a[numFigs][q].x = mx / 2 + rx * cos(TWO_PI * (double) q / mp);
240 a[numFigs][q].y = my / 2 + ry * sin(TWO_PI * (double) q / mp);
242 a[numFigs][mp].x = a[numFigs][0].x;
243 a[numFigs][mp].y = a[numFigs][0].y;
247 a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
250 for (q = 0; q < numPoints; q++) {
251 a[numFigs][q].x = mx / 2 + rx * sin(2 * TWO_PI * (double) q / mp);
252 a[numFigs][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp);
254 a[numFigs][mp].x = a[numFigs][0].x;
255 a[numFigs][mp].y = a[numFigs][0].y;
259 if (figType & FT_OPEN) {
260 /* sine wave, one period */
261 a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
262 for (q = 0; q < numPoints; q++) {
263 a[numFigs][q].x = ((double) q / numPoints) * mx;
264 a[numFigs][q].y = (1.0 - sin(((double) q / mp) * TWO_PI))
270 a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
271 for (q = 0; q < numPoints; q++) {
272 a[numFigs][q].x = ((double) q / mp) * mx;
273 a[numFigs][q].y = (1.0 - cos(((double) q / mp) * 3 * TWO_PI))
278 /* spiral, one endpoint at bottom */
279 a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
282 for (q = 0; q < numPoints; q++) {
283 a[numFigs][q].x = mx / 2 + ry * sin(5 * TWO_PI * (double) q / mp)
285 a[numFigs][q].y = my / 2 + ry * cos(5 * TWO_PI * (double) q / mp)
290 /* spiral, one endpoint at top */
291 a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
294 for (q = 0; q < numPoints; q++) {
295 a[numFigs][q].x = mx / 2 + ry * sin(6 * TWO_PI * (double) q / mp)
297 a[numFigs][q].y = my / 2 - ry * cos(6 * TWO_PI * (double) q / mp)
303 a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
304 for (q = 0; q < numPoints; q++) {
305 a[numFigs][q].x = ((double) q / mp) * mx;
306 a[numFigs][q].y = (1.0 - sin(((double) q / mp) * 5 * TWO_PI))
313 /* make some space around the figures. */
314 marginx = (mx + 1) / 10;
315 marginy = (my + 1) / 10;
316 scalex = (double) ((mx + 1) - 2.0 * marginx) / (mx + 1.0);
317 scaley = (double) ((my + 1) - 2.0 * marginy) / (my + 1.0);
318 for (q = 0; q < numFigs; q++)
319 for (w = 0; w < numPoints; w++) {
320 a[q][w].x = marginx + a[q][w].x * scalex;
321 a[q][w].y = marginy + a[q][w].y * scaley;
331 XWindowAttributes wa;
335 numPoints = get_integer_resource("points", "Integer");
336 steps = get_integer_resource("steps", "Integer");
337 delay = get_integer_resource("delay", "Integer");
338 ft = get_string_resource("figtype", "String");
340 if (strcmp(ft, "all") == 0)
342 else if (strcmp(ft, "open") == 0)
344 else if (strcmp(ft, "closed") == 0)
347 fprintf(stderr, "figtype should be `all', `open' or `closed'.\n");
352 steps = (random() % 400) + 100;
354 deltaGamma = 1.0 / steps;
355 XGetWindowAttributes(dpy, window, &wa);
357 scrHeight = wa.height;
359 gcv.foreground = get_pixel_resource("foreground", "Foreground", dpy, cmap);
360 gcDraw = XCreateGC(dpy, window, GCForeground, &gcv);
361 XSetForeground(dpy, gcDraw, gcv.foreground);
362 gcv.foreground = get_pixel_resource("background", "Background", dpy, cmap);
363 gcClear = XCreateGC(dpy, window, GCForeground, &gcv);
364 XClearWindow(dpy, window);
368 aCurr = aWork[nWork = 0];
370 currGamma = maxGamma + 1.0; /* force creation of new figure at startup */
373 { /* jwz for version 2.11 */
374 int width = random() % 10;
375 int style = LineSolid;
376 int cap = (width > 1 ? CapRound : CapButt);
377 int join = (width > 1 ? JoinRound : JoinBevel);
378 if (width == 1) width = 0;
379 XSetLineAttributes(dpy, gcDraw, width, style, cap, join);
380 XSetLineAttributes(dpy, gcClear, width, style, cap, join);
384 /* 55% of execution time */
389 XPoint *pa = aCurr, *pa1 = aFrom, *pa2 = aTo;
398 f1g = 1.0 - currGamma;
400 lg = 8192L * currGamma;
401 l1g = 8192L * (1.0 - currGamma);
403 for (q = numPoints; q; q--) {
405 pa->x = (short) (f1g * pa1->x + fg * pa2->x);
406 pa->y = (short) (f1g * pa1->y + fg * pa2->y);
408 pa->x = (short) ((l1g * pa1->x + lg * pa2->x) / 8192L);
409 pa->y = (short) ((l1g * pa1->y + lg * pa2->y) / 8192L);
417 /* 36% of execution time */
422 XPoint *old0, *old1, *new0, *new1;
424 /* Problem: update the window without too much flickering. I do
425 * this by handling each linesegment separately. First remove a
426 * line, then draw the new line. The problem is that this leaves
427 * small black pixels on the figure. To fix this, I draw the
428 * entire figure using XDrawLines() afterwards. */
434 for (q = numPoints - 1; q; q--) {
435 XDrawLine(dpy, window, gcClear,
436 old0->x, old0->y, old1->x, old1->y);
437 XDrawLine(dpy, window, gcDraw,
438 new0->x, new0->y, new1->x, new1->y);
445 XDrawLines(dpy, window, gcDraw, aCurr, numPoints, CoordModeOrigin);
450 /* neglectible % of execution time */
454 if (currGamma > maxGamma) {
456 if (maxGamma == 1.0) {
460 memcpy(aTmp, aCurr, numPoints * sizeof(XPoint));
466 } while (nTo == nFrom);
469 /* reverse the array to get more variation. */
473 for (i1 = 0, i2 = numPoints - 1; i1 < numPoints / 2; i1++, i2--) {
479 /* occationally interrupt the next run. */
481 maxGamma = 0.1 + 0.7 * (RND(1001) / 1000.0); /* partial run */
483 maxGamma = 1.0; /* full run */
489 aCurr = aWork[nWork ^= 1];
491 currGamma += deltaGamma;
496 /**************************************************************************
498 * P U B L I C F U N C T I O N S *
500 **************************************************************************/
503 screenhack(Display *disp, Window win)
510 screenhack_usleep(delay);