view 3rdparty/utils/viewgif/viewgif.c @ 3129:ce9f4ff0a380

l1 rel.asm: Do the module padding in a more portable way Add comments to describe what's happening and why.
author Neal Crook <foofoobedoo@gmail.com>
date Wed, 30 Nov 2016 22:10:56 +0000
parents aaae5eac20e1
children
line wrap: on
line source

/* OS-9 ViewGIF 2.0   Copyright (C) 1989 by Vaughn Cato */

/*
 * This program was specifically written for OS-9 on the Tandy Color
 * Computer 3 as its graphics routines will only work on that system.
 * The GIF decoding routines were originally taken from the Apollo
 * workstation version of viewgif by Ben Samit.  As noted in the source
 * code provided by Ben, most of his code was taken from a GIF to
 * PostScript converter by Scott Hemphill.  Because of their consideration
 * in providing the source code with their respective programs I am doing
 * the same.
 *
 * I encourage you to send any enhancements in the Color Computer version
 * you wish to be publicly distributed to me so that I may update the
 * program and re-release it.  In this way, a standard version of the
 * program can be maintained.
 *
 * My address is:
 * Vaughn Cato
 * 1244 E. Piedmont Rd. NE
 * Marietta, Ga. 30062
 */

/*
 * Any portion of this program may be freely used in any software provided
 * the source for that program is made freely available to the public and
 * credit is given to me, Ben Samit, and Scott Hemphill.
 */

#define EXTERN	/* force a defining instance of global variables */

#include <string.h>
#include "viewgif.h"

void			showdata();
char           *mapgpb();
extern int		errno;

DIRECT int      pauselen = -1;
DIRECT bool     global;

main(argc, argv)
int             argc;
char           *argv[];
{
	register char  *p;
	register bool  *cscan;
	char            opt;
	bool            quit;
	int             x, argnum;

	dfactor  = D_DITHER;
	magfact  = D_MAG;
	britefac = D_BRITE;
	infomode = D_INFO;
	graytype = D_GRAY;
	myheight = D_HEIGHT;

	zapmap = aligned = realrand = vefon = FALSE;
	flicker = newscrn = dispon = TRUE;

	for (cscan = &coloruse[MGCLUT]; cscan > coloruse; )
		*--cscan = TRUE;

	screen[0].winpath = screen[1].winpath = -1;

	for (argnum = 1; argnum < argc; ++argnum) {
		if (argv[argnum][0] == '-') {
			p = &argv[argnum][1];
			while (opt = *p++) {
				if (*p == '=')
					++p;
				switch (opt) {
				case 'd':
					if (*p == '\0')
						dfactor = 0;
					else {
						dfactor = atoi(p);
						if (dfactor < -MAXTOL1 || dfactor > MAXDITH1)
							error("Invalid dithering factor", 1);
					}
					break;
				case 'u':
					usefname = p;
					break;
				case 'm':
					magfact = atoi(p);
					if (magfact < MINMAG || magfact > MAXMAG)
						error("Invalid magnification", 1);
					break;
				case 'x':
					startx = atoi(p);
					if (startx < MINCOORD || startx > MAXCOORD)
						error("Invalid start x coordinate", 1);
					break;
				case 'y':
					starty = atoi(p);
					if (starty < MINCOORD || starty > MAXCOORD)
						error("Invalid start y coordinate", 1);
					break;
				case 'g':
					switch (*p) {
					case '2':
						graytype = MAX_GRAY;
						break;
					case '3':
						graytype = NTSC_GRAY;
						break;
					default:
						graytype = AVG_GRAY;
					}
					break;
				case 'a':
					aligned = TRUE;
					continue;
				case 'z':
					dispon = zapmap = TRUE;
					continue;
				case 'v':
					dispon = vefon = TRUE;
					if (*p != '\0')
						vefname = p;
					break;
				case 'r':
					realrand = TRUE;
					continue;
				case 's':
					infomode = NO_INFO;
					continue;
				case 'i':
					if (newscrn)
						infomode = MUCH_INFO;
					continue;
				case 'n':
					if (vefname == NULL)
						dispon = FALSE;
					continue;
				case 'p':
					pauselen = atoi(p);
					break;
				case 'c':
					newscrn = FALSE;
					infomode = NO_INFO;
					continue;
				case 'f':
					flicker = FALSE;
					continue;
				case 'b':
					britefac = atoi(p);
					if (britefac < MINBRITE || britefac > MAXBRITE)
						error("Invalid brightness factor", 1);
					break;
				case '?':
					usage();
				default:
					fatal("Unknown option");
				}
				break;
			}
			for (x = argnum + 1; x < argc; ++x)
				argv[x - 1] = argv[x];
			--argc;
			--argnum;
		}
	}

	if (argc < 2)
		usage();

	if ((infile = fopen(argv[1], "r")) == NULL)
		error("Cannot open input file", errno);

	if (flicker) {
		maxdith = MAXDITH2;
		minmod = SCALE2;
		approx = approx2;
	} else {
		maxdith = MAXDITH1;
		minmod = SCALE1;
		approx = approx1;
	}
	if (dfactor > maxdith)
		dfactor = maxdith;
	low0 = minmod / 2;
	up0 = low0 + 1;

	checksig();
	readscrn();
	if (!realrand)
		makerand();


	quit = FALSE;
	framenum = 0;
	do {
		switch (getc(infile)) {
		case '\0':
			break;
		case ',':
			++framenum;
			readimag();
			waituser();
			break;
		case ';':
			quit = TRUE;
			break;
		case '!':
			readext();
			break;
		default:
			quit = TRUE;
			break;
		}
		if (!dispon && vefname == NULL && (usefname == NULL || !newuse))
			break;
	} while (!quit);

	if (dispon) {
		if (zapmap) {
			if ((infile = freopen(argv[1], "r+", infile)) == NULL)
				error("Cannot rewrite global map", errno);
			else
				zapglobmap();
		}
		killwind();
	}

	actwin = 1;
	select();
	flushwin();
}

