X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=utils%2Ferase.c;h=ae15ac8003b02fe5cece3035ca357589c8b91e91;hb=78add6e627ee5f10e1fa6f3852602ea5066eee5a;hp=feefd69d7d2db06355536ff9ced2fea7680e3d1c;hpb=49f5b54f312fe4ac2e9bc47581a72451bd0e8439;p=xscreensaver diff --git a/utils/erase.c b/utils/erase.c index feefd69d..ae15ac80 100644 --- a/utils/erase.c +++ b/utils/erase.c @@ -1,5 +1,5 @@ /* erase.c: Erase the screen in various more or less interesting ways. - * Copyright (c) 1997-2001, 2006 Jamie Zawinski + * Copyright (c) 1997-2008 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 @@ -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; + + st->fizzle_rnd = + (unsigned short *) malloc (sizeof(unsigned short) * chunks); + + if (! st->fizzle_rnd) + return; - points = (XPoint *) malloc (chunk * sizeof(*points)); + 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); } @@ -451,7 +506,7 @@ random_squares (eraser_state *st) { st->cols = 10 + random() % 30; size = st->width / st->cols; - rows = (st->height / size) + 1; + rows = (size ? (st->height / size) : 0) + 1; st->nlines = st->cols * rows; st->lines = (int *) calloc (st->nlines, sizeof(*st->lines)); @@ -469,7 +524,7 @@ random_squares (eraser_state *st) } size = st->width / st->cols; - rows = (st->height / size) + 1; + rows = (size ? (st->height / size) : 0) + 1; for (i = st->nlines * st->prev_ratio; i < st->nlines * st->ratio; @@ -513,7 +568,9 @@ slide_lines (eraser_state *st) for (y = 0; y < st->height; y += h) { - if (tick & 1) + if (st->width <= step) + ; + else if (tick & 1) { XCopyArea (st->dpy, st->window, st->window, st->fg_gc, 0, y, st->width-step, h, step, y); @@ -572,12 +629,7 @@ losira (eraser_state *st) else if (st->ratio < mode2) /* squeeze from the top/bottom */ { double ratio = (st->ratio - mode1) / (mode2 - mode1); - double prev_ratio = (st->prev_ratio - mode1) / (mode2 - mode1); int max = st->height / 2; - int step = (max * ratio) - (max * prev_ratio); - - if (step <= 0) - step = 1; /* fill middle */ XFillRectangle (st->dpy, st->window, st->fg_gc, @@ -612,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; @@ -698,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); @@ -716,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); -} - -static void +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); @@ -746,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;