2 /**************************************************************************
5 * MODULE OF xscreensaver
7 * DESCRIPTION Bilinear interpolation for morphing line shapes.
9 * WRITTEN BY Sverre H. Huseby Glenn T. Lines
10 * Maridalsvn. 122, leil 101 Frysjavn. 3, 5. etg.
11 * N-0461 Oslo N-0883 Oslo
14 * Phone: +47 22 71 99 08 Phone: +47 22 23 71 99
15 * E-mail: sverrehu@ifi.uio.no E-mail: gtl@si.sintef.no
17 * The original idea, and the bilinear interpolation
18 * mathematics used, emerged in the head of the wise
21 * MODIFICATIONS march 1995
22 * * Converted from an MS-Windows program to X Window.
24 **************************************************************************/
30 #include "screenhack.h"
32 /**************************************************************************
34 * P R I V A T E D A T A *
36 **************************************************************************/
38 /* Define MARGINS to make some space around the figure */
42 #define TWO_PI (2.0 * M_PI)
43 #define RND(x) (random() % (x))
45 cFig = 0, /* Number of figure arrays. */
46 cPoint, /* Number of points in each array. */
47 nWork, /* Current work array number. */
48 nFrom, /* Current from array number. */
49 nTo; /* Current to array number. */
51 delay; /* usecs to wait between updates. */
53 *aWork[2], /* Working arrays. */
54 *a[MAXFIGS], /* The figure arrays. */
55 *aTmp, /* Used as source when interrupting morph */
56 *aPrev, /* Previous points displayed. */
57 *aCurr, /* The current points displayed. */
58 *aFrom, /* Figure converting from. */
59 *aTo; /* Figure converting to. */
73 /**************************************************************************
75 * P U B L I C D A T A *
77 **************************************************************************/
79 char *progclass = "LMorph";
82 "LMorph.background: black",
83 "LMorph.foreground: green",
90 XrmOptionDescRec options [] = {
91 { "-points", ".points", XrmoptionSepArg, 0 },
92 { "-steps", ".steps", XrmoptionSepArg, 0 },
93 { "-delay", ".delay", XrmoptionSepArg, 0 },
98 /**************************************************************************
100 * P R I V A T E F U N C T I O N S *
102 **************************************************************************/
109 if ((ret = malloc(size)) == NULL) {
110 fprintf(stderr, "lmorph: out of memory\n");
118 static double frnd (void)
121 * Hm. for some reason the second line (using RAND_MAX) didn't
122 * work on some machines, so I always use the first.
124 #ifndef dont_use_RAND_MAX
125 return (double) (random() & 0x7FFF) / 0x7FFF;
127 return ((double) random()) / RAND_MAX;
128 #endif /* RAND_MAX */
133 static void initPointArrays (void)
135 XWindowAttributes wa;
137 mx, my, /* Max screen coordinates. */
138 mp, /* Max point number. */
141 double scalex, scaley;
143 XGetWindowAttributes(dpy, window, &wa);
148 aWork[0] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
149 aWork[1] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
150 aTmp = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
156 a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
158 for (q = 0; q < s; q++) {
159 a[cFig][q].x = ((double) q / s) * mx;
161 a[cFig][s + q].x = mx;
162 a[cFig][s + q].y = ((double) q / s) * my;
163 a[cFig][2 * s + q].x = mx - ((double) q / s) * mx;
164 a[cFig][2 * s + q].y = my;
165 a[cFig][3 * s + q].x = 0;
166 a[cFig][3 * s + q].y = my - ((double) q / s) * my;
168 for (q = 4 * s; q < cPoint; q++)
169 a[cFig][q].x = a[cFig][q].y = 0;
170 a[cFig][mp].x = a[cFig][0].x;
171 a[cFig][mp].y = a[cFig][0].y;
177 a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
178 for (q = 0; q < cPoint; q++) {
179 a[cFig][q].x = ((double) q / cPoint) * mx;
180 a[cFig][q].y = (1.0 - sin(((double) q / mp) * TWO_PI)) * my / 2.0;
187 a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
190 for (q = 0; q < cPoint; q++) {
191 a[cFig][q].x = mx / 2 + rx * sin(1 * TWO_PI * (double) q / mp);
192 a[cFig][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp);
194 a[cFig][mp].x = a[cFig][0].x;
195 a[cFig][mp].y = a[cFig][0].y;
201 a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
204 for (q = 0; q < cPoint; q++) {
205 a[cFig][q].x = mx / 2 + ry * sin(3 * TWO_PI * (double) q / mp);
206 a[cFig][q].y = my / 2 + ry * cos(1 * TWO_PI * (double) q / mp);
208 a[cFig][mp].x = a[cFig][0].x;
209 a[cFig][mp].y = a[cFig][0].y;
215 a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
218 for (q = 0; q < cPoint; q++) {
219 a[cFig][q].x = mx / 2 + ry * (1 - 0.1 * frnd())
220 * sin(TWO_PI * (double) q / mp);
221 a[cFig][q].y = my / 2 + ry * (1 - 0.1 * frnd())
222 * cos(TWO_PI * (double) q / mp);
224 a[cFig][mp].x = a[cFig][0].x;
225 a[cFig][mp].y = a[cFig][0].y;
231 a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
234 for (q = 0; q < cPoint; q++) {
235 a[cFig][q].x = mx / 2 + ry * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp))
236 * sin(TWO_PI * (double) q / mp);
237 a[cFig][q].y = my / 2 + ry * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp))
238 * cos(TWO_PI * (double) q / mp);
240 a[cFig][mp].x = a[cFig][0].x;
241 a[cFig][mp].y = a[cFig][0].y;
247 a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
250 for (q = 0; q < cPoint; q++) {
251 a[cFig][q].x = mx / 2 + ry * sin(TWO_PI * (double) q / mp);
252 a[cFig][q].y = my / 2 + ry * cos(TWO_PI * (double) q / mp);
254 a[cFig][mp].x = a[cFig][0].x;
255 a[cFig][mp].y = a[cFig][0].y;
261 a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
264 for (q = 0; q < cPoint; q++) {
265 a[cFig][q].x = mx / 2 + rx * cos(TWO_PI * (double) q / mp);
266 a[cFig][q].y = my / 2 + ry * sin(TWO_PI * (double) q / mp);
268 a[cFig][mp].x = a[cFig][0].x;
269 a[cFig][mp].y = a[cFig][0].y;
275 a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
276 for (q = 0; q < cPoint; q++) {
277 a[cFig][q].x = ((double) q / mp) * mx;
278 a[cFig][q].y = (1.0 - cos(((double) q / mp) * 3 * TWO_PI)) * my / 2.0;
285 a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
288 for (q = 0; q < cPoint; q++) {
289 a[cFig][q].x = mx / 2 + rx * sin(2 * TWO_PI * (double) q / mp);
290 a[cFig][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp);
292 a[cFig][mp].x = a[cFig][0].x;
293 a[cFig][mp].y = a[cFig][0].y;
299 a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
302 for (q = 0; q < cPoint; q++) {
303 a[cFig][q].x = mx / 2 + ry * sin(5 * TWO_PI * (double) q / mp)
305 a[cFig][q].y = my / 2 + ry * cos(5 * TWO_PI * (double) q / mp)
313 a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
316 for (q = 0; q < cPoint; q++) {
317 a[cFig][q].x = mx / 2 + ry * sin(6 * TWO_PI * (double) q / mp)
319 a[cFig][q].y = my / 2 - ry * cos(6 * TWO_PI * (double) q / mp)
327 a[cFig] = (XPoint *) xmalloc(cPoint * sizeof(XPoint));
328 for (q = 0; q < cPoint; q++) {
329 a[cFig][q].x = ((double) q / mp) * mx;
330 a[cFig][q].y = (1.0 - sin(((double) q / mp) * 5 * TWO_PI)) * my / 2.0;
336 * Make some space around the figures.
338 marginx = (mx + 1) / 10;
339 marginy = (my + 1) / 10;
340 scalex = (double) ((mx + 1) - 2.0 * marginx) / (mx + 1.0);
341 scaley = (double) ((my + 1) - 2.0 * marginy) / (my + 1.0);
342 for (q = 0; q < cFig; q++)
343 for (w = 0; w < cPoint; w++) {
344 a[q][w].x = marginx + a[q][w].x * scalex;
345 a[q][w].y = marginy + a[q][w].y * scaley;
352 static void createPoints (void)
355 XPoint *pa = aCurr, *pa1 = aFrom, *pa2 = aTo;
359 lg = 8192L * gam, l1g = 8192L * (1.0 - gam);
360 for (q = 0; q < cPoint; q++) {
361 pa->x = (short) ((l1g * pa1->x + lg * pa2->x) / 8192L);
362 pa->y = (short) ((l1g * pa1->y + lg * pa2->y) / 8192L);
370 static void drawImage (void)
373 XPoint *old0, *old1, *new0, *new1;
376 * Problem: update the window without too much flickering. I do
377 * this by handling each linesegment separately. First remove a
378 * line, then draw the new line. The problem is that this leaves
379 * small black pixels on the figure. To fix this, I draw the
380 * entire figure using XDrawLines() afterwards.
387 for (q = cPoint - 1; q; q--) {
388 XDrawLine(dpy, window, gcClear,
389 old0->x, old0->y, old1->x, old1->y);
390 XDrawLine(dpy, window, gcDraw,
391 new0->x, new0->y, new1->x, new1->y);
398 XDrawLines(dpy, window, gcDraw, aCurr, cPoint, CoordModeOrigin);
402 static void initLMorph (void)
406 XWindowAttributes wa;
409 cPoint = get_integer_resource("points", "Integer");
410 steps = get_integer_resource("steps", "Integer");
411 delay = get_integer_resource("delay", "Integer");
414 steps = (random() % 400) + 100;
416 delta_gam = 1.0 / steps;
417 XGetWindowAttributes(dpy, window, &wa);
419 gcv.foreground = get_pixel_resource("foreground", "Foreground", dpy, cmap);
420 gcDraw = XCreateGC(dpy, window, GCForeground, &gcv);
421 XSetForeground(dpy, gcDraw, gcv.foreground);
422 gcv.foreground = get_pixel_resource("background", "Background", dpy, cmap);
423 gcClear = XCreateGC(dpy, window, GCForeground, &gcv);
424 XClearWindow(dpy, window);
427 aCurr = aWork[nWork = 0];
433 int width = random() % 10;
434 int style = LineSolid;
435 int cap = (width > 1 ? CapRound : CapButt);
436 int join = (width > 1 ? JoinRound : JoinBevel);
437 if (width == 1) width = 0;
438 XSetLineAttributes(dpy, gcDraw, width, style, cap, join);
439 XSetLineAttributes(dpy, gcClear, width, style, cap, join);
444 static void animateLMorph (void)
446 if (gam > maxGamma) {
448 if (maxGamma == 1.0) {
452 memcpy(aTmp, aCurr, cPoint * sizeof(XPoint));
458 } while (nTo == nFrom);
462 * Reverse the array to get more variation.
467 for (i1 = 0, i2 = cPoint - 1; i1 < cPoint / 2; i1++, i2--) {
474 * It may be nice to interrupt the next run.
477 maxGamma = 0.1 + 0.7 * (RND(1001) / 1000.0);
485 aCurr = aWork[nWork ^= 1];
492 /**************************************************************************
494 * P U B L I C F U N C T I O N S *
496 **************************************************************************/
499 screenhack(Display *disp, Window win)
506 screenhack_usleep(delay);