#ident "@(#)fades.c	1.5 91/04/03 XGRASP"
/*-
 * fades.c - grasp image fader.
 *
 * Copyright (c) 1991 by Patrick J. Naughton
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * This file is provided AS IS with no warranties of any kind.  The author
 * shall have no liability with respect to the infringement of copyrights,
 * trade secrets or any patents by this file or any part thereof.  In no
 * event will the author be liable for any lost revenue or profits or
 * other special, indirect and consequential damages.
 *
 * Comments and additions should be sent to the author:
 *
 *                     Patrick J. Naughton
 *                     Sun Microsystems
 *                     2550 Garcia Ave, MS 10-20
 *                     Mountain View, CA 94043
 *                     (415) 336-1080
 *
 */

#include <sys/time.h>
#include "grasp.h"

#define FADE_SNAP	0
#define FADE_WIPELR	1
#define FADE_WIPERL	2
#define FADE_WIPESC	3
#define FADE_WIPECS	4
#define FADE_ILACESIM	5
#define FADE_ILACE	6
#define FADE_WIPETLRBRL	7
#define FADE_WIPELLRRLR	8
#define FADE_WIPETB	9
#define FADE_WIPEBT	10
#define FADE_WIPETCBC	11
#define FADE_WIPECTB	12
#define FADE_ILACETBBT	13
#define FADE_WIPETTBBTB	14
#define FADE_WIPELTBRBT	15
#define FADE_QUARTERS	16
#define FADE_COLUMNS	17
#define FADE_DOUBLEINT	18
#define FADE_POUR	19
#define FADE_SPARKLE	20
#define FADE_DIAGONAL	21
#define FADE_OPEN_AP	22
#define FADE_CLOSE_AP	23
#define FADE_CLOCK	24
#define FADE_DOUBLEARC	25

#define ILACEW 16
#define WIPEW 4

extern ImageStruct *picreg[16];

