X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fdistort.c;h=ffaaa53e6b186539bfac5a44d77f4a5c8f76bda1;hb=8eb2873d7054e705c4e83f22d18c40946a9e2529;hp=7eed6281c8b9c4d3ecef180c77956506ae080fd9;hpb=c31d10b6605cd8dc1a7b61fef4256f06198767e5;p=xscreensaver diff --git a/hacks/distort.c b/hacks/distort.c index 7eed6281..ffaaa53e 100644 --- a/hacks/distort.c +++ b/hacks/distort.c @@ -20,16 +20,29 @@ * -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 #include "screenhack.h" #include +#include #ifdef HAVE_XSHM_EXTENSION # include "xshm.h" -static Bool use_shm; +static Bool use_shm = False; static XShmSegmentInfo shm_info; #endif /* HAVE_XSHM_EXTENSION */ @@ -41,7 +54,7 @@ struct coo { }; static struct coo xy_coo[10]; -static int delay, radius, speed, number, blackhole, vortex, magnify, reflect; +static int delay, radius, speed, number, blackhole, vortex, magnify, reflect, slow; static XWindowAttributes xgwa; static GC gc; static Window g_window; @@ -49,9 +62,11 @@ 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); @@ -61,6 +76,14 @@ 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) { XGCValues gcv; @@ -83,12 +106,15 @@ static void init_distort(Display *dpy, Window window) vortex = get_boolean_resource("vortex", "Boolean"); magnify = get_boolean_resource("magnify", "Boolean"); reflect = get_boolean_resource("reflect", "Boolean"); + slow = get_boolean_resource("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) { /* if no cmdline options are given, randomly choose one of: @@ -102,16 +128,17 @@ static void init_distort(Display *dpy, Window window) * -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; @@ -146,29 +173,39 @@ static void init_distort(Display *dpy, Window window) case 9: radius=100;number=1;speed=2;vortex=1;magnify=1;blackhole=1; effect=&move_lense;break; + case 10: + radius=80;number=1;speed=2;reflect=1; + draw = &reflect_draw;effect = &move_lense;break; + case 11: + radius=50;number=4;speed=2;reflect=1; + draw = &reflect_draw;effect = &move_lense;break; + +#if 0 /* jwz: not these */ + case 12: radius=50;number=4;speed=2; effect=&swamp_thing;break; - case 11: + case 13: radius=50;number=4;speed=2;blackhole=1; effect=&swamp_thing;break; - case 12: + case 14: radius=50;number=4;speed=2;vortex=1; effect=&swamp_thing;break; - case 13: + case 15: radius=50;number=4;speed=2;vortex=1;magnify=1; effect=&swamp_thing;break; - case 14: + case 16: radius=50;number=4;speed=2;vortex=1;magnify=1;blackhole=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; +#endif + + default: + abort(); break; } + /* but if the window is small, reduce default radius */ + if (xgwa.width < radius * 8) + radius = xgwa.width/8; } if (delay < 0) @@ -190,7 +227,6 @@ static void init_distort(Display *dpy, Window window) if (draw == NULL) draw = &plain_draw; - XGetWindowAttributes (dpy, window, &xgwa); black_pixel = BlackPixelOfScreen( xgwa.screen ); gcv.function = GXcopy; @@ -205,6 +241,12 @@ static void init_distort(Display *dpy, Window window) buffer_map = 0; orig_map = XGetImage(dpy, window, 0, 0, xgwa.width, xgwa.height, ~0L, ZPixmap); + buffer_map_cache = malloc(sizeof(unsigned long)*(2*radius+speed+2)*(2*radius+speed+2)); + + if (buffer_map_cache == NULL) { + perror("distort"); + exit(EXIT_FAILURE); + } # ifdef HAVE_XSHM_EXTENSION @@ -229,6 +271,31 @@ static void init_distort(Display *dpy, Window window) calloc(buffer_map->height, 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) { + case 32: + draw_routine = &fast_draw_32; + bpp_size = sizeof(CARD32); + break; + case 16: + draw_routine = &fast_draw_16; + bpp_size = sizeof(CARD16); + break; + case 8: + draw_routine = &fast_draw_8; + bpp_size = sizeof(CARD8); + break; + default: + draw_routine = &generic_draw; + break; + } + } else { + draw_routine = &generic_draw; + } init_round_lense(); for (i = 0; i < number; i++) { @@ -241,6 +308,7 @@ static void init_distort(Display *dpy, Window window) xy_coo[i].xmove = speed + (i%2)*2*(-speed); xy_coo[i].ymove = speed + (i%2)*2*(-speed); } + } /* example: initializes a "see-trough" matrix */ @@ -255,6 +323,26 @@ static void init_distort(Display *dpy, Window window) } } */ +static void convert(void) { + 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) { + 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; + } + } + } +} /* makes a lense with the Radius=loop and centred in * the point (radius, radius) @@ -264,7 +352,7 @@ static void make_round_lense(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(j = 0; j < ((0 == bpp_size) ? (2*radius+speed+2) : (buffer_map->bytes_per_line/bpp_size)); j++) { double r, d; r = sqrt ((i-radius)*(i-radius)+(j-radius)*(j-radius)); if (loop == 0) @@ -280,18 +368,18 @@ static void make_round_lense(int radius, int loop) * (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; } 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; + 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; } if (magnify) { r = sin(d*M_PI_2); @@ -319,6 +407,12 @@ static void make_round_lense(int radius, int loop) } } } + + /* 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(); + } } #ifndef EXIT_FAILURE @@ -328,23 +422,23 @@ static void make_round_lense(int radius, int loop) static void allocate_lense(void) { int i, j; + int s = ((0 != bpp_size) ? (buffer_map->bytes_per_line/bpp_size) : (2*radius+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 **)); + from = (int ***)malloc(s*sizeof(int **)); if (from == NULL) { perror("distort"); exit(EXIT_FAILURE); } - for (i = 0; i < 2*radius+speed+2; i++) { + for (i = 0; i < s; i++) { from[i] = (int **)malloc((2*radius+speed+2) * sizeof(int *)); if (from[i] == NULL) { perror("distort"); exit(EXIT_FAILURE); } - for (j = 0; j < 2*radius+speed+2; j++) { + for (j = 0; j < s; j++) { from[i][j] = (int *)malloc(2 * sizeof(int)); if (from[i][j] == NULL) { perror("distort"); @@ -375,35 +469,90 @@ static void init_round_lense(void) } } +/* 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 + */ + +static void fast_draw_8(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); + + while (u < (CARD8 *)(dest->data + sizeof(CARD8)*dest->height + *dest->bytes_per_line/sizeof(CARD8))) { + *u++ = t[*distort_matrix++]; + } +} + +static void fast_draw_16(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(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(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) + XPutPixel(dest, i, j, + XGetPixel(src, + from[i][j][0] + x, + from[i][j][1] + y)); +} /* generate an XImage of from[][][] and draw it on the screen */ -void plain_draw(int k) +static void plain_draw(int k) { - 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])); - } - } + if (xy_coo[k].x+2*radius+speed+2 > orig_map->width || + xy_coo[k].y+2*radius+speed+2 > orig_map->height) + return; + + draw_routine(orig_map, buffer_map, xy_coo[k].x, xy_coo[k].y, 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); + else + + if (!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(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 * 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(int k) { int i, j; int cx, cy; @@ -432,8 +581,8 @@ void reflect_draw(int k) 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) + if (x < 0 || x >= xgwa.width || + y < 0 || y >= xgwa.height) XPutPixel( buffer_map, j, i, black_pixel ); else XPutPixel( buffer_map, j, i, @@ -486,6 +635,7 @@ static void move_lense(int k) xy_coo[k].x = xy_coo[k].x + xy_coo[k].xmove; xy_coo[k].y = xy_coo[k].y + xy_coo[k].ymove; + /* bounce against othe lenses */ for (i = 0; i < number; i++) { if ((i != k) @@ -511,7 +661,7 @@ static void move_lense(int k) } /* make xy_coo[k] grow/shrink */ -void swamp_thing(int k) +static void swamp_thing(int k) { if (xy_coo[k].r >= radius) xy_coo[k].r_change = -abs(xy_coo[k].r_change); @@ -546,7 +696,7 @@ char *defaults [] = { "*visualID: Best", #endif - "*delay: 10000", + "*delay: 1000", "*radius: 0", "*speed: 0", "*number: 0", @@ -573,6 +723,7 @@ XrmOptionDescRec options [] = { { "-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" }, @@ -592,7 +743,8 @@ void screenhack(Display *dpy, Window window) draw(k); } - XSync(dpy, True); + XSync(dpy, False); + screenhack_handle_events (dpy); if (delay) usleep(delay); }