[net.sources] Mandelbrot sources

mikee@lumiere.UUCP (09/20/85)

The enclosed programs generate and display mandelbrot images.
They're "slightly" modified versions of the original from Martin
Minow.  My main additions were a compressed pixel-file format and
support for Tek 4105, 4107 and 4115 terminals.  See the readme
(and the source) for details.

Mike Edmonds

-- cut here ------ cut here ------ cut here ------ cut here ------ cut here --
#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	readme.txt
#	Makefile
#	mandefs.h
#	mancomp.c
#	mandisp.c
#	man4100.c
#	man4105.c
#	man4107.c
#	man4115.c
#	mancompress.c
#	manscreen.c
#	maniter.c
#	manfiles.c
#	manregis.c
# This archive created: Thu Sep 19 15:10:15 1985
export PATH; PATH=/bin:$PATH
if test -f 'readme.txt'
then
	echo shar: over-writing existing file "'readme.txt'"
fi
cat << \SHAR_EOF > 'readme.txt'
From Martin Minow:

>> This is a very quick hack to compute the Mandelbrot Set as described
>> in Scientific American, August 1985.  The program is presented only
>> as a stepping-stone for your own improvements.
>> 
>> There are four source files:
>> 
>> mancomp.c	Compute the Mandelbrot Set, writing a "pixel"
>> 		and "histogram" file.
>> 
>> mandisp.c	Read the files produced by mancomp.c, displaying the
>> 		computed values.  This program is -- hopefully --
>> 		independent of the display hardware/firmware.
>> 
>> manscreen.c	Screen I/O for operator interaction.  Assumes a
>> 		VT100 or similar terminal (with ANSI display controls),
>> 		but should be easy to adapt to other uses.  Used only
>> 		to get parameters and display program status.
>> 
>> manregis.c	Display output routines for Regis terminals, such as
>> 		the VT125, VT241, and PRO-350.  Tested only on the
>> 		PRO-350.
>> 
>> Note:
>> 
>> The programs have had only minimal testing.  They are quite slow.
>> You should redo the display routine (and adjust the size of the
>> Mandelbrot set) to take best advantage of your display hardware.
>> For example, you should compute an image that fills the screen.
>> 
>> You can generate spectacular color images on the PRO if you do
>> a little work.
>> 
>> Someone with better graphics and numerical analysis skills should
>> redo the computation in terms of scaled fixed-point arithmetic.
>> 
>> Exploration of the Mandelbrot Set and its effective display would
>> make a nice project for an introductory computer programming course.
>> 
>> Martin Minow
>> decvax!minow


I've made the following changes:

   1.	Converted the pixel file to a pseudo-compressed format.  Usual
	results are a 75 to 85% decrease in space requirements over the
	original.  Added a new program called "mancompress" to convert
	from one format to the other.

   2.	Improved the pixel-addressing accuracy and speed of the various
	display programs.  Added support for Tek 4105, 4107 and 4115
	terminals.  (Didn't retrofit the changes back to the regis code,
	so its broke.)

   3.	Added three new flags for output formatting:
	   -nb	gets rid of the reticular border around the display and
		scales it to fill the extra space,
	   -fs	enlarges the display to the width of whichever axis is
		largest and lops off portions of the other axis (thereby
		filling the screen without distorting the image), and
	   -fi	causes gaps between lines in the display to be filled 
		by displaying rectangles rather than lines (for low-
		resolution images).
	
   4.	Massive quantities of random hacking to clean and speed up the
	code.


To Do:

   1.	Martin's note re numerical analysis techniques is still true.
	The basic method of computing a pixel's value hasn't changed.

   2.	The color-spectrum algorithm for the 4115 is poor.  If anybody
	has a decent one, I'd appreciate a copy.


Enjoy!



Mike Edmonds
Tektronix, Inc.
S3G Unix Support

	UUCPnet:     {ucbvax,ihnp4,allegra,uw-beaver,...}!tektronix!mikee
	CSnet:	     mikee@tek
	ARPAnet:     mikee.tek@csnet-relay
	Snail Mail:  Tektronix, Inc.,
		     S3G Unix Support
		     Del.Sta. 19-333
		     PO Box 500, Beaverton, OR	97077
	MaBell:	     (503) 627-5340
SHAR_EOF
if test -f 'Makefile'
then
	echo shar: over-writing existing file "'Makefile'"
fi
cat << \SHAR_EOF > 'Makefile'
#
# $Header: Makefile,v 1.2 85/09/17 10:46:50 mikee Exp $
#
# $Log:	Makefile,v $
#	Revision 1.2  85/09/17  10:46:50  mikee
#	Massive hacking.
#	
#	Revision 1.1  85/08/26  15:28:51  mikee
#	Cleaned up, changed mandisp refs to man4105/7, etc.
#

CFLAGS = -O
LDFLAGS= -s
LDLIBS = -lm


CCOMP=	mancomp.c
OCOMP=	mancomp.o
DCOMP=	$(OCOMP) misc.a

C4105=	mandisp.c man4100.c man4105.c
O4105=	mandisp.o           man4105.o
D4105=	$(O4105) misc.a

C4107=	                    man4107.c
O4107=	mandisp.o           man4107.o
D4107=	$(O4107) misc.a

C4115=	                    man4115.c
O4115=	mandisp.o           man4115.o
D4115=	$(O4115) misc.a

CPRESS=	mancompress.c
OPRESS=	mancompress.o
DPRESS=	$(OPRESS) misc.a


CMISC=	manscreen.c maniter.c manfiles.c
OMISC=	manscreen.o maniter.o manfiles.o


HDRS=	mandefs.h
SRCS=	$(CCOMP) $(C4105) $(C4107) $(C4115) $(CPRESS) $(CMISC)
OBJS=	$(OCOMP) $(O4105) $(O4107) $(O4115) $(OPRESS) $(OMISC)
BINS=	mancomp man4105 man4107 man4115

all:	$(BINS)


mancomp:$(DCOMP)
	cc $(LDFLAGS) -o $@ $(DCOMP) $(LDLIBS); size $@

man4105:$(D4105)
	cc $(LDFLAGS) -o $@ $(D4105) $(LDLIBS); size $@

man4107:$(D4107)
	cc $(LDFLAGS) -o $@ $(D4107) $(LDLIBS); size $@

man4115:$(D4115)
	cc $(LDFLAGS) -o $@ $(D4115) $(LDLIBS); size $@


mancompress:$(DPRESS)
	cc $(LDFLAGS) -o $@ $(DPRESS) $(LDLIBS); size $@



misc.a: $(OMISC)
	ar rv misc.a $?
	ranlib misc.a

$(OBJS):	$(HDRS)
man4105.o:	man4100.c
man4107.o:	man4100.c
man4115.o:	man4100.c



print:;	pr -f -n Makefile | lpr
	cref $(HDRS) $(SRCS) | lpr


shar:;	shar readme.txt Makefile $(HDRS) $(SRCS) manregis.c > shar.out


clean:;	rm -f         $(OBJS) misc.a a.out core tags make.log
empty:;	rm -f $(BINS) $(OBJS) misc.a a.out core tags make.log
SHAR_EOF
if test -f 'mandefs.h'
then
	echo shar: over-writing existing file "'mandefs.h'"
fi
cat << \SHAR_EOF > 'mandefs.h'
/* $Header: mandefs.h,v 1.4 85/09/16 15:46:49 mikee Exp $
 *
 * $Log:	mandefs.h,v $
 *	Revision 1.4  85/09/16  15:46:49  mikee
 *	Removed decus C stuff, standardized global variable names
 *	and eliminated PIXREC definition.
 *	
 *	Revision 1.3  85/09/09	00:43:21  mikee
 *	Moved hist. and pixel file functions to manfiles.
 *
 *	Revision 1.2  85/08/27	00:34:31  mikee
 *	Converted to packed-pixel file format.
 *
 *	Revision 1.1  85/08/26	15:10:42  mikee
 *	Initial revision
 *
 */

/*
 * Mandelzoom (from Scientific American, August 1985).
 *
 * Global definitions, etc.
 */

#include	<stdio.h>
#include	<ctype.h>
#include	<math.h>

#define FALSE	0
#define TRUE	1
#define EOS	'\0'

#define MAX_NPIXEL	1280		/* Max. pixels in image		*/
#define MAX_NITER	1000		/* Max. iterations per pixel	*/


/*
 * Global variables.
 */
extern	int	Niter;		/* Maximum iterations			*/
extern	int	Npixel;		/* Number pixels on each side		*/
extern	double	RealOrigin;	/* Corner of the picture		*/
extern	double	ImagOrigin;
extern	double	SideLength;	/* Length of each side			*/

extern	int	Histogram[];	/* Pixel density histogram		*/
extern	int	HistTotal;	/* Sum of histogram values		*/
extern	int	HistMin;	/* First count in histogram		*/
extern	int	HistMax;	/* Last count in histogram		*/

extern	int	PixValue;	/* Current pixel value			*/
extern	int	PixCount;	/* Current pixel count (run length)	*/

/*
 * Macros.
 */
#define pixwrite(value) ( ((value) == PixValue)? PixCount++ : _pixwrite(value) )

#define ison(bits, word)	( ((word) & (bits)) != 0 )
#define isoff(bits, word)	( ((word) & (bits)) == 0 )
#define turnon(bits, word)	(word) |= (bits)
#define turnoff(bits, word)	(word) &= ~(bits)

#ifndef min
#define min(a,b)		( ((a) < (b))? (a) : (b) )
#define max(a,b)		( ((a) > (b))? (a) : (b) )
#endif	min

#define dbltoint(val)		(int)( (val) + (((val) < 0.0)? -0.5 : 0.5) )
SHAR_EOF
if test -f 'mancomp.c'
then
	echo shar: over-writing existing file "'mancomp.c'"
fi
cat << \SHAR_EOF > 'mancomp.c'
#ifndef lint
static char *RCSid = "$Header: mancomp.c,v 1.7 85/09/16 18:22:31 mikee Exp $";
#endif

/* $Log:	mancomp.c,v $
 *	Revision 1.7  85/09/16  18:22:31  mikee
 *	Changed global variable names and converted progress logger
 *	function from a paragraph inside the inner loop to a function
 *	called on an alarm.
 *	
 *	Revision 1.6  85/09/09	00:39:08  mikee
 *	Moved hist. and pixel file functions to manfiles.
 *
 *	Revision 1.5  85/09/05	12:47:22  mikee
 *	Replaced pixel computation inner loop by a call to pixvalue.
 *	Moved code to maniter.
 *
 *	Revision 1.4  85/09/03	17:36:58  mikee
 *	Increased displayed precision of parameters.
 *
 *	Revision 1.3  85/08/27	00:33:50  mikee
 *	Converted to packed-pixel file format.
 *
 *	Revision 1.2  85/08/26	17:49:27  mikee
 *	Corrected an error in the inner loop of the pixel comp
 *	rtn that caused pixel's iteration counts to run from
 *	0-niter rather than 0-(niter-1).
 *
 *	Revision 1.1  85/08/26	15:10:46  mikee
 *	Cleaned up code, shortened pixels from int to short, etc.
 *
 */

/*
 * Mandelzoom (from Scientific American, August 1985).
 * Recommended places for exploration (according to the article):
 *	 real  imaginary	side
 *	-2.00	 -1.25		2.50	Entire Mandelbrot set
 *	  .26	  0.00		 .01
 *	 -.76	  0.01		 .02
 *	-1.26	  0.01		 .02
 *
 * This program computes the Mandelbrot set, writing the pixels
 * to xxx.pix and the parameters (origin, size, and a pixel density
 * histogram to xxx.his).
 *
 * Option command line (for spawning):
 *	mandel origin_real origin_imag size npixel niter filename
 * or	mandel xxx.cmd			read commands from a file.
 * or	mandel				interactive
 *
 * Values are:
 *  orig_real	(double) lower-left hand corner of the picture (real part)
 *  orig_imag	(double) lower-left hand corner of the picture (imag part)
 *  size	(double) size of a side (defines the view into the set)
 *  npixel	(int)	 number of pixels on each side (max == 512)
 *				default = 100
 *  niter	(int)	 number of iterations per point.
 *				default = 100
 *  file	(string) name of output file (no type)
 *				default = mandel
 *
 * In "mandel file" format, each line generates a separate picture.
 *
 * Each picture causes two files to be written:
 *   file.his	(readable text format) contains picture definition parameters
 *		and a histogram of pixel values:
 *	orig_real orig_imag side npixel niter \n
 *	bottom top sum	(first non-zero histogram, last non-zero,
 *			  sum of histogram values).
 *	hist[bottom]	(number of pixels with count == bottom)
 *	...		(etc.)
 *	hist[top]	(number of pixels with specified count)
 *  file.pix	(binary format) contains Npixel rows, each containing Npixel
 *		integers, defining the count at each pixel location.
 *
 * Note: this program is very cpu intensive.  There are a maximum of
 *	4 * Niter * (Npixel**2) floating-point multiplies
 *     10 * Niter * (Npixel**2) other floating-point (add, compare, store)
 * per picture.
 *
 * Decus C bug note:
 *   all printf's that format floats must have only one floating-point
 *   parameter, and it must be the last parameter in the argument list.
 *   Also, Decus C doesn't support (double) x++.
 */