void
imagefade(fadestyle, im, xo, yo, speed)
    int         fadestyle;
    ImageStruct *im;
    int         speed;
    int         xo;
    int         yo;
{
    int         i;
    int         j;
    int         k;
    int         w = im->w;
    int         h = im->h;
    int         halfh = (h + 1) / 2;
    int         halfw = (w + 1) / 2;
    int         hpar = h & 1;
    int         wpar = w & 1;

    if (videomode < '4') {
	int         lastattr = -1;
	XImage     *xim = XGetImage(dsp, im->pix, 0, 0, w, h, 0xff, ZPixmap);
	for (j = 0; j < h; j++) {
	    char       *row = &xim->data[j * w];
	    for (i = 0; i < w / 2;) {
		char        s[81];
		char        attr = 0;

		k = i;
		do {
		    char        attr1 = row[2 * k + 1];
		    char        ch = row[2 * k];

		    if (ch == 0)
			s[k - i] = 32;
		    else {
			s[k - i] = ch;
			if (attr == 0) {
			    if (attr1 != 0)
				attr = attr1;
			} else if (attr != attr1)
			    break;
		    }
		    k++;
		} while (k < w / 2);
		s[k - i] = 0;
		if (attr != lastattr) {
		    XSetForeground(dsp, gc, attr & 0x0f);
		    XSetBackground(dsp, gc, (attr >> 4) & 0x0f);
		    lastattr = attr;
		}
		XDrawImageString(dsp, win, gc, i * 8, (j + 1) * 13 - 1, s, k - i);
		i = k;
	    }
	}
	free(xim->data);
	free(xim);
	return;
    }
    XSetClipRectangles(dsp, gc, 0, 0, &window, 1, 0);

#if 0	   /* are fades supposed to move with the window? */
    yo = window.y + window.height - h - yo;
    xo = window.x + xo;
#endif
    yo = YFLIPIM(yo, im);

    switch (fadestyle) {

    default:

    case FADE_SNAP:	/* 0 */
	XCopyArea(dsp, im->pix, win, gc,
		  0, 0, w, h, xo, yo);
	break;

    case FADE_WIPELR:	/* 1 */
	for (i = 0; i < w; i += WIPEW)
	    XCopyArea(dsp, im->pix, win, gc,
		      i, 0, WIPEW, h, xo + i, yo);
	break;

    case FADE_WIPERL:	/* 2 */
	for (i = w - WIPEW; i > -WIPEW; i -= WIPEW)
	    XCopyArea(dsp, im->pix, win, gc,
		      i, 0, WIPEW, h, xo + i, yo);
	break;

    case FADE_WIPESC:	/* 3 */
	for (i = 0; i <= halfw; i += WIPEW) {
	    XCopyArea(dsp, im->pix, win, gc,
		      i, 0, WIPEW, h, xo + i, yo + 0);
	    XCopyArea(dsp, im->pix, win, gc,
		      w - WIPEW - i, 0, WIPEW, h, xo + w - WIPEW - i, yo);
	}
	break;

    case FADE_WIPECS:	/* 4 */
	for (i = halfw; i >= -WIPEW; i -= WIPEW) {
	    XCopyArea(dsp, im->pix, win, gc,
		      i, 0, WIPEW, h, xo + i, yo);
	    XCopyArea(dsp, im->pix, win, gc,
		      w - WIPEW - i, 0, WIPEW, h, xo + w - WIPEW - i, yo);
	}
	break;

    case FADE_ILACESIM:	/* 5 */
	for (i = 0; i <= w - ILACEW; i += ILACEW)
	    for (j = 0; j < h; j += 2) {
		XCopyArea(dsp, im->pix, win, gc,
			  i, j, ILACEW, 1, xo + i, yo + j);
		XCopyArea(dsp, im->pix, win, gc,
			  w - ILACEW - i, j + 1, ILACEW, 1,
			  xo + w - ILACEW - i, yo + j + 1);
	    }
	break;

    case FADE_ILACE:	/* 6 */
	for (i = 0; i <= w - ILACEW; i += ILACEW)
	    for (j = 0; j < h; j += 2)
		XCopyArea(dsp, im->pix, win, gc,
			  i, j, ILACEW, 1, xo + i, yo + j);
	for (i = 0; i <= w - ILACEW; i += ILACEW)
	    for (j = 0; j < h; j += 2)
		XCopyArea(dsp, im->pix, win, gc,
			  w - ILACEW - i, j + 1, ILACEW, 1,
			  xo + w - ILACEW - i, yo + j + 1);
	break;

    case FADE_WIPETLRBRL:	/* 7 */
	for (i = 0; i <= w - WIPEW; i += WIPEW)
	    XCopyArea(dsp, im->pix, win, gc,
		      i, halfh, WIPEW, h - halfh, xo + i, yo + halfh);
	for (i = w - WIPEW; i > -WIPEW; i -= WIPEW)
	    XCopyArea(dsp, im->pix, win, gc,
		      i, 0, WIPEW, halfh, xo + i, yo);
	break;

    case FADE_WIPELLRRLR:	/* 8 */
	for (i = 0; i < halfw; i += WIPEW) {
	    XCopyArea(dsp, im->pix, win, gc,
		      i, 0, WIPEW, h, xo + i, yo);
	    XCopyArea(dsp, im->pix, win, gc,
		      halfw + i, 0, WIPEW, h, xo + halfw + i, yo);
	}
	break;

    case FADE_WIPETB:	/* 9 */
	for (j = 0; j < h; j++)
	    XCopyArea(dsp, im->pix, win, gc,
		      0, j, w, 1, xo, yo + j);
	break;

    case FADE_WIPEBT:	/* 10 */
	for (j = h; j >= 0; j--)
	    XCopyArea(dsp, im->pix, win, gc,
		      0, j, w, 1, xo, yo + j);
	break;

    case FADE_WIPETCBC:	/* 11 */
	for (j = 0; j < halfh + hpar; j++) {
	    XCopyArea(dsp, im->pix, win, gc,
		      0, j, w, 1, xo, yo + j);
	    XCopyArea(dsp, im->pix, win, gc,
		      0, h - j - 1, w, 1, xo, yo + h - j - 1);
	}
	break;

    case FADE_WIPECTB:	/* 12 */
	for (j = halfh + hpar - 1; j >= 0; j--) {
	    XCopyArea(dsp, im->pix, win, gc,
		      0, j, w, 1, xo, yo + j);
	    XCopyArea(dsp, im->pix, win, gc,
		      0, h - j - 1, w, 1, xo, yo + h - j - 1);
	}
	break;

    case FADE_ILACETBBT:	/* 13 */
	for (j = 0; j < h; j += 2) {
	    XCopyArea(dsp, im->pix, win, gc,
		      0, j, w, 1, xo, yo + j);
	    XSync(dsp, False);
	}
	for (j = h - 1 - hpar; j > 0; j -= 2) {
	    XCopyArea(dsp, im->pix, win, gc,
		      0, j, w, 1, xo, yo + j);
	    XSync(dsp, False);
	}
	break;

    case FADE_WIPETTBBTB:	/* 14 */
	for (j = 0; j < halfh + hpar; j++) {
	    XCopyArea(dsp, im->pix, win, gc,
		      0, j, w, 1, xo, yo + j);
	    XCopyArea(dsp, im->pix, win, gc,
		      0, halfh + j, w, 1, xo, yo + halfh + j);
	    XSync(dsp, False);
	}
	break;

    case FADE_WIPELTBRBT:	/* 15 */
	for (j = 0; j < h; j++) {
	    XCopyArea(dsp, im->pix, win, gc,
		      0, j, halfw, 1, xo, yo + j);
	    XCopyArea(dsp, im->pix, win, gc,
		      halfw, h - j, halfw, 1, xo + halfw, yo + h - j);
	    XSync(dsp, False);
	}
	break;

    case FADE_QUARTERS:	/* 16 */

	/* top left, top to bottom */
	for (j = 0; j <= halfh + hpar; j++) {
	    XCopyArea(dsp, im->pix, win, gc,
		      0, j, halfw + wpar, 1, xo, yo + j);
	    XSync(dsp, False);
	}

	/* bottom right, top to bottom */
	for (j = halfh + hpar; j < h; j++) {
	    XCopyArea(dsp, im->pix, win, gc,
		      halfw + wpar, j, halfw, 1, xo + halfw + wpar, yo + j);
	    XSync(dsp, False);
	}

	/* bottom left, bottom to top */
	for (j = h; j >= halfh; j--) {
	    XCopyArea(dsp, im->pix, win, gc,
		      0, j, halfw + wpar, 1, xo, yo + j);
	    XSync(dsp, False);
	}

	/* top right, bottom to top */
	for (j = halfh; j >= 0; j--) {
	    XCopyArea(dsp, im->pix, win, gc,
		      halfw + wpar, j, halfw, 1, xo + halfw + wpar, yo + j);
	    XSync(dsp, False);
	}
	break;

    case FADE_COLUMNS:	/* 17 */
	for (j = 0; j < h; j += 2)
	    for (i = 0; i < w; i += 16)
		XCopyArea(dsp, im->pix, win, gc,
			  i, j, 8, 2, xo + i, yo + j);

	for (j = h - 1; j >= -1; j -= 2)
	    for (i = 8; i < w; i += 16)
		XCopyArea(dsp, im->pix, win, gc,
			  i, j, 8, 2, xo + i, yo + j);

	break;

    case FADE_DOUBLEINT:	/* 18 */
	for (j = 0; j < h; j += 2)
	    for (i = 0; i < w; i += 16)
		XCopyArea(dsp, im->pix, win, gc,
			  i, j, 8, 1, xo + i, yo + j);
	for (j = h - 1; j >= 0; j -= 2)
	    for (i = 8; i < w; i += 16)
		XCopyArea(dsp, im->pix, win, gc,
			  i, j, 8, 1, xo + i, yo + j);
	for (j = 1; j < h; j += 2)
	    for (i = 0; i < w; i += 16)
		XCopyArea(dsp, im->pix, win, gc,
			  i, j, 8, 1, xo + i, yo + j);
	for (j = h - 2; j >= 0; j -= 2)
	    for (i = 8; i < w; i += 16)
		XCopyArea(dsp, im->pix, win, gc,
			  i, j, 8, 1, xo + i, yo + j);
	break;

    case FADE_POUR:	/* 19 */
	for (j = h - 1; j >= 0; j -= WIPEW)
	    for (i = 0; i < j; i++)
		XCopyArea(dsp, im->pix, win, gc,
			  0, j, w, WIPEW, xo + 0, yo + i);
	break;

    case FADE_SPARKLE:	/* 20 */
	{
	    int         boxsize = (w + 39) / 40;
	    int         cols = (w + (boxsize - 1)) / boxsize;
	    int         boxcount = (h + (boxsize - 1)) / boxsize * cols;
	    int        *order = (int *) malloc(boxcount * sizeof(int));

	    (void) srandom(getpid());
	    for (i = 0; i < boxcount; i++)
		order[i] = i;
	    for (i = 0; i < boxcount * boxsize; i++) {
		int         i1 = random() % boxcount;
		int         i2 = random() % boxcount;
		j = order[i1];
		order[i1] = order[i2];
		order[i2] = j;
	    }
	    for (i = 0; i < boxcount; i++) {
		int         x = (order[i] % cols) * boxsize;
		int         y = (order[i] / cols) * boxsize;
		XCopyArea(dsp, im->pix, win, gc,
			  x, y, boxsize, boxsize, xo + x, yo + y);
	    }
	    free(order);
	}
	break;

    case FADE_DIAGONAL:	/* 21 *//* not implemented */
	XCopyArea(dsp, im->pix, win, gc,
		  0, 0, w, h, xo, yo);
	break;
    case FADE_OPEN_AP:	/* 22 */
	for (i = 0; i <= MAX(w, h) / 2; i += WIPEW) {
	    /* left wedge */
	    XCopyArea(dsp, im->pix, win, gc,
		      halfw - i, halfh - i, WIPEW, 2 * i,
		      xo + halfw - i, yo + halfh - i);
	    /* top wedge */
	    XCopyArea(dsp, im->pix, win, gc,
		      halfw - i, halfh - i, 2 * i, WIPEW,
		      xo + halfw - i, yo + halfh - i);
	    /* right wedge */
	    XCopyArea(dsp, im->pix, win, gc,
		      halfw + i, halfh - i, WIPEW, 2 * i + WIPEW,
		      xo + halfw + i, yo + halfh - i);
	    /* bottom wedge */
	    XCopyArea(dsp, im->pix, win, gc,
		      halfw - i, halfh + i, 2 * i + WIPEW, WIPEW,
		      xo + halfw - i, yo + halfh + i);
	    XSync(dsp, False);
	}
	break;
    case FADE_CLOSE_AP:	/* 23 */
	for (i = MAX(w, h) / 2; i >= 0; i -= WIPEW) {
	    /* left wedge */
	    XCopyArea(dsp, im->pix, win, gc,
		      halfw - i, halfh - i, WIPEW, 2 * i,
		      xo + halfw - i, yo + halfh - i);
	    /* top wedge */
	    XCopyArea(dsp, im->pix, win, gc,
		      halfw - i, halfh - i, 2 * i, WIPEW,
		      xo + halfw - i, yo + halfh - i);
	    /* right wedge */
	    XCopyArea(dsp, im->pix, win, gc,
		      halfw + i, halfh - i, WIPEW, 2 * i + WIPEW,
		      xo + halfw + i, yo + halfh - i);
	    /* bottom wedge */
	    XCopyArea(dsp, im->pix, win, gc,
		      halfw - i, halfh + i, 2 * i + WIPEW, WIPEW,
		      xo + halfw - i, yo + halfh + i);
	    XSync(dsp, False);
	}
	break;
    case FADE_CLOCK:	/* 24 *//* not implemented */
	XCopyArea(dsp, im->pix, win, gc,
		  0, 0, w, h, xo, yo);
	break;
    case FADE_DOUBLEARC:	/* 25 *//* not implemented */
	XCopyArea(dsp, im->pix, win, gc,
		  0, 0, w, h, xo, yo);
	break;
    }
    XSetClipMask(dsp, gc, None);
    XSync(dsp, False);
}