makerand()
{
	register char	*rscan1, *rscan2;
	int				x, f2;
	char			temp;
	bool			oddrow, oddrc;

	f2 = maxdith / 2;

	/* initialize */
	x = 256;
	for (rscan2 = &randtab[16][0]; (rscan2 -= 16) >= &randtab[0][0]; )
		for (rscan1 = rscan2 + 16; rscan1 > rscan2; )
			*--rscan1 = (--x * f2) >> 8;

	/*
	 * permute randomly (I don't think the original made all
	 * permutations equally likely, alas)
	 */
	rscan1 = &randtab[0][0];
	for (x = 256; x > 0; x--) {
		rscan2 = rscan1 + (rand() % x);
		temp = *rscan1;
		*rscan1++ = *rscan2;
		*rscan2 = temp;
	}

	oddrow = FALSE;
	for (rscan2 = &randtab[16][0]; (rscan2 -= 16) >= &randtab[0][0]; ) {
		oddrc = oddrow = !oddrow;
		for (rscan1 = rscan2 + 16; --rscan1 >= rscan2; ) {
			if (oddrc = !oddrc)
				*rscan1 += maxdith;
			if (oddrow)
				*rscan1 += f2;
		}
	}
}

readuse()
{
	char            newname[64];
	register char  *ep;
	int             usefile;

	getusename(newname);
	if ((usefile = open(newname, 1)) == -1) {
		for (ep = &coloruse[MGCLUT]; --ep >= coloruse; )
			*ep = TRUE;
		newuse = TRUE;
	} else {
		read(usefile, coloruse, MGCLUT * sizeof(bool));
		close(usefile);
		if (infomode != NO_INFO)
			printf("Using usage file\n");
		newuse = FALSE;
	}
}

getusename(buffer)
{
	if (framenum > 1)
		sprintf(buffer, "%s%d", usefname, framenum);
	else
		strcpy(buffer, usefname);
}

