X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fdistort.c;h=7755f0283fda8c722c23ef29b1c2e28a06a4dd0c;hp=919aa4bd83219f88daab240017cfc0ea85c3f207;hb=49f5b54f312fe4ac2e9bc47581a72451bd0e8439;hpb=ccb7f4903325f92555a9722bba74b58346654ba0 diff --git a/hacks/distort.c b/hacks/distort.c index 919aa4bd..7755f028 100644 --- a/hacks/distort.c +++ b/hacks/distort.c @@ -1,5 +1,5 @@ /* -*- mode: C; tab-width: 4 -*- - * xscreensaver, Copyright (c) 1992-2005 Jamie Zawinski + * xscreensaver, Copyright (c) 1992-2006 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -36,86 +36,114 @@ #include #include "screenhack.h" -#include -#include +/*#include */ #ifdef HAVE_XSHM_EXTENSION # include "xshm.h" -static Bool use_shm = False; -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, slow; -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 unsigned long *buffer_map_cache; - -static int ***from; -static int ****from_array; -static int *fast_from = NULL; -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 (*draw_routine)(XImage *, XImage *, int, int, int *) = NULL; -static void fast_draw_8(XImage *, XImage *, int, int, int *); -static void fast_draw_16(XImage *, XImage *, int, int, int *); -static void fast_draw_32(XImage *, XImage *, int, int, int *); -static void generic_draw(XImage *, XImage *, int, int, int *); -static int bpp_size = 0; - - -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; + 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; - g_window=window; - g_dpy=dpy; + st->dpy = dpy; + st->window = window; - delay = get_integer_resource("delay", "Integer"); - radius = get_integer_resource("radius", "Integer"); - speed = get_integer_resource("speed", "Integer"); - number = get_integer_resource("number", "Integer"); + st->delay = get_integer_resource(st->dpy, "delay", "Integer"); + 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"); #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"); - slow = get_boolean_resource("slow", "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; - - XGetWindowAttributes (dpy, window, &xgwa); - - 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 @@ -139,62 +167,62 @@ static void init_distort(Display *dpy, Window window) 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=80;number=1;speed=2;reflect=1; - draw = &reflect_draw;effect = &move_lense;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;reflect=1; - draw = &reflect_draw;effect = &move_lense;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; + st->radius=50;st->number=4;st->speed=2; effect=&swamp_thing;break; case 13: - radius=50;number=4;speed=2;blackhole=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; + st->radius=50;st->number=4;st->speed=2;st->vortex=1; effect=&swamp_thing;break; case 15: - radius=50;number=4;speed=2;vortex=1;magnify=1; + st->radius=50;st->number=4;st->speed=2;st->vortex=1;st->magnify=1; effect=&swamp_thing;break; case 16: - radius=50;number=4;speed=2;vortex=1;magnify=1;blackhole=1; + st->radius=50;st->number=4;st->speed=2;st->vortex=1;st->magnify=1;st->blackhole=1; effect=&swamp_thing;break; #endif @@ -203,127 +231,134 @@ static void init_distort(Display *dpy, Window window) } /* but if the window is small, reduce default radius */ - if (xgwa.width < radius * 8) - radius = xgwa.width/8; + if (st->xgwa.width < st->radius * 8) + st->radius = st->xgwa.width/8; } /* never allow the radius to be too close to the min window dimension */ - if (radius >= xgwa.width * 0.45) radius = xgwa.width * 0.45; - if (radius >= xgwa.height * 0.45) radius = xgwa.height * 0.45; + 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 (effect == &swamp_thing && radius > 60) - radius = 60; - - 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; + 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; - 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); + return st; +} - load_random_image (xgwa.screen, window, window, NULL, NULL); +static void +distort_finish_loading (struct state *st) +{ + int i; - 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); - buffer_map_cache = malloc(sizeof(unsigned long)*(2*radius+speed+2)*(2*radius+speed+2)); + st->buffer_map_cache = malloc(sizeof(unsigned long)*(2*st->radius+st->speed+2)*(2*st->radius+st->speed+2)); - if (buffer_map_cache == NULL) { + 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); } - if ((buffer_map->byte_order == orig_map->byte_order) - && (buffer_map->depth == orig_map->depth) - && (buffer_map->format == ZPixmap) - && (orig_map->format == ZPixmap) - && !slow) { - switch (orig_map->bits_per_pixel) { + 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: - draw_routine = &fast_draw_32; - bpp_size = sizeof(CARD32); + st->draw_routine = &fast_draw_32; + st->bpp_size = sizeof(CARD32); break; case 16: - draw_routine = &fast_draw_16; - bpp_size = sizeof(CARD16); + st->draw_routine = &fast_draw_16; + st->bpp_size = sizeof(CARD16); break; case 8: - draw_routine = &fast_draw_8; - bpp_size = sizeof(CARD8); + st->draw_routine = &fast_draw_8; + st->bpp_size = sizeof(CARD8); break; default: - draw_routine = &generic_draw; + st->draw_routine = &generic_draw; break; } } else { - draw_routine = &generic_draw; + st->draw_routine = &generic_draw; } - init_round_lense(); + 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++) { @@ -334,22 +369,23 @@ static void init_distort(Display *dpy, Window window) } } */ -static void convert(void) { +static void convert(struct state *st) +{ int *p; int i, j; - fast_from = calloc(1, sizeof(int)*((buffer_map->bytes_per_line/bpp_size)*(2*radius+speed+2) + 2*radius+speed+2)); - if (fast_from == NULL) { + 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 = fast_from; - for (i = 0; i < 2*radius+speed+2; i++) { - for (j = 0; j < 2*radius+speed+2; j++) { - *(p + i + j*buffer_map->bytes_per_line/bpp_size) - = from[i][j][0] + xgwa.width*from[i][j][1]; - if (*(p + i + j*buffer_map->bytes_per_line/bpp_size) < 0 - || *(p + i + j*buffer_map->bytes_per_line/bpp_size) >= orig_map->height*orig_map->width) { - *(p + i + j*buffer_map->bytes_per_line/bpp_size) = 0; + 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; } } } @@ -358,12 +394,12 @@ static void convert(void) { /* 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 < ((0 == bpp_size) ? (2*radius+speed+2) : (buffer_map->bytes_per_line/bpp_size)); 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) @@ -373,7 +409,7 @@ static void make_round_lense(int radius, int loop) 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, @@ -384,20 +420,20 @@ static void make_round_lense(int radius, int loop) /* 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 + + st->from[i][j][0] = radius + cos(angle - atan2(radius-j, -(radius-i)))*r; - from[i][j][1] = radius + + 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); @@ -406,23 +442,23 @@ static void make_round_lense(int radius, int loop) * 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 != bpp_size) { - convert(); + if (0 != st->bpp_size) { + convert(st); } } @@ -430,28 +466,28 @@ static void make_round_lense(int radius, int loop) # define EXIT_FAILURE -1 #endif -static void allocate_lense(void) +static void allocate_lense(struct state *st) { int i, j; - int s = ((0 != bpp_size) ? (buffer_map->bytes_per_line/bpp_size) : (2*radius+speed+2)); + 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(s*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 < s; i++) { - from[i] = (int **)malloc((2*radius+speed+2) * sizeof(int *)); - if (from[i] == NULL) { + 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 < s; j++) { - from[i][j] = (int *)malloc(2 * sizeof(int)); - if (from[i][j] == NULL) { + st->from[i][j] = (int *)malloc(2 * sizeof(int)); + if (st->from[i][j] == NULL) { perror("distort"); exit(EXIT_FAILURE); } @@ -463,20 +499,20 @@ static void allocate_lense(void) * 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); } } @@ -490,7 +526,8 @@ static void init_round_lense(void) * distort_matrix is a precalculated array of how to distort the matrix */ -static void fast_draw_8(XImage *src, XImage *dest, int x, int y, int *distort_matrix) { +static void fast_draw_8(struct state *st, XImage *src, XImage *dest, int x, int y, int *distort_matrix) +{ CARD8 *u = (CARD8 *)dest->data; CARD8 *t = (CARD8 *)src->data + x + y*src->bytes_per_line/sizeof(CARD8); @@ -500,7 +537,8 @@ static void fast_draw_8(XImage *src, XImage *dest, int x, int y, int *distort_ma } } -static void fast_draw_16(XImage *src, XImage *dest, int x, int y, int *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); @@ -510,7 +548,8 @@ static void fast_draw_16(XImage *src, XImage *dest, int x, int y, int *distort_m } } -static void fast_draw_32(XImage *src, XImage *dest, int x, int y, int *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); @@ -520,39 +559,40 @@ static void fast_draw_32(XImage *src, XImage *dest, int x, int y, int *distort_m } } -static void generic_draw(XImage *src, XImage *dest, int x, int y, int *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 (from[i][j][0] + x >= 0 && - from[i][j][0] + x < src->width && - from[i][j][1] + y >= 0 && - from[i][j][1] + y < src->height) + 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, - from[i][j][0] + x, - from[i][j][1] + y)); + 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(int k) +static void plain_draw(struct state *st, int k) { - if (xy_coo[k].x+2*radius+speed+2 > orig_map->width || - xy_coo[k].y+2*radius+speed+2 > orig_map->height) + 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; - draw_routine(orig_map, buffer_map, xy_coo[k].x, xy_coo[k].y, fast_from); + 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 (use_shm) - XShmPutImage(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, False); + 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 (!use_shm) + if (!st->use_shm) # endif - 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); } @@ -563,67 +603,67 @@ static void plain_draw(int k) * it should be possible to use the from[][] to speed it up * (once I figure out the algorithm used :) */ -static 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; - if (ny >= orig_map->height) ny = orig_map->height-1; - 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 */ } } @@ -631,24 +671,24 @@ static void new_rnd_coo(int k) } /* 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; /* bounce against othe lenses */ - for (i = 0; i < number; i++) { + for (i = 0; i < st->number; i++) { if ((i != k) /* This commented test is for rectangular lenses (not currently used) and @@ -656,54 +696,100 @@ static void move_lense(int k) && (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 */ -static 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]; } - +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; + } + + for (k = 0; k < st->number; k++) { + st->effect(st,k); + st->draw(st,k); + } + return st->delay; +} + +static void +distort_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +distort_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} -char *progclass = "Distort"; +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); +} -char *defaults [] = { + + + +static const char *distort_defaults [] = { "*dontClearRoot: True", + "*background: Black", #ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */ "*visualID: Best", #endif @@ -712,52 +798,38 @@ char *defaults [] = { "*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" }, - { "-slow", ".slow", XrmoptionNoArg, "True" }, +static XrmOptionDescRec distort_options [] = { + { "-delay", ".delay", 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)