#include	"mandefs.h"
#include	<signal.h>

#define DEF_FILENAME	"mandel"	/* Default output filename	*/
#define DEF_NITER	100		/* Default number of iterations */
#define DEF_NPIXEL	100		/* Default number of pixels	*/
#define MAX_ARGS	8		/* Command line arguments	*/

char		line[BUFSIZ];		/* General text work area	*/
char		filename[81];		/* Output file name work area	*/
char		*myargv[MAX_ARGS];	/* To build command arguments	*/
int		myargc;			/* Index into myargv[]		*/

main(argc, argv)
int		argc;
char		*argv[];
{
	char	stdoutbuf[BUFSIZ];

	setbuf(stdout, stdoutbuf);	/* do explicit output buffering */

	Niter = DEF_NITER;
	Npixel = DEF_NPIXEL;
	RealOrigin = -2.0;
	ImagOrigin = -1.25;
	SideLength = 2.5;

	if (argc <= 1) {
	    while (interactive()) {
		doit();
	    }
	}
	else if (argc == 2 && !isdigit(argv[1][0])) {
	    if (freopen(argv[1], "r", stdin) == NULL) {
		perror(argv[1]);
		exit(EOF);
	    }
	    while (comfile()) {
		getarguments(myargc, myargv);
		doit();
	    }
	}
	else {
	    getarguments(argc, argv);
	    doit();
	}
	exit(0);
}

doit()
{
	if ((hisopen(filename, 'w') == TRUE)
	 && (pixopen(filename, 'w') == TRUE)) {
	    process();
	    hiswrite();
	}
	hisclose();
	pixclose();
}

static	x,y;			/* Row/col counters			*/
static	double	interval;	/* Time between progress notifications	*/

process()
/*
 * Compute the Mandelbrot set.
 */
{
	double	offset[MAX_NPIXEL];	/* Pixel offsets (from origin)	*/
	double	c_real[MAX_NPIXEL];	/* Real axis position		*/
	double	float_pixels;		/* To compute pixel position	*/
	int	progress();

	if (isatty(fileno(stdout))) {	/* start progress logger */
	    signal(SIGALRM, progress);
	    interval = 1.0;
	    alarm(dbltoint(interval));
	}

	/*
	 * Precompute the position of each pixel on the real axis.
	 * This loop should not be "unrolled" to a succession of
	 * additions as that would lose accuracy.  Given what
	 * follows, the cost isn't excessive.
	 */
	float_pixels = Npixel;
	for (x = 0; x < Npixel ; x++) {
	    register double gap;
	    offset[x] = gap = (SideLength * ((double) x)) / float_pixels;
	    c_real[x] = RealOrigin + gap;
	}

	for (y = 0; y < Npixel; y++) {
	    register double c_imag;

	    c_imag = ImagOrigin + offset[y];

	    for (x = 0; x < Npixel; x++) {
		register value = pixvalue(c_real[x], c_imag);
		pixwrite(value);
	    }
	    pixflush();
	}

	alarm(0);			/* turn off progress logger */
}

progress()
{
	double	pct;

	pct = (double)(((y * Npixel) + x) * 100) / (double)(Npixel * Npixel);

	scr_move(7, 1);
	printf("Current position = %04d,%04d - %.2f%% completed.", y, x, pct);
	scr_eol();
	fflush(stdout);

	if ((interval *= 1.1) > 120.0)
		interval = 120.0;
	signal(SIGALRM, progress);
	alarm(dbltoint(interval));
}

getarguments(argcount, argstring)
int		argcount;
char		*argstring[];
/*
 * Process argv[] from command line or pseudo argv[] from a file.
 */
{
	register int		i;

	if (argcount < 5) {
	    printf("Missing arguments, need at least\n");
	    printf("real-origin, imaginary-origin, side-length\n");
	}
	else {
	    RealOrigin	= atof(argstring[1]);
	    ImagOrigin	= atof(argstring[2]);
	    SideLength	= atof(argstring[3]);
	    strcpy(filename, DEF_FILENAME);
	    Niter	= DEF_NITER;
	    Npixel	= DEF_NPIXEL;
	    switch (argcount) {
	    default:
		printf("Extra arguments ignored:\n");
		for (i = 7; i < argcount; i++)
		    printf(" arg[%d] = \"%s\"\n", i, argstring[i]);
	    case 7:
		strcpy(filename, argstring[6]);
	    case 6:
		if ((Niter = atoi(argstring[5])) > MAX_NITER) {
		    printf("%d iterations max.\n", MAX_NITER);
		    Niter = MAX_NITER;
		}
	    case 5:
		Npixel = atoi(argstring[4]);
	    }
	    if (Npixel > MAX_NPIXEL)
		Npixel = MAX_NPIXEL;
	    printf("corner = [%.15g,",	RealOrigin);
	    printf("%.15g], ",		ImagOrigin);
	    printf("side = %.15g, ",	SideLength);
	    printf("%d pixels, %d iterations\n", Npixel, Niter);
	    fflush(stdout);
	}
}

interactive()
/*
 * Read commands from the terminal -- assumed to be a VT100 or similar.
 */
{
	if (isatty(fileno(stdin)))
	    scr_clear();
	if (!getcomplex(1, "Lower-left Corner (real, imaginary)",
		&RealOrigin, &ImagOrigin)
	 || !getdouble(2,  "Side Length", &SideLength)
	 || !getint(3,"Number of pixels on a side",
		&Npixel, DEF_NPIXEL, MAX_NPIXEL)
	 || !getint(4,	"Iterations",
		&Niter, DEF_NITER, MAX_NITER)
	 || !getstring(5, "Output filename", filename, DEF_FILENAME))
	    return (FALSE);
	return (TRUE);
}

comfile()
/*
 * Read commands from an indirect command file.
 */
{
	register char	*lp;

	if (gets(line) == NULL)
	    return (FALSE);
	myargv[0] = "";
	for (myargc = 1, lp = line; *lp != EOS && myargc < MAX_ARGS;) {
	    while (isspace(*lp))
		lp++;
	    myargv[myargc++] = lp;
	    while(*lp && !isspace(*lp))
		lp++;
	    if (*lp != EOS)
		*lp++ = EOS;
	}
	return (TRUE);
}
SHAR_EOF
if test -f 'mandisp.c'
then
	echo shar: over-writing existing file "'mandisp.c'"
fi
cat << \SHAR_EOF > 'mandisp.c'
#ifndef lint
static char *RCSid = "$Header: mandisp.c,v 1.6 85/09/18 16:32:23 mikee Exp $";
#endif

/* $Log:	mandisp.c,v $
 *	Revision 1.6  85/09/18  16:32:23  mikee
 *	Changed global variable names, added "fill" (-fi) mode (for drawing
 *	low resolution images using rectangles rather than lines), added
 *	handler to reset terminal after interrupt and removed pixel address
 *	calculation code from "process" to speed things up.
 *	
 *	Revision 1.5  85/09/09	00:42:32  mikee
 *	Moved hist. and pixel file functions to manfiles.
 *
 *	Revision 1.4  85/09/03	17:41:04  mikee
 *	Increased displayed precision of parameters, displayed special
 *	tick marks to show areas that will be off the screen during
 *	a "fill-screen" enlargement and changed spectrum allocation
 *	algorithm.
 *
 *	Revision 1.3  85/08/27	21:19:04  s3g
 *	Added "fill-screen" mode and made color selection a little
 *	more intelligent.
 *
 *	Revision 1.2  85/08/27	00:34:38  mikee
 *	Converted to packed-pixel file format.
 *
 *	Revision 1.1  85/08/26	15:14:11  mikee
 *	Cleaned up code, shortened pixels from int to short,
 *	made display interface more generic, etc.
 *
 */

/*
 * Display Mandelbrot set pixels.
 *
 * Usage: mandisp [-nb] [-fs] [-fi] [pixel-file-prefix]
 *	-nb	Don't print a numbered grid around the display.
 *		(Default = FALSE - print the border)
 *	-fs	Expand display to fill screen (implies -nb).
 *		(Default = FALSE - print the border)
 *	-fi	Fill in gaps between lines.
 *		(Default = FALSE - leave gaps blank).
 *	prefix	Pixel (suffix = .pix) and histogram (.his) file prefix.
 *		(Default = mandel).
 */

#include	"mandefs.h"
#include	<signal.h>

#define DEF_FILENAME	"mandel"

/*
 * Display system statistics (set by display functions).
 */
extern int	Max_Xpixel;
extern int	Max_Ypixel;
extern int	Gray_Scale;
extern int	Tick;
extern int	Cxsize;
extern int	Cysize;

/*
 * These values are computed locally based on the above.
 */
int	dpixel, xpixel, ypixel; /* Number of display pixels per side	*/
int	xorigin, yorigin;	/* Address of lower-left corner		*/
int	xaddrs[MAX_NPIXEL];	/* Screen address corresponding to	*/
int	yaddrs[MAX_NPIXEL];	/* each pixel in the pixel file.	*/
int	density[MAX_NITER];	/* Density (color) of each iter. level	*/


int	Border = TRUE;		/* Should we display a pretty border?	*/
int	Expand = FALSE;		/* Should we expand the display?	*/
int	Fill = FALSE;		/* Fill in blank lines?			*/

char	line[BUFSIZ];
char	filename[81];

main(argc, argv)
int		argc;
char		*argv[];
{
	char	stdoutbuf[BUFSIZ];

	setbuf(stdout, stdoutbuf);	/* do explicit output buffering */

	if (argc <= 1) {
	    while (interactive()) {
		doit();
	    }
	}
	else {
	    register i;

	    for (i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-nb") == 0) {
			Border = FALSE;
			continue;
		}
		if (strcmp(argv[i], "-fs") == 0) {
			Border = FALSE;
			Expand = TRUE;
			continue;
		}
		if (strcmp(argv[i], "-fi") == 0) {
			Fill = TRUE;
			continue;
		}
		strcpy(filename, argv[i]);
		doit();
	    }
	}
	dsp_finis();
	scr_clear();
}

doit()
{
	int	dointr();

	if ((pixopen(filename, 'r') != TRUE)
	 || (hisopen(filename, 'r') != TRUE)
	 || (hisread() != TRUE)) {
		hisclose();
		pixclose();
		if (isatty(fileno(stdin))) {
			printf("Press return to continue.\n");
			gets(line);
		}
		return;
	}

	scr_clear();
	scr_move(2, 1);

	printf("origin %.15g, %.15g\n", RealOrigin, ImagOrigin);
	printf("side   %.15g\n", SideLength);
	printf("npixel %d\n", Npixel);
	printf("niter  %d\n", Niter);
	fflush(stdout);

	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
		signal(SIGINT, dointr);
	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
		signal(SIGHUP, dointr);
	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
		signal(SIGQUIT, dointr);

	dsp_init();

	set_gray_scale();
	if (Border)
		border();
	else if (Expand)
		fill_screen();
	else
		no_border();
	process();

	hisclose();
	pixclose();
}

/*
 * Clean up terminal modes after an interrupt.
 */
dointr()
{
	char	tempbuf[BUFSIZ];
	setbuf(stdout, tempbuf);	/* throw away current output buffer */
	dsp_finis();
	scr_clear();
	exit(EOF);
}