writeuse()
{
	register char  *cp, *gp;
	int             usecount, usefile;
	char            newname[64];

	usecount = 0;
	for (gp = &globuse[globcolors], cp = &coloruse[globcolors];
		 --gp, --cp >= coloruse; )
	{
		if (*cp) {
			*gp = TRUE;
			++usecount;
		}
	}
	if (infomode != NO_INFO)
		printf("%d out of %d colors used.\n", usecount, globcolors);
	if (usefname != NULL) {
		getusename(newname);
		if (newuse) {
			if ((usefile = creat(newname, 3)) == -1)
				error("Cannot create usage file", errno);
			else
				write(usefile, coloruse, globcolors);
		}
		close(usefile);
	}
}

zapglobmap()
{
	register rgbcolor	*gp, *used;
	register int		i;

	for (i = 0; i < globcolors; i++) {
		if (globuse[i]) {
			used = &globclut[i];
			for (gp = &globclut[i = globcolors]; --i, --gp >= globclut; )
			{
				if (!globuse[i]) {
					gp->red   = used->red;
					gp->green = used->green;
					gp->blue  = used->blue;
				}
			}
			fseek(infile, clutpos, 0);
			fwrite(globclut, sizeof(rgbcolor), globcolors, infile);
			return;
		}
	}
}

saveimag()
{
	register cocoscreen	*sscan;
	char            	newname[64];
	int             	file, x, scrnum, scrntype = 0;

	for (scrnum = 0; scrnum <= flicker; ++scrnum) {
		sscan = &screen[scrnum];
		strcpy(newname, vefname);
		if (framenum > 1)
			sprintf(newname + strlen(newname), "%d", framenum);
		if (scrnum == 1)
			strcat(newname, ".2");
		actwin = sscan->winpath;
		select();
		flushwin();
		if ((file = creat(newname, 3)) == -1)
			error("Cannot create vef file", errno);
		else {
			write(file, &scrntype, sizeof(scrntype));
			write(file, sscan->pal, MCCLUT * sizeof(colorcode));
			for (x = 0; x < 8; ++x)
				write(file, gpbufptr, 160);
			for (x = 0; x < MROWS; ++x) {
				getblk(groupnum, bufnum, 0, x, MCOLS - 1, 1);
				flushwin();
				write(file, gpbufptr, 160);
			}
			close(file);
		}
	}
}

readext()
{
	char            buf[255];
	int				count;

	(void) getc(infile);
	while (count = getc(infile))
		fread(buf, 1, count, infile);
}

DIRECT int      real_x, real_y;
DIRECT int      x_coord, y_coord;

typedef struct {
	int		ilv_r0;		/* starting row */
	int		ilv_dr;		/* step size */
}	ilvspec;

static ilvspec	ilvdat[] = {
	{1, 2}, /* .|.|.|.|.|.|.|.|. */
	{2, 4}, /* ..|...|...|...|.. */
	{4, 8}, /* ....|.......|.... */
	{0, 8},	/* |.......|.......| */
};

