source: trunk/third/xscreensaver/hacks/distort.c @ 20148

Revision 20148, 21.5 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- mode: C; tab-width: 4 -*-
2 * xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997, 1998, 2002, 2003
3 * Jamie Zawinski <jwz@jwz.org>
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation.  No representations are made about the suitability of this
10 * software for any purpose.  It is provided "as is" without express or
11 * implied warranty.
12 */
13
14/* distort
15 * by Jonas Munsin (jmunsin@iki.fi) and Jamie Zawinski <jwz@jwz.org>
16 * TODO:
17 *      -check the allocations in init_round_lense again, maybe make it possible again
18 *       to use swamp without pre-allocating/calculating (although that
19 *       makes it slower) - -swamp is memory hungry
20 *      -more distortion matrices (fortunately, I'm out of ideas :)
21 * Stuff that would be cool but probably too much of a resource hog:
22 *      -some kind of interpolation to avoid jaggies
23 *    -large speed values leaves the image distorted
24 * program idea borrowed from a screensaver on a non-*NIX OS,
25 *
26 * 28 Sep 1999 Jonas Munsin (jmunsin@iki.fi)
27 *    Added about 10x faster algortim for 8, 16 and 32 bpp (modifies pixels
28 *    directly avoiding costly XPutPixle(XGetPixel()) calls, inspired by
29 *    xwhirl made by horvai@clipper.ens.fr (Peter Horvai) and the XFree86
30 *    Xlib sources.
31 *    This piece of code is really horrible, but it works, and at the moment
32 *    I don't have time or inspiration to fix something that works (knock
33 *    on wood).
34 * 08 Oct 1999 Jonas Munsin (jmunsin@iki.fi)
35 *      Corrected several bugs causing references beyond allocated memory.
36 */
37
38#include <math.h>
39#include "screenhack.h"
40#include <X11/Xutil.h>
41#include <X11/Xmd.h>
42
43#ifdef HAVE_XSHM_EXTENSION
44# include "xshm.h"
45static Bool use_shm = False;
46static XShmSegmentInfo shm_info;
47#endif /* HAVE_XSHM_EXTENSION */
48
49struct coo {
50        int x;
51        int y;
52        int r, r_change;
53        int xmove, ymove;
54};
55static struct coo xy_coo[10];
56
57static int delay, radius, speed, number, blackhole, vortex, magnify, reflect, slow;
58static XWindowAttributes xgwa;
59static GC gc;
60static Window g_window;
61static Display *g_dpy;
62static unsigned long black_pixel;
63
64static XImage *orig_map, *buffer_map;
65static unsigned long *buffer_map_cache;
66
67static int ***from;
68static int ****from_array;
69static int *fast_from = NULL;
70static void (*effect) (int) = NULL;
71static void move_lense(int);
72static void swamp_thing(int);
73static void new_rnd_coo(int);
74static void init_round_lense(void);
75static void (*draw) (int) = NULL;
76static void reflect_draw(int);
77static void plain_draw(int);
78
79static void (*draw_routine)(XImage *, XImage *, int, int, int *) = NULL;
80static void fast_draw_8(XImage *, XImage *, int, int, int *);
81static void fast_draw_16(XImage *, XImage *, int, int, int *);
82static void fast_draw_32(XImage *, XImage *, int, int, int *);
83static void generic_draw(XImage *, XImage *, int, int, int *);
84static int bpp_size = 0;
85
86
87static void init_distort(Display *dpy, Window window)
88{
89        XGCValues gcv;
90        long gcflags;
91        int i;
92
93        g_window=window;
94        g_dpy=dpy;
95
96        delay = get_integer_resource("delay", "Integer");
97        radius = get_integer_resource("radius", "Integer");
98        speed = get_integer_resource("speed", "Integer");
99        number = get_integer_resource("number", "Integer");
100
101#ifdef HAVE_XSHM_EXTENSION
102        use_shm = get_boolean_resource("useSHM", "Boolean");
103#endif /* HAVE_XSHM_EXTENSION */
104       
105        blackhole = get_boolean_resource("blackhole", "Boolean");
106        vortex = get_boolean_resource("vortex", "Boolean");
107        magnify = get_boolean_resource("magnify", "Boolean");
108        reflect = get_boolean_resource("reflect", "Boolean");
109        slow = get_boolean_resource("slow", "Boolean");
110       
111        if (get_boolean_resource("swamp", "Boolean"))
112                effect = &swamp_thing;
113        if (get_boolean_resource("bounce", "Boolean"))
114                effect = &move_lense;
115
116        XGetWindowAttributes (dpy, window, &xgwa);
117
118        if (effect == NULL && radius == 0 && speed == 0 && number == 0
119                && !blackhole && !vortex && !magnify && !reflect) {
120/* if no cmdline options are given, randomly choose one of:
121 * -radius 50 -number 4 -speed 1 -bounce
122 * -radius 50 -number 4 -speed 1 -blackhole
123 * -radius 50 -number 4 -speed 1 -vortex
124 * -radius 50 -number 4 -speed 1 -vortex -magnify
125 * -radius 50 -number 4 -speed 1 -vortex -magnify -blackhole
126 * -radius 100 -number 1 -speed 2 -bounce
127 * -radius 100 -number 1 -speed 2 -blackhole
128 * -radius 100 -number 1 -speed 2 -vortex
129 * -radius 100 -number 1 -speed 2 -vortex -magnify
130 * -radius 100 -number 1 -speed 2 -vortex -magnify -blackhole
131 * -radius 80 -number 1 -speed 2 -reflect
132 * -radius 50 -number 3 -speed 2 -reflect
133 * jwz: not these
134 *   -radius 50 -number 4 -speed 2 -swamp
135 *   -radius 50 -number 4 -speed 2 -swamp -blackhole
136 *   -radius 50 -number 4 -speed 2 -swamp -vortex
137 *   -radius 50 -number 4 -speed 2 -swamp -vortex -magnify
138 *   -radius 50 -number 4 -speed 2 -swamp -vortex -magnify -blackhole
139 */
140               
141                i = (random() % 12 /* 17 */);
142
143                draw = &plain_draw;
144
145                switch (i) {
146                        case 0:
147                                radius=50;number=4;speed=1;
148                                effect=&move_lense;break;
149                        case 1:
150                                radius=50;number=4;speed=1;blackhole=1;
151                                effect=&move_lense;break;
152                        case 2:
153                                radius=50;number=4;speed=1;vortex=1;
154                                effect=&move_lense;break;
155                        case 3:
156                                radius=50;number=4;speed=1;vortex=1;magnify=1;
157                                effect=&move_lense;break;
158                        case 4:
159                                radius=50;number=4;speed=1;vortex=1;magnify=1;blackhole=1;
160                                effect=&move_lense;break;
161                        case 5:
162                                radius=100;number=1;speed=2;
163                                effect=&move_lense;break;
164                        case 6:
165                                radius=100;number=1;speed=2;blackhole=1;
166                                effect=&move_lense;break;
167                        case 7:
168                                radius=100;number=1;speed=2;vortex=1;
169                                effect=&move_lense;break;
170                        case 8:
171                                radius=100;number=1;speed=2;vortex=1;magnify=1;
172                                effect=&move_lense;break;
173                        case 9:
174                                radius=100;number=1;speed=2;vortex=1;magnify=1;blackhole=1;
175                                effect=&move_lense;break;
176
177                        case 10:
178                                radius=80;number=1;speed=2;reflect=1;
179                                draw = &reflect_draw;effect = &move_lense;break;
180                        case 11:
181                                radius=50;number=4;speed=2;reflect=1;
182                                draw = &reflect_draw;effect = &move_lense;break;
183
184#if 0 /* jwz: not these */
185                        case 12:
186                                radius=50;number=4;speed=2;
187                                effect=&swamp_thing;break;
188                        case 13:
189                                radius=50;number=4;speed=2;blackhole=1;
190                                effect=&swamp_thing;break;
191                        case 14:
192                                radius=50;number=4;speed=2;vortex=1;
193                                effect=&swamp_thing;break;
194                        case 15:
195                                radius=50;number=4;speed=2;vortex=1;magnify=1;
196                                effect=&swamp_thing;break;
197                        case 16:
198                                radius=50;number=4;speed=2;vortex=1;magnify=1;blackhole=1;
199                                effect=&swamp_thing;break;
200#endif
201
202            default:
203                abort(); break;
204                }
205
206        /* but if the window is small, reduce default radius */
207        if (xgwa.width < radius * 8)
208          radius = xgwa.width/8;
209        }
210
211    /* never allow the radius to be too close to the min window dimension
212     */
213    if (radius >= xgwa.width  * 0.45) radius = xgwa.width  * 0.45;
214    if (radius >= xgwa.height * 0.45) radius = xgwa.height * 0.45;
215
216
217    /* -swamp mode consumes vast amounts of memory, proportional to radius --
218       so throttle radius to a small-ish value (60 => ~30MB.)
219     */
220    if (effect == &swamp_thing && radius > 60)
221      radius = 60;
222
223        if (delay < 0)
224                delay = 0;
225        if (radius <= 0)
226                radius = 60;
227        if (speed <= 0)
228                speed = 2;
229        if (number <= 0)
230                number=1;
231        if (number >= 10)
232                number=1;
233        if (effect == NULL)
234                effect = &move_lense;
235        if (reflect) {
236                draw = &reflect_draw;
237                effect = &move_lense;
238        }
239        if (draw == NULL)
240                draw = &plain_draw;
241
242        black_pixel = BlackPixelOfScreen( xgwa.screen );
243
244        gcv.function = GXcopy;
245        gcv.subwindow_mode = IncludeInferiors;
246        gcflags = GCForeground |GCFunction;
247        if (use_subwindow_mode_p(xgwa.screen, window)) /* see grabscreen.c */
248                gcflags |= GCSubwindowMode;
249        gc = XCreateGC (dpy, window, gcflags, &gcv);
250
251    load_random_image (xgwa.screen, window, window, NULL);
252
253        buffer_map = 0;
254        orig_map = XGetImage(dpy, window, 0, 0, xgwa.width, xgwa.height,
255                                                 ~0L, ZPixmap);
256        buffer_map_cache = malloc(sizeof(unsigned long)*(2*radius+speed+2)*(2*radius+speed+2));
257
258        if (buffer_map_cache == NULL) {
259                perror("distort");
260                exit(EXIT_FAILURE);
261        }
262
263# ifdef HAVE_XSHM_EXTENSION
264
265        if (use_shm)
266          {
267                buffer_map = create_xshm_image(dpy, xgwa.visual, orig_map->depth,
268                                                                           ZPixmap, 0, &shm_info,
269                                                                           2*radius + speed + 2,
270                                                                           2*radius + speed + 2);
271                if (!buffer_map)
272                  use_shm = False;
273          }
274# endif /* HAVE_XSHM_EXTENSION */
275
276        if (!buffer_map)
277          {
278                buffer_map = XCreateImage(dpy, xgwa.visual,
279                                                                  orig_map->depth, ZPixmap, 0, 0,
280                                                                  2*radius + speed + 2, 2*radius + speed + 2,
281                                                                  8, 0);
282                buffer_map->data = (char *)
283                  calloc(buffer_map->height, buffer_map->bytes_per_line);
284        }
285
286        if ((buffer_map->byte_order == orig_map->byte_order)
287                        && (buffer_map->depth == orig_map->depth)
288                        && (buffer_map->format == ZPixmap)
289                        && (orig_map->format == ZPixmap)
290                        && !slow) {
291                switch (orig_map->bits_per_pixel) {
292                        case 32:
293                                draw_routine = &fast_draw_32;
294                                bpp_size = sizeof(CARD32);
295                                break;
296                        case 16:
297                                draw_routine = &fast_draw_16;
298                                bpp_size = sizeof(CARD16);
299                                break;
300                        case 8:
301                                draw_routine = &fast_draw_8;
302                                bpp_size = sizeof(CARD8);
303                                break;
304                        default:
305                                draw_routine = &generic_draw;
306                                break;
307                }
308        } else {
309                draw_routine = &generic_draw;
310        }
311        init_round_lense();
312
313        for (i = 0; i < number; i++) {
314                new_rnd_coo(i);
315                if (number != 1)
316                        xy_coo[i].r = (i*radius)/(number-1); /* "randomize" initial */
317                else
318                         xy_coo[i].r = 0;
319                xy_coo[i].r_change = speed + (i%2)*2*(-speed);  /* values a bit */
320                xy_coo[i].xmove = speed + (i%2)*2*(-speed);
321                xy_coo[i].ymove = speed + (i%2)*2*(-speed);
322        }
323
324}
325
326/* example: initializes a "see-trough" matrix */
327/* static void make_null_lense(void)
328{
329        int i, j;
330        for (i = 0; i < 2*radius+speed+2; i++) {
331                for (j = 0 ; j < 2*radius+speed+2 ; j++) {
332                        from[i][j][0]=i;
333                        from[i][j][1]=j;
334                }
335        }
336}
337*/
338static void convert(void) {
339        int *p;
340        int i, j;
341        fast_from = calloc(1, sizeof(int)*((buffer_map->bytes_per_line/bpp_size)*(2*radius+speed+2) + 2*radius+speed+2));
342        if (fast_from == NULL) {
343                perror("distort");
344                exit(EXIT_FAILURE);
345        }
346        p = fast_from;
347        for (i = 0; i < 2*radius+speed+2; i++) {
348                for (j = 0; j < 2*radius+speed+2; j++) {
349                        *(p + i + j*buffer_map->bytes_per_line/bpp_size)
350                                = from[i][j][0] + xgwa.width*from[i][j][1];
351                        if (*(p + i + j*buffer_map->bytes_per_line/bpp_size) < 0
352                                        || *(p + i + j*buffer_map->bytes_per_line/bpp_size) >= orig_map->height*orig_map->width) {
353                                *(p + i + j*buffer_map->bytes_per_line/bpp_size) = 0;
354                        }
355                }
356        }
357}
358
359/* makes a lense with the Radius=loop and centred in
360 * the point (radius, radius)
361 */
362static void make_round_lense(int radius, int loop)
363{
364        int i, j;
365
366        for (i = 0; i < 2*radius+speed+2; i++) {
367                for(j = 0; j < ((0 == bpp_size) ? (2*radius+speed+2) : (buffer_map->bytes_per_line/bpp_size)); j++) {
368                        double r, d;
369                        r = sqrt ((i-radius)*(i-radius)+(j-radius)*(j-radius));
370                        if (loop == 0)
371                          d=0.0;
372                        else
373                          d=r/loop;
374
375                        if (r < loop-1) {
376
377                                if (vortex) { /* vortex-twist effect */
378                                        double angle;
379                /* this one-line formula for getting a nice rotation angle is borrowed
380                 * (with permission) from the whirl plugin for gimp,
381                 * Copyright (C) 1996 Federico Mena Quintero
382                 */
383                /* 5 is just a constant used because it looks good :) */
384                                        angle = 5*(1-d)*(1-d);
385
386        /* Avoid atan2: DOMAIN error message */
387                                        if ((radius-j) == 0.0 && (radius-i) == 0.0) {
388                                                from[i][j][0] = radius + cos(angle)*r;
389                                                from[i][j][1] = radius + sin(angle)*r;
390                                        } else {
391                                                from[i][j][0] = radius +
392                                                        cos(angle - atan2(radius-j, -(radius-i)))*r;
393                                                from[i][j][1] = radius +
394                                                        sin(angle - atan2(radius-j, -(radius-i)))*r;
395                                        }
396                                        if (magnify) {
397                                                r = sin(d*M_PI_2);
398                                                if (blackhole && r != 0) /* blackhole effect */
399                                                        r = 1/r;
400                                                from[i][j][0] = radius + (from[i][j][0]-radius)*r;
401                                                from[i][j][1] = radius + (from[i][j][1]-radius)*r;
402                                        }
403                                } else { /* default is to magnify */
404                                        r = sin(d*M_PI_2);
405                               
406        /* raising r to different power here gives different amounts of
407         * distortion, a negative value sucks everything into a black hole
408         */
409                                /*      r = r*r; */
410                                        if (blackhole && r != 0) /* blackhole effect */
411                                                r = 1/r;
412                                                                        /* bubble effect (and blackhole) */
413                                        from[i][j][0] = radius + (i-radius)*r;
414                                        from[i][j][1] = radius + (j-radius)*r;
415                                }
416                        } else { /* not inside loop */
417                                from[i][j][0] = i;
418                                from[i][j][1] = j;
419                        }
420                }
421        }
422
423        /* this is really just a quick hack to keep both the compability mode with all depths and still
424         * allow the custom optimized draw routines with the minimum amount of work */
425        if (0 != bpp_size) {
426                convert();
427        }
428}
429
430#ifndef EXIT_FAILURE
431# define EXIT_FAILURE -1
432#endif
433
434static void allocate_lense(void)
435{
436        int i, j;
437        int s = ((0 != bpp_size) ? (buffer_map->bytes_per_line/bpp_size) : (2*radius+speed+2));
438        /* maybe this should be redone so that from[][][] is in one block;
439         * then pointers could be used instead of arrays in some places (and
440         * maybe give a speedup - maybe also consume less memory)
441         */
442        from = (int ***)malloc(s*sizeof(int **));
443        if (from == NULL) {
444                perror("distort");
445                exit(EXIT_FAILURE);
446        }
447        for (i = 0; i < s; i++) {
448                from[i] = (int **)malloc((2*radius+speed+2) * sizeof(int *));
449                if (from[i] == NULL) {
450                        perror("distort");
451                        exit(EXIT_FAILURE);
452                }
453                for (j = 0; j < s; j++) {
454                        from[i][j] = (int *)malloc(2 * sizeof(int));
455                        if (from[i][j] == NULL) {
456                                perror("distort");
457                                exit(EXIT_FAILURE);
458                        }
459                }
460        }
461}
462
463/* from_array in an array containing precalculated from matrices,
464 * this is a double faced mem vs speed trade, it's faster, but eats
465 * _a lot_ of mem for large radius (is there a bug here? I can't see it)
466 */
467static void init_round_lense(void)
468{
469        int k;
470
471        if (effect == &swamp_thing) {
472                from_array = (int ****)malloc((radius+1)*sizeof(int ***));
473                for (k=0; k <= radius; k++) {
474                        allocate_lense();
475                        make_round_lense(radius, k);
476                        from_array[k] = from;
477                }
478        } else { /* just allocate one from[][][] */
479                allocate_lense();
480                make_round_lense(radius,radius);
481        }
482}
483
484/* If fast_draw_8, fast_draw_16 or fast_draw_32 are to be used, the following properties
485 * of the src and dest XImages must hold (otherwise the generic, slooow, method provided
486 * by X is to be used):
487 *      src->byte_order == dest->byte_order
488 *      src->format == ZPixmap && dest->format == ZPixmap
489 *      src->depth == dest->depth == the depth the function in question asumes
490 * x and y is the coordinates in src from where to cut out the image from,
491 * distort_matrix is a precalculated array of how to distort the matrix
492 */
493
494static void fast_draw_8(XImage *src, XImage *dest, int x, int y, int *distort_matrix) {
495        CARD8 *u = (CARD8 *)dest->data;
496        CARD8 *t = (CARD8 *)src->data + x + y*src->bytes_per_line/sizeof(CARD8);
497
498        while (u < (CARD8 *)(dest->data + sizeof(CARD8)*dest->height
499                                *dest->bytes_per_line/sizeof(CARD8))) {
500                *u++ = t[*distort_matrix++];
501        }
502}
503
504static void fast_draw_16(XImage *src, XImage *dest, int x, int y, int *distort_matrix) {
505        CARD16 *u = (CARD16 *)dest->data;
506        CARD16 *t = (CARD16 *)src->data + x + y*src->bytes_per_line/sizeof(CARD16);
507
508        while (u < (CARD16 *)(dest->data + sizeof(CARD16)*dest->height
509                                *dest->bytes_per_line/sizeof(CARD16))) {
510                *u++ = t[*distort_matrix++];
511        }
512}
513
514static void fast_draw_32(XImage *src, XImage *dest, int x, int y, int *distort_matrix) {
515        CARD32 *u = (CARD32 *)dest->data;
516        CARD32 *t = (CARD32 *)src->data + x + y*src->bytes_per_line/sizeof(CARD32);
517
518        while (u < (CARD32 *)(dest->data + sizeof(CARD32)*dest->height
519                                *dest->bytes_per_line/sizeof(CARD32))) {
520                *u++ = t[*distort_matrix++];
521        }
522}
523
524static void generic_draw(XImage *src, XImage *dest, int x, int y, int *distort_matrix) {
525        int i, j;
526        for (i = 0; i < dest->width; i++)
527                for (j = 0; j < dest->height; j++)
528                        if (from[i][j][0] + x >= 0 &&
529                                        from[i][j][0] + x < src->width &&
530                                        from[i][j][1] + y >= 0 &&
531                                        from[i][j][1] + y < src->height)
532                                XPutPixel(dest, i, j,
533                                                XGetPixel(src,
534                                                        from[i][j][0] + x,
535                                                        from[i][j][1] + y));
536}
537
538/* generate an XImage of from[][][] and draw it on the screen */
539static void plain_draw(int k)
540{
541        if (xy_coo[k].x+2*radius+speed+2 > orig_map->width ||
542                        xy_coo[k].y+2*radius+speed+2 > orig_map->height)
543                return;
544
545        draw_routine(orig_map, buffer_map, xy_coo[k].x, xy_coo[k].y, fast_from);
546
547# ifdef HAVE_XSHM_EXTENSION
548        if (use_shm)
549                XShmPutImage(g_dpy, g_window, gc, buffer_map, 0, 0, xy_coo[k].x, xy_coo[k].y,
550                                2*radius+speed+2, 2*radius+speed+2, False);
551        else
552
553        if (!use_shm)
554# endif
555                XPutImage(g_dpy, g_window, gc, buffer_map, 0, 0, xy_coo[k].x, xy_coo[k].y,
556                                2*radius+speed+2, 2*radius+speed+2);
557
558}
559
560
561/* generate an XImage from the reflect algoritm submitted by
562 * Randy Zack <randy@acucorp.com>
563 * draw really got too big and ugly so I split it up
564 * it should be possible to use the from[][] to speed it up
565 * (once I figure out the algorithm used :)
566 */
567static void reflect_draw(int k)
568{
569        int i, j;
570        int     cx, cy;
571        int     ly, lysq, lx, ny, dist, rsq = radius * radius;
572
573        cx = cy = radius;
574        if (xy_coo[k].ymove > 0)
575                cy += speed;
576        if (xy_coo[k].xmove > 0)
577                cx += speed;
578
579        for(i = 0 ; i < 2*radius+speed+2; i++) {
580                ly = i - cy;
581                lysq = ly * ly;
582                ny = xy_coo[k].y + i;
583                if (ny >= orig_map->height) ny = orig_map->height-1;
584                for(j = 0 ; j < 2*radius+speed+2 ; j++) {
585                        lx = j - cx;
586                        dist = lx * lx + lysq;
587                        if (dist > rsq ||
588                                ly < -radius || ly > radius ||
589                                lx < -radius || lx > radius)
590                                XPutPixel( buffer_map, j, i,
591                                                   XGetPixel( orig_map, xy_coo[k].x + j, ny ));
592                        else if (dist == 0)
593                                XPutPixel( buffer_map, j, i, black_pixel );
594                        else {
595                                int     x = xy_coo[k].x + cx + (lx * rsq / dist);
596                                int     y = xy_coo[k].y + cy + (ly * rsq / dist);
597                                if (x < 0 || x >= xgwa.width ||
598                                        y < 0 || y >= xgwa.height)
599                                        XPutPixel( buffer_map, j, i, black_pixel );
600                                else
601                                        XPutPixel( buffer_map, j, i,
602                                                           XGetPixel( orig_map, x, y ));
603                        }
604                }
605        }
606
607        XPutImage(g_dpy, g_window, gc, buffer_map, 0, 0, xy_coo[k].x, xy_coo[k].y,
608                        2*radius+speed+2, 2*radius+speed+2);
609}
610
611/* create a new, random coordinate, that won't interfer with any other
612 * coordinates, as the drawing routines would be significantly slowed
613 * down if they were to handle serveral layers of distortions
614 */
615static void new_rnd_coo(int k)
616{
617        int i;
618
619        xy_coo[k].x = (random() % (xgwa.width-2*radius));
620        xy_coo[k].y = (random() % (xgwa.height-2*radius));
621       
622        for (i = 0; i < number; i++) {
623                if (i != k) {
624                        if ((abs(xy_coo[k].x - xy_coo[i].x) <= 2*radius+speed+2)
625                         && (abs(xy_coo[k].y - xy_coo[i].y) <= 2*radius+speed+2)) {
626                                xy_coo[k].x = (random() % (xgwa.width-2*radius));
627                                xy_coo[k].y = (random() % (xgwa.height-2*radius));
628                                i=-1; /* ugly */
629                        }
630                }
631        }
632}
633
634/* move lens and handle bounces with walls and other lenses */
635static void move_lense(int k)
636{
637        int i;
638
639        if (xy_coo[k].x + 2*radius + speed + 2 >= xgwa.width)
640                xy_coo[k].xmove = -abs(xy_coo[k].xmove);
641        if (xy_coo[k].x <= speed)
642                xy_coo[k].xmove = abs(xy_coo[k].xmove);
643        if (xy_coo[k].y + 2*radius + speed + 2 >= xgwa.height)
644                xy_coo[k].ymove = -abs(xy_coo[k].ymove);
645        if (xy_coo[k].y <= speed)
646                xy_coo[k].ymove = abs(xy_coo[k].ymove);
647
648        xy_coo[k].x = xy_coo[k].x + xy_coo[k].xmove;
649        xy_coo[k].y = xy_coo[k].y + xy_coo[k].ymove;
650
651        /* bounce against othe lenses */
652        for (i = 0; i < number; i++) {
653                if ((i != k)
654               
655/* This commented test is for rectangular lenses (not currently used) and
656 * the one used is for circular ones
657                && (abs(xy_coo[k].x - xy_coo[i].x) <= 2*radius)
658                && (abs(xy_coo[k].y - xy_coo[i].y) <= 2*radius)) { */
659
660                && ((xy_coo[k].x - xy_coo[i].x)*(xy_coo[k].x - xy_coo[i].x)
661                  + (xy_coo[k].y - xy_coo[i].y)*(xy_coo[k].y - xy_coo[i].y)
662                        <= 2*radius*2*radius)) {
663
664                        int x, y;
665                        x = xy_coo[k].xmove;
666                        y = xy_coo[k].ymove;
667                        xy_coo[k].xmove = xy_coo[i].xmove;
668                        xy_coo[k].ymove = xy_coo[i].ymove;
669                        xy_coo[i].xmove = x;
670                        xy_coo[i].ymove = y;
671                }
672        }
673
674}
675
676/* make xy_coo[k] grow/shrink */
677static void swamp_thing(int k)
678{
679        if (xy_coo[k].r >= radius)
680                xy_coo[k].r_change = -abs(xy_coo[k].r_change);
681       
682        if (xy_coo[k].r <= 0) {
683                from = from_array[0];
684                draw(k);
685                xy_coo[k].r_change = abs(xy_coo[k].r_change);
686                new_rnd_coo(k);
687                xy_coo[k].r=xy_coo[k].r_change;
688                return;
689        }
690
691        xy_coo[k].r = xy_coo[k].r + xy_coo[k].r_change;
692
693        if (xy_coo[k].r >= radius)
694                xy_coo[k].r = radius;
695        if (xy_coo[k].r <= 0)
696                xy_coo[k].r=0;
697
698        from = from_array[xy_coo[k].r];
699}
700
701
702
703
704char *progclass = "Distort";
705
706char *defaults [] = {
707        "*dontClearRoot:                True",
708#ifdef __sgi    /* really, HAVE_READ_DISPLAY_EXTENSION */
709        "*visualID:                     Best",
710#endif
711
712        "*delay:                        1000",
713        "*radius:                       0",
714        "*speed:                        0",
715        "*number:                       0",
716        "*vortex:                       False",
717        "*magnify:                      False",
718        "*swamp:                        False",
719        "*bounce:                       False",
720        "*reflect:                      False",
721        "*blackhole:            False",
722#ifdef HAVE_XSHM_EXTENSION
723        "*useSHM:                       False",         /* xshm turns out not to help. */
724#endif /* HAVE_XSHM_EXTENSION */
725        0
726};
727
728XrmOptionDescRec options [] = {
729        { "-delay",     ".delay",       XrmoptionSepArg, 0 },
730        { "-radius",    ".radius",      XrmoptionSepArg, 0 },
731        { "-speed",     ".speed",       XrmoptionSepArg, 0 },
732        { "-number",    ".number",      XrmoptionSepArg, 0 },
733        { "-swamp",     ".swamp",       XrmoptionNoArg, "True" },
734        { "-bounce",    ".bounce",      XrmoptionNoArg, "True" },
735        { "-reflect",   ".reflect",     XrmoptionNoArg, "True" },
736        { "-vortex",    ".vortex",      XrmoptionNoArg, "True" },
737        { "-magnify",   ".magnify",     XrmoptionNoArg, "True" },
738        { "-blackhole", ".blackhole",   XrmoptionNoArg, "True" },
739        { "-slow",      ".slow",        XrmoptionNoArg, "True" },
740#ifdef HAVE_XSHM_EXTENSION
741        { "-shm",               ".useSHM",      XrmoptionNoArg, "True" },
742        { "-no-shm",    ".useSHM",      XrmoptionNoArg, "False" },
743#endif /* HAVE_XSHM_EXTENSION */
744        { 0, 0, 0, 0 }
745};
746
747
748void screenhack(Display *dpy, Window window)
749{
750        int k;
751
752        init_distort (dpy, window);
753        while (1) {
754                for (k = 0; k < number; k++) {
755                        effect(k);
756                        draw(k);
757                }
758
759                XSync(dpy, False);
760        screenhack_handle_events (dpy);
761                if (delay) usleep(delay);
762        }
763
764}
Note: See TracBrowser for help on using the repository browser.