process()
{
	register x, y, oldx, oldy, old_dens, new_dens;
	int	 width;

	width = (dpixel + (Npixel - 1)) / Npixel;

	if (Fill == TRUE && width > 1) {

		oldy = -1;
		for (y = 0; y < Npixel; y++) {
			if (pixread(y, 0) != TRUE)
				return;

			if (yaddrs[y] < 0 || yaddrs[y] == oldy) {
				for (x = PixCount ; x < Npixel ; x += PixCount)
					if (pixread(y, x) != TRUE)
						return;
				continue;
			}
			dsp_move(xorigin, (oldy = yaddrs[y]));

			oldx = xorigin;
			old_dens = density[PixValue];
			for (x = PixCount ; x < Npixel ; x += PixCount) {
				if (pixread(y, x) != TRUE)
					return;

				new_dens = density[PixValue];
				if (new_dens != old_dens) {
					register len = xaddrs[x] - oldx;
					if (len > 0) {
						dsp_rect(old_dens, len, width);
						oldx = xaddrs[x];
					}
					old_dens = new_dens;
				}
			}

			if ((x = xorigin + xpixel) > oldx)
				dsp_rect(old_dens, x - oldx, width);
			dsp_endline();
		}

	} else {
		oldy = -1;
		for (y = 0; y < Npixel; y++) {
			if (pixread(y, 0) != TRUE)
				return;

			if (yaddrs[y] < 0 || yaddrs[y] == oldy) {
				for (x = PixCount ; x < Npixel ; x += PixCount)
					if (pixread(y, x) != TRUE)
						return;
				continue;
			}
			dsp_move(xorigin, (oldy = yaddrs[y]));

			oldx = xorigin;
			old_dens = density[PixValue];
			for (x = PixCount ; x < Npixel ; x += PixCount) {
				if (pixread(y, x) != TRUE)
					return;

				new_dens = density[PixValue];
				if (new_dens != old_dens) {
					register len = xaddrs[x] - oldx;
					if (len > 0) {
						dsp_draw(old_dens, len);
						oldx = xaddrs[x];
					}
					old_dens = new_dens;
				}
			}

			if ((x = xorigin + xpixel) > oldx)
				dsp_draw(old_dens, x - oldx);
			dsp_endline();
		}
	}
	stall();
}

set_gray_scale()
/*
 * Take the density histogram and turn it into a gray scale.
 * (This should probably be interactive.)
 */
{
	int	 colors = Gray_Scale;
	int	 hihist = HistMax;
	int	 lodens = 0;
	register locount = 0, midcount, hicount = HistTotal;
	register sections;

	sections = getsects(hihist, lodens, 1);
	if (sections < 2)
		return;
	if (colors >= sections) {
		double	factor, curcolor;

		factor = (double) colors / (double) sections;
		for (curcolor = 0.0 ; hihist >= HistMin ; hihist--) {
			if (Histogram[hihist] > 0) {
				density[hihist] = dbltoint(curcolor);
				curcolor += factor;
			}
		}
		return;
	}

	if (Histogram[HistMax] >= (HistTotal / 500)) {
		density[hihist--] = lodens++;
		hicount -= Histogram[HistMax];
		colors--;
	}

	while ((midcount = ((locount + hicount) / 2)) > locount) {
		register sections = getsects(hihist, lodens, midcount);
		if (sections < colors)
			hicount = midcount;
		else if (sections > colors)
			locount = midcount;
		else {
			while (getsects(hihist, lodens, --midcount) == colors)
				;
			midcount++;
			break;
		}
	}
	getsects(hihist, lodens, midcount);
}

getsects(hihist, lodens, count)
	register hihist, lodens, count;
{
	register dens = lodens, used;

	for (used = 0 ; hihist >= HistMin ; hihist--) {
		density[hihist] = dens;
		used += Histogram[hihist];
		if (used >= count) {
			used = 0;
			dens++;
		}
	}
	if (used > 0)
		dens++;
	return (dens - lodens);
}

fill_screen()
/*
 * Expand display to fill screen.
 */
{
	xorigin = 0;
	yorigin = (Cysize * 3) / 2;

	xpixel = (Max_Xpixel - 1);
	ypixel = (Max_Ypixel - 1) - yorigin;
	dpixel = max(xpixel, ypixel);

	pixaddrs(xaddrs, xorigin, Max_Xpixel);
	pixaddrs(yaddrs, yorigin, Max_Ypixel);
}

no_border()
/*
 * No border is to be drawn.  Determine optimum location for display.
 */
{
	xpixel = (Max_Xpixel - 1);
	ypixel = (Max_Ypixel - 1) - ((Cysize * 3) / 2);

	if (xpixel >= ypixel) {
		xorigin = (xpixel - ypixel) / 2;
		yorigin = (Max_Ypixel - 1) - ypixel;
		dpixel = xpixel = ypixel;
	} else {
		xorigin = 0;
		yorigin = ((Max_Ypixel - 1) - xpixel) / 2;
		dpixel = ypixel = xpixel;
	}

	pixaddrs(xaddrs, xorigin, xorigin + xpixel);
	pixaddrs(yaddrs, yorigin, yorigin + ypixel);
}

border()
/*
 * Draw a pretty border
 */
{
	register x, y;
	int	 left, right, top, bottom;
	int	 tickx[4], ticky[2];
	int	 do_value;
	double	 offset, gap;

	xpixel = (Max_Xpixel - 1);
	ypixel = (Max_Ypixel - 1) - ((Cysize * 3) / 2);

	if (xpixel >= ypixel) {
	    top = Max_Ypixel - 1;
	    bottom = Cysize * 3;
	    left = (xpixel - (top - bottom)) / 2;
	    right = left + (top - bottom);

	    offset = (1.0 - ((double)ypixel / (double)xpixel)) / 2.0;
	    offset *= (double)ypixel;
	    tickx[0] = left - (Tick * 2);
	    tickx[1] = left;
	    tickx[2] = right + (Tick * 2);
	    tickx[3] = right;
	    ticky[0] = top - dbltoint(offset);
	    ticky[1] = bottom + dbltoint(offset);

	    dpixel = xpixel = ypixel = (top - bottom) - (2 * (Tick + 1));

	} else {
	    right = Max_Xpixel - 1;
	    left = Cxsize * 8;
	    bottom = (ypixel - (right - left)) / 2;
	    top = bottom + (right - left);

	    offset = (1.0 - ((double)xpixel / (double)ypixel)) / 2.0;
	    offset *= (double)xpixel;
	    tickx[0] = bottom - (Tick * 2);
	    tickx[1] = bottom;
	    tickx[2] = top + (Tick * 2);
	    tickx[3] = top;
	    ticky[0] = right - dbltoint(offset);
	    ticky[1] = left + dbltoint(offset);

	    dpixel = xpixel = ypixel = (right - left) - (2 * (Tick + 1));
	}

	xorigin = left + Tick + 1;
	yorigin = bottom + Tick + 1;

	pixaddrs(xaddrs, xorigin, xorigin + xpixel);
	pixaddrs(yaddrs, yorigin, yorigin + ypixel);

	dsp_line(left, top, right, top);
	dsp_line(right, top, right, bottom);
	dsp_line(right, bottom, left, bottom);
	dsp_line(left, bottom, left, top);

	gap = SideLength / ((double) xpixel);

	do_value = TRUE;
	offset = 0.0;
	for (y = 0 ; y <= 10 ; y++) {
	    x = dbltoint(offset) + xorigin;

	    dsp_line(x, bottom, x, bottom + Tick);
	    dsp_line(x, top,	x, top	  - Tick);
	    if (do_value) {
		sprintf(line, "%9.6f", RealOrigin + (offset * gap));
		dsp_text(x - (Cxsize * 5), bottom - ((Cysize * 3) / 2), line);
	    }
	    do_value = !do_value;
	    offset += ((double) xpixel / 10.0);
	}

	do_value = TRUE;
	offset = 0.0;
	for (x = 0 ; x <= 10 ; x++) {
	    y = dbltoint(offset) + yorigin;

	    dsp_line(left,  y, left  + Tick, y);
	    dsp_line(right, y, right - Tick, y);
	    if (do_value) {
		sprintf(line, "%9.6f", ImagOrigin + (offset * gap));
		dsp_text(left - (Cxsize * 10), y - (Cysize / 3), line);
	    }
	    do_value = !do_value;
	    offset += ((double) xpixel / 10.0);
	}

	for (y = 0 ; y < 2 ; y++)
	    for (x = 0 ; x < 4 ; x += 2)
		dsp_line(tickx[x], ticky[y], tickx[x+1], ticky[y]);
}

pixaddrs(array, minadr, maxadr)
	register int	array[], minadr, maxadr;
/*
 * Given the min/max addresses and the number display
 * pixels on the screen (in "dpixel") calculate the screen
 * address for each pixel in the pixel-file array.
 *
 * Side-effect: if the distance between min and max is less than
 * "dpixel", the addresses will be "scaled" towards the middle.
 * (Ie, high and low pixels will be lopped off.)
 */
{
	register pixel;
	double	 factor;		/* Screen pixels per file pixel */
	double	 curadr;

	factor = (double) dpixel / (double) Npixel;
	curadr = (double) ((minadr - dpixel) + maxadr) / 2.0;

	for (pixel = 0 ; pixel < Npixel ; pixel++) {
		register addr = dbltoint(curadr);
		if (addr < minadr || addr >= maxadr)
			array[pixel] = -1;
		else
			array[pixel] = addr;
		curadr += factor;
	}
}

interactive()
{
	if (isatty(fileno(stdin)))
	    scr_clear();
	if (!getstring(1, "Input filename", filename, DEF_FILENAME))
	    return FALSE;
	return TRUE;
}

stall()
{
	dsp_text(0, 0, "Press return to continue");
	dsp_done();
	gets(line);
	dsp_finis();
}
SHAR_EOF
if test -f 'man4100.c'
then
	echo shar: over-writing existing file "'man4100.c'"
fi
cat << \SHAR_EOF > 'man4100.c'
/* $Header: man4100.c,v 1.2 85/09/18 23:27:42 mikee Exp $
**
**  Tektronix 4100 graphics terminal commands, constants and macros.
**
**  This file is designed to be included into a source file which invokes
**  the defined 4100-series commands.  Unless "SLOW" is defined, most of the
**  commands will be compiled as macros for speed.
**
**  Mike Edmonds - 9/85
**
**	$Log:	man4100.c,v $
**	    Revision 1.2  85/09/18  23:27:42  mikee
**	    Added code to pxraster to handle 8 bit pixels.
**	    
**	    Revision 1.1  85/09/16  15:48:41  mikee
**	    Initial revision
**	    
*/

#define ON	1		/* Mode switches		*/
#define OFF	0
#define ANSI	1
#define TEK	0


/*
 * Convert from pixel number to logical address and back.
 */
#ifndef SLOW
#define adrconv(adr,in,out)	( (((adr) * (out)) + ((out) / 2)) / (in) )
#define xpixtoaddr(pix)		adrconv((pix), MAX_XPIXEL, MAX_XADDR)
#define ypixtoaddr(pix)		adrconv((pix), MAX_YPIXEL, MAX_YADDR)
#define xaddrtopix(adr)		adrconv((adr), MAX_XADDR, MAX_XPIXEL)
#define yaddrtopix(adr)		adrconv((adr), MAX_YADDR, MAX_YPIXEL)
#else	SLOW
xpixtoaddr(pix)
	int	pix;
{
	return (((pix * MAX_XADDR) + (MAX_XADDR / 2)) / MAX_XPIXEL);
}
ypixtoaddr(pix)
	int	pix;
{
	return (((pix * MAX_YADDR) + (MAX_YADDR / 2)) / MAX_YPIXEL);
}
xaddrtopix(adr)
	int	adr;
{
	return (((adr * MAX_XPIXEL) + (MAX_XPIXEL / 2)) / MAX_XADDR);
}
yaddrtopix(adr)
	int	adr;
{
	return (((adr * MAX_YPIXEL) + (MAX_YPIXEL / 2)) / MAX_YADDR);
}
#endif

/*
 * Switch terminal into various modes.
 */
#ifndef SLOW
#define code(sw)		{ fputs("\033%!", stdout); encode(sw); }
#define vector_mode()		  putchar('\035')
#define alpha_mode()		  putchar('\037')
#else	SLOW
code()
	int	sw;
{
	fputs("\033%!0", stdout);
	encode(sw);
}
vector_mode()
{
	putchar('\035');
}
alpha_mode()
{
	putchar('\037');
}
#endif	SLOW

/*
 * Turn dialog area on and off and clear graphics region.
 */
#ifndef SLOW
#define davisibility(sw)	{ fputs("\033LV", stdout); encode(sw); }
#define page()			  fputs("\033\014", stdout)
#else	SLOW
davisibility(sw)
	int	sw;
{
	fputs("\033LV1", stdout);
	encode(sw);
}
page()
{
	fputs("\033\014", stdout);
}
#endif	SLOW

/*
 * Cancel whatever's going on.
 */
#ifndef SLOW
#define cancel()		  fputs("\033KC", stdout)
#else	SLOW
cancel()
{
	fputs("\033KC", stdout);
}
#endif	SLOW

/*
 * Set color maps.
 */
#ifndef SLOW
#define cmode(spec, over, gray) { fputs("\033TM", stdout); \
				  encode(spec); encode(over); encode(gray); }
#define cmap(idx, hue, light, satur) \
				{ fputs("\033TG", stdout); \
				  encode(1); encode(4); encode(idx); \
				  encode(hue); encode(light); encode(satur); }