readimag()
{
	BYTE				buf[9];
	unsigned        	left, top, width, height;
	bool            	local, intrlevd;
	int             	lclbits;
	int             	row, rowoffset;
	register int		n;
	int					lineread, hold, xpos, x;
	register ilvspec   *ilvscan;

	readuse();
	newwind();

	/* read header info */
	fread(buf, sizeof(BYTE), sizeof(buf) / sizeof(BYTE), infile);
	left = arith(buf[0]) | (buf[1] << 8);
	top  = arith(buf[2]) | (buf[3] << 8);
	imagwid  = width = arith(buf[4]) | (buf[5] << 8);
	imaghigh = height = arith(buf[6]) | (buf[7] << 8);

	if (infomode != NO_INFO)
		printf("gif dimensions: %d x %d pixels\n", imagwid, imaghigh);

	local = buf[8] & 0x80;
	intrlevd = buf[8] & 0x40;

	if (local) {
		char            tempbuf[3];

		lclbits = (buf[8] & 0x7) + 1;
		for (x = 1 << lclbits; --x >= 0; )
			fread(tempbuf, 3, 1, infile);
	} else if (!global)
		fatal("no CLUT present for image");

	ilevtab[MROWS] = ILEVEND;
	for (x = MROWS; --x >= 0; )
		ilevtab[x] = ILEVMISS;

	if (!aligned)
		n = myheight;
	else {
		for (n = imaghigh; n > 200; n /= 2)
			;
	}
	n *= magfact;

	rowoffset = 3 * starty * magfact;
	lineread = 0;
	if (intrlevd) {
		for (ilvscan = &ilvdat[elements(ilvdat)]; --ilvscan >= ilvdat; ) {
			for (x = ilvscan->ilv_r0; x < imaghigh; x += ilvscan->ilv_dr) {
				row = (long) x * n / imaghigh - rowoffset;
				if (row >= 0 && row < MROWS)
					ilevtab[row] = lineread;
				++lineread;
			}
		}
	} else {
		for (x = 0; x < imaghigh; ++x) {
			row = (long) x * n / imaghigh - rowoffset;
			if (row >= 0 && row < MROWS)
				ilevtab[row] = lineread;
			++lineread;
		}
	}

	x = startx * (imagwid / 64);
	hold = xpos = 0;
	while (xpos < mywidth) {
		for (hold += mywidth * magfact; hold >= imagwid; hold -= imagwid)
			xtab[xpos++] = x;
		x++;
	}

	real_x = real_y = 0;
	x_coord = y_coord = 0;

	if (dispon || (usefname != NULL && newuse)) {
		readrast(width, height);
		writeuse();
		if (vefname != NULL)
			saveimag();
	}
}

DIRECT int      datum;
DIRECT int      bits;
char            buf[255];

readrast(width, height)
unsigned        width, height;
{
	register char		   *ch;
	register codetype	   *cscan;
	int						count, code;

	datasize = getc(infile);
	codesize = datasize + 1;
	codemask = (1 << codesize) - 1;
	clear = 1 << datasize;
	eoi = clear + 1;
	bits = 16;

	/* initialize code table */
	for (cscan = &codetab[code = clear]; --cscan, --code >= 0; ) {
		cscan->prefix = (codetype *) NULL;
		cscan->first = cscan->suffix = code;
	}

	while ((count = getc(infile)) > 0) {
		fread(buf, sizeof(*buf), count, infile);
		for (ch = buf; --count >= 0; )
			addbyte(*ch++);
	}

	datum >>= bits;
	for (bits = 16 - bits; x_coord != 0 && bits >= codesize; bits -= codesize) {
		process(datum & codemask);
		datum >>= codesize;
	}
}

addbyte(c)
char            c;
{
	/*
	 *	datum += (long)(*ch & 0xff) << bits;
	 *	bits += 8;
	 *	while (bits >= codesize) {
	 *		code = datum & codemask;
	 *		datum >>= codesize;
	 *		bits -= codesize;
	 *		if (code == eoi)
	 *			goto exitloop;
	 *		process(code);
	 *	}
	 */
#asm
 ldb 5,s
 lda <bits+1
 suba #7
 bls _addb3
 sta <bits+1
 lda <datum
 sta <datum+1
 stb <datum
 lda #1
 bra _addb4
_addb3
 lda #8
_addb1
 lsrb
 ror <datum
 ror <datum+1
_addb4
 dec <bits+1
 bne _addb2
* pshs d
 tfr d,u
 ldd <codesize
 std <bits
 ldd <datum
 anda <codemask
 andb <codemask+1
 pshs d
 lbsr process
 leas 2,s
* puls d
 tfr u,d
_addb2
 deca
 bne _addb1
#endasm
}

