X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=utils%2Ferase.c;h=ae15ac8003b02fe5cece3035ca357589c8b91e91;hp=ce48db11a434f8ee6d6dba624a4e60327e3799d2;hb=78add6e627ee5f10e1fa6f3852602ea5066eee5a;hpb=39809ded547bdbb08207d3e514950425215b4410 diff --git a/utils/erase.c b/utils/erase.c index ce48db11..ae15ac80 100644 --- a/utils/erase.c +++ b/utils/erase.c @@ -53,6 +53,9 @@ struct eraser_state { /* data for random_squares */ int cols; + /* data for fizzle */ + unsigned short *fizzle_rnd; + }; @@ -369,27 +372,79 @@ squaretate (eraser_state *st) static void fizzle (eraser_state *st) { + const double overshoot = 1.0625; + + unsigned int x, y, i; + const unsigned int size = 256; + unsigned short *rnd; XPoint *points; - int chunk = 20000; - int npoints = st->width * st->height * 4; - npoints *= (st->ratio - st->prev_ratio); + unsigned int npoints = + (unsigned int)(size * size * st->ratio * overshoot) - + (unsigned int)(size * size * st->prev_ratio * overshoot); + + if (st->ratio >= 1.0) + { + free (st->fizzle_rnd); + st->fizzle_rnd = NULL; + return; + } + + if (! st->fizzle_rnd) + { + unsigned int chunks = + ((st->width + size - 1) / size) * ((st->height + size - 1) / size); + unsigned int i; - points = (XPoint *) malloc (chunk * sizeof(*points)); + st->fizzle_rnd = + (unsigned short *) malloc (sizeof(unsigned short) * chunks); + + if (! st->fizzle_rnd) + return; + + for (i = 0; i != chunks; i++) + st->fizzle_rnd[i] = NRAND(0x10000) | 1; /* Seed can't be 0. */ + } + + points = (XPoint *) malloc ((npoints + 1) * sizeof(*points)); if (! points) return; - while (npoints > 0) + rnd = st->fizzle_rnd; + + for (y = 0; y < st->height; y += 256) { - int remain = (chunk > npoints ? npoints : chunk); - int i; - for (i = 0; i < remain; i++) + for (x = 0; x < st->width; x += 256) { - int r = random(); - points[i].x = r % st->width; - points[i].y = (r >> 16) % st->height; + unsigned int need0 = 0; + unsigned short r = *rnd; + for (i = 0; i != npoints; i++) + { + points[i].x = r % size + x; + points[i].y = (r >> 8) % size + y; + + /* Xorshift. This has a period of 2^16, which exactly matches + the number of pixels in each 256x256 chunk. + + Other shift constants are possible, but it's hard to say + which constants are best: a 2^16 period PRNG will never score + well on BigCrush. + */ + r = (r ^ (r << 3)) & 0xffff; + r = r ^ (r >> 5); + r = (r ^ (r << 11)) & 0xffff; + need0 |= (r == 0x8080); /* Can be anything, really. */ + } + + if (need0) + { + points[npoints].x = x; + points[npoints].y = y; + } + + XDrawPoints (st->dpy, st->window, st->bg_gc, + points, npoints + need0, CoordModeOrigin); + *rnd = r; + rnd++; } - XDrawPoints (st->dpy, st->window, st->bg_gc, - points, remain, CoordModeOrigin); - npoints -= remain; } free (points); } @@ -609,7 +664,7 @@ losira (eraser_state *st) radius*2, radius*2, 180*64, 180*64); } - else /* starburst */ + else if (st->ratio < mode3) /* starburst */ { double ratio = (st->ratio - mode2) / (mode3 - mode2); double r2 = ratio * radius * 4; @@ -695,6 +750,7 @@ eraser_init (Display *dpy, Window window) which = -1; else which = get_integer_resource(dpy, "eraseMode", "Integer"); + free (s); if (which < 0 || which >= countof(erasers)) which = random() % countof(erasers); @@ -713,28 +769,12 @@ eraser_init (Display *dpy, Window window) } -static Bool -eraser_draw (eraser_state *st, Bool first_p) -{ - double now = (first_p ? st->start_time : double_time()); - double duration = st->stop_time - st->start_time; - - st->prev_ratio = st->ratio; - st->ratio = (now - st->start_time) / duration; - - if (st->ratio > 1.0) - st->ratio = 1.0; - - st->fn (st); - XSync (st->dpy, False); - - return (st->ratio < 1.0); -} - void eraser_free (eraser_state *st) { - XClearWindow (st->dpy, st->window); + XClearWindow (st->dpy, st->window); /* Final draw is black-on-black. */ + st->ratio = 1.0; + st->fn (st); /* Free any memory. May also draw, but that doesn't matter. */ XFreeGC (st->dpy, st->fg_gc); XFreeGC (st->dpy, st->bg_gc); free (st); @@ -743,13 +783,26 @@ eraser_free (eraser_state *st) eraser_state * erase_window (Display *dpy, Window window, eraser_state *st) { + double now, duration; Bool first_p = False; if (! st) { first_p = True; st = eraser_init (dpy, window); } - if (! eraser_draw (st, first_p)) + + now = (first_p ? st->start_time : double_time()); + duration = st->stop_time - st->start_time; + + st->prev_ratio = st->ratio; + st->ratio = (now - st->start_time) / duration; + + if (st->ratio < 1.0) + { + st->fn (st); + XSync (st->dpy, False); + } + else { eraser_free (st); st = 0;