#else	SLOW
cmode(spec, overlay, gray)		/* set color definition mode */
	int	spec, overlay, gray;
{
	fputs("\033TM", stdout);
	encode(spec);
	encode(overlay);
	encode(gray);
}
cmap(index, hue, light, satur)		/* set surface color map */
	int	index, hue, light, satur;
{
	fputs("\033TG", stdout);
	encode(1);
	encode(4);
	encode(index);
	encode(hue);
	encode(light);
	encode(satur);
}
#endif	SLOW

/*
 * Change line style and color.
 */
#ifndef SLOW
#define linestyle(style)	{ fputs("\033MV", stdout); \
				  encode(style); }
#define lineindex(index)	{ fputs("\033ML", stdout); \
				  encode(index); }
#else	SLOW
linestyle(style)
	int	style;
{
	fputs("\033MV", stdout);
	encode(style);
}
lineindex(index)
	int	index;
{
	fputs("\033ML", stdout);
	encode(index);
}
#endif	SLOW

/*
 * Build panels.
 */
#ifndef SLOW
#define fillpattern(ptrn)	{ fputs("\033MP", stdout); \
				  encode(ptrn); }
#define beginpanel(x,y,border)	{ fputs("\033LP", stdout); \
				  encode_xy(x, y); encode(border); }
#define endpanel()		{ fputs("\033LE", stdout); }
#else	SLOW
fillpattern(ptrn)			/* define a fill pattern */
	int	ptrn;
{
	fputs("\033MP", stdout);
	encode(ptrn);
}
beginpanel(x, y, border)		/* begin a panel definition */
	int	x, y, border;
{
	fputs("\033LP", stdout);
	encode_xy(x, y);
	encode(border);
}
endpanel()				/* end a panel definition */
{
	fputs("\033LE", stdout);
}
#endif	SLOW

/*
 * Display graphtext.
 */
#ifndef SLOW
#define gtindex(index)		{ fputs("\033MT", stdout); \
				  encode(index); }
#define gtprecision(prec)	{ fputs("\033MQ", stdout); \
				  encode(prec); }
#define gtsize(wd, hi, sp)	{ fputs("\033MC", stdout); \
				  encode(wd); encode(hi); encode(sp); }
#define gamode(mode)		{ fputs("\033MG", stdout); \
				  encode(mode); }
#define gtext(str)		{ fputs("\033LT", stdout); \
				  encode(strlen(str)); fputs(str, stdout); }
#else	SLOW
gtindex(index)				/* set text color */
	int	index;
{
	fputs("\033MT", stdout);
	encode(index);
}
gtprecision(prec)			/* define precision */
	int	prec;
{
	fputs("\033MQ", stdout);
	encode(prec);
}
gtsize(wide, high, space)		/* define text size */
	int	wide, high, space;
{
	fputs("\033MC", stdout);
	encode(wide);
	encode(high);
	encode(space);
}
gamode(mode)				/* set writing mode */
	int	mode;
{
	fputs("\033MG", stdout);
	encode(mode);
}
gtext(str)				/* display a string */
	char	*str;
{
	fputs("\033LT", stdout);
	encode(strlen(str));
	fputs(str, stdout);
}
#endif	SLOW

/*
 * Set surface definition.
 */
sdefinition(surfaces, bits)
	int	surfaces, bits[];
{
	register count;

	fputs("\033RD", stdout);
	encode(surfaces);
	for (count = 0; count < surfaces ; count++) {
		encode(bits[count]);
	}
	fflush(stdout);			/* terminal takes time to handle this */
	sleep(2);
}

/*
 * Move and draw commands.
 */
#ifndef SLOW
#define move(x,y)		{ fputs("\033LF", stdout); encode_xy(x, y); }
#define draw(x,y)		{ fputs("\033LG", stdout); encode_xy(x, y); }
#else	SLOW
move(x,y)
	int	x, y;
{
	fputs("\033LF", stdout);
	encode_xy(x, y);
}
draw(x,y)
	int	x, y;
{
	fputs("\033LG", stdout);
	encode_xy(x, y);
}
#endif	SLOW

/*
 * Pixel operations.
 */
#ifndef SLOW
#define pxbegin(surf, alu, bits) \
				{ fputs("\033RU", stdout); \
				  encode(surf); encode(alu); encode(bits); }
#define pxposition(x, y)	{ fputs("\033RH", stdout); \
				  encode_xy(x,y); }
#define pxrectangle(ux,uy, lx,ly, index) \
				{ fputs("\033RR", stdout); \
				  encode_xy(ux,uy); encode_xy(lx,ly); \
				  encode(index); }
#define pxviewport(ux,uy, lx,ly) \
				{ fputs("\033RS", stdout); \
				  encode_xy(ux,uy); encode_xy(lx,ly); }
#else	SLOW
pxbegin(surface, alumode, bits)		/* begin pixel operations */
	int	surface, alumode, bits;
{
	fputs("\033RU", stdout);
	encode(surface);
	encode(alumode);
	encode(bits);
}
pxposition(x, y)			/* set pixel beam position */
	int	x, y;
{
	fputs("\033RH", stdout);
	encode_xy(x,y);
}
pxrectangle(ux,uy, lx,ly, index)	/* rectangle fill */
	int	ux,uy, lx,ly, index;
{
	fputs("\033RR", stdout);
	encode_xy(ux,uy);
	encode_xy(lx,ly);
	encode(index);
}
pxviewport(ux,uy, lx,ly)		/* set pixel viewport */
	int	ux,uy, lx,ly;
{
	fputs("\033RS", stdout);
	encode_xy(ux,uy);
	encode_xy(lx,ly);
}
#endif	SLOW

/*
 * Raster write.
 */
pxraster(pixels, indexes)
	int	pixels, indexes[];
{
	register pixel = 0;
	if (pixels <= 0)
		return;
	fputs("\033RP", stdout);
	encode(pixels);

#if (BITS == 1)
#define pxrasterlength(pixels)	(((pixels) + 5) / 6)

	encode(pxrasterlength(pixels));
	while (pixel < pixels) {
		register unsigned word = 0, bit;
		for (bit = 0 ; bit < 6 ; bit++) {
			word <<= 1;
			if (pixel < pixels)
				word |= indexes[pixel++] & 0x1;
		}
		putchar(word + 0x20);
	}
#endif (BITS == 1)

#if (BITS == 2)
#define pxrasterlength(pixels)	(((pixels) + 2) / 3)

	encode(pxrasterlength(pixels));
	while (pixel < pixels) {
		register unsigned word = 0, pair;
		for (pair = 0 ; pair < 3 ; pair++) {
			word <<= 2;
			if (pixel < pixels)
				word |= indexes[pixel++] & 0x3;
		}
		putchar(word + 0x20);
	}
#endif (BITS == 2)

#if (BITS == 3)
#define pxrasterlength(pixels)	(((pixels) + 1) / 2)

	encode(pxrasterlength(pixels));
	while (pixel < pixels) {
		register unsigned word = indexes[pixel++] & 0x7;
		word <<= 3;
		if (pixel < pixels)
			word |= indexes[pixel++] & 0x7;
		putchar(word + 0x20);
	}
#endif (BITS == 3)

#if (BITS == 4)
#define pxrasterlength(pixels)	((((pixels) * 4) + 5) / 6)

	encode(pxrasterlength(pixels));
	while (pixel < pixels) {
		register unsigned word = indexes[pixel++] & 0xf;
		word <<= 2;
		if (pixel < pixels) {
			register unsigned temp = indexes[pixel++];
			word |= (temp >> 2) & 0x3;
			putchar(word + 0x20);
			word = (temp & 0x3) << 4;
			if (pixel < pixels)
				word |= indexes[pixel++] & 0xf;
		}
		putchar(word + 0x20);
	}
#endif (BITS == 4)

#if (BITS == 6)
#define pxrasterlength(pixels)	(pixels)

	encode(pxrasterlength(pixels));
	while (pixel < pixels) {
		putchar((indexes[pixel++] & 0x3f) + 0x20);
	}
#endif (BITS == 6)

#if (BITS == 8)
#define pxrasterlength(pixels)	((((pixels) * 8) + 5) / 6)

	encode(pxrasterlength(pixels));
	while (pixel < pixels) {
		register unsigned word = indexes[pixel++] & 0xff;
		putchar((word >> 2) + 0x20);
		word = (word << 4) & 0x30;
		if (pixel < pixels) {
			register unsigned temp = indexes[pixel++] & 0xff;
			word |= temp >> 4;
			putchar(word + 0x20);
			word = (temp << 2) & 0x3c;
			if (pixel < pixels) {
				temp = indexes[pixel++] & 0xff;
				word |= temp >> 6;
				putchar(word + 0x20);
				word = temp & 0x3f;
			}
		}
		putchar(word + 0x20);
	}
#endif (BITS == 8)
}

/*
 * Runlength write.
 */
pxrunlength(runs, lengths, indexes)
	int	runs, lengths[], indexes[];
{
	register run;
	if (runs > 0) {
		fputs("\033RL", stdout);
		encode(runs);
		for (run = 0 ; run < runs ; run++)
			encode((lengths[run] << BITS) + indexes[run]);
	}
}

/*
 * Convert xy pair to terminal encoded syntax.
 */
encode_xy(x,y)
	register x,y;
{
	static	lasthix = 0xfff,
		lasthiy = 0xfff,
		lastloy = 0xfff,
		lastext = 0xfff;
	int	hix, lox, hiy, loy, ext;

	if (x < 0)			x = 0;
	else if (x >= MAX_XADDR)	x = MAX_XADDR - 1;
	if (y < 0)			y = 0;
	else if (y >= MAX_YADDR)	y = MAX_YADDR - 1;

	hix = x & 0xf80;
	lox = x & 0x07c;
	hiy = y & 0xf80;
	loy = y & 0x07c;
	ext = ((y & 0x03) << 2) | (x & 0x03);

	if (hiy != lasthiy) {
		lasthiy = hiy;
		putchar( (hiy >> 7) | 0x20 );
	}

	if (ext != lastext) {
		lastext = ext;
		putchar( ext | 0x60 );
		lastloy = loy;
		putchar( (loy >> 2) | 0x60 );

		if (hix != lasthix) {
			lasthix = hix;
			putchar( (hix >> 7) | 0x20 );
		}

	} else if (hix != lasthix) {
		lastloy = loy;
		putchar( (loy >> 2) | 0x60 );
		lasthix = hix;
		putchar( (hix >> 7) | 0x20 );

	} else if (loy != lastloy) {
		lastloy = loy;
		putchar( (loy >> 2) | 0x60 );
	}

	putchar( (lox >> 2) | 0x40 );
}

/*
 * Convert integer parameter to terminal syntax.
 */
encode(i)
	register i;
{
	char	buffer[50];
	register char	*bp = &buffer[49];

	*bp-- = '\0';
	if (i < 0) {
		i = -i;
		*bp-- = (i & 0xf) | 0x20;
	} else {
		*bp-- = (i & 0xf) | 0x30;
	}

	i >>= 4;
	while (i > 0) {
		*bp-- = (i & 0x3f) | 0x40;
		i >>= 6;
	}
	while (*++bp)
		putchar(*bp);

}
SHAR_EOF
if test -f 'man4105.c'
then
	echo shar: over-writing existing file "'man4105.c'"
fi
cat << \SHAR_EOF > 'man4105.c'
#ifndef lint
static char *RCSid = "$Header: man4105.c,v 1.3 85/09/18 14:23:37 mikee Exp $";
#endif

/* $Log:	man4105.c,v $
 *	Revision 1.3  85/09/18  14:23:37  mikee
 *	Changed global variable names, corrected MAX_YADDR and added
 *	dsp_rect().
 *	
 *	Revision 1.2  85/09/03	17:23:32  mikee
 *	Re-arranged spectrum order.
 *
 *	Revision 1.1  85/08/26	15:10:43  mikee
 *	Initial revision
 *
 */

/*
 * Display Mandelbrot set pixels.
 *
 * This version has been modified to support a Tektronix 4105
 * graphics display terminal.  It uses the 4105's "move" and
 * "draw" commands.  Consequently, it can handle most other
 * 41-series terminals with only minor mods.
 */

#include	"mandefs.h"


#define MAX_XPIXEL	480	/* Pixels in the display		*/
#define MAX_YPIXEL	360
#define MAX_XADDR	4096	/* Addresses on the display		*/
#define MAX_YADDR	3133
#define TICK		4	/* Length of boarder tick-marks		*/
#define CXSIZE		6	/* Character width			*/
#define CYSIZE		11	/* Character height			*/
#define LINE_DENS	1	/* Density of display's border (if any)	*/
#define BITS		3	/* Number bits needed to encode color	*/

static	int	Spectrum[] =	/* 4105 color indexes in spectrum order	*/
	{ 0, 6, 2, 7, 3, 5, 4, 1, 0 };
#define GRAY_SCALE	( sizeof(Spectrum) / sizeof(int) )


/*
 * Globalize (most of) these values for the main display code.
 */