process(code)
int             code;
{
	register codetype       *p, *cp;
	static DIRECT int		avail;
	static DIRECT codetype	*oldcp;

	if (code == clear) {
		/* clear table */
		codesize = datasize + 1;
		codemask = (1 << codesize) - 1;
		avail = clear + 2;
		oldcp = NULL;
	} else if (code < avail) {
		outcode(cp = &codetab[code]);	/* output the code */
		if (oldcp != NULL) {
			/* add new entry */
			p = &codetab[avail++];
			/* prefix is previous code, first is prefix's first */
			p->first = (p->prefix = oldcp)->first;
			p->suffix = cp->first;	/* suffix is first of current */
			if ((avail & codemask) == 0 && avail < MCODE) {
				/* increase code size */
				codesize++;
				codemask += avail;
			}
		}
		oldcp = cp;
	} else if (code == avail && oldcp != NULL) {
		/* repeat of last code */
		p = &codetab[avail++];
		/* prefix is previous code, first is prefix's first */
		p->first = (p->prefix = oldcp)->first;
		p->suffix = p->first;		/* Suffix is first of last */
		outcode(p);
		if ((avail & codemask) == 0 && avail < MCODE) {
			/* increase code size */
			codesize++;
			codemask += avail;
		}
		oldcp = &codetab[code];
	} else
		fatal("illegal code in raster data");
}

/*
 * outcode() -- we finally get the data out of the LZ decompression, and
 * fill a buffer until we get a line's worth of data.  The loop with x0
 * and x is intended to take advantage of the mostly increasing nature
 * of ilevtab[], replacing an O(n**2) loop that was there before.  Timing,
 * however, shows that the change doesn't affect display time, so the
 * performance bottleneck must be elsewhere.  Rats.
 */
outcode(p)
codetype       *p;
{
	register BYTE		*sp = &codestk[0];
	register int		x;
	static DIRECT int	x0 = 0;

	for (; p; p = p->prefix)
		*sp++ = p->suffix;

	while (--sp >= &codestk[0]) {
		coloruse[arith(*sp)] = TRUE;
		if (real_x == 0) {
			y_coord = -1;
			x = x0;
			do {
				if (++x >= myheight)
					x = 0;
				if (ilevtab[x] == real_y) {
					x0 = y_coord = x;
					break;
				}
			} while (x != x0);
		}
		if (y_coord >= 0) {
			while (xtab[x_coord] == real_x)
				linestor[x_coord++] = arith(*sp);
		}
		if (++real_x >= imagwid) {
			if (y_coord >= 0 && dispon) {
				do {
					doline();
				} while (ilevtab[++y_coord] == ILEVMISS);
			}
			real_x = x_coord = 0;
			++real_y;
		}
	}
}

DIRECT int      bitcount, pixperbyte;
DIRECT char    *byteptr;

doline()
{
	register xlate	*p;
	register char	*rrow;
	register int	x, addval, scrnum;
	cocoscreen		*sscan;

	rrow = &randtab[y_coord & 15][0];

	for (sscan = &screen[scrnum = (flicker ? 2 : 1)]; --sscan, --scrnum >= 0;)
	{
		actwin = sscan->winpath;
		bitcount = pixperbyte;
		byteptr = gpbufptr;
		if (dfactor > 0) {
			for (x = 0; x < mywidth; ++x) {
				addval = (realrand) ? rand85(y_coord + x)
									: rrow[x & 15];
				for (p = &transtab[linestor[x]][1]; p->addval <= addval; )
					p++;
				--p;
				addpixel(p->clutval[scrnum]);
			}
		} else {
			for (x = 0; x < mywidth; ++x)
				addpixel(transtab[linestor[x]][0].clutval[scrnum]);
		}
		if (flicker)
			select();
		putblk(groupnum, bufnum, 0, y_coord);
		flushwin();
	}
}

