+static void
+random_squares (eraser_state *st)
+{
+ int i, size, rows;
+
+ if (st->ratio == 0.0)
+ {
+ st->cols = 10 + random() % 30;
+ size = st->width / st->cols;
+ rows = (size ? (st->height / size) : 0) + 1;
+ st->nlines = st->cols * rows;
+ st->lines = (int *) calloc (st->nlines, sizeof(*st->lines));
+
+ for (i = 0; i < st->nlines; i++) /* every square */
+ st->lines[i] = i;
+
+ for (i = 0; i < st->nlines; i++) /* shuffle */
+ {
+ int t, r;
+ t = st->lines[i];
+ r = random() % st->nlines;
+ st->lines[i] = st->lines[r];
+ st->lines[r] = t;
+ }
+ }
+
+ size = st->width / st->cols;
+ rows = (size ? (st->height / size) : 0) + 1;
+
+ for (i = st->nlines * st->prev_ratio;
+ i < st->nlines * st->ratio;
+ i++)
+ {
+ int x = st->lines[i] % st->cols;
+ int y = st->lines[i] / st->cols;
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ st->width * x / st->cols,
+ st->height * y / rows,
+ size+1, size+1);
+ }
+
+ if (st->ratio >= 1.0)
+ {
+ free (st->lines);
+ st->lines = 0;
+ }
+}
+
+
+/* I first saw something like this, albeit in reverse, in an early Tetris
+ implementation for the Mac.
+ -- Torbjörn Andersson <torbjorn@dev.eurotime.se>
+ */
+static void
+slide_lines (eraser_state *st)
+{
+ int max = st->width * 1.1;
+ int nlines = 40;
+ int h = st->height / nlines;
+ int y, step;
+ int tick = 0;
+
+ if (h < 10)
+ h = 10;
+
+ step = (max * st->ratio) - (max * st->prev_ratio);
+ if (step <= 0)
+ step = 1;
+
+ for (y = 0; y < st->height; y += h)
+ {
+ 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);
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ 0, y, step, h);
+ }
+ else
+ {
+ XCopyArea (st->dpy, st->window, st->window, st->fg_gc,
+ step, y, st->width-step, h, 0, y);
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ st->width-step, y, step, h);
+ }
+
+ tick++;
+ }
+}
+
+
+/* from Frederick Roeber <roeber@xigo.com> */
+static void
+losira (eraser_state *st)
+{
+ double mode1 = 0.55;
+ double mode2 = mode1 + 0.30;
+ double mode3 = 1.0;
+ int radius = 10;
+
+ if (st->ratio < mode1) /* squeeze from the sides */
+ {
+ double ratio = st->ratio / mode1;
+ double prev_ratio = st->prev_ratio / mode1;
+ int max = st->width / 2;
+ int step = (max * ratio) - (max * prev_ratio);
+
+ if (step <= 0)
+ step = 1;
+
+ /* pull from left */
+ XCopyArea (st->dpy, st->window, st->window, st->fg_gc,
+ 0, 0, max - step, st->height, step, 0);
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ 0, 0, max * ratio, st->height);
+
+ /* pull from right */
+ XCopyArea (st->dpy, st->window, st->window, st->fg_gc,
+ max+step, 0, max - step, st->height, max, 0);
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ max + max*(1-ratio), 0, max, st->height);
+
+ /* expand white from center */
+ XFillRectangle (st->dpy, st->window, st->fg_gc,
+ max - (radius * ratio), 0,
+ radius * ratio * 2, st->height);
+ }
+ else if (st->ratio < mode2) /* squeeze from the top/bottom */
+ {
+ double ratio = (st->ratio - mode1) / (mode2 - mode1);
+ int max = st->height / 2;
+
+ /* fill middle */
+ XFillRectangle (st->dpy, st->window, st->fg_gc,
+ st->width/2 - radius,
+ max * ratio,
+ radius*2, st->height * (1 - ratio));
+
+ /* fill left and right */
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ 0, 0, st->width/2 - radius, st->height);
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ st->width/2 + radius, 0, st->width/2, st->height);
+
+ /* fill top and bottom */
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ 0, 0, st->width, max * ratio);
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ 0, st->height - (max * ratio),
+ st->width, max);
+
+ /* cap top */
+ XFillArc (st->dpy, st->window, st->fg_gc,
+ st->width/2 - radius,
+ max * ratio - radius,
+ radius*2, radius*2,
+ 0, 180*64);
+
+ /* cap bottom */
+ XFillArc (st->dpy, st->window, st->fg_gc,
+ st->width/2 - radius,
+ st->height - (max * ratio + radius),
+ radius*2, radius*2,
+ 180*64, 180*64);
+ }
+ else /* starburst */
+ {
+ double ratio = (st->ratio - mode2) / (mode3 - mode2);
+ double r2 = ratio * radius * 4;
+ XArc arc[9];
+ int i;
+ int angle = 360*64/countof(arc);
+
+ for (i = 0; i < countof(arc); i++)
+ {
+ double th;
+ arc[i].angle1 = angle * i;
+ arc[i].angle2 = angle;
+ arc[i].width = radius*2 * (1 + ratio);
+ arc[i].height = radius*2 * (1 + ratio);
+ arc[i].x = st->width / 2 - radius;
+ arc[i].y = st->height / 2 - radius;
+
+ th = ((arc[i].angle1 + (arc[i].angle2 / 2)) / 64.0 / 180 * M_PI);
+
+ arc[i].x += r2 * cos (th);
+ arc[i].y -= r2 * sin (th);
+ }
+
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ 0, 0, st->width, st->height);
+ XFillArcs (st->dpy, st->window, st->fg_gc, arc, countof(arc));
+ }
+}