int	Max_Xpixel = MAX_XPIXEL;
int	Max_Ypixel = MAX_YPIXEL;
int	Gray_Scale = GRAY_SCALE;
int	Tick = TICK;
int	Cxsize = CXSIZE;
int	Cysize = CYSIZE;


/*
 * Display routines:
 *	dsp_init()		Initialize for bit-map writing, clear screen.
 *	dsp_done()		Done writing to the bit-map (don't clear)
 *	dsp_finis()		All done (about to exit to o.s., clear screen)
 *	dsp_move(x,y)		Move bitmap cursor to to this row-column
 *	dsp_rect(d,len,wide)	Draw a rectangle at current location
 *	dsp_draw(d,len)		Draw a horizontal line of the selected density
 *	dsp_endline()		End a horizontal line of pixels
 *	dsp_text(x,y,t)		Write text string from this position
 *	dsp_line(xf,yf,xt,yt)	Draw line from [xf,yf] to [xt,yt]
 */
#include	"man4100.c"

static	Last_X, Last_Y;			/* last known beam coordinates */


dsp_init()
/*
 * Start writing to the bitmap display.
 */
{
	code(TEK);			/* switch to tek mode */
	davisibility(OFF);		/* blank out dialog area */
	page();				/* clear the graphics region */
	colormap();			/* initialize color map */
	linestyle(0);			/* solid lines */
}


dsp_done()
/*
 * Stop writing to the bitmap (don't clear it).
 */
{
	alpha_mode();			/* take out of vector mode */
	fflush(stdout);
}


dsp_finis()
/*
 * Exiting, clear display.
 */
{
	alpha_mode();			/* take out of vector mode */
	davisibility(ON);		/* bring back dialog area */
	code(ANSI);			/* put back in ansi mode */
	fflush(stdout);
}


dsp_move(x, y)
int		x, y;
/*
 * Move bitmap cursor to this position.
 * (Since we're using "move" and "draw" commands rather than pixel
 * operations, we have to convert the given address from pixel mode
 * back to its logical address equivalent.)
 */
{
	move(xpixtoaddr(Last_X = x), ypixtoaddr(Last_Y = y));
}


dsp_rect(density, length, width)
int		density;
int		length;
int		width;
/*
 * Draw a rectangle of this density.
 * On entrance, cursor is at the lower-left corner.
 * Leave the cursor at the lower-right.
 */
{
	int	new_top	   = Last_Y + (width - 1);
	int	new_bottom = Last_Y;
	int	new_left   = Last_X;
	int	new_right  = Last_X + length;

	Last_X = new_right;

	new_top	   = ypixtoaddr(new_top);
	new_bottom = ypixtoaddr(new_bottom);
	new_left   = xpixtoaddr(new_left);
	new_right  = xpixtoaddr(new_right);

	fillpattern(-(Spectrum[density % GRAY_SCALE]));
	beginpanel(new_left, new_bottom, 0);
	vector_mode();
	encode_xy(new_left, new_top);
	encode_xy(new_right, new_top);
	encode_xy(new_right, new_bottom);
	alpha_mode();
	endpanel();
}


dsp_draw(density, length)
int		density;
int		length;
/*
 * Draw a line of this density.
 * On entrance, cursor is at the left edge of the line.
 * Leave the cursor at the end of the line.
 */
{
	lineindex(Spectrum[density % GRAY_SCALE]);
	draw(xpixtoaddr(Last_X += length), ypixtoaddr(Last_Y));
}


dsp_endline()
/*
 * End a horizontal line.
 */
{
	/* dummy function */
}


dsp_text(x, y, text)
int		x, y;
char		*text;
/*
 * Display a string at the given location.
 */
{
	gtindex(LINE_DENS);		/* set text color */
	gamode(1);			/* overlay chars on each other */
	gtsize(0, 50, 0);		/* set character size */
	dsp_move(x, y);			/* position beam */
	gtext(text);			/* do it */
}


dsp_line(xfrom, yfrom, xto, yto)
int		xfrom, yfrom;
int		xto,   yto;
/*
 * Draw a line
 */
{
	lineindex(LINE_DENS);
	move(xpixtoaddr(xfrom), ypixtoaddr(yfrom));
	draw(xpixtoaddr(xto), ypixtoaddr(yto));
	Last_X = xto;
	Last_Y = yto;
}


static
colormap()
/*
 * Initialize the terminal's color map.
 */
{
	cmap(00,   0,   0,   0);	/* black (clear) */
	cmap(01,   0, 100,   0);	/* white */
	cmap(02, 120,  75, 100);	/* red */
	cmap(03, 240,  75, 100);	/* green */
	cmap(04,   0,  75, 100);	/* blue */
	cmap(05, 300,  44, 100);	/* cyan */
	cmap(06,  60,  44, 100);	/* magenta */
	cmap(07, 180,  44, 100);	/* yellow */
}
SHAR_EOF
if test -f 'man4107.c'
then
	echo shar: over-writing existing file "'man4107.c'"
fi
cat << \SHAR_EOF > 'man4107.c'
#ifndef lint
static char *RCSid = "$Header: man4107.c,v 1.3 85/09/18 14:23:49 mikee Exp $";
#endif

/* $Log:	man4107.c,v $
 *	Revision 1.3  85/09/18  14:23:49  mikee
 *	Changed global variable names, corrected MAX_YADDR def, added
 *	dsp_rect() and converted to array-style runlength and raster
 *	writes.
 *	
 *	Revision 1.2  85/09/03	17:24:21  mikee
 *	Re-arranged spectrum order.
 *
 *	Revision 1.1  85/08/26	15:10:44  mikee
 *	Initial revision
 *
 */

/*
 * Display Mandelbrot set pixels.
 *
 * This version has been modified to support a Tektronix 4107
 * graphics display terminal.  It uses the 4107 pixel operations
 * (which are MUCH faster then the corresponding "move" and "draw"
 * commands).  Consequently, it will handle most other 41-series
 * terminals with only minor mods.
 */

#include	"mandefs.h"


#define MAX_XPIXEL	640	/* Pixels in the display		*/
#define MAX_YPIXEL	480
#define MAX_XADDR	4096	/* Addresses on the display		*/
#define MAX_YADDR	3133
#define TICK		4	/* Length of boarder tick-marks		*/
#define CXSIZE		8	/* Character width			*/
#define CYSIZE		14	/* Character height			*/
#define LINE_DENS	1	/* Density of display's border (if any) */
#define BITS		4	/* Number bits needed to encode color 	*/

static	int	Spectrum[] = 	/* 4107 color indexes in spectrum order	*/
	{ 0, 9, 6, 10, 2, 11, 7, 12, 3, 13, 5, 14, 4, 15, 1, 9, 0 };
#define GRAY_SCALE	( sizeof(Spectrum) / sizeof(int) )


/*
 * Globalize (most of) these values for the main display code.
 */
int	Max_Xpixel = MAX_XPIXEL;
int	Max_Ypixel = MAX_YPIXEL;
int	Gray_Scale = GRAY_SCALE;
int	Tick = TICK;
int	Cxsize = CXSIZE;
int	Cysize = CYSIZE;


/*
 * Display routines:
 *	dsp_init()		Initialize for bit-map writing, clear screen.
 *	dsp_done()		Done writing to the bit-map (don't clear)
 *	dsp_finis()		All done (about to exit to o.s., clear screen)
 *	dsp_move(x,y)		Move bitmap cursor to to this row-column
 *	dsp_rect(d,len,wide)	Draw a rectangle at current location
 *	dsp_draw(d,len)		Draw a horizontal line of the selected density
 *	dsp_endline()		End a horizontal line of pixels
 *	dsp_text(x,y,t)		Write text string from this position
 *	dsp_line(xf,yf,xt,yt)	Draw line from [xf,yf] to [xt,yt]
 */
#include	"man4100.c"

static	Last_X, Last_Y;		/* Last known beam coordinates		*/

static	Runs;			/* Pixel runs (in RunLengths)		*/
static	Pixels;			/* Individual pixels (in Densities)	*/
static	RunLengths[MAX_XPIXEL]; /* Lengths of the pixel runs		*/
static	Densities[MAX_XPIXEL];	/* Run or pixel densities (indexes)	*/


dsp_init()
/*
 * Start writing to the bitmap display.
 */
{
	code(TEK);			/* switch to tek mode */
	davisibility(OFF);		/* blank out dialog area */
	page();				/* clear the graphics region */
	colormap();			/* initialize color map */
	linestyle(0);			/* solid lines */
	pxbegin(1, 11, BITS);		/* ready terminal for pixel ops */
	pxviewport(0, 0, (MAX_XPIXEL - 1), (MAX_YPIXEL - 1));

	Runs = Pixels = 0;		/* initialize static memory */
}


dsp_done()
/*
 * Stop writing to the bitmap (don't clear it).
 */
{
	alpha_mode();			/* take out of vector mode */
	fflush(stdout);
}


dsp_finis()
/*
 * Exiting, clear display.
 */
{
	alpha_mode();			/* take out of vector mode */
	davisibility(ON);		/* bring back dialog area */
	code(ANSI);			/* put back in ansi mode */
	fflush(stdout);
}


dsp_move(x, y)
int		x, y;
/*
 * Move bitmap cursor to this position.
 */
{
	pxposition((Last_X = x), (Last_Y = y));
}


dsp_rect(density, length, width)
int		density;
int		length;
int		width;
/*
 * Draw a rectangle of this density.
 * On entrance, cursor is at the lower-left corner.
 * Leave the cursor at the lower-right.
 */
{
	length += Last_X;
	width  += Last_Y - 1;
	pxrectangle(Last_X, width, length, Last_Y,
		Spectrum[density % GRAY_SCALE]);
	Last_X = length;
}


dsp_draw(density, length)
int		density;
int		length;
/*
 * Draw a line of this density.
 * On entrance, cursor is at the left edge of the line.
 * Leave the cursor at the end of the line.
 */
{
	int	rastlen;

	if ((rastlen = pxrasterlength(length)) > 2) {
		if (Pixels > 0) {
			if (rastlen < 8)	/* hysteresis */
				goto chgtopixels;
			pxraster(Pixels, Densities);
			Pixels = 0;
		}
		RunLengths[Runs] = length;
		Densities[Runs]	 = Spectrum[density % GRAY_SCALE];
		if (++Runs >= MAX_XPIXEL) {
			pxrunlength(Runs, RunLengths, Densities);
			Runs = 0;
		}

	} else if (length > 0) {
		if (Runs > 0) {
			pxrunlength(Runs, RunLengths, Densities);
			Runs = 0;
		}
chgtopixels:
		density = Spectrum[density % GRAY_SCALE];
		do {
			Densities[Pixels] = density;
			if (++Pixels >= MAX_XPIXEL) {
				pxraster(Pixels, Densities);
				Pixels = 0;
			}
		} while (--length > 0);
	}
	Last_X += length;
}


dsp_endline()
/*
 * End a horizontal line.  Flush remaining runs or pixels.
 */
{
	if (Runs > 0) {
		pxrunlength(Runs, RunLengths, Densities);
		Runs = 0;
	} else if (Pixels > 0) {
		pxraster(Pixels, Densities);
		Pixels = 0;
	}
}


dsp_text(x, y, text)
int		x, y;
char		*text;
/*
 * Display a string at the given location.
 */
{
	gtindex(LINE_DENS);		/* set text color */
	gamode(1);			/* overlay chars on each other */
	gtsize(0, 50, 0);		/* set character size */
					/* position beam */
	move(xpixtoaddr(x), ypixtoaddr(y));
	gtext(text);			/* do it */
}


dsp_line(xfrom, yfrom, xto, yto)
int		xfrom, yfrom;
int		xto,   yto;
/*
 * Draw a line
 */
{
	lineindex(LINE_DENS);
	move(xpixtoaddr(xfrom), ypixtoaddr(yfrom));
	draw(xpixtoaddr(xto), ypixtoaddr(yto));
}


static
colormap()
/*
 * Initialize the terminal's color map.
 */
{
	cmode(3, 0, 0);
	cmap(00,   0,   0,   0);	/* black (clear) */
	cmap(01,   0, 100,   0);	/* white */
	cmap(02, 120,  75, 100);	/* red */
	cmap(03, 240,  75, 100);	/* green */
	cmap(04,   0,  75, 100);	/* blue */
	cmap(05, 300,  44, 100);	/* cyan */
	cmap(06,  60,  44, 100);	/* magenta */
	cmap(07, 180,  44, 100);	/* yellow */
	cmap(08,   0,  50,   0);	/* dark-gray */
	cmap(09,   0,  75,   0);	/* light-gray */
	cmap(10,  82,  62,  92);	/* red-magenta */
	cmap(11, 158,  62, 100);	/* orange */
	cmap(12, 202,  62,  92);	/* grean-yellow */
	cmap(13, 278,  62, 100);	/* green-cyan */
	cmap(14, 322,  62,  92);	/* blue-cyan */
	cmap(15,  38,  62, 100);	/* blue-magenta */
}
SHAR_EOF
if test -f 'man4115.c'
then
	echo shar: over-writing existing file "'man4115.c'"
