source: trunk/third/xscreensaver/hacks/lmorph.c @ 15683

Revision 15683, 16.8 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15682, which included commits to RCS files with non-trunk default branches.
Line 
1/* lmorph, Copyright (c) 1993-1999 Sverre H. Huseby and Glenn T. Lines
2 *
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation.  No representations are made about the suitability of this
8 * software for any purpose.  It is provided "as is" without express or
9 * implied warranty.
10 */
11
12/*------------------------------------------------------------------------
13 |
14 |  FILE            lmorph.c
15 |  MODULE OF       xscreensaver
16 |
17 |  DESCRIPTION     Smooth and non-linear morphing between 1D curves.
18 |
19 |  WRITTEN BY      Sverre H. Huseby                Glenn T. Lines
20 |                  Kurvn. 30                       Østgaardsgt. 5
21 |                  N-0495 Oslo                     N-0474 Oslo
22 |                  Norway                          Norway
23 |
24 |                  Phone:  +47 901 63 579          Phone:  +47 22 04 67 28
25 |                  E-mail: sverrehu@online.no      E-mail: glennli@ifi.uio.no
26 |                  URL:    http://home.sol.no/~sverrehu/
27 |
28 |                  The original idea, and the bilinear interpolation
29 |                  mathematics used, emerged in the head of the wise
30 |                  Glenn T. Lines.
31 |
32 |  MODIFICATIONS   october 1999 (shh)
33 |                    * Removed option to use integer arithmetic.
34 |                    * Increased default number of points, and brightened
35 |                      the foreground color a little bit.
36 |                    * Minor code cleanup (very minor, that is).
37 |                    * Default number of steps is no longer random.
38 |                    * Added -linewidth option (and resource).
39 |
40 |                  october 1999 (gtl)
41 |                    * Added cubic interpolation between shapes
42 |                    * Added non-linear transformation speed 
43 |
44 |                  june 1998 (shh)
45 |                    * Minor code cleanup.
46 |
47 |                  january 1997 (shh)
48 |                    * Some code reformatting.
49 |                    * Added possibility to use float arithmetic.
50 |                    * Added -figtype option.
51 |                    * Made color blue default.
52 |
53 |                  december 1995 (jwz)
54 |                    * Function headers converted from ANSI to K&R.
55 |                    * Added posibility for random number of steps, and
56 |                      made this the default.
57 |
58 |                  march 1995 (shh)
59 |                    * Converted from an MS-Windows program to X Window.
60 |
61 |                  november 1993 (gtl, shh, lots of beer)
62 |                    * Original Windows version (we didn't know better).
63 +----------------------------------------------------------------------*/
64
65#include <stdio.h>
66#include <stdlib.h>
67#include <string.h>
68#include <math.h>
69#include "screenhack.h"
70
71/*-----------------------------------------------------------------------+
72|  PRIVATE DATA                                                          |
73+-----------------------------------------------------------------------*/
74
75/* define MARGINS to make some space around the figure. */
76#define MARGINS
77
78#define MAXFIGS    20
79#define TWO_PI     (2.0 * M_PI)
80#define RND(x)     (random() % (x))
81
82#define FT_OPEN    1
83#define FT_CLOSED  2
84#define FT_ALL     (FT_OPEN | FT_CLOSED)
85
86static int
87    numFigs = 0,                /* number of figure arrays. */
88    numPoints,                  /* number of points in each array. */
89    nWork,                      /* current work array number. */
90    nFrom,                      /* current from array number. */
91    nTo,                        /* current to array number. */
92    nNext,                      /* current next array number (after to).*/
93    shift,                      /* shifts the starting point of a figure */
94    figType;
95static long delay;              /* usecs to wait between updates. */
96static XPoint
97    *aWork[2],                  /* working arrays. */
98    *a[MAXFIGS],                /* the figure arrays. */
99    *aTmp,                      /* used as source when interrupting morph */
100    *aPrev,                     /* previous points displayed. */
101    *aCurr,                     /* the current points displayed. */ 
102    *aFrom,                     /* figure converting from. */
103    *aTo,                       /* figure converting to. */
104    *aNext,                     /* figure converting to next time. */
105    *aSlopeFrom,                /* slope at start of morph */
106    *aSlopeTo;                  /* slope at end of morph */
107static int         scrWidth, scrHeight;
108static double      currGamma, maxGamma = 1.0, deltaGamma;
109static GC          gcDraw, gcClear;
110static Display     *dpy;
111static Window      window;
112
113/*-----------------------------------------------------------------------+
114|  PUBLIC DATA                                                           |
115+-----------------------------------------------------------------------*/
116
117char *progclass = "LMorph";
118
119char *defaults [] = {
120    ".background: black",
121    ".foreground: #4444FF",
122    "*points: 200",
123    "*steps: 150",
124    "*delay: 70000",
125    "*figtype: all",
126    "*linewidth: 5",
127    0
128};
129
130XrmOptionDescRec options [] = {
131    { "-points",      ".points",      XrmoptionSepArg, 0 },
132    { "-steps",       ".steps",       XrmoptionSepArg, 0 },
133    { "-delay",       ".delay",       XrmoptionSepArg, 0 },
134    { "-figtype",     ".figtype",     XrmoptionSepArg, 0 },
135    { "-linewidth",   ".linewidth",   XrmoptionSepArg, 0 },
136    { 0, 0, 0, 0 }
137};
138int options_size = (sizeof (options) / sizeof (options[0]));
139
140/*-----------------------------------------------------------------------+
141|  PRIVATE FUNCTIONS                                                     |
142+-----------------------------------------------------------------------*/
143
144static void *
145xmalloc(size_t size)
146{
147    void *ret;
148
149    if ((ret = malloc(size)) == NULL) {
150        fprintf(stderr, "lmorph: out of memory\n");
151        exit(1);
152    }
153    return ret;
154}
155
156static void
157initPointArrays(void)
158{
159    int    q, w;
160    int    mx, my;            /* max screen coordinates. */
161    int    mp;                /* max point number. */
162    int    s, rx, ry;
163    int    marginx, marginy;
164    double scalex, scaley;
165
166    mx = scrWidth - 1;
167    my = scrHeight - 1;
168    mp = numPoints - 1;
169
170    aWork[0] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
171    aWork[1] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
172    aTmp     = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
173
174    if (figType & FT_CLOSED) {
175        /* rectangle */
176        a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
177        s = numPoints / 4;
178        for (q = 0; q < s; q++) {
179            a[numFigs][q].x = ((double) q / s) * mx;
180            a[numFigs][q].y = 0;
181            a[numFigs][s + q].x = mx;
182            a[numFigs][s + q].y = ((double) q / s) * my;
183            a[numFigs][2 * s + q].x = mx - ((double) q / s) * mx;
184            a[numFigs][2 * s + q].y = my;
185            a[numFigs][3 * s + q].x = 0;
186            a[numFigs][3 * s + q].y = my - ((double) q / s) * my;
187        }
188        for (q = 4 * s; q < numPoints; q++)
189            a[numFigs][q].x = a[numFigs][q].y = 0;
190        a[numFigs][mp].x = a[numFigs][0].x;
191        a[numFigs][mp].y = a[numFigs][0].y;
192        ++numFigs;
193
194        /*  */
195        a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
196        rx = mx / 2;
197        ry = my / 2;
198        for (q = 0; q < numPoints; q++) {
199            a[numFigs][q].x = mx / 2 + rx * sin(1 * TWO_PI * (double) q / mp);
200            a[numFigs][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp);
201        }
202        a[numFigs][mp].x = a[numFigs][0].x;
203        a[numFigs][mp].y = a[numFigs][0].y;
204        ++numFigs;
205
206        /*  */
207        a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
208        rx = mx / 2;
209        ry = my / 2;
210        for (q = 0; q < numPoints; q++) {
211            a[numFigs][q].x = mx / 2 + ry * sin(3 * TWO_PI * (double) q / mp);
212            a[numFigs][q].y = my / 2 + ry * cos(1 * TWO_PI * (double) q / mp);
213        }
214        a[numFigs][mp].x = a[numFigs][0].x;
215        a[numFigs][mp].y = a[numFigs][0].y;
216        ++numFigs;
217
218        /*  */
219        a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
220        rx = mx / 2;
221        ry = my / 2;
222        for (q = 0; q < numPoints; q++) {
223            a[numFigs][q].x = mx / 2 + ry
224                * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp))
225                * sin(TWO_PI * (double) q / mp);
226            a[numFigs][q].y = my / 2 + ry
227                * (0.8 - 0.2 * sin(30 * TWO_PI * q / mp))
228                * cos(TWO_PI * (double) q / mp);
229        }
230        a[numFigs][mp].x = a[numFigs][0].x;
231        a[numFigs][mp].y = a[numFigs][0].y;
232        ++numFigs;
233
234
235        /* */
236        a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
237        rx = mx / 2;
238        ry = my / 2;
239        for (q = 0; q < numPoints; q++) {
240            a[numFigs][q].x = mx / 2 + ry * sin(TWO_PI * (double) q / mp);
241            a[numFigs][q].y = my / 2 + ry * cos(TWO_PI * (double) q / mp);
242        }
243        a[numFigs][mp].x = a[numFigs][0].x;
244        a[numFigs][mp].y = a[numFigs][0].y;
245        ++numFigs;
246
247
248        /*  */
249        a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
250        rx = mx / 2;
251        ry = my / 2;
252        for (q = 0; q < numPoints; q++) {
253            a[numFigs][q].x = mx / 2 + rx * cos(TWO_PI * (double) q / mp);
254            a[numFigs][q].y = my / 2 + ry * sin(TWO_PI * (double) q / mp);
255        }
256        a[numFigs][mp].x = a[numFigs][0].x;
257        a[numFigs][mp].y = a[numFigs][0].y;
258        ++numFigs;
259
260        /*  */
261        a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
262        rx = mx / 2;
263        ry = my / 2;
264        for (q = 0; q < numPoints; q++) {
265            a[numFigs][q].x = mx / 2 + rx * sin(2 * TWO_PI * (double) q / mp);
266            a[numFigs][q].y = my / 2 + ry * cos(3 * TWO_PI * (double) q / mp);
267        }
268        a[numFigs][mp].x = a[numFigs][0].x;
269        a[numFigs][mp].y = a[numFigs][0].y;
270        ++numFigs;
271    }
272
273    if (figType & FT_OPEN) {
274        /* sine wave, one period */
275        a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
276        for (q = 0; q < numPoints; q++) {
277            a[numFigs][q].x = ((double) q / numPoints) * mx;
278            a[numFigs][q].y = (1.0 - sin(((double) q / mp) * TWO_PI))
279                * my / 2.0;
280        }
281        ++numFigs;
282
283        /*  */
284        a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
285        for (q = 0; q < numPoints; q++) {
286            a[numFigs][q].x = ((double) q / mp) * mx;
287            a[numFigs][q].y = (1.0 - cos(((double) q / mp) * 3 * TWO_PI))
288                * my / 2.0;
289        }
290        ++numFigs;
291
292        /* spiral, one endpoint at bottom */
293        a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
294        rx = mx / 2;
295        ry = my / 2;
296        for (q = 0; q < numPoints; q++) {
297            a[numFigs][q].x = mx / 2 + ry * sin(5 * TWO_PI * (double) q / mp)
298                * ((double) q / mp);
299            a[numFigs][q].y = my / 2 + ry * cos(5 * TWO_PI * (double) q / mp)
300                * ((double) q / mp);
301        }
302        ++numFigs;
303
304        /* spiral, one endpoint at top */
305        a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
306        rx = mx / 2;
307        ry = my / 2;
308        for (q = 0; q < numPoints; q++) {
309            a[numFigs][q].x = mx / 2 + ry * sin(6 * TWO_PI * (double) q / mp)
310                * ((double) q / mp);
311            a[numFigs][q].y = my / 2 - ry * cos(6 * TWO_PI * (double) q / mp)
312                * ((double) q / mp);
313        }
314        ++numFigs;
315
316        /*  */
317        a[numFigs] = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
318        for (q = 0; q < numPoints; q++) {
319            a[numFigs][q].x = ((double) q / mp) * mx;
320            a[numFigs][q].y = (1.0 - sin(((double) q / mp) * 5 * TWO_PI))
321                * my / 2.0;
322        }
323        ++numFigs;
324    }
325
326#ifdef MARGINS
327    /* make some space around the figures.  */
328    marginx = (mx + 1) / 10;
329    marginy = (my + 1) / 10;
330    scalex = (double) ((mx + 1) - 2.0 * marginx) / (mx + 1.0);
331    scaley = (double) ((my + 1) - 2.0 * marginy) / (my + 1.0);
332    for (q = 0; q < numFigs; q++)
333        for (w = 0; w < numPoints; w++) {
334            a[q][w].x = marginx + a[q][w].x * scalex;
335            a[q][w].y = marginy + a[q][w].y * scaley;
336        }
337#endif
338}
339
340static void
341initLMorph(void)
342{
343    int               steps;
344    XGCValues         gcv;
345    XWindowAttributes wa;
346    Colormap          cmap;
347    char              *ft;
348    int               i;
349
350    numPoints = get_integer_resource("points", "Integer");
351    steps = get_integer_resource("steps", "Integer");
352    delay = get_integer_resource("delay", "Integer");
353    ft = get_string_resource("figtype", "String");
354
355    if (strcmp(ft, "all") == 0)
356        figType = FT_ALL;
357    else if (strcmp(ft, "open") == 0)
358        figType = FT_OPEN;
359    else if (strcmp(ft, "closed") == 0)
360        figType = FT_CLOSED;
361    else {
362        fprintf(stderr, "figtype should be `all', `open' or `closed'.\n");
363        figType = FT_ALL;
364    }
365
366    if (steps <= 0)
367      steps = (random() % 400) + 100;
368
369    deltaGamma = 1.0 / steps;
370    XGetWindowAttributes(dpy, window, &wa);
371    scrWidth = wa.width;
372    scrHeight = wa.height;
373    cmap = wa.colormap;
374    gcv.foreground = get_pixel_resource("foreground", "Foreground", dpy, cmap);
375    gcDraw = XCreateGC(dpy, window, GCForeground, &gcv);
376    XSetForeground(dpy, gcDraw, gcv.foreground);
377    gcv.foreground = get_pixel_resource("background", "Background", dpy, cmap);
378    gcClear = XCreateGC(dpy, window, GCForeground, &gcv);
379    XClearWindow(dpy, window);
380
381    initPointArrays();
382    aCurr = aWork[nWork = 0];
383    aPrev = NULL;
384    currGamma = maxGamma + 1.0;  /* force creation of new figure at startup */
385    nTo = RND(numFigs);
386    do {
387        nNext = RND(numFigs);
388    } while (nNext == nTo);
389
390    aSlopeTo = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
391    aSlopeFrom = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
392    aNext = (XPoint *) xmalloc(numPoints * sizeof(XPoint));
393
394    for (i = 0; i < numPoints ; i++) {
395        aSlopeTo[i].x = 0.0;
396        aSlopeTo[i].y = 0.0;
397    }
398
399    {   /* jwz for version 2.11 */
400        /*      int width = random() % 10;*/
401        int width = get_integer_resource("linewidth", "Integer");
402        int style = LineSolid;
403        int cap   = (width > 1 ? CapRound  : CapButt);
404        int join  = (width > 1 ? JoinRound : JoinBevel);
405        if (width == 1)
406            width = 0;
407        XSetLineAttributes(dpy, gcDraw,  width, style, cap, join);
408        XSetLineAttributes(dpy, gcClear, width, style, cap, join);
409    }
410}
411
412/* 55% of execution time */
413static void
414createPoints(void)
415{
416    int    q;
417    XPoint *pa = aCurr, *pa1 = aFrom, *pa2 = aTo;
418    XPoint *qa1 = aSlopeFrom, *qa2 = aSlopeTo;
419    float  fg, f1g;
420    float  speed;
421
422    fg  = currGamma;
423    f1g = 1.0 - currGamma;
424    for (q = numPoints; q; q--) {
425        speed = 0.45 * sin(TWO_PI * (double) (q + shift) / (numPoints - 1));
426        fg = currGamma + 1.67 * speed
427            * exp(-200.0 * (currGamma - 0.5 + 0.7 * speed)
428                  * (currGamma - 0.5 + 0.7 * speed));
429
430        f1g = 1.0 - fg;
431        pa->x = (short) (f1g * f1g * f1g * pa1->x + f1g * f1g * fg
432                         * (3 * pa1->x + qa1->x) + f1g * fg * fg
433                         * (3 * pa2->x - qa2->x) + fg * fg * fg * pa2->x);
434        pa->y = (short) (f1g * f1g * f1g * pa1->y + f1g * f1g * fg
435                         * (3 * pa1->y + qa1->y) + f1g * fg * fg
436                         * (3 * pa2->y - qa2->y) + fg * fg * fg * pa2->y);
437
438        ++pa;
439        ++pa1;
440        ++pa2;
441        ++qa1;
442        ++qa2;
443    }
444}
445
446/* 36% of execution time */
447static void
448drawImage(void)
449{
450    int    q;
451    XPoint *old0, *old1, *new0, *new1;
452
453    /* Problem: update the window without too much flickering. I do
454     * this by handling each linesegment separately. First remove a
455     * line, then draw the new line. The problem is that this leaves
456     * small black pixels on the figure. To fix this, we draw the
457     * entire figure using XDrawLines() afterwards. */
458    if (aPrev) {
459        old0 = aPrev;
460        old1 = aPrev + 1;
461        new0 = aCurr;
462        new1 = aCurr + 1;
463        for (q = numPoints - 1; q; q--) {
464           XDrawLine(dpy, window, gcClear,
465             old0->x, old0->y, old1->x, old1->y);
466            XDrawLine(dpy, window, gcDraw,
467                      new0->x, new0->y, new1->x, new1->y);
468            ++old0;
469            ++old1;
470            ++new0;
471            ++new1;
472        }
473    }
474    XDrawLines(dpy, window, gcDraw, aCurr, numPoints, CoordModeOrigin);
475
476    XFlush(dpy);
477}
478
479/* neglectible % of execution time */
480static void
481animateLMorph(void)
482{
483    int i;
484    if (currGamma > maxGamma) {
485        currGamma = 0.0;
486        nFrom = nTo;
487        nTo = nNext;
488        aFrom = a[nFrom];
489        aTo = a[nTo];
490        do {
491            nNext = RND(numFigs);
492        } while (nNext == nTo);
493        aNext = a[nNext];
494
495        shift = RND(numPoints);
496        if (RND(2)) {
497            /* reverse the array to get more variation. */
498            int    i1, i2;
499            XPoint p;
500           
501            for (i1 = 0, i2 = numPoints - 1; i1 < numPoints / 2; i1++, i2--) {
502                p = aNext[i1];
503                aNext[i1] = aNext[i2];
504                aNext[i2] = p;
505            }
506        }
507
508        /* calculate the slopes */
509        for (i = 0; i < numPoints ; i++) {
510            aSlopeFrom[i].x = aSlopeTo[i].x;
511            aSlopeFrom[i].y = aSlopeTo[i].y;
512            aSlopeTo[i].x = aNext[i].x - aTo[i].x;
513            aSlopeTo[i].y = (aNext[i].y - aTo[i].y);
514        }
515    }
516
517    createPoints();
518    drawImage();
519    aPrev = aCurr;
520    aCurr = aWork[nWork ^= 1];
521
522    currGamma += deltaGamma;
523}
524
525/*-----------------------------------------------------------------------+
526|  PUBLIC FUNCTIONS                                                      |
527+-----------------------------------------------------------------------*/
528
529void
530screenhack(Display *disp, Window win)
531{
532    dpy = disp;
533    window = win;
534    initLMorph();
535    for (;;) {
536        animateLMorph();
537        screenhack_handle_events (dpy);
538        usleep(delay);
539        }
540
541}
Note: See TracBrowser for help on using the repository browser.