addpixel(c)
{
	/*
	 *	*byteptr = (*byteptr << (gmode ? 2 : 4)) | c;
	 *	if (--bitcount == 0) {
	 *		byteptr++;
	 *		bitcount = pixperbyte;
	 *	}
	 *
	 * (The spelling discrepancy here is due to the 6809's chopping off
	 * identifier lengths at a different point than the assembler appears to!)
	 */
#asm
 ldx <byteptr
 ldb ,x
 lda <gmode+1
 bne _addpix1
 lslb
 lslb
_addpix1
 lslb
 lslb
 orb 5,s
 stb ,x
 dec <bitcount+1
 bne _addpix2
 leax 1,x
 stx <byteptr
 lda <pixperby+1
 sta <bitcount+1
_addpix2
#endasm
}

rand85(n)
int             n;
{
	register unsigned	result;

	result = rand() % maxdith;
	if (n & 1)
		result += maxdith + 1;
	return result;
}

readscrn()
{
	char            	buf[7];
	int             	x;
	register rgbcolor	*rp;

	fread(buf, sizeof(*buf), 7, infile);
	imagwid = arith(buf[0]) | (buf[1] << 8);
	imaghigh = arith(buf[2]) | (buf[3] << 8);
	if (infomode != NO_INFO)
		printf("%d x %d screen\n", imagwid, imaghigh);
	global = (buf[4] & 0x80) != 0;
	if (global) {
		globbits = (buf[4] & 0x07) + 1;
		globcolors = 1 << globbits;
		if (infomode != NO_INFO)
			printf("global bitmap: %d colors\n", globcolors);
		clutpos = ftell(infile);
		fread(globclut, 3, globcolors, infile);
		if (infomode == MUCH_INFO) {
			for (rp = globclut, x = 0; x < globcolors; rp++, x++) {
				printf("color %d = %3d,%3d,%3d\n", x,
				       arith(rp->red), arith(rp->green), arith(rp->blue));
			}
		}
	} else
		fatal("cannot handle non-global bitmaps");
}

/*
 * newwind() -- the big banana; determine the CoCo CLUT(s) that will
 * best display the GIF image given the GIF CLUT.
 */

newwind()
{
	register cocoscreen	*sscan;
	register bool		*bscan;
	register colorcode	*cscan;
	rgbcolor			*rgbp;
	bool				first;
	char				blip;
	int					x, hival, loval, midval;

	fixgmap();

	if (infomode != NO_INFO) {
		printf("Analyzing..");
		fflush(stdout);
	}

	loval = -MAXTOL1;
	midval = hival = dfactor;

	while (loval <= hival) {
		dfactor = midval;
		if (setmap()) {
			loval = midval + 1;
			blip = '+';
		} else {
			hival = midval - 1;
			blip = '-';
		}
		if (infomode != NO_INFO) {
			putchar(blip);
			fflush(stdout);
		}
		midval = (loval + hival) / 2;
	}

	if (dfactor != hival) {
		dfactor = hival;
		setmap();
	}

	if (infomode != NO_INFO) {
		putchar('\n');
		showdata();
	}

	if (screen[0].clutsize <= 4 && !vefon) {
		gmode = TRUE;
		mywidth = 640;
		pixperbyte = 4;
	} else {
		gmode = FALSE;
		mywidth = 320;
		pixperbyte = 2;
	}

	first = TRUE;
	for (sscan = &screen[(flicker ? 2 : 1)]; --sscan >= screen; ) {
		if (dispon)
			sscan->winpath = initwin(first, sscan->winpath);
		for (cscan = &sscan->pal[x = sscan->clutsize]; --cscan, --x >= 0; ) {
			*cscan = colorval(&sscan->clut[x]);
			if (dispon)
				palette(x, *cscan);
		}
		if (dispon) {
			border(0);
			flushwin();
		}
		first = FALSE;
	}
	for (bscan = &coloruse[globcolors]; --bscan >= coloruse; )
		*bscan = FALSE;
}

/* colorval() -- encode an RGB222 value the way the GIME likes it */