fi
cat << \SHAR_EOF > 'man4115.c'
#ifndef lint
static char *RCSid = "$Header: man4115.c,v 1.3 85/09/18 23:28:25 mikee Exp $";
#endif

/* $Log:	man4115.c,v $
 *	Revision 1.3  85/09/18  23:28:25  mikee
 *	Altered spectrum generation algorithm
 *	
 *	Revision 1.2  85/09/16  16:40:14  mikee
 *	Changed global variable names, corrected MAX_YADDR def, added
 *	dsp_rect() and converted to array-style runlength and raster
 *	writes.
 *	
 *	Revision 1.1  85/09/09	00:35:49  mikee
 *	Initial revision
 *
 */

/*
 * Display Mandelbrot set pixels.
 *
 * This version has been modified to support a Tektronix 4115
 * graphics display terminal.  It uses the 4115 pixel operations
 * (which are MUCH faster then the corresponding "move" and "draw"
 * commands).  Consequently, it will handle most other 41-series
 * terminals with only minor mods.
 */

#include	"mandefs.h"


#define MAX_XPIXEL	1280	/* Pixels in the display		*/
#define MAX_YPIXEL	978
#define MAX_XADDR	4096	/* Addresses on the display		*/
#define MAX_YADDR	3133
#define GRAY_SCALE	253	/* Density ranges			*/
#define TICK		8	/* Length of boarder tick-marks		*/
#define CXSIZE		10	/* Character width			*/
#define CYSIZE		20	/* Character height			*/
#define BITS		8	/* number bits needed to encode color	*/

/*
 * Globalize (most of) these values for the main display code.
 */
int	Max_Xpixel = MAX_XPIXEL;
int	Max_Ypixel = MAX_YPIXEL;
int	Gray_Scale = GRAY_SCALE;
int	Tick = TICK;
int	Cxsize = CXSIZE;
int	Cysize = CYSIZE;


/*
 * Display routines:
 *	dsp_init()		Initialize for bit-map writing, clear screen.
 *	dsp_done()		Done writing to the bit-map (don't clear)
 *	dsp_finis()		All done (about to exit to o.s., clear screen)
 *	dsp_move(x,y)		Move bitmap cursor to to this row-column
 *	dsp_rect(d,len,wide)	Draw a rectangle at current location
 *	dsp_draw(d,len)		Draw a horizontal line of the selected density
 *	dsp_endline()		End a horizontal line of pixels
 *	dsp_text(x,y,t)		Write text string from this position
 *	dsp_line(xf,yf,xt,yt)	Draw line from [xf,yf] to [xt,yt]
 */
#include	"man4100.c"

static	Last_X, Last_Y;		/* Last known beam coordinates		*/

static	Runs;			/* Pixel runs (in RunLengths)		*/
static	Pixels;			/* Individual pixels (in Densities)	*/
static	RunLengths[MAX_XPIXEL]; /* Lengths of the pixel runs		*/
static	Densities[MAX_XPIXEL];	/* Run or pixel densities (indexes)	*/


dsp_init()
/*
 * Start writing to the bitmap display.
 */
{
	int	surfaces[1];

	code(TEK);			/* switch to tek mode */
	surfaces[0] = BITS;		/* define surface */
	sdefinition(1, surfaces);
	davisibility(OFF);		/* blank out dialog area */
	page();				/* clear the graphics region */
	colormap();			/* define color map */
	linestyle(0);			/* solid lines */
	pxbegin(1, 11, BITS);		/* ready terminal for pixel ops */
	pxviewport(0, 0, (MAX_XPIXEL - 1), (MAX_YPIXEL - 1));

	Runs = Pixels = 0;		/* initialize static memory */
}


dsp_done()
/*
 * Stop writing to the bitmap (don't clear it).
 */
{
	alpha_mode();			/* take out of vector mode */
	fflush(stdout);
}


dsp_finis()
/*
 * Exiting, clear display.
 */
{
	alpha_mode();			/* take out of vector mode */
	davisibility(ON);		/* bring back dialog area */
	code(ANSI);			/* put back in ansi mode */
	fflush(stdout);
}


dsp_move(x, y)
int		x, y;
/*
 * Move bitmap cursor to this position.
 */
{
	pxposition((Last_X = x), (Last_Y = y));
}


dsp_rect(density, length, width)
int		density;
int		length;
int		width;
/*
 * Draw a rectangle of this density.
 * On entrance, cursor is at the lower-left corner.
 * Leave the cursor at the lower-right.
 */
{
	length += Last_X;
	width  += Last_Y - 1;
	pxrectangle(Last_X, width, length, Last_Y, density % GRAY_SCALE);
	Last_X = length;
}


dsp_draw(density, length)
int		density;
int		length;
/*
 * Draw a line of this density.
 * On entrance, cursor is at the left edge of the line.
 * Leave the cursor at the end of the line.
 */
{
	int	rastlen;

	if ((rastlen = pxrasterlength(length)) > 2) {
		if (Pixels > 0) {
			if (rastlen < 8)	/* hysteresis */
				goto chgtopixels;
			pxraster(Pixels, Densities);
			Pixels = 0;
		}
		RunLengths[Runs] = length;
		Densities[Runs]	 = density % GRAY_SCALE;
		if (++Runs >= MAX_XPIXEL) {
			pxrunlength(Runs, RunLengths, Densities);
			Runs = 0;
		}

	} else if (length > 0) {
		if (Runs > 0) {
			pxrunlength(Runs, RunLengths, Densities);
			Runs = 0;
		}
chgtopixels:
		density %= GRAY_SCALE;
		do {
			Densities[Pixels] = density;
			if (++Pixels >= MAX_XPIXEL) {
				pxraster(Pixels, Densities);
				Pixels = 0;
			}
		} while (--length > 0);
	}
	Last_X += length;
}


dsp_endline()
/*
 * End a horizontal line.  Flush remaining runs or pixels.
 */
{
	if (Runs > 0) {
		pxrunlength(Runs, RunLengths, Densities);
		Runs = 0;
	} else if (Pixels > 0) {
		pxraster(Pixels, Densities);
		Pixels = 0;
	}
}


dsp_text(x, y, text)
int		x, y;
char		*text;
/*
 * Display a string at the given location.
 */
{
	gtindex(GRAY_SCALE);		/* set text color */
	gamode(1);			/* overlay chars on each other */
					/* set character size */
	gtsize(CXSIZE * 2, CYSIZE * 2, CXSIZE);
					/* position beam */
	move(xpixtoaddr(x), ypixtoaddr(y));
	gtext(text);			/* do it */
}


dsp_line(xfrom, yfrom, xto, yto)
int		xfrom, yfrom;
int		xto,   yto;
/*
 * Draw a line
 */
{
	lineindex(GRAY_SCALE);
	move(xpixtoaddr(xfrom), ypixtoaddr(yfrom));
	draw(xpixtoaddr(xto), ypixtoaddr(yto));
}



/*
 * Generate a color spectrum.
 */

#define PI		(double)3.1415926535897932384626433
#define torad(deg)	((deg) * (PI / 180.0))

colormap()
{
	double	 angle;
	register color;

	cmode(4, 0, 0);
	cmap(0, 0, 0, 0);
	cmap(GRAY_SCALE, 255, 255, 255);

	angle = torad(105.0);

	for (color = 1 ; color < GRAY_SCALE ; color++) {
		double	red, green, blue, cutline;

		if (angle >= torad(360.0))
			angle  -= torad(360.0);

		cutline = (sin((angle * 6.0) - torad(90.0)) + 1.0) / 3.0;

		blue  = fabs(sin(angle))	        - cutline;
		green = fabs(sin(angle + torad(60.0)))  - cutline;
		red   = fabs(sin(angle + torad(120.0)))	- cutline;
		if (blue  < 0.0)  blue  = 0.0;
		if (green < 0.0)  green = 0.0;
		if (red	  < 0.0)  red   = 0.0;
		blue  *= 255.0 / (1.0 - cutline);
		green *= 255.0 / (1.0 - cutline);
		red   *= 255.0 / (1.0 - cutline);

		cmap(color, dbltoint(red), dbltoint(green), dbltoint(blue));

		angle  += torad(180.0) / (double)(GRAY_SCALE - 1);
	}
}
SHAR_EOF
if test -f 'mancompress.c'
then
	echo shar: over-writing existing file "'mancompress.c'"
fi
cat << \SHAR_EOF > 'mancompress.c'
#ifndef lint
static char *RCSid = "$Header: mancompress.c,v 1.2 85/09/16 18:21:23 mikee Exp $";
#endif

/* $Log:	mancompress.c,v $
 *	Revision 1.2  85/09/16  18:21:23  mikee
 *	Changed global variable names and eliminated PIXREC ref's.
 *	
 *	Revision 1.1  85/09/09	00:36:33  mikee
 *	Initial revision
 *
 */

/*
 * This program can be used to compress an existing pixel file
 * using the "latest and greatest" version of the "manfiles"
 * compression techniques.
 *
 * Mike Edmonds - 9/6
 *
 * Usage: mancompress [-v] [input-filename-prefix] [output-filename-prefix]
 *	-v	verify output against input
 *		(default = off)
 *	prefix	pixel and histogram file prefix
 *		(default = "mandel" and "mandel.new")
 */

#include	"mandefs.h"

static	char	*Progname;		/* Program name			*/

static	int	 Verify = FALSE;	/* Verify flag			*/

static	char	*InFile = NULL;		/* File name prefixes		*/
static	char	*OutFile = NULL;

static	short	PixArray[MAX_NPIXEL][MAX_NPIXEL];

#define DEFINPUT	"mandel"
#define DEFOUTPUT	"mandel.new"

main(argc, argv)
	int	 argc;
	char	*argv[];
{
	char	stdoutbuf[BUFSIZ];

	setbuf(stdout, stdoutbuf);	/* do explicit output buffering */

	Progname = *argv;

	getargs(argc, argv);

	if (compress()) {
		if (Verify && verify() != TRUE)
			exit(EOF);
		exit(0);
	}
	exit(EOF);
}

getargs(argc, argv)
	int	 argc;
	char	*argv[];
{
	while (--argc) {
		argv++;

		if (strcmp(*argv, "-v") == 0)
			Verify = TRUE;

		else if (InFile == NULL)
			InFile = *argv;

		else if (OutFile == NULL)
			OutFile = *argv;

		else {
			char	err[BUFSIZ];

			sprintf(err, "Option `%s' invalid", *argv);
			perror(err);
			sprintf(err,
		"Usage: %s [-v] [input-prefix] [output-prefix]", Progname);
			perror(err);
			exit(EOF);
		}
	}
	if (InFile == NULL)
		InFile = DEFINPUT;
	if (OutFile == NULL)
		OutFile = DEFOUTPUT;
}

compress()
/*
 * Read the input file into memory and write it out again.
 *	(Reading the whole pixel array into memory is necessary because
 *	the "manfiles" functions aren't able to handle two files at once
 *	and I don't feel like fixing them.)
 */
{
	register x, y;

	fprintf(stderr, "Input phase starting.\n");

	if ((hisopen(InFile, 'r') != TRUE)
	 || (hisread() != TRUE)
	 || (hisclose() != TRUE)
	 || (pixopen(InFile, 'r') != TRUE))
		return FALSE;

	for (y = 0 ; y < Npixel ; y++) {
		for (x = 0 ; x < Npixel ; ) {
			if (pixread(y, x) != TRUE)
				return FALSE;
			while (PixCount-- > 0)
				PixArray[y][x++] = PixValue;
		}
	}

	if (pixclose() != TRUE)
		return FALSE;

	fprintf(stderr, "Input phase completed.\n");
	fprintf(stderr, "Output phase starting.\n");

	if ((hisopen(OutFile, 'w') != TRUE)
	 || (pixopen(OutFile, 'w') != TRUE))
		return FALSE;

	for (y = 0 ; y < Npixel ; y++) {
		for (x = 0 ; x < Npixel ; x++)
			pixwrite(PixArray[y][x]);
		pixflush();
	}

	if ((pixclose() != TRUE)
	 || (hiswrite() != TRUE)
	 || (hisclose() != TRUE))
		return FALSE;

	fprintf(stderr, "Output phase completed.\n");

	return TRUE;
}

