1 /* -*- mode: C; tab-width: 4 -*-
2 * xscreensaver, Copyright (c) 1992-2014 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
14 * by Jonas Munsin (jmunsin@iki.fi) and Jamie Zawinski <jwz@jwz.org>
16 * -check the allocations in init_round_lense again, maybe make it possible again
17 * to use swamp without pre-allocating/calculating (although that
18 * makes it slower) - -swamp is memory hungry
19 * -more distortion matrices (fortunately, I'm out of ideas :)
20 * Stuff that would be cool but probably too much of a resource hog:
21 * -some kind of interpolation to avoid jaggies
22 * -large speed values leaves the image distorted
23 * program idea borrowed from a screensaver on a non-*NIX OS,
25 * 28 Sep 1999 Jonas Munsin (jmunsin@iki.fi)
26 * Added about 10x faster algortim for 8, 16 and 32 bpp (modifies pixels
27 * directly avoiding costly XPutPixle(XGetPixel()) calls, inspired by
28 * xwhirl made by horvai@clipper.ens.fr (Peter Horvai) and the XFree86
30 * This piece of code is really horrible, but it works, and at the moment
31 * I don't have time or inspiration to fix something that works (knock
33 * 08 Oct 1999 Jonas Munsin (jmunsin@iki.fi)
34 * Corrected several bugs causing references beyond allocated memory.
39 #include "screenhack.h"
40 /*#include <X11/Xmd.h>*/
42 #ifdef HAVE_XSHM_EXTENSION
44 #endif /* HAVE_XSHM_EXTENSION */
46 #define CARD32 unsigned int
47 #define CARD16 unsigned short
48 #define CARD8 unsigned char
62 struct coo xy_coo[10];
64 int delay, radius, speed, number, blackhole, vortex, magnify, reflect, slow;
68 XWindowAttributes xgwa;
70 unsigned long black_pixel;
72 XImage *orig_map, *buffer_map;
73 unsigned long *buffer_map_cache;
81 #ifdef HAVE_XSHM_EXTENSION
83 XShmSegmentInfo shm_info;
84 #endif /* HAVE_XSHM_EXTENSION */
86 void (*effect) (struct state *, int);
87 void (*draw) (struct state *, int);
88 void (*draw_routine) (struct state *st, XImage *, XImage *, int, int, int *);
90 async_load_state *img_loader;
95 static void move_lense(struct state *, int);
96 static void swamp_thing(struct state *, int);
97 static void new_rnd_coo(struct state *, int);
98 static void init_round_lense(struct state *st);
99 static void reflect_draw(struct state *, int);
100 static void plain_draw(struct state *, int);
102 static void fast_draw_8 (struct state *st, XImage *, XImage *, int, int, int *);
103 static void fast_draw_16(struct state *st, XImage *, XImage *, int, int, int *);
104 static void fast_draw_32(struct state *st, XImage *, XImage *, int, int, int *);
105 static void generic_draw(struct state *st, XImage *, XImage *, int, int, int *);
108 static void distort_finish_loading (struct state *);
111 distort_reset (struct state *st)
118 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
120 st->delay = get_integer_resource(st->dpy, "delay", "Integer");
121 st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
122 st->radius = get_integer_resource(st->dpy, "radius", "Integer");
123 st->speed = get_integer_resource(st->dpy, "speed", "Integer");
124 st->number = get_integer_resource(st->dpy, "number", "Integer");
126 st->blackhole = get_boolean_resource(st->dpy, "blackhole", "Boolean");
127 st->vortex = get_boolean_resource(st->dpy, "vortex", "Boolean");
128 st->magnify = get_boolean_resource(st->dpy, "magnify", "Boolean");
129 st->reflect = get_boolean_resource(st->dpy, "reflect", "Boolean");
130 st->slow = get_boolean_resource(st->dpy, "slow", "Boolean");
132 if (st->delay < 0) st->delay = 0;
133 if (st->duration < 1) st->duration = 1;
136 s = get_string_resource(st->dpy, "effect", "String");
137 if (s && !strcasecmp(s,"swamp"))
138 st->effect = &swamp_thing;
139 else if (s && !strcasecmp(s,"bounce"))
140 st->effect = &move_lense;
141 else if (s && !strcasecmp(s,"none"))
144 fprintf(stderr,"%s: bogus effect: %s\n", progname, s);
146 if (st->effect == NULL && st->radius == 0 && st->speed == 0 && st->number == 0
147 && !st->blackhole && !st->vortex && !st->magnify && !st->reflect) {
148 /* if no cmdline options are given, randomly choose one of:
149 * -radius 125 -number 4 -speed 1 -bounce
150 * -radius 125 -number 4 -speed 1 -blackhole
151 * -radius 125 -number 4 -speed 1 -vortex
152 * -radius 125 -number 4 -speed 1 -vortex -magnify
153 * -radius 125 -number 4 -speed 1 -vortex -magnify -blackhole
154 * -radius 250 -number 1 -speed 2 -bounce
155 * -radius 250 -number 1 -speed 2 -blackhole
156 * -radius 250 -number 1 -speed 2 -vortex
157 * -radius 250 -number 1 -speed 2 -vortex -magnify
158 * -radius 250 -number 1 -speed 2 -vortex -magnify -blackhole
159 * -radius 80 -number 1 -speed 2 -reflect
160 * -radius 125 -number 3 -speed 2 -reflect
162 * -radius 125 -number 4 -speed 2 -swamp
163 * -radius 125 -number 4 -speed 2 -swamp -blackhole
164 * -radius 125 -number 4 -speed 2 -swamp -vortex
165 * -radius 125 -number 4 -speed 2 -swamp -vortex -magnify
166 * -radius 125 -number 4 -speed 2 -swamp -vortex -magnify -blackhole
169 i = (random() % 12 /* 17 */);
171 st->draw = &plain_draw;
175 st->radius=125;st->number=4;st->speed=1;
176 st->effect=&move_lense;break;
178 st->radius=125;st->number=4;st->speed=1;st->blackhole=1;
179 st->effect=&move_lense;break;
181 st->radius=125;st->number=4;st->speed=1;st->vortex=1;
182 st->effect=&move_lense;break;
184 st->radius=125;st->number=4;st->speed=1;st->vortex=1;st->magnify=1;
185 st->effect=&move_lense;break;
187 st->radius=125;st->number=4;st->speed=1;st->vortex=1;st->magnify=1;st->blackhole=1;
188 st->effect=&move_lense;break;
190 st->radius=250;st->number=1;st->speed=2;
191 st->effect=&move_lense;break;
193 st->radius=250;st->number=1;st->speed=2;st->blackhole=1;
194 st->effect=&move_lense;break;
196 st->radius=250;st->number=1;st->speed=2;st->vortex=1;
197 st->effect=&move_lense;break;
199 st->radius=250;st->number=1;st->speed=2;st->vortex=1;st->magnify=1;
200 st->effect=&move_lense;break;
202 st->radius=250;st->number=1;st->speed=2;st->vortex=1;st->magnify=1;st->blackhole=1;
203 st->effect=&move_lense;break;
206 st->radius=80;st->number=1;st->speed=2;st->reflect=1;
207 st->draw = &reflect_draw;st->effect = &move_lense;break;
209 st->radius=125;st->number=4;st->speed=2;st->reflect=1;
210 st->draw = &reflect_draw;st->effect = &move_lense;break;
212 #if 0 /* jwz: not these */
214 st->radius=125;st->number=4;st->speed=2;
215 effect=&swamp_thing;break;
217 st->radius=125;st->number=4;st->speed=2;st->blackhole=1;
218 effect=&swamp_thing;break;
220 st->radius=125;st->number=4;st->speed=2;st->vortex=1;
221 effect=&swamp_thing;break;
223 st->radius=125;st->number=4;st->speed=2;st->vortex=1;st->magnify=1;
224 effect=&swamp_thing;break;
226 st->radius=125;st->number=4;st->speed=2;st->vortex=1;st->magnify=1;st->blackhole=1;
227 effect=&swamp_thing;break;
235 /* never allow the radius to be too close to the min window dimension
237 if (st->radius > st->xgwa.width * 0.3) st->radius = st->xgwa.width * 0.3;
238 if (st->radius > st->xgwa.height * 0.3) st->radius = st->xgwa.height * 0.3;
241 /* -swamp mode consumes vast amounts of memory, proportional to radius --
242 so throttle radius to a small-ish value (60 => ~30MB.)
244 if (st->effect == &swamp_thing && st->radius > 60)
255 if (st->number >= 10)
257 if (st->effect == NULL)
258 st->effect = &move_lense;
260 st->draw = &reflect_draw;
261 st->effect = &move_lense;
263 if (st->draw == NULL)
264 st->draw = &plain_draw;
268 distort_init (Display *dpy, Window window)
270 struct state *st = (struct state *) calloc (1, sizeof(*st));
277 #ifdef HAVE_XSHM_EXTENSION
278 st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean");
279 #endif /* HAVE_XSHM_EXTENSION */
283 st->black_pixel = BlackPixelOfScreen( st->xgwa.screen );
285 gcv.function = GXcopy;
286 gcv.subwindow_mode = IncludeInferiors;
287 gcflags = GCFunction;
288 if (use_subwindow_mode_p(st->xgwa.screen, st->window)) /* see grabscreen.c */
289 gcflags |= GCSubwindowMode;
290 st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv);
292 /* On MacOS X11, XGetImage on a Window often gets an inexplicable BadMatch,
293 possibly due to the window manager having occluded something? It seems
294 nondeterministic. Loading the image into a pixmap instead fixes it. */
295 if (st->pm) XFreePixmap (st->dpy, st->pm);
296 st->pm = XCreatePixmap (st->dpy, st->window,
297 st->xgwa.width, st->xgwa.height, st->xgwa.depth);
299 st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window,
301 st->start_time = time ((time_t *) 0);
306 distort_finish_loading (struct state *st)
310 st->start_time = time ((time_t *) 0);
313 if (! st->pm) abort();
314 XClearWindow (st->dpy, st->window);
315 XCopyArea (st->dpy, st->pm, st->window, st->gc,
316 0, 0, st->xgwa.width, st->xgwa.height, 0, 0);
317 st->orig_map = XGetImage(st->dpy, st->pm, 0, 0,
318 st->xgwa.width, st->xgwa.height,
320 st->buffer_map_cache = malloc(sizeof(unsigned long)*(2*st->radius+st->speed+2)*(2*st->radius+st->speed+2));
322 if (st->buffer_map_cache == NULL) {
327 # ifdef HAVE_XSHM_EXTENSION
331 st->buffer_map = create_xshm_image(st->dpy, st->xgwa.visual, st->orig_map->depth,
332 ZPixmap, 0, &st->shm_info,
333 2*st->radius + st->speed + 2,
334 2*st->radius + st->speed + 2);
338 # endif /* HAVE_XSHM_EXTENSION */
342 st->buffer_map = XCreateImage(st->dpy, st->xgwa.visual,
343 st->orig_map->depth, ZPixmap, 0, 0,
344 2*st->radius + st->speed + 2, 2*st->radius + st->speed + 2,
346 st->buffer_map->data = (char *)
347 calloc(st->buffer_map->height, st->buffer_map->bytes_per_line);
350 if ((st->buffer_map->byte_order == st->orig_map->byte_order)
351 && (st->buffer_map->depth == st->orig_map->depth)
352 && (st->buffer_map->format == ZPixmap)
353 && (st->orig_map->format == ZPixmap)
355 switch (st->orig_map->bits_per_pixel) {
357 st->draw_routine = &fast_draw_32;
358 st->bpp_size = sizeof(CARD32);
361 st->draw_routine = &fast_draw_16;
362 st->bpp_size = sizeof(CARD16);
365 st->draw_routine = &fast_draw_8;
366 st->bpp_size = sizeof(CARD8);
369 st->draw_routine = &generic_draw;
373 st->draw_routine = &generic_draw;
375 init_round_lense(st);
377 for (i = 0; i < st->number; i++) {
380 st->xy_coo[i].r = (i*st->radius)/(st->number-1); /* "randomize" initial */
383 st->xy_coo[i].r_change = st->speed + (i%2)*2*(-st->speed); /* values a bit */
384 st->xy_coo[i].xmove = st->speed + (i%2)*2*(-st->speed);
385 st->xy_coo[i].ymove = st->speed + (i%2)*2*(-st->speed);
389 /* example: initializes a "see-trough" matrix */
390 /* static void make_null_lense(struct state *st)
393 for (i = 0; i < 2*radius+speed+2; i++) {
394 for (j = 0 ; j < 2*radius+speed+2 ; j++) {
401 static void convert(struct state *st)
405 st->fast_from = calloc(1, sizeof(int)*((st->buffer_map->bytes_per_line/st->bpp_size)*(2*st->radius+st->speed+2) + 2*st->radius+st->speed+2));
406 if (st->fast_from == NULL) {
411 for (i = 0; i < 2*st->radius+st->speed+2; i++) {
412 for (j = 0; j < 2*st->radius+st->speed+2; j++) {
413 *(p + i + j*st->buffer_map->bytes_per_line/st->bpp_size)
414 = st->from[i][j][0] + st->xgwa.width*st->from[i][j][1];
415 if (*(p + i + j*st->buffer_map->bytes_per_line/st->bpp_size) < 0
416 || *(p + i + j*st->buffer_map->bytes_per_line/st->bpp_size) >= st->orig_map->height*st->orig_map->width) {
417 *(p + i + j*st->buffer_map->bytes_per_line/st->bpp_size) = 0;
423 /* makes a lense with the Radius=loop and centred in
424 * the point (radius, radius)
426 static void make_round_lense(struct state *st, int radius, int loop)
430 for (i = 0; i < 2*radius+st->speed+2; i++) {
431 for(j = 0; j < ((0 == st->bpp_size) ? (2*radius+st->speed+2) : (st->buffer_map->bytes_per_line/st->bpp_size)); j++) {
433 r = sqrt ((i-radius)*(i-radius)+(j-radius)*(j-radius));
441 if (st->vortex) { /* vortex-twist effect */
443 /* this one-line formula for getting a nice rotation angle is borrowed
444 * (with permission) from the whirl plugin for gimp,
445 * Copyright (C) 1996 Federico Mena Quintero
447 /* 5 is just a constant used because it looks good :) */
448 angle = 5*(1-d)*(1-d);
450 /* Avoid atan2: DOMAIN error message */
451 if ((radius-j) == 0.0 && (radius-i) == 0.0) {
452 st->from[i][j][0] = radius + cos(angle)*r;
453 st->from[i][j][1] = radius + sin(angle)*r;
455 st->from[i][j][0] = radius +
456 cos(angle - atan2(radius-j, -(radius-i)))*r;
457 st->from[i][j][1] = radius +
458 sin(angle - atan2(radius-j, -(radius-i)))*r;
462 if (st->blackhole && r != 0) /* blackhole effect */
464 st->from[i][j][0] = radius + (st->from[i][j][0]-radius)*r;
465 st->from[i][j][1] = radius + (st->from[i][j][1]-radius)*r;
467 } else { /* default is to magnify */
470 /* raising r to different power here gives different amounts of
471 * distortion, a negative value sucks everything into a black hole
474 if (st->blackhole && r != 0) /* blackhole effect */
476 /* bubble effect (and blackhole) */
477 st->from[i][j][0] = radius + (i-radius)*r;
478 st->from[i][j][1] = radius + (j-radius)*r;
480 } else { /* not inside loop */
481 st->from[i][j][0] = i;
482 st->from[i][j][1] = j;
487 /* this is really just a quick hack to keep both the compability mode with all depths and still
488 * allow the custom optimized draw routines with the minimum amount of work */
489 if (0 != st->bpp_size) {
495 # define EXIT_FAILURE -1
498 static void allocate_lense(struct state *st)
501 int s = ((0 != st->bpp_size) ? (st->buffer_map->bytes_per_line/st->bpp_size) : (2*st->radius+st->speed+2));
502 /* maybe this should be redone so that from[][][] is in one block;
503 * then pointers could be used instead of arrays in some places (and
504 * maybe give a speedup - maybe also consume less memory)
506 st->from = (int ***)malloc(s*sizeof(int **));
507 if (st->from == NULL) {
511 for (i = 0; i < s; i++) {
512 st->from[i] = (int **)malloc((2*st->radius+st->speed+2) * sizeof(int *));
513 if (st->from[i] == NULL) {
517 for (j = 0; j < s; j++) {
518 st->from[i][j] = (int *)malloc(2 * sizeof(int));
519 if (st->from[i][j] == NULL) {
527 /* from_array in an array containing precalculated from matrices,
528 * this is a double faced mem vs speed trade, it's faster, but eats
529 * _a lot_ of mem for large radius (is there a bug here? I can't see it)
531 static void init_round_lense(struct state *st)
535 if (st->effect == &swamp_thing) {
536 st->from_array = (int ****)malloc((st->radius+1)*sizeof(int ***));
537 for (k=0; k <= st->radius; k++) {
539 make_round_lense(st, st->radius, k);
540 st->from_array[k] = st->from;
542 } else { /* just allocate one from[][][] */
544 make_round_lense(st, st->radius,st->radius);
548 /* If fast_draw_8, fast_draw_16 or fast_draw_32 are to be used, the following properties
549 * of the src and dest XImages must hold (otherwise the generic, slooow, method provided
550 * by X is to be used):
551 * src->byte_order == dest->byte_order
552 * src->format == ZPixmap && dest->format == ZPixmap
553 * src->depth == dest->depth == the depth the function in question asumes
554 * x and y is the coordinates in src from where to cut out the image from,
555 * distort_matrix is a precalculated array of how to distort the matrix
558 static void fast_draw_8(struct state *st, XImage *src, XImage *dest, int x, int y, int *distort_matrix)
560 CARD8 *u = (CARD8 *)dest->data;
561 CARD8 *t = (CARD8 *)src->data + x + y*src->bytes_per_line/sizeof(CARD8);
563 while (u < (CARD8 *)(dest->data + sizeof(CARD8)*dest->height
564 *dest->bytes_per_line/sizeof(CARD8))) {
565 *u++ = t[*distort_matrix++];
569 static void fast_draw_16(struct state *st, XImage *src, XImage *dest, int x, int y, int *distort_matrix)
571 CARD16 *u = (CARD16 *)dest->data;
572 CARD16 *t = (CARD16 *)src->data + x + y*src->bytes_per_line/sizeof(CARD16);
574 while (u < (CARD16 *)(dest->data + sizeof(CARD16)*dest->height
575 *dest->bytes_per_line/sizeof(CARD16))) {
576 *u++ = t[*distort_matrix++];
580 static void fast_draw_32(struct state *st, XImage *src, XImage *dest, int x, int y, int *distort_matrix)
582 CARD32 *u = (CARD32 *)dest->data;
583 CARD32 *t = (CARD32 *)src->data + x + y*src->bytes_per_line/sizeof(CARD32);
585 while (u < (CARD32 *)(dest->data + sizeof(CARD32)*dest->height
586 *dest->bytes_per_line/sizeof(CARD32))) {
587 *u++ = t[*distort_matrix++];
591 static void generic_draw(struct state *st, XImage *src, XImage *dest, int x, int y, int *distort_matrix)
594 for (i = 0; i < dest->width; i++)
595 for (j = 0; j < dest->height; j++)
596 if (st->from[i][j][0] + x >= 0 &&
597 st->from[i][j][0] + x < src->width &&
598 st->from[i][j][1] + y >= 0 &&
599 st->from[i][j][1] + y < src->height)
600 XPutPixel(dest, i, j,
602 st->from[i][j][0] + x,
603 st->from[i][j][1] + y));
606 /* generate an XImage of from[][][] and draw it on the screen */
607 static void plain_draw(struct state *st, int k)
609 if (st->xy_coo[k].x+2*st->radius+st->speed+2 > st->orig_map->width ||
610 st->xy_coo[k].y+2*st->radius+st->speed+2 > st->orig_map->height)
613 st->draw_routine(st, st->orig_map, st->buffer_map, st->xy_coo[k].x, st->xy_coo[k].y, st->fast_from);
615 # ifdef HAVE_XSHM_EXTENSION
617 XShmPutImage(st->dpy, st->window, st->gc, st->buffer_map, 0, 0, st->xy_coo[k].x, st->xy_coo[k].y,
618 2*st->radius+st->speed+2, 2*st->radius+st->speed+2, False);
623 XPutImage(st->dpy, st->window, st->gc, st->buffer_map, 0, 0, st->xy_coo[k].x, st->xy_coo[k].y,
624 2*st->radius+st->speed+2, 2*st->radius+st->speed+2);
629 /* generate an XImage from the reflect algoritm submitted by
630 * Randy Zack <randy@acucorp.com>
631 * draw really got too big and ugly so I split it up
632 * it should be possible to use the from[][] to speed it up
633 * (once I figure out the algorithm used :)
635 static void reflect_draw(struct state *st, int k)
639 int ly, lysq, lx, ny, dist, rsq = st->radius * st->radius;
641 cx = cy = st->radius;
642 if (st->xy_coo[k].ymove > 0)
644 if (st->xy_coo[k].xmove > 0)
647 for(i = 0 ; i < 2*st->radius+st->speed+2; i++) {
650 ny = st->xy_coo[k].y + i;
651 if (ny >= st->orig_map->height) ny = st->orig_map->height-1;
652 for(j = 0 ; j < 2*st->radius+st->speed+2 ; j++) {
654 dist = lx * lx + lysq;
656 ly < -st->radius || ly > st->radius ||
657 lx < -st->radius || lx > st->radius)
658 XPutPixel( st->buffer_map, j, i,
659 XGetPixel( st->orig_map, st->xy_coo[k].x + j, ny ));
661 XPutPixel( st->buffer_map, j, i, st->black_pixel );
663 int x = st->xy_coo[k].x + cx + (lx * rsq / dist);
664 int y = st->xy_coo[k].y + cy + (ly * rsq / dist);
665 if (x < 0 || x >= st->xgwa.width ||
666 y < 0 || y >= st->xgwa.height)
667 XPutPixel( st->buffer_map, j, i, st->black_pixel );
669 XPutPixel( st->buffer_map, j, i,
670 XGetPixel( st->orig_map, x, y ));
675 XPutImage(st->dpy, st->window, st->gc, st->buffer_map, 0, 0, st->xy_coo[k].x, st->xy_coo[k].y,
676 2*st->radius+st->speed+2, 2*st->radius+st->speed+2);
679 /* create a new, random coordinate, that won't interfer with any other
680 * coordinates, as the drawing routines would be significantly slowed
681 * down if they were to handle serveral layers of distortions
683 static void new_rnd_coo(struct state *st, int k)
688 st->xy_coo[k].x = (random() % (st->xgwa.width-2*st->radius));
689 st->xy_coo[k].y = (random() % (st->xgwa.height-2*st->radius));
691 for (i = 0; i < st->number; i++) {
693 if ((abs(st->xy_coo[k].x - st->xy_coo[i].x) <= 2*st->radius+st->speed+2)
694 && (abs(st->xy_coo[k].y - st->xy_coo[i].y) <= 2*st->radius+st->speed+2)) {
695 st->xy_coo[k].x = (random() % (st->xgwa.width-2*st->radius));
696 st->xy_coo[k].y = (random() % (st->xgwa.height-2*st->radius));
700 if (loop++ > 1000) return; /* let's not get stuck */
704 /* move lens and handle bounces with walls and other lenses */
705 static void move_lense(struct state *st, int k)
709 if (st->xy_coo[k].x + 2*st->radius + st->speed + 2 >= st->xgwa.width)
710 st->xy_coo[k].xmove = -abs(st->xy_coo[k].xmove);
711 if (st->xy_coo[k].x <= st->speed)
712 st->xy_coo[k].xmove = abs(st->xy_coo[k].xmove);
713 if (st->xy_coo[k].y + 2*st->radius + st->speed + 2 >= st->xgwa.height)
714 st->xy_coo[k].ymove = -abs(st->xy_coo[k].ymove);
715 if (st->xy_coo[k].y <= st->speed)
716 st->xy_coo[k].ymove = abs(st->xy_coo[k].ymove);
718 st->xy_coo[k].x = st->xy_coo[k].x + st->xy_coo[k].xmove;
719 st->xy_coo[k].y = st->xy_coo[k].y + st->xy_coo[k].ymove;
721 /* bounce against othe lenses */
722 for (i = 0; i < st->number; i++) {
725 /* This commented test is for rectangular lenses (not currently used) and
726 * the one used is for circular ones
727 && (abs(xy_coo[k].x - xy_coo[i].x) <= 2*radius)
728 && (abs(xy_coo[k].y - xy_coo[i].y) <= 2*radius)) { */
730 && ((st->xy_coo[k].x - st->xy_coo[i].x)*(st->xy_coo[k].x - st->xy_coo[i].x)
731 + (st->xy_coo[k].y - st->xy_coo[i].y)*(st->xy_coo[k].y - st->xy_coo[i].y)
732 <= 2*st->radius*2*st->radius)) {
735 x = st->xy_coo[k].xmove;
736 y = st->xy_coo[k].ymove;
737 st->xy_coo[k].xmove = st->xy_coo[i].xmove;
738 st->xy_coo[k].ymove = st->xy_coo[i].ymove;
739 st->xy_coo[i].xmove = x;
740 st->xy_coo[i].ymove = y;
746 /* make xy_coo[k] grow/shrink */
747 static void swamp_thing(struct state *st, int k)
749 if (st->xy_coo[k].r >= st->radius)
750 st->xy_coo[k].r_change = -abs(st->xy_coo[k].r_change);
752 if (st->xy_coo[k].r <= 0) {
753 st->from = st->from_array[0];
755 st->xy_coo[k].r_change = abs(st->xy_coo[k].r_change);
757 st->xy_coo[k].r=st->xy_coo[k].r_change;
761 st->xy_coo[k].r = st->xy_coo[k].r + st->xy_coo[k].r_change;
763 if (st->xy_coo[k].r >= st->radius)
764 st->xy_coo[k].r = st->radius;
765 if (st->xy_coo[k].r <= 0)
768 st->from = st->from_array[st->xy_coo[k].r];
773 distort_draw (Display *dpy, Window window, void *closure)
775 struct state *st = (struct state *) closure;
778 if (st->img_loader) /* still loading */
780 st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
781 if (! st->img_loader) { /* just finished */
782 distort_finish_loading (st);
787 if (!st->img_loader &&
788 st->start_time + st->duration < time ((time_t *) 0)) {
789 if (st->pm) XFreePixmap (st->dpy, st->pm);
790 st->pm = XCreatePixmap (st->dpy, st->window,
791 st->xgwa.width, st->xgwa.height, st->xgwa.depth);
792 st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window,
797 for (k = 0; k < st->number; k++) {
805 distort_reshape (Display *dpy, Window window, void *closure,
806 unsigned int w, unsigned int h)
808 struct state *st = (struct state *) closure;
809 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
810 /* XClearWindow (dpy, window); */
811 /* Why doesn't this work? */
812 if (st->orig_map) /* created in distort_finish_loading, might be early */
813 XPutImage (st->dpy, st->window, st->gc, st->orig_map,
814 0, 0, st->orig_map->width, st->orig_map->height, 0, 0);
818 distort_event (Display *dpy, Window window, void *closure, XEvent *event)
820 struct state *st = (struct state *) closure;
821 if (screenhack_event_helper (dpy, window, event))
830 distort_free (Display *dpy, Window window, void *closure)
832 struct state *st = (struct state *) closure;
833 XFreeGC (st->dpy, st->gc);
834 if (st->pm) XFreePixmap (dpy, st->pm);
835 if (st->orig_map) XDestroyImage (st->orig_map);
836 if (st->buffer_map) XDestroyImage (st->buffer_map);
837 if (st->from) free (st->from);
838 if (st->fast_from) free (st->fast_from);
839 if (st->from_array) free (st->from_array);
846 static const char *distort_defaults [] = {
847 "*dontClearRoot: True",
848 "*background: Black",
850 #ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
865 #ifdef HAVE_XSHM_EXTENSION
866 "*useSHM: False", /* xshm turns out not to help. */
867 #endif /* HAVE_XSHM_EXTENSION */
869 "*ignoreRotation: True",
870 "*rotateImages: True",
875 static XrmOptionDescRec distort_options [] = {
876 { "-delay", ".delay", XrmoptionSepArg, 0 },
877 { "-duration", ".duration", XrmoptionSepArg, 0 },
878 { "-radius", ".radius", XrmoptionSepArg, 0 },
879 { "-speed", ".speed", XrmoptionSepArg, 0 },
880 { "-number", ".number", XrmoptionSepArg, 0 },
882 { "-effect", ".effect", XrmoptionSepArg, 0 },
883 { "-swamp", ".effect", XrmoptionNoArg, "swamp" },
884 { "-bounce", ".effect", XrmoptionNoArg, "bounce" },
886 { "-reflect", ".reflect", XrmoptionNoArg, "True" },
887 { "-vortex", ".vortex", XrmoptionNoArg, "True" },
888 { "-magnify", ".magnify", XrmoptionNoArg, "True" },
889 { "-blackhole", ".blackhole", XrmoptionNoArg, "True" },
890 { "-slow", ".slow", XrmoptionNoArg, "True" },
891 #ifdef HAVE_XSHM_EXTENSION
892 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
893 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
894 #endif /* HAVE_XSHM_EXTENSION */
898 XSCREENSAVER_MODULE ("Distort", distort)