colorval(color)
register rgbcolor		*color;
{
	static char		cocode[] = {'\000', '\001', '\010', '\011'};

	return  (((cocode[color->red & 3] << 1) |
			   cocode[color->green & 3]) << 1) | cocode[color->blue & 3];
}

/*
 * showdata() -- display a bunch of information on the CLUTs used
 * if it's been asked for
 */
void
showdata()
{
	register rgbcolor		*rscan;
	register cocoscreen		*sscan;
	int						x, y;

	if (dfactor > 0)
		printf("Dithering factor = %d\n", dfactor);
	else
		printf("Color tolerance = %d\n", -dfactor);
	fputs("Resulting coco CLUT: ", stdout);
	printf("%d colors", screen[0].clutsize);
	if (flicker)
		printf(" + %d colors\n", screen[1].clutsize);
	else
		putchar('\n');
	if (infomode == MUCH_INFO) {
		for (x = 0; x < (flicker ? 1 : 2); x++) {
			sscan = &screen[x];
			for (rscan = sscan->clut, y = 0; y < sscan->clutsize; y++) {
				printf("%2d:%d,%d,%d=%d\n", y,
					rscan->red, rscan->green, rscan->blue, colorval(rscan));
				rscan++;
			}
			putchar('\n');
		}
		fputs("Translation table:\n", stdout);
		for (x = 0; x < globcolors; ++x) {
			if (coloruse[x]) {
				printf("%3d:", x);
				for (y = 0; y < 4 && transtab[x][y].addval != BOGUSDITH; ++y) {
					printf(" %3d=%3d",
						transtab[x][y].addval, transtab[x][y].clutval[0]);
					if (flicker)
						printf(",%3d", transtab[x][y].clutval[1]);
				}
				putchar('\n');
			}
		}
	}
}

/*
 * fixgmap() -- scale colors in the GIF image global CLUT in accordance
 * with the brightness specification, and in passing, convert to gray
 * if requested (either using the average of the components or their
 * maximum).
 */
fixgmap()
{
	register rgbcolor	*rscan;
	int             	x, r, g, b;

	for (rscan = &globclut[x = globcolors]; --rscan, --x >= 0; ) {
		if (coloruse[x]) {
			r = arith(rscan->red);
			g = arith(rscan->green);
			b = arith(rscan->blue);
			switch (graytype) {
			case AVG_GRAY:
				r = g = b = (r + g + b) / 3;
				break;
			case NTSC_GRAY:
				r = g = b = (30 * r + 59 * g + 11 * b) / 100;
				break;
			case MAX_GRAY:
				if (g > r)
					r = g;
				if (b > r)
					r = b;
				g = b = r;
				break;
			}
			rscan->red   = (britefac * r) >> 4;
			rscan->green = (britefac * g) >> 4;
			rscan->blue  = (britefac * b) >> 4;
		}
	}
}

killwind()
{
	mapgpb(screen[flicker].winpath, groupnum, bufnum, 0);
	killbuf(groupnum, bufnum);
}

waituser()
{
	char            	c;
	int             	x;
	register cocoscreen	*sscan;

	if (dispon) {
		if (pauselen < 0) {
			for (x = 5; --x >= 0; )
				bell();
			flushwin();
		}
		if (flicker) {
			pauselen *= 30;
			do {
				for (sscan = &screen[2]; --sscan >= screen; ) {
					actwin = sscan->winpath;
					select();
					flushwin();
					sleep(2);
					if (ready(actwin)) {
						read(actwin, &c, 1);
						if (c == '\n')
							return;
					}
				}
			} while (pauselen < 0 || --pauselen >= 0);
		} else if (pauselen > 0) {
			sleep(60 * pauselen);
		} else if (pauselen < 0) {
			do {
				read(screen[0].winpath, &c, 1);
			} while (c != '\n');
		}
	}
}

ready(path)
int             path;
{
#asm
 lda 5,s
 ldb #SS.Ready
 os9 I$GetStt
 bcc _ready1
 ldd #0
 bra _ready2
_ready1
 ldd #1
_ready2
#endasm
}