verify()
/*
 * Read the output file back in and compare it with the original.
 */
{
	register x, y, errcnt;

	fprintf(stderr, "Verify phase starting.\n");

	if (pixopen(OutFile, 'r') != TRUE)
		return FALSE;

	errcnt = 0;
	for (y = 0 ; y < Npixel ; y++) {
		for (x = 0 ; x < Npixel ; ) {
			if (pixread(y, x) != TRUE)
				return FALSE;
			while (PixCount-- > 0) {
				if (PixArray[y][x] != PixValue) {
					fprintf(stderr,
						"\tpixel[%d,%d] differs", y, x);
					fprintf(stderr,
						" - wrote %d", PixArray[y][x]);
					fprintf(stderr,
						", read %d\n", PixValue);
					if (++errcnt > 100)
						break;
				}
				x++;
			}
		}
		if (errcnt > 100) {
			fprintf(stderr, "Too many errors - giving up\n");
			break;
		}
	}

	if (pixclose() != TRUE)
		return FALSE;

	fprintf(stderr, "Verify phase completed.");
	if (errcnt == 0) {
		fprintf(stderr, "  No errors found.\n");
		return TRUE;
	} else {
		fprintf(stderr, "  %d errors found.\n", errcnt);
		return FALSE;
	}
}
SHAR_EOF
if test -f 'manscreen.c'
then
	echo shar: over-writing existing file "'manscreen.c'"
fi
cat << \SHAR_EOF > 'manscreen.c'
#ifndef lint
static char *RCSid = "$Header: manscreen.c,v 1.2 85/09/16 15:49:20 mikee Exp $";
#endif

/* $Log:	manscreen.c,v $
 *	Revision 1.2  85/09/16  15:49:20  mikee
 *	Removed "fcreate" bizarreness.
 *	
 *	Revision 1.1  85/08/26	15:15:10  mikee
 *	Cleaned up code.
 *
 */

/*
 * (Textual) screen handling for Mandelbrot programs.
 * Also prompt/input routines and some other junk.
 */

#include	"mandefs.h"

extern char		line[];		/* General scratch (input line) */

/*
 * Prompt and read (integer/real/complex/string)
 */

getint(row, prompt, result, def_value, max_value)
int		row;
char		*prompt;
int		*result;
int		def_value;
int		max_value;
{
again:	*result = def_value;
	if (isatty(fileno(stdin))) {
	    scr_move(row, 1);
	    scr_eol();
	    printf("%s (0:%d) <%d>: ",
		prompt, max_value, def_value);
	    fflush(stdout);
	}
	if (gets(line) == NULL)
	    return (FALSE);
	if (line[0] != EOS)
	    *result = atoi(line);
	if (*result < 0 || *result > max_value) {
	    printf("\nvalue %d out of range 0 .. %d, try again",
		*result, max_value);
	    scr_eol();
	    goto again;
	}
	return (TRUE);
}

int
getdouble(row, prompt, result)
int		row;
char		*prompt;
double		*result;
{
again:	if (isatty(fileno(stdin))) {
	    scr_move(row, 1);
	    scr_eol();
	    printf("%s: ", prompt);
	    fflush(stdout);
	}
	if (gets(line) == NULL)
	    return (FALSE);
	if (line[0] == EOS) {
	    printf("No default permitted, try again\n");
	    goto again;
	}
	*result = atof(line);
	return (TRUE);
}

getcomplex(row, prompt, real, imag)
int		row;
char		*prompt;
double		*real, *imag;
{
	extern	 char	*index();
	register char	*lp;

again:	if (isatty(fileno(stdin))) {
	    scr_move(row, 1);
	    scr_eol();
	    printf("%s: ", prompt);
	    fflush(stdout);
	}
	if (gets(line) == NULL)
	    return (FALSE);
	else if (line[0] == EOS) {
	    printf("No default permitted, try again\n");
	    goto again;
	}
	else if ((lp = index(line, ',')) == NULL) {
	    printf("Need two values, separated by a comma\n");
	    goto again;
	}
	*lp = EOS;
	*real = atof(line);
	*imag = atof(lp + 1);
	return (TRUE);
}

getstring(row, prompt, result, def_value)
int		row;
char		*prompt;
char		*result;
char		*def_value;
{
	strcpy(result, def_value);
	if (isatty(fileno(stdin))) {
	    scr_move(row, 1);
	    scr_eol();
	    printf("%s <%s>: ", prompt, result);
	    fflush(stdout);
	}
	if (gets(line) == NULL)
	    return (FALSE);
	if (line[0] != EOS)
	    strcpy(result, line);
	return (TRUE);
}

/*
 * Display routines (text -- for commands)  These assume ANSI controls:
 *	scr_clear()	Clear screen, Home cursor
 *	scr_home()	Home cursor
 *	scr_move(r,c)	Move to row r, column c (upper-left == 1,1)
 *	scr_eol()	Clear to end of line
 */

scr_clear()
{
	scr_home();
	printf("\033[2J");		/* ANSI Erase display	*/
}

scr_home()
{
	scr_move(1, 1);
}

scr_move(row, col)
{
	printf("\033[%d;%dH", row, col);/* ANSI Cursor Position */
}

scr_eol()
{
	printf("\033[0K");		/* ANSI Erase Line	*/
}
SHAR_EOF
if test -f 'maniter.c'
then
	echo shar: over-writing existing file "'maniter.c'"
fi
cat << \SHAR_EOF > 'maniter.c'
#ifndef lint
static char *RCSid = "$Header: maniter.c,v 1.2 85/09/16 15:50:20 mikee Exp $";
#endif

/* $Log:	maniter.c,v $
 *	Revision 1.2  85/09/16  15:50:20  mikee
 *	Changed global variable names.
 *	
 *	Revision 1.1  85/09/09	00:37:35  mikee
 *	Initial revision
 *
 */

/*
 * Calculate a mandelbrot pixel value:
 *
 *	1. Set z to 0 + 0i and
 *	   set c to the pixel location (real, imag)
 *
 *	2. Perform step 3 until either
 *	   1. count reaches the selected number of iterations or
 *	   2. the "size" of z exceeds 2.0, where size is defined
 *	      as sqrt(z_real**2 + z_imag**2)
 *	      (we don't bother with the square root.)
 *
 *	3. z = z**2 + c;
 *	   count = count + 1;
 *	   size = size of z as defined above.
 *
 *	4. return the count.
 *
 * This function is in a special source file of its own so that massive
 * optimizations can be done.  Since it is called so often, ANY speed-ups
 * here result in significant improvements in mancomp.
 */

#include	"mandefs.h"

pixvalue(c_real, c_imag)
	register double c_real;
	register double c_imag;
{
	register count = 0;
	register double z_real = c_real;
	register double z_imag = c_imag;

	for (;;) {
		register double z2_real;
		register double z2_imag;

		z2_real = z_real * z_real;
		z2_imag = z_imag * z_imag;

		if ((z2_real + z2_imag) > 4.0)
			return count;
		if (++count >= Niter)
			return --count;

		z_imag = (z_real * z_imag * 2.0) + c_imag;
		z_real = z2_real - z2_imag + c_real;
	}
}
SHAR_EOF
if test -f 'manfiles.c'
then
	echo shar: over-writing existing file "'manfiles.c'"
fi
cat << \SHAR_EOF > 'manfiles.c'
#ifndef lint
static char *RCSid = "$Header: manfiles.c,v 1.2 85/09/18 16:17:16 mikee Exp $";
#endif

/* $Log:	manfiles.c,v $
 *	Revision 1.2  85/09/18  16:17:16  mikee
 *	Changed global variable names, recoded double-precision scanf's,
 *	eliminated PIXREC ref's and converted short read/writes from 
 *	non-portable fread/fwrite to portable getc/putc.
 *	
 *	Revision 1.1  85/09/09	00:37:03  mikee
 *	Initial revision
 *
 */

/*
 * Functions to read and write mandelbrot pixel and histogram files.
 *
 *   hisopen(prefix, mode)	opens histogram file
 *   hisread()			reads data from above file
 *   hiswrite()			calculates (where necessary) and writes data
 *   hisclose()			closes file
 *
 *   pixopen(prefix, mode)	opens and initializes pixel file
 *   pixread(recd, row, col)	reads next pixel record from file
 *   pixwrite(value)		writes the given pixel record
 *   pixflush()			called at end of a row of pixels
 *   pixclose()			closes file
 */

#include	"mandefs.h"


int	Niter;				/* Maximum iterations		*/
int	Npixel;				/* Number pixels on each side	*/
double	RealOrigin;			/* Corner of the picture	*/
double	ImagOrigin;
double	SideLength;			/* Length of each side		*/

int	Histogram[MAX_NPIXEL];		/* Pixel density histogram	*/
int	HistTotal;			/* Sum of histogram values	*/
int	HistMin, HistMax;		/* First/last count in histogram*/

static	char	HistName[81];	/* Histogram file name			*/
static	FILE   *HistFile;	/* Histogram file pointer		*/

hisopen(prefix, mode)
	char	*prefix, mode;
/*
 * Open histogram file.
 */
{
	sprintf(HistName, "%s.his", prefix);
	if (mode == 'r')
		HistFile = fopen(HistName, "r");
	else
		HistFile = fopen(HistName, "w");

	if (HistFile == NULL) {
		char	err[BUFSIZ];
		sprintf(err, "Can't open %s", HistName);
		perror(err);
		return FALSE;
	}

	bzero(Histogram, sizeof(Histogram));

	return TRUE;
}

hisread()
/*
 * Read the data from the histogram file into memory.
 */
{
	char	 line[BUFSIZ], sreal[100], simag[100], sside[100];
	register i, fields;

	if (fgets(line, sizeof(line), HistFile) == NULL) {
		perror("Histogram file -- first line missing");
		return FALSE;
	}
	fields = sscanf(line, "%s %s %s %d %d",
		sreal, simag, sside, &Npixel, &Niter);
	if (fields != 5) {
		char	err[BUFSIZ];
		sprintf(err, "First hist line didn't scan\n\"%s\"\n", line);
		perror(err);
		return FALSE;
	}
	RealOrigin = atof(sreal);
	ImagOrigin = atof(simag);
	SideLength = atof(sside);

	if (fgets(line, sizeof(line), HistFile) == NULL) {
		perror("Histogram file -- second line missing");
		return FALSE;
	}
	fields = sscanf(line, "%d %d %d", &HistMin, &HistMax, &HistTotal);
	if (fields != 3) {
		char	err[BUFSIZ];
		sprintf(err, "Second hist line didn't scan\n\"%s\"\n", line);
		perror(err);
		return FALSE;
	}

	for (i = HistMin; i <= HistMax; i++) {
		if (fgets(line, sizeof(line), HistFile) == NULL) {
			perror("Histogram file -- data line(s) missing");
			return FALSE;
		}
		fields = sscanf(line, "%d", &Histogram[i]);
		if (fields != 1) {
			char	err[BUFSIZ];
			sprintf(err, "Histogram[%d] didn't scan\n\"%s\"\n",
				i, line);
			perror(err);
			return FALSE;
		}
	}
	return TRUE;
}

hiswrite()
/*
 * Calculate and write histogram file.
 */
{
	register i;

	fprintf(HistFile, "%.15g %.15g %.15g %d %d\n",
		RealOrigin, ImagOrigin, SideLength, Npixel, Niter);

	for (HistMin = 0; HistMin < Niter; HistMin++)
		if (Histogram[HistMin] != 0)
			break;
	for (HistMax = Niter - 1; HistMax > HistMin; HistMax--)
		if (Histogram[HistMax] != 0)
			break;
	for (HistTotal = 0, i = HistMin; i <= HistMax; i++)
		HistTotal += Histogram[i];

	fprintf(HistFile, "%d %d %d\n", HistMin, HistMax, HistTotal);

	for (i = HistMin; i <= HistMax; i++)
		fprintf(HistFile, "%d\n", Histogram[i]);

	return TRUE;
}

hisclose()
/*
 * Close the histogram file and mark it closed.
 */
{
	if (HistFile) {
		fclose(HistFile);
		HistFile = NULL;
		return TRUE;
	}
	return FALSE;
}

/*
 * The following functions attempt to write and read pixel files in the
 * most space efficient manner possible.  Their intent is to use a little
 * intelligence about normal pixel value distribution within a pixel file
 * to compress out duplicated data.
 */

static	char	PixlName[81];	/* Pixel file name			*/
static	FILE   *PixlFile;	/* Pixel file pointer			*/

int	PixValue;		/* Pixel value				*/
int	PixCount;		/* Pixel count (run length)		*/

static	PixMode;		/* Read/write compression mode		*/
static	LowValue;		/* Last low pixel value			*/
static	PixRun[MAX_NPIXEL];	/* Run of individual pixel values	*/
static	RunLength;		/* Length of current run (if any)	*/

				/* Pixel compression modes		*/
