/* -*- mode: C; tab-width: 4 -*-
- * xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997, 1998
- * Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1992-2013 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* -more distortion matrices (fortunately, I'm out of ideas :)
* Stuff that would be cool but probably too much of a resource hog:
* -some kind of interpolation to avoid jaggies
+ * -large speed values leaves the image distorted
* program idea borrowed from a screensaver on a non-*NIX OS,
+ *
+ * 28 Sep 1999 Jonas Munsin (jmunsin@iki.fi)
+ * Added about 10x faster algortim for 8, 16 and 32 bpp (modifies pixels
+ * directly avoiding costly XPutPixle(XGetPixel()) calls, inspired by
+ * xwhirl made by horvai@clipper.ens.fr (Peter Horvai) and the XFree86
+ * Xlib sources.
+ * This piece of code is really horrible, but it works, and at the moment
+ * I don't have time or inspiration to fix something that works (knock
+ * on wood).
+ * 08 Oct 1999 Jonas Munsin (jmunsin@iki.fi)
+ * Corrected several bugs causing references beyond allocated memory.
*/
#include <math.h>
#include "screenhack.h"
-#include <X11/Xutil.h>
+/*#include <X11/Xmd.h>*/
#ifdef HAVE_XSHM_EXTENSION
# include "xshm.h"
-static Bool use_shm;
-static XShmSegmentInfo shm_info;
#endif /* HAVE_XSHM_EXTENSION */
+#define CARD32 unsigned int
+#define CARD16 unsigned short
+#define CARD8 unsigned char
+
+
struct coo {
int x;
int y;
int r, r_change;
int xmove, ymove;
};
-static struct coo xy_coo[10];
-
-static int delay, radius, speed, number, blackhole, vortex, magnify, reflect;
-static XWindowAttributes xgwa;
-static GC gc;
-static Window g_window;
-static Display *g_dpy;
-static unsigned long black_pixel;
-
-static XImage *orig_map, *buffer_map;
-
-static int ***from;
-static int ****from_array;
-static void (*effect) (int) = NULL;
-static void move_lense(int);
-static void swamp_thing(int);
-static void new_rnd_coo(int);
-static void init_round_lense(void);
-static void (*draw) (int) = NULL;
-static void reflect_draw(int);
-static void plain_draw(int);
-
-static void init_distort(Display *dpy, Window window)
+
+struct state {
+ Display *dpy;
+ Window window;
+
+ struct coo xy_coo[10];
+
+ int delay, radius, speed, number, blackhole, vortex, magnify, reflect, slow;
+ int duration;
+ time_t start_time;
+
+ XWindowAttributes xgwa;
+ GC gc;
+ unsigned long black_pixel;
+
+ XImage *orig_map, *buffer_map;
+ unsigned long *buffer_map_cache;
+
+ int ***from;
+ int ****from_array;
+ int *fast_from;
+
+ int bpp_size;
+
+#ifdef HAVE_XSHM_EXTENSION
+ Bool use_shm;
+ XShmSegmentInfo shm_info;
+#endif /* HAVE_XSHM_EXTENSION */
+
+ void (*effect) (struct state *, int);
+ void (*draw) (struct state *, int);
+ void (*draw_routine) (struct state *st, XImage *, XImage *, int, int, int *);
+
+ async_load_state *img_loader;
+};
+
+
+static void move_lense(struct state *, int);
+static void swamp_thing(struct state *, int);
+static void new_rnd_coo(struct state *, int);
+static void init_round_lense(struct state *st);
+static void reflect_draw(struct state *, int);
+static void plain_draw(struct state *, int);
+
+static void fast_draw_8 (struct state *st, XImage *, XImage *, int, int, int *);
+static void fast_draw_16(struct state *st, XImage *, XImage *, int, int, int *);
+static void fast_draw_32(struct state *st, XImage *, XImage *, int, int, int *);
+static void generic_draw(struct state *st, XImage *, XImage *, int, int, int *);
+
+
+static void distort_finish_loading (struct state *);
+
+static void *
+distort_init (Display *dpy, Window window)
{
+ struct state *st = (struct state *) calloc (1, sizeof(*st));
XGCValues gcv;
long gcflags;
int i;
+ char *s;
+
+ st->dpy = dpy;
+ st->window = window;
- g_window=window;
- g_dpy=dpy;
+ st->delay = get_integer_resource(st->dpy, "delay", "Integer");
+ st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
+ st->radius = get_integer_resource(st->dpy, "radius", "Integer");
+ st->speed = get_integer_resource(st->dpy, "speed", "Integer");
+ st->number = get_integer_resource(st->dpy, "number", "Integer");
- delay = get_integer_resource("delay", "Integer");
- radius = get_integer_resource("radius", "Integer");
- speed = get_integer_resource("speed", "Integer");
- number = get_integer_resource("number", "Integer");
+ if (st->delay < 0) st->delay = 0;
+ if (st->duration < 1) st->duration = 1;
#ifdef HAVE_XSHM_EXTENSION
- use_shm = get_boolean_resource("useSHM", "Boolean");
+ st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean");
#endif /* HAVE_XSHM_EXTENSION */
- blackhole = get_boolean_resource("blackhole", "Boolean");
- vortex = get_boolean_resource("vortex", "Boolean");
- magnify = get_boolean_resource("magnify", "Boolean");
- reflect = get_boolean_resource("reflect", "Boolean");
+ st->blackhole = get_boolean_resource(st->dpy, "blackhole", "Boolean");
+ st->vortex = get_boolean_resource(st->dpy, "vortex", "Boolean");
+ st->magnify = get_boolean_resource(st->dpy, "magnify", "Boolean");
+ st->reflect = get_boolean_resource(st->dpy, "reflect", "Boolean");
+ st->slow = get_boolean_resource(st->dpy, "slow", "Boolean");
- if (get_boolean_resource("swamp", "Boolean"))
- effect = &swamp_thing;
- if (get_boolean_resource("bounce", "Boolean"))
- effect = &move_lense;
-
- if (effect == NULL && radius == 0 && speed == 0 && number == 0
- && !blackhole && !vortex && !magnify && !reflect) {
+ st->effect = NULL;
+ s = get_string_resource(st->dpy, "effect", "String");
+ if (s && !strcasecmp(s,"swamp"))
+ st->effect = &swamp_thing;
+ else if (s && !strcasecmp(s,"bounce"))
+ st->effect = &move_lense;
+ else if (s && !strcasecmp(s,"none"))
+ ;
+ else if (s && *s)
+ fprintf(stderr,"%s: bogus effect: %s\n", progname, s);
+
+ XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+
+ if (st->effect == NULL && st->radius == 0 && st->speed == 0 && st->number == 0
+ && !st->blackhole && !st->vortex && !st->magnify && !st->reflect) {
/* if no cmdline options are given, randomly choose one of:
* -radius 50 -number 4 -speed 1 -bounce
* -radius 50 -number 4 -speed 1 -blackhole
* -radius 100 -number 1 -speed 2 -vortex
* -radius 100 -number 1 -speed 2 -vortex -magnify
* -radius 100 -number 1 -speed 2 -vortex -magnify -blackhole
- * -radius 50 -number 4 -speed 2 -swamp
- * -radius 50 -number 4 -speed 2 -swamp -blackhole
- * -radius 50 -number 4 -speed 2 -swamp -vortex
- * -radius 50 -number 4 -speed 2 -swamp -vortex -magnify
- * -radius 50 -number 4 -speed 2 -swamp -vortex -magnify -blackhole
* -radius 80 -number 1 -speed 2 -reflect
* -radius 50 -number 3 -speed 2 -reflect
+ * jwz: not these
+ * -radius 50 -number 4 -speed 2 -swamp
+ * -radius 50 -number 4 -speed 2 -swamp -blackhole
+ * -radius 50 -number 4 -speed 2 -swamp -vortex
+ * -radius 50 -number 4 -speed 2 -swamp -vortex -magnify
+ * -radius 50 -number 4 -speed 2 -swamp -vortex -magnify -blackhole
*/
- i = (random() % 17);
+ i = (random() % 12 /* 17 */);
- draw = &plain_draw;
+ st->draw = &plain_draw;
switch (i) {
case 0:
- radius=50;number=4;speed=1;
- effect=&move_lense;break;
+ st->radius=50;st->number=4;st->speed=1;
+ st->effect=&move_lense;break;
case 1:
- radius=50;number=4;speed=1;blackhole=1;
- effect=&move_lense;break;
+ st->radius=50;st->number=4;st->speed=1;st->blackhole=1;
+ st->effect=&move_lense;break;
case 2:
- radius=50;number=4;speed=1;vortex=1;
- effect=&move_lense;break;
+ st->radius=50;st->number=4;st->speed=1;st->vortex=1;
+ st->effect=&move_lense;break;
case 3:
- radius=50;number=4;speed=1;vortex=1;magnify=1;
- effect=&move_lense;break;
+ st->radius=50;st->number=4;st->speed=1;st->vortex=1;st->magnify=1;
+ st->effect=&move_lense;break;
case 4:
- radius=50;number=4;speed=1;vortex=1;magnify=1;blackhole=1;
- effect=&move_lense;break;
+ st->radius=50;st->number=4;st->speed=1;st->vortex=1;st->magnify=1;st->blackhole=1;
+ st->effect=&move_lense;break;
case 5:
- radius=100;number=1;speed=2;
- effect=&move_lense;break;
+ st->radius=100;st->number=1;st->speed=2;
+ st->effect=&move_lense;break;
case 6:
- radius=100;number=1;speed=2;blackhole=1;
- effect=&move_lense;break;
+ st->radius=100;st->number=1;st->speed=2;st->blackhole=1;
+ st->effect=&move_lense;break;
case 7:
- radius=100;number=1;speed=2;vortex=1;
- effect=&move_lense;break;
+ st->radius=100;st->number=1;st->speed=2;st->vortex=1;
+ st->effect=&move_lense;break;
case 8:
- radius=100;number=1;speed=2;vortex=1;magnify=1;
- effect=&move_lense;break;
+ st->radius=100;st->number=1;st->speed=2;st->vortex=1;st->magnify=1;
+ st->effect=&move_lense;break;
case 9:
- radius=100;number=1;speed=2;vortex=1;magnify=1;blackhole=1;
- effect=&move_lense;break;
+ st->radius=100;st->number=1;st->speed=2;st->vortex=1;st->magnify=1;st->blackhole=1;
+ st->effect=&move_lense;break;
+
case 10:
- radius=50;number=4;speed=2;
- effect=&swamp_thing;break;
+ st->radius=80;st->number=1;st->speed=2;st->reflect=1;
+ st->draw = &reflect_draw;st->effect = &move_lense;break;
case 11:
- radius=50;number=4;speed=2;blackhole=1;
- effect=&swamp_thing;break;
+ st->radius=50;st->number=4;st->speed=2;st->reflect=1;
+ st->draw = &reflect_draw;st->effect = &move_lense;break;
+
+#if 0 /* jwz: not these */
case 12:
- radius=50;number=4;speed=2;vortex=1;
+ st->radius=50;st->number=4;st->speed=2;
effect=&swamp_thing;break;
case 13:
- radius=50;number=4;speed=2;vortex=1;magnify=1;
+ st->radius=50;st->number=4;st->speed=2;st->blackhole=1;
effect=&swamp_thing;break;
case 14:
- radius=50;number=4;speed=2;vortex=1;magnify=1;blackhole=1;
+ st->radius=50;st->number=4;st->speed=2;st->vortex=1;
effect=&swamp_thing;break;
case 15:
- radius=80;number=1;speed=2;reflect=1;
- draw = &reflect_draw;effect = &move_lense;break;
- case 16: default:
- radius=50;number=4;speed=2;reflect=1;
- draw = &reflect_draw;effect = &move_lense;break;
+ st->radius=50;st->number=4;st->speed=2;st->vortex=1;st->magnify=1;
+ effect=&swamp_thing;break;
+ case 16:
+ st->radius=50;st->number=4;st->speed=2;st->vortex=1;st->magnify=1;st->blackhole=1;
+ effect=&swamp_thing;break;
+#endif
+
+ default:
+ abort(); break;
}
+ /* but if the window is small, reduce default radius */
+ if (st->xgwa.width < st->radius * 8)
+ st->radius = st->xgwa.width/8;
}
- if (delay < 0)
- delay = 0;
- if (radius <= 0)
- radius = 60;
- if (speed <= 0)
- speed = 2;
- if (number <= 0)
- number=1;
- if (number >= 10)
- number=1;
- if (effect == NULL)
- effect = &move_lense;
- if (reflect) {
- draw = &reflect_draw;
- effect = &move_lense;
+ /* never allow the radius to be too close to the min window dimension
+ */
+ if (st->radius >= st->xgwa.width * 0.45) st->radius = st->xgwa.width * 0.45;
+ if (st->radius >= st->xgwa.height * 0.45) st->radius = st->xgwa.height * 0.45;
+
+
+ /* -swamp mode consumes vast amounts of memory, proportional to radius --
+ so throttle radius to a small-ish value (60 => ~30MB.)
+ */
+ if (st->effect == &swamp_thing && st->radius > 60)
+ st->radius = 60;
+
+ if (st->delay < 0)
+ st->delay = 0;
+ if (st->radius <= 0)
+ st->radius = 60;
+ if (st->speed <= 0)
+ st->speed = 2;
+ if (st->number <= 0)
+ st->number=1;
+ if (st->number >= 10)
+ st->number=1;
+ if (st->effect == NULL)
+ st->effect = &move_lense;
+ if (st->reflect) {
+ st->draw = &reflect_draw;
+ st->effect = &move_lense;
}
- if (draw == NULL)
- draw = &plain_draw;
+ if (st->draw == NULL)
+ st->draw = &plain_draw;
- XGetWindowAttributes (dpy, window, &xgwa);
- black_pixel = BlackPixelOfScreen( xgwa.screen );
+ st->black_pixel = BlackPixelOfScreen( st->xgwa.screen );
gcv.function = GXcopy;
gcv.subwindow_mode = IncludeInferiors;
- gcflags = GCForeground |GCFunction;
- if (use_subwindow_mode_p(xgwa.screen, window)) /* see grabscreen.c */
+ gcflags = GCFunction;
+ if (use_subwindow_mode_p(st->xgwa.screen, st->window)) /* see grabscreen.c */
gcflags |= GCSubwindowMode;
- gc = XCreateGC (dpy, window, gcflags, &gcv);
+ st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv);
+
+ st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window,
+ st->window, 0, 0);
+ st->start_time = time ((time_t) 0);
+ return st;
+}
+
+static void
+distort_finish_loading (struct state *st)
+{
+ int i;
- grab_screen_image (xgwa.screen, window);
+ st->start_time = time ((time_t) 0);
- buffer_map = 0;
- orig_map = XGetImage(dpy, window, 0, 0, xgwa.width, xgwa.height,
+ st->buffer_map = 0;
+ st->orig_map = XGetImage(st->dpy, st->window, 0, 0, st->xgwa.width, st->xgwa.height,
~0L, ZPixmap);
+ st->buffer_map_cache = malloc(sizeof(unsigned long)*(2*st->radius+st->speed+2)*(2*st->radius+st->speed+2));
+
+ if (st->buffer_map_cache == NULL) {
+ perror("distort");
+ exit(EXIT_FAILURE);
+ }
# ifdef HAVE_XSHM_EXTENSION
- if (use_shm)
+ if (st->use_shm)
{
- buffer_map = create_xshm_image(dpy, xgwa.visual, orig_map->depth,
- ZPixmap, 0, &shm_info,
- 2*radius + speed + 2,
- 2*radius + speed + 2);
- if (!buffer_map)
- use_shm = False;
+ st->buffer_map = create_xshm_image(st->dpy, st->xgwa.visual, st->orig_map->depth,
+ ZPixmap, 0, &st->shm_info,
+ 2*st->radius + st->speed + 2,
+ 2*st->radius + st->speed + 2);
+ if (!st->buffer_map)
+ st->use_shm = False;
}
# endif /* HAVE_XSHM_EXTENSION */
- if (!buffer_map)
+ if (!st->buffer_map)
{
- buffer_map = XCreateImage(dpy, xgwa.visual,
- orig_map->depth, ZPixmap, 0, 0,
- 2*radius + speed + 2, 2*radius + speed + 2,
+ st->buffer_map = XCreateImage(st->dpy, st->xgwa.visual,
+ st->orig_map->depth, ZPixmap, 0, 0,
+ 2*st->radius + st->speed + 2, 2*st->radius + st->speed + 2,
8, 0);
- buffer_map->data = (char *)
- calloc(buffer_map->height, buffer_map->bytes_per_line);
+ st->buffer_map->data = (char *)
+ calloc(st->buffer_map->height, st->buffer_map->bytes_per_line);
}
- init_round_lense();
+ if ((st->buffer_map->byte_order == st->orig_map->byte_order)
+ && (st->buffer_map->depth == st->orig_map->depth)
+ && (st->buffer_map->format == ZPixmap)
+ && (st->orig_map->format == ZPixmap)
+ && !st->slow) {
+ switch (st->orig_map->bits_per_pixel) {
+ case 32:
+ st->draw_routine = &fast_draw_32;
+ st->bpp_size = sizeof(CARD32);
+ break;
+ case 16:
+ st->draw_routine = &fast_draw_16;
+ st->bpp_size = sizeof(CARD16);
+ break;
+ case 8:
+ st->draw_routine = &fast_draw_8;
+ st->bpp_size = sizeof(CARD8);
+ break;
+ default:
+ st->draw_routine = &generic_draw;
+ break;
+ }
+ } else {
+ st->draw_routine = &generic_draw;
+ }
+ init_round_lense(st);
- for (i = 0; i < number; i++) {
- new_rnd_coo(i);
- if (number != 1)
- xy_coo[i].r = (i*radius)/(number-1); /* "randomize" initial */
+ for (i = 0; i < st->number; i++) {
+ new_rnd_coo(st,i);
+ if (st->number != 1)
+ st->xy_coo[i].r = (i*st->radius)/(st->number-1); /* "randomize" initial */
else
- xy_coo[i].r = 0;
- xy_coo[i].r_change = speed + (i%2)*2*(-speed); /* values a bit */
- xy_coo[i].xmove = speed + (i%2)*2*(-speed);
- xy_coo[i].ymove = speed + (i%2)*2*(-speed);
+ st->xy_coo[i].r = 0;
+ st->xy_coo[i].r_change = st->speed + (i%2)*2*(-st->speed); /* values a bit */
+ st->xy_coo[i].xmove = st->speed + (i%2)*2*(-st->speed);
+ st->xy_coo[i].ymove = st->speed + (i%2)*2*(-st->speed);
}
}
/* example: initializes a "see-trough" matrix */
-/* static void make_null_lense(void)
+/* static void make_null_lense(struct state *st)
{
int i, j;
for (i = 0; i < 2*radius+speed+2; i++) {
}
}
*/
+static void convert(struct state *st)
+{
+ int *p;
+ int i, j;
+ 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));
+ if (st->fast_from == NULL) {
+ perror("distort");
+ exit(EXIT_FAILURE);
+ }
+ p = st->fast_from;
+ for (i = 0; i < 2*st->radius+st->speed+2; i++) {
+ for (j = 0; j < 2*st->radius+st->speed+2; j++) {
+ *(p + i + j*st->buffer_map->bytes_per_line/st->bpp_size)
+ = st->from[i][j][0] + st->xgwa.width*st->from[i][j][1];
+ if (*(p + i + j*st->buffer_map->bytes_per_line/st->bpp_size) < 0
+ || *(p + i + j*st->buffer_map->bytes_per_line/st->bpp_size) >= st->orig_map->height*st->orig_map->width) {
+ *(p + i + j*st->buffer_map->bytes_per_line/st->bpp_size) = 0;
+ }
+ }
+ }
+}
/* makes a lense with the Radius=loop and centred in
* the point (radius, radius)
*/
-static void make_round_lense(int radius, int loop)
+static void make_round_lense(struct state *st, int radius, int loop)
{
int i, j;
- for (i = 0; i < 2*radius+speed+2; i++) {
- for(j = 0; j < 2*radius+speed+2; j++) {
+ for (i = 0; i < 2*radius+st->speed+2; i++) {
+ for(j = 0; j < ((0 == st->bpp_size) ? (2*radius+st->speed+2) : (st->buffer_map->bytes_per_line/st->bpp_size)); j++) {
double r, d;
r = sqrt ((i-radius)*(i-radius)+(j-radius)*(j-radius));
if (loop == 0)
if (r < loop-1) {
- if (vortex) { /* vortex-twist effect */
+ if (st->vortex) { /* vortex-twist effect */
double angle;
/* this one-line formula for getting a nice rotation angle is borrowed
* (with permission) from the whirl plugin for gimp,
* Copyright (C) 1996 Federico Mena Quintero
*/
- /* 2.5 is just a constant used because it looks good :) */
- angle = 2.5*(1-d)*(1-d);
+ /* 5 is just a constant used because it looks good :) */
+ angle = 5*(1-d)*(1-d);
/* Avoid atan2: DOMAIN error message */
if ((radius-j) == 0.0 && (radius-i) == 0.0) {
- from[i][j][0] = radius + cos(angle)*r;
- from[i][j][1] = radius + sin(angle)*r;
+ st->from[i][j][0] = radius + cos(angle)*r;
+ st->from[i][j][1] = radius + sin(angle)*r;
} else {
- from[i][j][0] = radius +
- cos(angle - atan2(radius-j, -(radius-i)))*r;
- from[i][j][1] = radius +
- sin(angle - atan2(radius-j, -(radius-i)))*r;
+ st->from[i][j][0] = radius +
+ cos(angle - atan2(radius-j, -(radius-i)))*r;
+ st->from[i][j][1] = radius +
+ sin(angle - atan2(radius-j, -(radius-i)))*r;
}
- if (magnify) {
+ if (st->magnify) {
r = sin(d*M_PI_2);
- if (blackhole && r != 0) /* blackhole effect */
+ if (st->blackhole && r != 0) /* blackhole effect */
r = 1/r;
- from[i][j][0] = radius + (from[i][j][0]-radius)*r;
- from[i][j][1] = radius + (from[i][j][1]-radius)*r;
+ st->from[i][j][0] = radius + (st->from[i][j][0]-radius)*r;
+ st->from[i][j][1] = radius + (st->from[i][j][1]-radius)*r;
}
} else { /* default is to magnify */
r = sin(d*M_PI_2);
* distortion, a negative value sucks everything into a black hole
*/
/* r = r*r; */
- if (blackhole && r != 0) /* blackhole effect */
+ if (st->blackhole && r != 0) /* blackhole effect */
r = 1/r;
/* bubble effect (and blackhole) */
- from[i][j][0] = radius + (i-radius)*r;
- from[i][j][1] = radius + (j-radius)*r;
+ st->from[i][j][0] = radius + (i-radius)*r;
+ st->from[i][j][1] = radius + (j-radius)*r;
}
} else { /* not inside loop */
- from[i][j][0] = i;
- from[i][j][1] = j;
+ st->from[i][j][0] = i;
+ st->from[i][j][1] = j;
}
}
}
+
+ /* this is really just a quick hack to keep both the compability mode with all depths and still
+ * allow the custom optimized draw routines with the minimum amount of work */
+ if (0 != st->bpp_size) {
+ convert(st);
+ }
}
#ifndef EXIT_FAILURE
# define EXIT_FAILURE -1
#endif
-static void allocate_lense(void)
+static void allocate_lense(struct state *st)
{
int i, j;
+ int s = ((0 != st->bpp_size) ? (st->buffer_map->bytes_per_line/st->bpp_size) : (2*st->radius+st->speed+2));
/* maybe this should be redone so that from[][][] is in one block;
* then pointers could be used instead of arrays in some places (and
* maybe give a speedup - maybe also consume less memory)
*/
-
- from = (int ***)malloc((2*radius+speed+2) * sizeof(int **));
- if (from == NULL) {
+ st->from = (int ***)malloc(s*sizeof(int **));
+ if (st->from == NULL) {
perror("distort");
exit(EXIT_FAILURE);
}
- for (i = 0; i < 2*radius+speed+2; i++) {
- from[i] = (int **)malloc((2*radius+speed+2) * sizeof(int *));
- if (from[i] == NULL) {
+ for (i = 0; i < s; i++) {
+ st->from[i] = (int **)malloc((2*st->radius+st->speed+2) * sizeof(int *));
+ if (st->from[i] == NULL) {
perror("distort");
exit(EXIT_FAILURE);
}
- for (j = 0; j < 2*radius+speed+2; j++) {
- from[i][j] = (int *)malloc(2 * sizeof(int));
- if (from[i][j] == NULL) {
+ for (j = 0; j < s; j++) {
+ st->from[i][j] = (int *)malloc(2 * sizeof(int));
+ if (st->from[i][j] == NULL) {
perror("distort");
exit(EXIT_FAILURE);
}
* this is a double faced mem vs speed trade, it's faster, but eats
* _a lot_ of mem for large radius (is there a bug here? I can't see it)
*/
-static void init_round_lense(void)
+static void init_round_lense(struct state *st)
{
int k;
- if (effect == &swamp_thing) {
- from_array = (int ****)malloc((radius+1)*sizeof(int ***));
- for (k=0; k <= radius; k++) {
- allocate_lense();
- make_round_lense(radius, k);
- from_array[k] = from;
+ if (st->effect == &swamp_thing) {
+ st->from_array = (int ****)malloc((st->radius+1)*sizeof(int ***));
+ for (k=0; k <= st->radius; k++) {
+ allocate_lense(st);
+ make_round_lense(st, st->radius, k);
+ st->from_array[k] = st->from;
}
} else { /* just allocate one from[][][] */
- allocate_lense();
- make_round_lense(radius,radius);
+ allocate_lense(st);
+ make_round_lense(st, st->radius,st->radius);
}
}
+/* If fast_draw_8, fast_draw_16 or fast_draw_32 are to be used, the following properties
+ * of the src and dest XImages must hold (otherwise the generic, slooow, method provided
+ * by X is to be used):
+ * src->byte_order == dest->byte_order
+ * src->format == ZPixmap && dest->format == ZPixmap
+ * src->depth == dest->depth == the depth the function in question asumes
+ * x and y is the coordinates in src from where to cut out the image from,
+ * distort_matrix is a precalculated array of how to distort the matrix
+ */
-/* generate an XImage of from[][][] and draw it on the screen */
-void plain_draw(int k)
+static void fast_draw_8(struct state *st, XImage *src, XImage *dest, int x, int y, int *distort_matrix)
{
- int i, j;
- for(i = 0 ; i < 2*radius+speed+2; i++) {
- for(j = 0 ; j < 2*radius+speed+2 ; j++) {
- if (xy_coo[k].x+from[i][j][0] >= 0 &&
- xy_coo[k].x+from[i][j][0] < xgwa.width &&
- xy_coo[k].y+from[i][j][1] >= 0 &&
- xy_coo[k].y+from[i][j][1] < xgwa.height)
- XPutPixel(buffer_map, i, j,
- XGetPixel(orig_map,
- xy_coo[k].x+from[i][j][0],
- xy_coo[k].y+from[i][j][1]));
- }
+ CARD8 *u = (CARD8 *)dest->data;
+ CARD8 *t = (CARD8 *)src->data + x + y*src->bytes_per_line/sizeof(CARD8);
+
+ while (u < (CARD8 *)(dest->data + sizeof(CARD8)*dest->height
+ *dest->bytes_per_line/sizeof(CARD8))) {
+ *u++ = t[*distort_matrix++];
}
+}
+
+static void fast_draw_16(struct state *st, XImage *src, XImage *dest, int x, int y, int *distort_matrix)
+{
+ CARD16 *u = (CARD16 *)dest->data;
+ CARD16 *t = (CARD16 *)src->data + x + y*src->bytes_per_line/sizeof(CARD16);
+
+ while (u < (CARD16 *)(dest->data + sizeof(CARD16)*dest->height
+ *dest->bytes_per_line/sizeof(CARD16))) {
+ *u++ = t[*distort_matrix++];
+ }
+}
+
+static void fast_draw_32(struct state *st, XImage *src, XImage *dest, int x, int y, int *distort_matrix)
+{
+ CARD32 *u = (CARD32 *)dest->data;
+ CARD32 *t = (CARD32 *)src->data + x + y*src->bytes_per_line/sizeof(CARD32);
+
+ while (u < (CARD32 *)(dest->data + sizeof(CARD32)*dest->height
+ *dest->bytes_per_line/sizeof(CARD32))) {
+ *u++ = t[*distort_matrix++];
+ }
+}
+
+static void generic_draw(struct state *st, XImage *src, XImage *dest, int x, int y, int *distort_matrix)
+{
+ int i, j;
+ for (i = 0; i < dest->width; i++)
+ for (j = 0; j < dest->height; j++)
+ if (st->from[i][j][0] + x >= 0 &&
+ st->from[i][j][0] + x < src->width &&
+ st->from[i][j][1] + y >= 0 &&
+ st->from[i][j][1] + y < src->height)
+ XPutPixel(dest, i, j,
+ XGetPixel(src,
+ st->from[i][j][0] + x,
+ st->from[i][j][1] + y));
+}
+
+/* generate an XImage of from[][][] and draw it on the screen */
+static void plain_draw(struct state *st, int k)
+{
+ if (st->xy_coo[k].x+2*st->radius+st->speed+2 > st->orig_map->width ||
+ st->xy_coo[k].y+2*st->radius+st->speed+2 > st->orig_map->height)
+ return;
+
+ st->draw_routine(st, st->orig_map, st->buffer_map, st->xy_coo[k].x, st->xy_coo[k].y, st->fast_from);
+
+# ifdef HAVE_XSHM_EXTENSION
+ if (st->use_shm)
+ XShmPutImage(st->dpy, st->window, st->gc, st->buffer_map, 0, 0, st->xy_coo[k].x, st->xy_coo[k].y,
+ 2*st->radius+st->speed+2, 2*st->radius+st->speed+2, False);
+ else
+
+ if (!st->use_shm)
+# endif
+ XPutImage(st->dpy, st->window, st->gc, st->buffer_map, 0, 0, st->xy_coo[k].x, st->xy_coo[k].y,
+ 2*st->radius+st->speed+2, 2*st->radius+st->speed+2);
- XPutImage(g_dpy, g_window, gc, buffer_map, 0, 0, xy_coo[k].x, xy_coo[k].y,
- 2*radius+speed+2, 2*radius+speed+2);
}
+
/* generate an XImage from the reflect algoritm submitted by
* Randy Zack <randy@acucorp.com>
* draw really got too big and ugly so I split it up
* it should be possible to use the from[][] to speed it up
* (once I figure out the algorithm used :)
*/
-void reflect_draw(int k)
+static void reflect_draw(struct state *st, int k)
{
int i, j;
int cx, cy;
- int ly, lysq, lx, ny, dist, rsq = radius * radius;
+ int ly, lysq, lx, ny, dist, rsq = st->radius * st->radius;
- cx = cy = radius;
- if (xy_coo[k].ymove > 0)
- cy += speed;
- if (xy_coo[k].xmove > 0)
- cx += speed;
+ cx = cy = st->radius;
+ if (st->xy_coo[k].ymove > 0)
+ cy += st->speed;
+ if (st->xy_coo[k].xmove > 0)
+ cx += st->speed;
- for(i = 0 ; i < 2*radius+speed+2; i++) {
+ for(i = 0 ; i < 2*st->radius+st->speed+2; i++) {
ly = i - cy;
lysq = ly * ly;
- ny = xy_coo[k].y + i;
- for(j = 0 ; j < 2*radius+speed+2 ; j++) {
+ ny = st->xy_coo[k].y + i;
+ if (ny >= st->orig_map->height) ny = st->orig_map->height-1;
+ for(j = 0 ; j < 2*st->radius+st->speed+2 ; j++) {
lx = j - cx;
dist = lx * lx + lysq;
if (dist > rsq ||
- ly < -radius || ly > radius ||
- lx < -radius || lx > radius)
- XPutPixel( buffer_map, j, i,
- XGetPixel( orig_map, xy_coo[k].x + j, ny ));
+ ly < -st->radius || ly > st->radius ||
+ lx < -st->radius || lx > st->radius)
+ XPutPixel( st->buffer_map, j, i,
+ XGetPixel( st->orig_map, st->xy_coo[k].x + j, ny ));
else if (dist == 0)
- XPutPixel( buffer_map, j, i, black_pixel );
+ XPutPixel( st->buffer_map, j, i, st->black_pixel );
else {
- int x = xy_coo[k].x + cx + (lx * rsq / dist);
- int y = xy_coo[k].y + cy + (ly * rsq / dist);
- if (x < 0 || x >= xgwa.width ||
- y < 0 || y >= xgwa.height)
- XPutPixel( buffer_map, j, i, black_pixel );
+ int x = st->xy_coo[k].x + cx + (lx * rsq / dist);
+ int y = st->xy_coo[k].y + cy + (ly * rsq / dist);
+ if (x < 0 || x >= st->xgwa.width ||
+ y < 0 || y >= st->xgwa.height)
+ XPutPixel( st->buffer_map, j, i, st->black_pixel );
else
- XPutPixel( buffer_map, j, i,
- XGetPixel( orig_map, x, y ));
+ XPutPixel( st->buffer_map, j, i,
+ XGetPixel( st->orig_map, x, y ));
}
}
}
- XPutImage(g_dpy, g_window, gc, buffer_map, 0, 0, xy_coo[k].x, xy_coo[k].y,
- 2*radius+speed+2, 2*radius+speed+2);
+ XPutImage(st->dpy, st->window, st->gc, st->buffer_map, 0, 0, st->xy_coo[k].x, st->xy_coo[k].y,
+ 2*st->radius+st->speed+2, 2*st->radius+st->speed+2);
}
/* create a new, random coordinate, that won't interfer with any other
* coordinates, as the drawing routines would be significantly slowed
* down if they were to handle serveral layers of distortions
*/
-static void new_rnd_coo(int k)
+static void new_rnd_coo(struct state *st, int k)
{
int i;
- xy_coo[k].x = (random() % (xgwa.width-2*radius));
- xy_coo[k].y = (random() % (xgwa.height-2*radius));
+ st->xy_coo[k].x = (random() % (st->xgwa.width-2*st->radius));
+ st->xy_coo[k].y = (random() % (st->xgwa.height-2*st->radius));
- for (i = 0; i < number; i++) {
+ for (i = 0; i < st->number; i++) {
if (i != k) {
- if ((abs(xy_coo[k].x - xy_coo[i].x) <= 2*radius+speed+2)
- && (abs(xy_coo[k].y - xy_coo[i].y) <= 2*radius+speed+2)) {
- xy_coo[k].x = (random() % (xgwa.width-2*radius));
- xy_coo[k].y = (random() % (xgwa.height-2*radius));
+ if ((abs(st->xy_coo[k].x - st->xy_coo[i].x) <= 2*st->radius+st->speed+2)
+ && (abs(st->xy_coo[k].y - st->xy_coo[i].y) <= 2*st->radius+st->speed+2)) {
+ st->xy_coo[k].x = (random() % (st->xgwa.width-2*st->radius));
+ st->xy_coo[k].y = (random() % (st->xgwa.height-2*st->radius));
i=-1; /* ugly */
}
}
}
/* move lens and handle bounces with walls and other lenses */
-static void move_lense(int k)
+static void move_lense(struct state *st, int k)
{
int i;
- if (xy_coo[k].x + 2*radius + speed + 2 >= xgwa.width)
- xy_coo[k].xmove = -abs(xy_coo[k].xmove);
- if (xy_coo[k].x <= speed)
- xy_coo[k].xmove = abs(xy_coo[k].xmove);
- if (xy_coo[k].y + 2*radius + speed + 2 >= xgwa.height)
- xy_coo[k].ymove = -abs(xy_coo[k].ymove);
- if (xy_coo[k].y <= speed)
- xy_coo[k].ymove = abs(xy_coo[k].ymove);
+ if (st->xy_coo[k].x + 2*st->radius + st->speed + 2 >= st->xgwa.width)
+ st->xy_coo[k].xmove = -abs(st->xy_coo[k].xmove);
+ if (st->xy_coo[k].x <= st->speed)
+ st->xy_coo[k].xmove = abs(st->xy_coo[k].xmove);
+ if (st->xy_coo[k].y + 2*st->radius + st->speed + 2 >= st->xgwa.height)
+ st->xy_coo[k].ymove = -abs(st->xy_coo[k].ymove);
+ if (st->xy_coo[k].y <= st->speed)
+ st->xy_coo[k].ymove = abs(st->xy_coo[k].ymove);
- xy_coo[k].x = xy_coo[k].x + xy_coo[k].xmove;
- xy_coo[k].y = xy_coo[k].y + xy_coo[k].ymove;
+ st->xy_coo[k].x = st->xy_coo[k].x + st->xy_coo[k].xmove;
+ st->xy_coo[k].y = st->xy_coo[k].y + st->xy_coo[k].ymove;
- for (i = 0; i < number; i++) {
+ /* bounce against othe lenses */
+ for (i = 0; i < st->number; i++) {
if ((i != k)
/* This commented test is for rectangular lenses (not currently used) and
&& (abs(xy_coo[k].x - xy_coo[i].x) <= 2*radius)
&& (abs(xy_coo[k].y - xy_coo[i].y) <= 2*radius)) { */
- && ((xy_coo[k].x - xy_coo[i].x)*(xy_coo[k].x - xy_coo[i].x)
- + (xy_coo[k].y - xy_coo[i].y)*(xy_coo[k].y - xy_coo[i].y)
- <= 2*radius*2*radius)) {
+ && ((st->xy_coo[k].x - st->xy_coo[i].x)*(st->xy_coo[k].x - st->xy_coo[i].x)
+ + (st->xy_coo[k].y - st->xy_coo[i].y)*(st->xy_coo[k].y - st->xy_coo[i].y)
+ <= 2*st->radius*2*st->radius)) {
int x, y;
- x = xy_coo[k].xmove;
- y = xy_coo[k].ymove;
- xy_coo[k].xmove = xy_coo[i].xmove;
- xy_coo[k].ymove = xy_coo[i].ymove;
- xy_coo[i].xmove = x;
- xy_coo[i].ymove = y;
+ x = st->xy_coo[k].xmove;
+ y = st->xy_coo[k].ymove;
+ st->xy_coo[k].xmove = st->xy_coo[i].xmove;
+ st->xy_coo[k].ymove = st->xy_coo[i].ymove;
+ st->xy_coo[i].xmove = x;
+ st->xy_coo[i].ymove = y;
}
}
}
/* make xy_coo[k] grow/shrink */
-void swamp_thing(int k)
+static void swamp_thing(struct state *st, int k)
{
- if (xy_coo[k].r >= radius)
- xy_coo[k].r_change = -abs(xy_coo[k].r_change);
+ if (st->xy_coo[k].r >= st->radius)
+ st->xy_coo[k].r_change = -abs(st->xy_coo[k].r_change);
- if (xy_coo[k].r <= 0) {
- from = from_array[0];
- draw(k);
- xy_coo[k].r_change = abs(xy_coo[k].r_change);
- new_rnd_coo(k);
- xy_coo[k].r=xy_coo[k].r_change;
+ if (st->xy_coo[k].r <= 0) {
+ st->from = st->from_array[0];
+ st->draw(st,k);
+ st->xy_coo[k].r_change = abs(st->xy_coo[k].r_change);
+ new_rnd_coo(st,k);
+ st->xy_coo[k].r=st->xy_coo[k].r_change;
return;
}
- xy_coo[k].r = xy_coo[k].r + xy_coo[k].r_change;
+ st->xy_coo[k].r = st->xy_coo[k].r + st->xy_coo[k].r_change;
- if (xy_coo[k].r >= radius)
- xy_coo[k].r = radius;
- if (xy_coo[k].r <= 0)
- xy_coo[k].r=0;
+ if (st->xy_coo[k].r >= st->radius)
+ st->xy_coo[k].r = st->radius;
+ if (st->xy_coo[k].r <= 0)
+ st->xy_coo[k].r=0;
- from = from_array[xy_coo[k].r];
+ st->from = st->from_array[st->xy_coo[k].r];
}
-\f
+static unsigned long
+distort_draw (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ int k;
+
+ if (st->img_loader) /* still loading */
+ {
+ st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
+ if (! st->img_loader) { /* just finished */
+ distort_finish_loading (st);
+ }
+ return st->delay;
+ }
+
+ if (!st->img_loader &&
+ st->start_time + st->duration < time ((time_t) 0)) {
+ st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window,
+ st->window, 0, 0);
+ return st->delay;
+ }
+
+ for (k = 0; k < st->number; k++) {
+ st->effect(st,k);
+ st->draw(st,k);
+ }
+ return st->delay;
+}
-char *progclass = "Distort";
+static void
+distort_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
+{
+ struct state *st = (struct state *) closure;
+ XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+ /* XClearWindow (dpy, window); */
+ /* Why doesn't this work? */
+ if (st->orig_map) /* created in distort_finish_loading, might be early */
+ XPutImage (st->dpy, st->window, st->gc, st->orig_map,
+ 0, 0, st->orig_map->width, st->orig_map->height, 0, 0);
+}
-char *defaults [] = {
+static Bool
+distort_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+ return False;
+}
+
+static void
+distort_free (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ XFreeGC (st->dpy, st->gc);
+ if (st->orig_map) XDestroyImage (st->orig_map);
+ if (st->buffer_map) XDestroyImage (st->buffer_map);
+ if (st->from) free (st->from);
+ if (st->fast_from) free (st->fast_from);
+ if (st->from_array) free (st->from_array);
+ free (st);
+}
+
+
+\f
+
+static const char *distort_defaults [] = {
"*dontClearRoot: True",
+ "*background: Black",
+ "*fpsSolid: true",
#ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
"*visualID: Best",
#endif
- "*delay: 10000",
+ "*delay: 20000",
+ "*duration: 120",
"*radius: 0",
"*speed: 0",
"*number: 0",
+ "*slow: False",
"*vortex: False",
"*magnify: False",
- "*swamp: False",
- "*bounce: False",
"*reflect: False",
"*blackhole: False",
+ "*effect: none",
#ifdef HAVE_XSHM_EXTENSION
"*useSHM: False", /* xshm turns out not to help. */
#endif /* HAVE_XSHM_EXTENSION */
0
};
-XrmOptionDescRec options [] = {
- { "-delay", ".delay", XrmoptionSepArg, 0 },
- { "-radius", ".radius", XrmoptionSepArg, 0 },
- { "-speed", ".speed", XrmoptionSepArg, 0 },
- { "-number", ".number", XrmoptionSepArg, 0 },
- { "-swamp", ".swamp", XrmoptionNoArg, "True" },
- { "-bounce", ".bounce", XrmoptionNoArg, "True" },
- { "-reflect", ".reflect", XrmoptionNoArg, "True" },
- { "-vortex", ".vortex", XrmoptionNoArg, "True" },
- { "-magnify", ".magnify", XrmoptionNoArg, "True" },
- { "-blackhole", ".blackhole", XrmoptionNoArg, "True" },
+static XrmOptionDescRec distort_options [] = {
+ { "-delay", ".delay", XrmoptionSepArg, 0 },
+ { "-duration", ".duration", XrmoptionSepArg, 0 },
+ { "-radius", ".radius", XrmoptionSepArg, 0 },
+ { "-speed", ".speed", XrmoptionSepArg, 0 },
+ { "-number", ".number", XrmoptionSepArg, 0 },
+
+ { "-effect", ".effect", XrmoptionSepArg, 0 },
+ { "-swamp", ".effect", XrmoptionNoArg, "swamp" },
+ { "-bounce", ".effect", XrmoptionNoArg, "bounce" },
+
+ { "-reflect", ".reflect", XrmoptionNoArg, "True" },
+ { "-vortex", ".vortex", XrmoptionNoArg, "True" },
+ { "-magnify", ".magnify", XrmoptionNoArg, "True" },
+ { "-blackhole", ".blackhole", XrmoptionNoArg, "True" },
+ { "-slow", ".slow", XrmoptionNoArg, "True" },
#ifdef HAVE_XSHM_EXTENSION
- { "-shm", ".useSHM", XrmoptionNoArg, "True" },
- { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
+ { "-shm", ".useSHM", XrmoptionNoArg, "True" },
+ { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
#endif /* HAVE_XSHM_EXTENSION */
- { 0, 0, 0, 0 }
+ { 0, 0, 0, 0 }
};
-
-void screenhack(Display *dpy, Window window)
-{
- int k;
-
- init_distort (dpy, window);
- while (1) {
- for (k = 0; k < number; k++) {
- effect(k);
- draw(k);
- }
-
- XSync(dpy, False);
- screenhack_handle_events (dpy);
- if (delay) usleep(delay);
- }
-
-}
+XSCREENSAVER_MODULE ("Distort", distort)