#define CM_CHAR		0x8000	  /* Pixels encoded in chars		*/
#define CM_ADD		0x4000	  /* Pixels encoded as offsets from low */
#define CM_LOW		0x2000	  /* New low value follows		*/
#define CM_RUN		0x1000	  /* Run of individual pixels follow	*/
#define CM_SPARE2	0x0800	  /* Spare				*/
#define CM_SPARE3	0x0400	  /* Spare				*/
#define CM_MODES	0xfc00	  /* All mode bits			*/

#define MAXCHAR		0xff	/* Maximum value encodable in a char	*/
#define MAXSHORT	0xffff	/* Maximum value encodable in a short	*/
#define MAXCOUNT	0x03ff	/* Maximum pixel count (short - modes)	*/

/*
 * Primitive I/O routines.
 */
static
putshort(value)
	register value;
{
	putc(value & MAXCHAR, PixlFile);
	putc(value >> 8, PixlFile);
}
static
getshort()
{
	register value = getc(PixlFile);
	return (value | (getc(PixlFile) << 8));
}

static
putpixel(value)
	register value;
{
	if (ison(CM_CHAR, PixMode)) {
		if (ison(CM_ADD, PixMode))
			putc(value - LowValue, PixlFile);
		else
			putc(value, PixlFile);
	} else
		putshort(value);

	if (ison(CM_LOW, PixMode)) {
		turnoff(CM_LOW, PixMode);
		LowValue = value;
	}
}
static
getpixel()
{
	register value;

	if (ison(CM_CHAR, PixMode)) {
		if (ison(CM_ADD, PixMode))
			value = getc(PixlFile) + LowValue;
		else
			value = getc(PixlFile);
	} else
		value = getshort();

	if (ison(CM_LOW, PixMode)) {
		turnoff(CM_LOW, PixMode);
		LowValue = value;
	}
	return value;
}

pixopen(prefix, mode)
	char	*prefix, mode;
/*
 * Open pixel file and initialize static data.
 */
{
	sprintf(PixlName, "%s.pix", prefix);
	if (mode == 'r')
		PixlFile = fopen(PixlName, "r");
	else
		PixlFile = fopen(PixlName, "w");

	if (PixlFile == NULL) {
		char	line[BUFSIZ];
		sprintf(line, "Can't open %s", PixlName);
		perror(line);
		return FALSE;
	}

	PixCount = 0;
	PixValue = -1;
	PixMode = LowValue = 0;

	return TRUE;
}

pixread(row, col)
	int	row, col;
/*
 * Read the next group of identical pixels.
 */
{
	static	runused = 0;		/* pixels used out of current run */

	if (ison(CM_RUN, PixMode)) {
readrun:
		PixValue = PixRun[runused];
		for (PixCount = 1 ;; PixCount++) {
			if (++runused >= RunLength) {
				turnoff(CM_RUN, PixMode);
				break;
			} else if (PixValue != PixRun[runused])
				break;
		}
		return TRUE;
	}

	PixMode = getshort();
	PixCount = PixMode & MAXCOUNT;

	if (ison(CM_RUN, PixMode)) {
		RunLength = runused = 0;
		while (PixCount-- > 0)
			PixRun[RunLength++] = getpixel();
		goto readrun;
	}
	PixValue = getpixel();

	if (feof(PixlFile)) {
		char	err[BUFSIZ];
		sprintf(err, "early eof; file %s, row %d - missing %d pixels",
			PixlName, row, Npixel - col);
		perror(err);
		sleep(2);
		return FALSE;
	}
	return TRUE;
}

_pixwrite(newvalue)
	register newvalue;
/*
 * Write a group of identical pixels.
 */
{
	if (PixCount > 4) {
		Histogram[PixValue] += PixCount;

		if (ison(CM_RUN, PixMode)) {
			register cnt = 0;
			putshort(PixMode | RunLength);
			while (RunLength-- > 0)
				putpixel(PixRun[cnt++]);
			turnoff(CM_RUN, PixMode);
		}
		PixMode = pixmode(PixValue);
		do {
			register cnt = PixCount & MAXCOUNT;
			putshort(PixMode | cnt);
			putpixel(PixValue);
			PixCount -= cnt;
		} while (PixCount > 0) ;

	} else if (PixCount > 0) {
		register newmode = pixmode(PixValue);

		Histogram[PixValue] += PixCount;

		if (ison(CM_RUN, PixMode)) {
			if (newmode == PixMode) {
				if ((RunLength + PixCount) >= MAXCOUNT) {
					register cnt = 0;
					putshort(PixMode | RunLength);
					while (RunLength-- > 0)
						putpixel(PixRun[cnt++]);
				}
				do {
					PixRun[RunLength++] = PixValue;
				} while (--PixCount > 0);
				goto byebye;
			} else {
				register cnt = 0;
				putshort(PixMode | RunLength);
				while (RunLength-- > 0)
					putpixel(PixRun[cnt++]);
				turnoff(CM_RUN, newmode);
			}
		}
		if (ison(CM_LOW, newmode)) {
			PixMode = newmode;
			do {
				register cnt = PixCount & MAXCOUNT;
				putshort(PixMode | cnt);
				putpixel(PixValue);
				PixCount -= cnt;
			} while (PixCount > 0) ;
		} else {
			PixMode = newmode | CM_RUN;
			RunLength = 0;
			do {
				PixRun[RunLength++] = PixValue;
			} while (--PixCount > 0);
		}
	}
byebye:
	PixCount = 1;
	PixValue = newvalue;

	return TRUE;
}

pixflush()
/*
 * Write stored pixels.
 */
{
	_pixwrite(-1);
	PixCount = 0;

	if (ison(CM_RUN, PixMode)) {
		register cnt = 0;
		putshort(PixMode | RunLength);
		while (RunLength-- > 0)
			putpixel(PixRun[cnt++]);
		turnoff(CM_RUN, PixMode);
	}

	if (ferror(PixlFile)) {
		perror("pixel file write error");
		return FALSE;
	}
	return TRUE;
}

pixclose()
/*
 * Close the pixel file and mark it closed.
 */
{
	if (PixlFile) {
		pixflush();
		fclose(PixlFile);
		PixlFile = NULL;
		return TRUE;
	}
	return FALSE;
}

static
pixmode(value)
	register value;
/*
 * Using the upcoming pixel value and the current compression mode,
 * determine the new optimal compression mode.
 */
{
	register oldmode = PixMode;

	if (value <= MAXCHAR) {
		switch (oldmode & (CM_CHAR | CM_ADD)) {
		    case CM_CHAR:
			return oldmode;
		    case CM_CHAR | CM_ADD:
			if (value >= LowValue)
				return oldmode;
			break;
		    default:
			if (value >= LowValue)
				return (oldmode | CM_CHAR);
			break;
		}
		return (CM_CHAR | CM_LOW);

	} else {
		register diff;

		if (((diff = (value - LowValue)) < 0) || (diff > MAXCHAR))
			return CM_LOW;

		if ((oldmode & (CM_CHAR | CM_ADD)) == (CM_CHAR | CM_ADD))
			return oldmode;
		else
			return (oldmode | CM_ADD);
	}
}
SHAR_EOF
if test -f 'manregis.c'
then
	echo shar: over-writing existing file "'manregis.c'"
fi
cat << \SHAR_EOF > 'manregis.c'
#ifndef lint
static char *RCSid = "$Header: manregis.c,v 1.0 85/08/23 11:22:23 mikee Exp $";
#endif
/*
 * Display Mandelbrot set pixels.
 *
 * This version uses the Regis display protocol (for Dec VT125,
 * VT240, and PRO-350).  It should be "fairly" easy to adapt
 * it for other displays.
 */

#include	<stdio.h>
#include	<ctype.h>
#ifdef vms
#include	errno
#define	IO_ERROR	errno
#endif
#define FALSE	0
#define TRUE	1
#define	EOS	'\0'

/*
 * The Regis screen is fixed at 767 horizontal by 479 vertical pixels.
 * Although there is are relative coordinate system commands, we don't bother.
 * XORIGIN and YORIGIN define the lower-left corner of the Mandelbrot display.
 */

#define	MAX_NPIXEL	400
#define	SMAXX		768
#define SMAXY		480
#define XORIGIN		300
#define YORIGIN		425
#define GRAY_SCALE	13		/* Density ranges from 0 to 12	*/
#define	TICK		8		/* Length of boarder tick-marks	*/
#define	CXSIZE		8		/* Character width		*/
#define	CYSIZE		10		/* Character height		*/
/*
 * Globalize these values for the main display code.
 */
int	max_npixel = MAX_NPIXEL;
int	smaxx = SMAXX;
int	smaxy = SMAXY;
int	xorigin = XORIGIN;
int	yorigin = YORIGIN;
int	gray_scale = GRAY_SCALE;	/* Make known to mandisp.c	*/
int	tick = TICK;
int	cxsize = CXSIZE;
int	cysize = CYSIZE;

/*
 * Display routines for the bit-map display.
 *	dsp_init()		Initialize for bit-map writing, clear screen.
 *	dsp_done()		Done writing to the bit-map (don't clear)
 *	dsp_finis()		All done (about to exit to o.s., clear screen)
 *	dsp_move(r,c)		Move bitmap cursor to to this row-column
 *	dsp_endline()		Finish off a scanline
 *	dsp_draw(d,len)		Draw a horizontal line of the selected density
 *	dsp_text(r,c,t)		Write text string from this position
 *	dsp_line(x,yf,xt,yt)	Draw line from [xf,yf] to [xt,yt]
 */

dsp_init()
/*
 * Start writing to the bitmap display.
 */
{
	printf("\33P1pS[0,0]S(E)S(C0)");	/* Regis initialize	*/
	printf("S(M0(L0)1(L25)2(L50)3(L75))");	/* Regis Luminance	*/
}

dsp_done()
/*
 * Stop writing to the bitmap (don't clear it).
 */
{
	printf("\033\\");
	fflush(stdout);
}

dsp_finis()
/*
 * Exiting, clear display.
 */
{
	printf("\033P1pS(E)\033\\");
	fflush(stdout);
}

dsp_move(row, col)
int		row, col;
/*
 * Move bitmap cursor to this position.
 */
{
	printf("P[%d,%d]", row, col);
}

dsp_endline()
/*
 * Executed at the end of a scan line.
 */
{
	printf("W(I3)W(P1)");		/* Reset density to known state	*/
	fflush(stdout);
}

char	*dens_command[GRAY_SCALE] = {	/* Regis display controls	*/
	"W(I0)",			/*  0 == black			*/
	"W(I1)W(P6)",			/*  1 == dim,  sparse dots	*/
	"W(I1)W(P4)",			/*  2 == dim,  half-dense dots	*/
	"W(I1)W(P5)",			/*  3 == dim,  dense dots	*/
	"W(I1)W(P1)",			/*  4 == dim,  full line	*/
	"W(I2)W(P6)",			/*  5 == mid,  sparse dots	*/
	"W(I2)W(P4)",			/*  6 == mid,  half-dense dots	*/
	"W(I2)W(P5)",			/*  7 == mid,  dense dots	*/
	"W(I2)W(P1)",			/*  8 == mid,  full line	*/
	"W(I3)W(P6)",			/*  9 == full, sparse dots	*/
	"W(I3)W(P4)",			/* 10 == full, half-dense dots	*/
	"W(I3)W(P5)",			/* 11 == full, dense dots	*/
	"W(I3)W(P1)",			/* 12 == full, full line	*/
};

dsp_draw(density, length)
int		density;
int		length;
/*
 * Draw a line of this density.
 * On entrance, cursor is at the left edge of the line.
 * Leave the cursor at the end of the line.
 */
{
	if (density < 0)
	    density = 0;
	else if (density >= GRAY_SCALE)
	    density = GRAY_SCALE - 1;
	printf("%sV[+%d]", dens_command[density], length);
}


dsp_text(row, col, text)
int		row, col;
char		*text;		/* Must not contain a single quote "'"	*/
{
	dsp_move(row, col);
	printf("T'%s'", text);
}

dsp_line(xfrom, yfrom, xto, yto)
int		xfrom, yfrom;
int		xto,   yto;
/*
 * Draw a line
 */
{
	dsp_move(xfrom, yfrom);
	printf("V[%d,%d]", xto, yto);
}
SHAR_EOF
#	End of shell archive
exit 0
-- 

Mike Edmonds
S3G Unix Support Manager

	UUCPnet:     {ucbvax,ihnp4,allegra,uw-beaver,...}!tektronix!mikee
	CSnet:	     mikee@tek
	ARPAnet:     mikee.tek@csnet-relay
	Snail Mail:  Tektronix, Inc.,
		     S3G Unix Support
		     Del.Sta. 19-333
		     PO Box 500, Beaverton, OR	97077
	MaBell:	     (503) 627-5340