/*
*
*  Raster image display program for the IBM PC  
*
*	This program takes HDF file images or binary images, one byte per pixel,
*  and displays them on the PC's color graphics screen.  The dimensions of the
*  image are specified on the command line for the binary images, or are in the
*  HDF file.  Each image is read from the file, then displayed in the specified
*  position on the screen.  Portions of the image that do not fit on the screen
*  are clipped.
*
*	Command line options are as follows:
*		-b xdim ydim		: The dimensions of the binary file, and specifies 
*								binary file type of data
*		-m mapfile			: The name of a palette for a binary file
*		-v 					: Sets VGA display mode
*		-e					: Sets EGA display mode (default)
*		-9					: Sets Number 9 display mode
*		-h					: Specifies reading from an HDF file (default)
*		-c					: Center the image on the screen
*		-p xwhere ywhere 	: Specify an x & y position for the upper left hand
*								corner of the screen
*		-a					: Set animation mode
*		-A					: Set animation mode and specify animation of multiple
*								images from only one hdf file
*		-s					: Specifies only one binary image and name is filename
*		filename			: The file containing a list of binary images or
*								an HDF file containing images
*  example use:	display -b 256 256 -c -m palette.pal list.dat
*	 the file 'list.dat' must contain a list of file names of the images
*	 that are to be displayed in sequence.
*
*  Note:  for binary file usage, both the -b xdim ydim and the -m mapfile
*		options must be used for the correct displaying of the image.
*		The file name at the end of the command line is a mandatory command
*		line parameter, the rest of the command line parameters are optional.
*
*  The options available while an image is being displayed can be shown by
*		typing '?'
*
*  The rest of the external C functions can be found in "options.c"
*
*  National Center for Supercomputing Applications, University of Illinois
*  153 Computing Applications Building
*  605 E. Springfield Ave.
*  Champaign, IL  61820	 (217)244-0072
*
*  Quincey Koziol			August 1988
*
*/

#include "show.h"		/* include file for other include files and variables */

/* declarations of types for routines used */

extern long DFgetelement();	/* HDF call to get an element from a file */
extern long DFputelement();	/* HDF call to put an element in a file */
extern long unrleit();			/* call to un-run length encode a line of an image */
extern int	DFsetfind();		/* HDF call to start a wildcard find operation */
extern int	DFfind();			/* HDF call to perform the wildcard find */
extern int	DFupdate();			/* HDF call to update a file after changes have been written */
extern int	DFaccess();			/* HDF call to initiate reads or writes on a file */
extern int	DFdup();			/* HDF call to create a new tag/ref indentical to an old one */
extern int	DFclose();			/* HDF call to close an HDF file */
extern int expand();	/* routine to expand a given box in the image to fill the screen */
extern int interpolate();	/* routine to expand and smooth a given box in the image to fill the screen */
extern int getfnl();
#ifdef LATTICE
extern char *malloc();			/* memory allocation procedure */
extern char *calloc();			/* another memory allocation procedure */
#endif
#ifdef QAK
extern unsigned char pixelcolor();	/* returns the color of a pixel specified */
#endif
extern DF	*DFopen();			/* HDF call to open a file and return a pointer to that file */
extern void unimcomp();		/* call to uncompress an imcomp compressed line */
extern void read_pic();		/* routine to read in an imcomp compressed HDF image in ega mode */
extern void readpic();			/* routine to read in a raster image from an HDF file */
extern void readcpic();		/* routine to read in a run-length-encoded image from an HDF file */
extern void readipic();		/* routine to read in an imcomp compressed HDF image for other display modes */
extern void loadega();			/* procedure to read in an HDF palette in ega mode */
extern void select_pal();		/* procedure to select a palette of 16 colors out of 256 */
extern void grafmode();		/* routine to go into the correct graphics mode */
extern void textmode();		/* routine to go into text mode */
extern void showpic();			/* routine to display the picture on the screen when in graphics mode */
extern void loadpal();			/* procedure to load the palette for other display modes */
extern void showpal();	/* routine to show the palette on the screen */
extern void nopal();	/* routine to remove the palette from the screen */
extern void options();	/* main routine to execute runtime options from */
extern void putpal();			/* routine reload the internal palette which the values from current palette arrays */
extern void findpal();	/* routine to get a new palette from an HDF file */
extern void newpal();			/* routine to get a new palette in binary mode */
extern void initpal();			/* procedure to load in the initial palette */
extern void rawpic();			/* call to read in the binary image */
extern void printdir();		/* routine to display a list of palettes in the current directory */
extern void swap();			/* swap two character values */
#ifdef QAK
extern void slidepal();		/* slide the palette left or right */
#endif
extern void squishpal();	/* compress or expand the palette */
#ifdef MOUSE
extern void mousefunc();	/* mouse functions for screen manipulation */
#endif
extern void updatescrn();		/* updates the screen with the image, color bar and mouse cursor */
/*void t16line();*/				/* blast a targa line out to the targa board */
/*void pline();*/
/*void GraphInit();*/			/* routine in 'tarinit.c' to initialize the targa board */
extern void makepal();			/* make a grey scale palette as the first palette */
extern void displayerr();		/* display a string on the text screen */
extern void usage();			/* display the command line parameters */
extern void debug();			/* display debugging variables */
extern void debugf();			/* display float debugging variables */
extern void waitq();	/* routine to wait for a keypress */
#ifdef QAK
extern void bounce();	/* routine to bounce a ball on the screen until keyboard or mouse status is changed */
#endif
extern void swapint();	/* routine to swap two integer values */
extern void parse();	/* parse the commands generated by options() */
extern void NO9setup();		/* number nine routines to initialize the screen */
extern void clrbuf();
extern void RG9gmode();
extern void RG9clrscr();
extern void RG9init();
extern void draw_mouse();
extern void erase_mouse();
extern void read_mouse();
extern void strsfn();

void main(argc,argv)		/* main routine */
	int argc;		/* argument count */
	char *argv[];	/* pointer to the argument list */
{
	mode=EGA;		/*default mode for displaying images */
	maxx=640;
	maxy=350;
	pal_height=7;
	if(argc<2){		/* if there are no command line parameters then print them */
		usage();
		exit(0);
	  }	/* end if */
	for (i=1; i<argc; i++) {	  /* look at each parm */
		if (*argv[i]=='-') {
			switch ( *(argv[i]+1)) { 
				case 'c':	/*  centering  */
					center=1;				/* set centering to calculate after the dimensions have been found */
					break;

				case 'p':	/* special position */
					xwhere=atoi(argv[++i]);
					ywhere=atoi(argv[++i]);
					if (xwhere > maxx || ywhere > maxy) {
						puts("Invalid position\n");
						usage();
						exit(1);
					  }	/* end if */
					break;

				case 'h':	/* the file type specified in HDF */
					filetype='h';
					break;

				case 'a':	/* set animation mode */
					animate=1;
					one_file=0;
					break;

				case 'A':	/* set one file animation mode for hdf files */
					animate=1;
					one_file=1;
					break;

				case 's':	/* set single binary image mode */
					oneimage=1;
					break;

				case 'b':	/* the files are going to be binary raster 8 */
					filetype='b';
					xdim=atoi(argv[++i]);
					ydim=atoi(argv[++i]);
					if (xdim < 1 || ydim < 1) {
						puts("Invalid dimensions\n");
						usage();
						exit(1);
					  } /* end if */
					break;

				case VGA:	/* display mode is vga */
					mode=*(argv[i]+1);
					maxx=320;
					maxy=200;
					pal_height=7;
					break;

				case EGA:	/* display mode is ega */
					mode=*(argv[i]+1);
					maxx=640;
					maxy=350;
					pal_height=7;
					break;

#ifdef FUTURE
 				case TARGA:	/* display mode is t16 */
 					mode=*(argv[i]+1);
 					maxx=512;
 					maxy=485;
 					break;
#endif

				case NO9:	/* display mode is no9 */
					mode=*(argv[i]+1);
					maxx=512;
					maxy=500;
					pal_height=15;
					break;

				case 'm':	/* name of palette file for binary images */
					strcpy(palfile,argv[i+1]);
					break;

				default:	/* not a valid command parameter, so tell them the parameters */
					usage();
					exit(1);
			  } /* end switch */
		  } /* end if */
	  } /* end for */
	pal_yoff=0;

/* set the directory from the command */
	getcwd(old_path,64);					/* get the current directory */
	old_drive=toupper(*old_path)-'A'+1;		/* get the drive number of the old drive */
	strcpy(old_path,old_path+2);			/* insert the slash in front of the directory */
	strsfn(argv[argc-1],drive,path,node,ext);		/* convert the filename on the command line into a drive, path, node, and extension */
	new_drive=toupper(*drive)-'A'+1;
	if(new_drive>0)
		_dos_setdrive(new_drive,&new_drive);		/* change the current drive */
	strcpy(filename,path);
	if((i=strcmp(filename,""))!=0) {		/* check for null directory */
		if((i=chdir(filename))!=0) {		/* set the directory and check for a bad directory */
			printf("Bad Path Specified, Error=%d\n",i);
			exit(1);
		  }	/* end if */
	  }	/* end if */
	strcpy(argv[argc-1],node);				/* make the filename again */
	strcat(argv[argc-1],".");
	strcat(argv[argc-1],ext);

/* start doing stuff with the image(s) */

	if(animate) {		/* do both hdf and raster animations here */
		if(filetype==HDF) {		/* do a hdf animation */
			if(one_file==1) {	/* animate all the images from just one hdf file */
				grafmode();		/* go to correct graphics screen type and load palette */
				do {			/* cycle through until the user wants to get out */
					strcpy(filename,argv[argc-1]);		/* get a copy of the file to be read */
					file_attr=0;						/* just look for normal files */
					file_err=find_1st(filename,file_attr);	/* get the first file to display */

					do {								/* display all the files */

						strcpy(filename,DTAPTR+30);			/* get the filename from the find routine */

/* Open DF file for reading */

						if(NULL==(dff=DFopen(filename,DFACC_ALL,16))) {
							printf("Cannot open HDF file, HDF error:%d\n", DFerror);
							chdir(old_path);				/* restore the old path */
							exit(1);
						  }	/* end if */

/* get the dimensions */

						if(first_hdf==1) {
							DFsetfind(dff,DFTG_ID8,DFREF_WILDCARD);	/* set wildcard find to image dimension searching */

							if(!DFfind(dff,&ddstr)) {			/* look for image dimensions */
								if(0>DFgetelement(dff,ddstr.tag,ddstr.ref,&dims)) {
									printf("Error getting dimensions from file: %d\n",DFerror);
									chdir(old_path);				/* restore the old path */
									exit(1);
								  }	/* end if */
							  }	/* end if */
							else {
								printf("error from DFfind %d\n",DFerror);
								chdir(old_path);				/* restore the old path */
								exit(1);
							  }	/* end else */

							xdim=intswap(dims.xdim);
							ydim=intswap(dims.ydim);

							if(center) {				/* find the image's position on the screen */
								xwhere=(maxx-xdim)/2;
								ywhere=(maxy-ydim)/2;
								if(xwhere<0) 
									xwhere=0;			/* if larger than screen, */
								if(ywhere<0)			/* don't center it */
									ywhere=0;
							  }	/* end if */

/* allocate memory for the image, if not enough, then error */

							if(enoughspace(xdim,ydim)) {
								printf(mem_error);
								chdir(old_path);				/* restore the old path */
								exit(1);
							  } /* end if */
							first_hdf=0;				/* reset the first_hdf bit */
						  }	/* end if */

/* cycle through all of the raster images in the file */

						c=' ';
						cycled=0;
						DFsetfind(dff,DFTG_RI8,DFREF_WILDCARD);		/* set wildcard search for raster 8 images */
	
						while(!DFfind(dff,&ddstr) && animate && !getout) {		/* look for the raster 8 images */
							imtag=ddstr.tag;		/* keep track of the image's tag and reference numbers for later */
							imref=ddstr.ref;
							readpic(xdim,ydim);		/* block read from disk */
							if(!cycled)
								initpal();			/* loads in the palette from disk */
							showpic();		/* put the picture on the screen */
							cycled=1;		/* set flag to display that an animation has occured */
							if(kbhit()) {	/* check for keypress to interupt animation */
								i=getch();	/* flush the keyboard buffer */
								if(i==0)				/* get extended code if necessary */
									i=getch();
								if(show)		/* if palette is supposed to be display then display it again */
									showpal();
								options();
							  }	/* end if */
						  } /* end while */
	
/* cycle through all of the run length compressed images in the file */

						c=' ';
						DFsetfind(dff,DFTG_CI8,DFREF_WILDCARD);

						while(!DFfind(dff,&ddstr) && animate && !getout) {
							imtag=ddstr.tag;		/* keep track of the image's tag and reference numbers for later */
							imref=ddstr.ref;
								readcpic(xdim,ydim);		/* block read run length compressed image from disk */
							if(!cycled)
								initpal();			/* loads in the palette from disk */
							showpic();			/* put image on the screen */
							cycled=1;		/* set flag to display that an animation has occured */
							if(kbhit()) {	/* check for keypress to interupt animation */
								i=getch();	/* flush the keyboard buffer */
								if(i==0)				/* get extended code if necessary */
									i=getch();
								if(show)		/* if palette is supposed to be display then display it again */
									showpal();
								options();
							  }	/* end if */
						  } /* end while */

/* cycle through all of the imcomp compressed images in the file */

						c=' ';
						DFsetfind(dff,DFTG_II8,DFREF_WILDCARD);	/* set wildcard search for imcomp compressed images */

						while(!DFfind(dff,&ddstr) && animate && !getout) {		/* look for imcomp compressed images */
							imtag=ddstr.tag;		/* keep track of the image's tag and reference numbers for later */
							imref=ddstr.ref;
							if(!doneinit) {		/* if the palette hasn't been initialized */
								initpal();		/* then initialize it for incomp compressed images */
								doneinit=1;
							  }	/* end if */
							if(mode==EGA) {			/* initialize things a certain way for ega mode */
					 			read_pic(xdim,ydim);		/* block read from disk for ega mode */
								select_pal(xdim,ydim,0); 	/* set up the translation table for ega */
								memcpy(egapals[0],regrs,16);
							  }	/* end if */
							else
								readipic(xdim,ydim);	/* block read from disk for other modes */
							showpic();			/* put the image on the screen */
							cycled=1;		/* set flag to display that an animation has occured */
							if(kbhit()) {	/* check for keypress to interupt animation */
								i=getch();	/* flush the keyboard buffer */
								if(i==0)				/* get extended code if necessary */
									i=getch();
								if(show)		/* if palette is supposed to be display then display it again */
									showpal();
								options();
							  }	/* end if */
						  } /* end while */
						DFclose(dff);			/* close the hdf file */
					  }	while((file_err=findnext())==0);	/* keep reading files until an error is returned (no more files) */
					for(i=anispeed; i>0; i--);	/* delay loop */
					if(cycled) {
						showpic();
						if(show)		/* if palette is supposed to be display then display it again */
							showpal();
						options();
					  }	/* end if */
				  }	while(c!='q' && animate && cycled && !getout);	/* keep cycling until the user wants out */
			  }	/* end if */
			else {			/* animate from a list of hdf files */
				grafmode();			/* go into correct graphics mode */
				c=' ';
				while(c!='q' && animate && !getout) {		/* open file with list of file names to display */
					if(NULL==(fp=fopen(argv[argc-1],"ra"))) {
						textmode();
						printf("\n%s: Error opening %s",argv[0],argv[argc-1]);
						chdir(old_path);				/* restore the old path */
						exit(0);
					  } /* end if */
	
					if(palmax==-1 && *palfile!=NULL)	/* if there is a palette specified then load it */
						newpal(palfile);
					putpal();

/* cycle through all of the file names */

					*filename='\0';

					while((NULL!=fgets(filename,100,fp)) && animate && !getout) {
						if(*filename<33)
							break;				/* exit the program if end of list */
						p=filename;
						while(*p>32)			/*  find the first non printable char or space */
							p++;
						*p='\0';				/*  truncate the file name for use by open */

						file_attr=0;						/* just look for normal files */
						file_err=find_1st(filename,file_attr);	/* get the first file to display */

						do {								/* display all the files */

							strcpy(filename,DTAPTR+30);			/* get the filename from the find routine */
/* Open DF file for reading */

							if(NULL==(dff=DFopen(filename,DFACC_ALL,16))) {
								printf("Cannot open HDF file=%s, HDF error:%d\n",filename,DFerror);
								chdir(old_path);				/* restore the old path */
								exit(1);
							  }	/* end if */

							if(first_hdf==1) {		/* the first time through an hdf animation, get the dimensions and allocate spcae, etc. */

/* get the dimensions */

								DFsetfind(dff,DFTG_ID8,DFREF_WILDCARD);	/* set wildcard find to image dimension searching */

								if(!DFfind(dff,&ddstr)) {			/* look for image dimensions */
									if(0>DFgetelement(dff,ddstr.tag,ddstr.ref,&dims)) {
										printf("Error getting dimensions from file: %d\n",DFerror);
										chdir(old_path);				/* restore the old path */
										exit(1);
									  }	/* end if */
								  }	/* end if */
								else {
									printf("error from DFfind %d\n",DFerror);
									chdir(old_path);				/* restore the old path */
									exit(1);
								  }	/* end else */

								xdim=intswap(dims.xdim);
								ydim=intswap(dims.ydim);

								if(center) {				/* find the image's position on the screen */
									xwhere=(maxx-xdim)/2;
									ywhere=(maxy-ydim)/2;
									if(xwhere<0) 
										xwhere=0;			/* if larger than screen, */
									if(ywhere<0)			/* don't center it */
										ywhere=0;
								  }	/* end if */

/* allocate memory for the image, if not enough, then error */

								if(enoughspace(xdim,ydim)) {
									printf(mem_error);
									chdir(old_path);				/* restore the old path */
									exit(1);
								  } /* end if */

								first_hdf=0;
							  }	/* end if */

/* cycle through all of the raster images in the file */

							c=' ';
							cycled=0;
							DFsetfind(dff,DFTG_RI8,DFREF_WILDCARD);		/* set wildcard search for raster 8 images */

							while(!DFfind(dff,&ddstr) && animate && !getout) {		/* look for the raster 8 images */
								imtag=ddstr.tag;		/* keep track of the image's tag and reference numbers for later */
								imref=ddstr.ref;
								readpic(xdim,ydim);		/* block read from disk */
								if(!cycled)
									initpal();			/* loads in the palette from disk */
								showpic();		/* put the picture on the screen */
								cycled=1;		/* set flag to display that an animation has occured */
								if(kbhit()) {	/* check for keypress to interupt animation */
									i=getch();	/* flush the keyboard buffer */
									if(i==0)				/* get extended code if necessary */
										i=getch();
									if(show)		/* if palette is supposed to be display then display it again */
										showpal();
									options();
								  }	/* end if */
							  } /* end while */

/* cycle through all of the run length compressed images in the file */

							c=' ';
							DFsetfind(dff,DFTG_CI8,DFREF_WILDCARD);

							while(!DFfind(dff,&ddstr) && animate && !getout) {
								imtag=ddstr.tag;		/* keep track of the image's tag and reference numbers for later */
								imref=ddstr.ref;
								readcpic(xdim,ydim);		/* block read run length compressed image from disk */
								if(!cycled)
								initpal();			/* loads in the palette from disk */
								showpic();			/* put image on the screen */
								cycled=1;		/* set flag to display that an animation has occured */
								if(kbhit()) {	/* check for keypress to interupt animation */
									i=getch();	/* flush the keyboard buffer */
									if(i==0)				/* get extended code if necessary */
										i=getch();
									if(show)		/* if palette is supposed to be display then display it again */
										showpal();
									options();
								  }	/* end if */
							  } /* end while */

/* cycle through all of the imcomp compressed images in the file */

							c=' ';
							DFsetfind(dff,DFTG_II8,DFREF_WILDCARD);	/* set wildcard search for imcomp compressed images */

							while(!DFfind(dff,&ddstr) && animate && !getout) {		/* look for imcomp compressed images */
								imtag=ddstr.tag;		/* keep track of the image's tag and reference numbers for later */
								imref=ddstr.ref;
								if(!doneinit) {		/* if the palette hasn't been initialized */
									initpal();		/* then initialize it for incomp compressed images */
									doneinit=1;
								  }	/* end if */

								if(mode==EGA) {			/* initialize things a certain way for ega mode */
						 			read_pic(xdim,ydim);		/* block read from disk for ega mode */
									select_pal(xdim,ydim,0); 	/* set up the translation table for ega */
									memcpy(egapals[0],regrs,16);
								  }	/* end if */
								else
									readipic(xdim,ydim);	/* block read from disk for other modes */
								showpic();			/* put the image on the screen */
								cycled=1;		/* set flag to display that an animation has occured */
								if(kbhit()) {	/* check for keypress to interupt animation */
									i=getch();	/* flush the keyboard buffer */
									if(i==0)				/* get extended code if necessary */
										i=getch();
									if(show)		/* if palette is supposed to be display then display it again */
										showpal();
									options();
								  }	/* end if */
							  } /* end while */
							DFclose(dff);			/* close the hdf file */
						  }	while((file_err=findnext())==0);	/* keep going until no more files with that name */
					  }	/* end while */
					for(i=anispeed; i>0; i--);	/* delay loop */
					if(cycled) {
						showpic();
						if(show)		/* if palette is supposed to be display then display it again */
							showpal();
						options();
					  }	/* end if */
				  }	/* end while */
			  }	/* end else */
		  }	/* end if */
		else {					/* do a raster eight animation */

/* allocate memory for the image, if not enough, then error */

			if(enoughspace(xdim,ydim)) {
				printf(mem_error);
				chdir(old_path);				/* restore the old path */
				exit(1);
			  }	/* end if */

			if(center) {				/* find the image's position on the screen */
				xwhere=(maxx-xdim)/2;
				ywhere=(maxy-ydim)/2;
				if(xwhere<0) 
					xwhere=0;			/* if larger than screen, */
				if(ywhere<0)			/* don't center it */
					ywhere=0;
			  }	/* end if */
			  
			grafmode();			/* go into correct graphics mode */

/* open file with list of file names to display */

			if(one_file==1) {	/* if there is only one file name specified for the animation */
				c=' ';
				while(c!='q' && animate && !getout) {

					if(palmax==-1 && *palfile!=NULL)	/* if there is a palette specified then load it */
						newpal(palfile);
					putpal();

/* cycle through all of the file names */

					file_attr=0;			/* look for normal files */
					file_err=find_1st(argv[argc-1],file_attr);	/* get the name of the first file which matches */

					do {
						strcpy(filename,DTAPTR+30);

						if(0>(file=open(filename,O_RDONLY | O_RAW))) {		/* open the image file */
							textmode();
							printf("\n%s: Error opening image file: %s",argv[0],filename);
							chdir(old_path);				/* restore the old path */
							exit(1);
						  }	/* end if */
						rawpic(file,xdim,ydim);			/* block read image from from disk */
						close(file);					/* close the image file */
						showpic();			/* put the image on the screen */
						if(kbhit()) {	/* check for keypress to interupt animation */
							i=getch();	/* flush the keyboard buffer */
							if(i==0)				/* get extended code if necessary */
								i=getch();
							if(show)		/* if palette is supposed to be display then display it again */
								showpal();
							options();
						  }	/* end if */
						for(i=anispeed; i>0; i--);	/* delay loop */
					  }	while((file_err=findnext())==0);	/* keep cycling through the files until all the filenames are exhausted */
					showpic();
					if(show)		/* if palette is supposed to be display then display it again */
						showpal();
					options();			/* do the fancy things on the screen */
				  }	/* end while */
			  }	/* end if */
			else {				/* animate from a file of filenames */
				c=' ';
				while(c!='q' && animate && !getout) {
					if(NULL==(fp=fopen(argv[argc-1],"ra"))) {
						printf("\n%s: Error opening %s",argv[0],argv[argc-1]);
						chdir(old_path);				/* restore the old path */
						exit(0);
					  } /* end if */

					if(palmax==-1 && *palfile!=NULL)	/* if there is a palette specified then load it */
						newpal(palfile);
					putpal();

/* cycle through all of the file names */

					*filename='\0';

					while((NULL!=fgets(filename,100,fp)) && animate && !getout) {
						if(*filename<33)
							break;				/* exit the program if end of list */
						p=filename;
						while(*p>32)			/*  find the first non printable char or space */
							p++;
						*p='\0';				/*  truncate the file name for use by open */

						file_attr=0;			/* look for normal files */
						file_err=find_1st(filename,file_attr);	/* get the name of the first file which matches */

						do {
							strcpy(filename,DTAPTR+30);

							if(0>(file=open(filename,O_RDONLY | O_RAW))) {		/* open the image file */
								textmode();
								printf("\n%s: Error opening image file: %s",argv[0],filename);
								chdir(old_path);				/* restore the old path */
								exit(1);
							  }	/* end if */
							rawpic(file,xdim,ydim);			/* block read image from from disk */
							close(file);					/* close the image file */
							showpic();			/* put the image on the screen */
							if(kbhit()) {	/* check for keypress to interupt animation */
								i=getch();	/* flush the keyboard buffer */
								if(i==0)				/* get extended code if necessary */
									i=getch();
								if(show)		/* if palette is supposed to be display then display it again */
									showpal();
								options();
							  }	/* end if */
							for(i=anispeed; i>0; i--);	/* delay loop */
						  }	while((file_err=findnext())==0);	/* keep cycling through the files until all the filenames are exhausted */
					  } /* end while */
					showpic();
					if(show)		/* if palette is supposed to be display then display it again */
						showpal();
					options();			/* do the fancy things on the screen */
				  }	/* end while */
			  }	/* end else */
		  }	/* end else */
	  }	/* end if */
	else {	/* regular non-animation file loading */
		if(filetype==HDF) {		/* hdf files specified */

/* Open DF file for reading */

			if(NULL==(dff=DFopen(argv[argc-1],DFACC_ALL,16))) {
				printf("Cannot open HDF file, HDF error:%d\n", DFerror);
				chdir(old_path);				/* restore the old path */
				exit(1);
			  }	/* end if */

/* get the dimensions */

			DFsetfind(dff,DFTG_ID8,DFREF_WILDCARD);	/* set wildcard find to image dimension searching */

			if(!DFfind(dff,&ddstr)) {			/* look for image dimensions */
				if(0>DFgetelement(dff,ddstr.tag,ddstr.ref,&dims)) {
					printf("Error getting dimensions from file: %d\n",DFerror);
					chdir(old_path);				/* restore the old path */
					exit(1);
				  }	/* end if */
			  }	/* end if */
			else{
				printf("error from DFfind %d\n",DFerror);
				chdir(old_path);				/* restore the old path */
				exit(1);
			  }	/* end else */
		
			xdim=intswap(dims.xdim);
			ydim=intswap(dims.ydim);

			if(center) {				/* find the image's position on the screen */
				xwhere=(maxx-xdim)/2;
				ywhere=(maxy-ydim)/2;
				if(xwhere<0) 
					xwhere=0;			/* if larger than screen, */
				if(ywhere<0)			/* don't center it */
					ywhere=0;
			  }	/* end if */

/* allocate memory for the image, if not enough, then error */

			if(enoughspace(xdim,ydim)) {
				printf(mem_error);
				chdir(old_path);				/* restore the old path */
				exit(1);
			  } /* end if */

			grafmode();		/* go to correct graphics screen type and load palette */

/* cycle through all of the raster images in the file */

			DFsetfind(dff,DFTG_RI8,DFREF_WILDCARD);		/* set wildcard search for raster 8 images */

			while(!DFfind(dff,&ddstr) && !getout) {		/* look for the raster 8 images */
				imtag=ddstr.tag;		/* keep track of the image's tag and reference numbers for later */
				imref=ddstr.ref;
				readpic(xdim,ydim);		/* block read from disk */
				initpal();			/* loads in the palette from disk */
				showpic();		/* put the picture on the screen */
				if(show)		/* if palette is supposed to be display then display it again */
					showpal();
				options();		/* call routine for screen options */
			  } /* end while */

/* cycle through all of the run length compressed images in the file */

			DFsetfind( dff, DFTG_CI8, DFREF_WILDCARD);

			while(!DFfind( dff, &ddstr) && !getout) {
				imtag=ddstr.tag;		/* keep track of the image's tag and reference numbers for later */
				imref=ddstr.ref;
 				readcpic(xdim,ydim);		/* block read run length compressed image from disk */
				initpal();			/* loads in the palette from disk */
				showpic();			/* put image on the screen */
				if(show)		/* if palette is supposed to be display then display it again */
					showpal();
				options();			/* call routine for screen options */
			  } /* end while */

/* cycle through all of the imcomp compressed images in the file */

			DFsetfind(dff,DFTG_II8,DFREF_WILDCARD);	/* set wildcard search for imcomp compressed images */

			while(!DFfind(dff,&ddstr) && !getout) {		/* look for imcomp compressed images */
				imtag=ddstr.tag;		/* keep track of the image's tag and reference numbers for later */
				imref=ddstr.ref;
				initpal();				/* neccessary for imcomp compressed images */
				if(mode==EGA){			/* initialize things a certain way for ega mode */
			 		read_pic(xdim,ydim);		/* block read from disk for ega mode */
					select_pal(xdim,ydim,0); 	/* set up the translation table for ega */
					memcpy(egapals[0],regrs,16);
				  }	/* end if */
				else
					readipic(xdim,ydim);	/* block read from disk for other modes */
				showpic();			/* put the image on the screen */
				if(show)		/* if palette is supposed to be display then display it again */
					showpal();
				options();			/* call routine for screen options */
			  } /* end while */
			DFclose(dff);			/* close the hdf file */
		  } /* end if */
		else {		/* do raster images */

/* allocate memory for the image, if not enough, then error */

			if(enoughspace(xdim,ydim)) {
				printf(mem_error);
				chdir(old_path);				/* restore the old path */
				exit(1);
			  }	/* end if */

			if(center) {				/* find the image's position on the screen */
				xwhere=(maxx-xdim)/2;
				ywhere=(maxy-ydim)/2;
				if(xwhere<0) 
					xwhere=0;			/* if larger than screen, */
				if(ywhere<0)			/* don't center it */
					ywhere=0;
			  }	/* end if */

/* open file with list of file names to display */
			if(oneimage) {	/* only read in one image and display it */
				if(0>(file=open(argv[argc-1],O_RDONLY|O_RAW))) {		/* open the image file */
					printf("\n%s: Error opening image file: %s",argv[0],argv[argc-1]);
					chdir(old_path);				/* restore the old path */
					exit(0);
				  }	/* end if */
				rawpic(file,xdim,ydim);			/* block read image from from disk */
				close(file);					/* close the image file */
				grafmode();			/* go into correct graphics mode */
				newpal(palfile);	/* load the new palette */
				putpal();
				showpic();			/* put the image on the screen */
				options();			/* do the fancy things on the screen */
			  }	/* end if */
			else {		/* read in a list of image names to display */
				if(NULL==(fp=fopen(argv[argc-1],"ra"))) {
					printf("\n%s: Error opening %s",argv[0],argv[argc-1]);
					chdir(old_path);				/* restore the old path */
					exit(1);
				  } /* end if */

/* cycle through all of the file names */

				*filename='\0';

				while(NULL!=fgets(filename,100,fp) && !getout) {
					if(*filename<33)
						break;				/* exit the program if end of list */
					p=filename;
					while(*p>32)			/*  find the first non printable char or space */
						p++;
					*p='\0';				/*  truncate the file name for use by open */
					if(0>(file=open(filename,O_RDONLY|O_RAW))) {		/* open the image file */
						textmode();
						printf("\n%s: Error opening image file: %s",argv[0],filename);
						chdir(old_path);				/* restore the old path */
						exit(1);
					  }	/* end if */
					rawpic(file,xdim,ydim);			/* block read image from from disk */
					close(file);					/* close the image file */
					grafmode();						/* go into correct graphics mode */
					if(palmax==-1 && *palfile!=NULL)	/* if there is a palette specified then load it */
						newpal(palfile);
					putpal();
					showpic();			/* put the image on the screen */
					options();			/* do the fancy things on the screen */
/*
*  insert each image functions here(click or gwrite)
*/
/* 			gwrite(filename); */
				  } /* end while */
			  }	/* end else */
		  }	/* end else */
	  } /* end else */
	textmode();
	chdir(old_path);				/* restore the old path */
	_dos_setdrive(old_drive,&old_drive);	/* and drive */
} /* end main */

/**********************************************************************
*  Function	:	enoughspace
*  Purpose	:	make enough room for the maximum row and column size.
*			Image memory is allocated line by line because of 64k data
*			limitation of the PC.
*  Parameters	:
*			c - the number of columns in the image
*			l - the number of lines in the image
*  Returns	:
*			1 if not enough memory
*			0 if enough memory
*  Calls	:	max()
*  Called by	:	main()
**********************************************************************/
int enoughspace(c,l)
int l,	/* the number of lines in image */
	c;	/* the number of columns in the image */
{
	int i;	/* local counting variable */

   	for (i=0; i < l; i++) {				/* allocate each line separately */
		store[i]=malloc(max(c,256)); /* with a minimum of 256 pixels per line allocated */

		if (store[i]==NULL)   		/* malloc returned not enough */
			return(1);
	}	/* end for */
	return(0);					 		/* successful return */
} /* end enoughspace() */

/**********************************************************************
*  Function	:	rawpic
*  Purpose	:	block read the binary image from disk and copy to main memory
*					storage.
*  Parameters	:
*			file - the file pointer
*			len	 - the length of a line (xdim)
*			lines - the number of lines (ydim)
*  Returns	:	none
*  Calls	:	none
*  Called by	:	main()
**********************************************************************/
void rawpic(file,len,lines)
int file,	/* the file pointer */
	len,	/* the length of a line of the binary image */
	lines;	/* the number of lines in the image */
{
	int i,	/* local temporary counting variable */
		lno,	/* the current line number */
		readsize,	/* the size to block read */
		readfact;	/* the block reading factor */
	char *p;	/* pointer to the buffer */

	readfact=RAWSIZE/len-5;
	readsize=readfact*len;	  /* get good blocking factor */

	lno=0;
	do {
		read(file,raw,readsize);		/* read one block */
		p=raw;						/* point to that block */

/*
*  for this block, copy each line into it's own reserved memory
*/
		for (i=0; i < readfact && lno < lines; i++) {
			memcpy(store[lno++],p,len);
			p += len;
		} /* end for */

	} while (lno < lines);

} /* end rawpic() */

/**********************************************************************
*  Function	:	readpic
*  Purpose	:	block read the image from the HDf file into main memory
*					storage
*  Parameters	:
*			len - the length of a line (xdim)
*			lines - the number of lines (ydim)
*  Returns	:	none
*  Calls	:	DFaccess(), DFread()
*  Called by	:	main()
**********************************************************************/
void readpic(len,lines)
int len,	/* the length of a line */
	lines;	/* the number of lines */
{
	int i,j,	/* local temporary counting variable */
		lno,	/* the current line number */
		readsize,	/* the size to block read */
		readfact;	/* the block reading factor */
	char *p;	/* pointer to the buffer */

/* prime DF routines */

	DFaccess( dff, ddstr.tag, ddstr.ref, "r");	/* tell HDF to start reading */

	readfact=RAWSIZE/len - 5;
	readsize= readfact*len;	  /* get good blocking factor */
	lno=0;
	do {
		j=(int) DFread(dff,raw,(long)readsize);		/* read one block */
		p=raw;						/* point to that block */

/* for this block, copy each line into it's own reserved memory */

		for (i=0; i*len < j && lno < lines; i++) {
			memcpy(store[lno++],p,len);
			p += len;
		  } /* end for */
	  } while (lno < lines);
} /* end readpic() */

/**********************************************************************
*  Function	:	readcpic
*  Purpose	:	bloack read a run-length compressed image from an HDF
*			file and store it in main memory, doing run length 
*			decompression as it goes
*  Parameters	:
*			len - the length of a line of the image (xdim)
*			lines - the number of lines in the image (ydim)
*  Returns	:	none
*  Calls	:	DFaccess(),DFread(),unrleit()
*  Called by	:	main()
**********************************************************************/
void readcpic(len,lines)
int len,	/* the length of a line */
	lines;	/* the number of lines */
{
	int	i;	/* temporary counting variable */
	long n,	/* the number of bytes read into the buffer */
		bufleft,	/* the number of bytes left in the buffer */
		crowsize,	/* the maximum compressed row size */
		readsize,	/* the size of the block to read in */
		totalread;	/* also the number of bytes read into the buffer */
	unsigned char *in;	/* pointer to the buffer for data */

/* prime DF routines */

	DFaccess( dff, ddstr.tag, ddstr.ref, "r");	/* set HDF to begin reading */

	readsize=RAWSIZE - 16;
	in=raw;
	n=DFread(dff, in,readsize);		/* block read in data from HDF file */
	totalread=n;
	crowsize=(long)xdim*121/120 +1;		/* maximum rowsize of compressed data */
	bufleft=n;
	for (i=0; i<ydim; i++) {		/* uncompress until end of file or buffer */
		n=unrleit(in, store[i], (long) xdim);
		in += n;
		bufleft -= n;
		if (bufleft<crowsize) {		/* if row is chopped then read more in */
			memcpy(raw, in, bufleft);
			in=raw;
			n=DFread(dff,&in[bufleft],readsize-bufleft);
			totalread += n;
			bufleft += n;
		} /* end if */
	} /* end for */
} /* end readcpic() */

/**********************************************************************
*  Function	:	readipic
*  Purpose	:	block read in HDF image and do imcomp decompression as
*			it goes
*  Parameters	:
*			len - the length of a line (xdim)
*			lines - the number of lines in image (ydim)
*  Returns	:	none
*  Calls	:	DFaccess(), DFread(), unimcomp(), memcpy()
*  Called by	:	main()
**********************************************************************/
void readipic(len,lines)
int len,	/* the length of a line of the image */
	lines;	/* the number of lines in the image */
{
	int i,	/* local temporary counting variable */
		lno,	/* the current line number */
		readsize,	/* the size to block read */
		readline,	/* the block reading factor */
		itread;		/* the number of bytes read in */
	char *p,	/* pointer to the buffer */
		*endp;	/* pointer to the end of the buffer */

/* prime DF routines */

	DFaccess( dff, ddstr.tag, ddstr.ref, "r");

	readline=RAWSIZE /xdim -5;
	readsize=readline*xdim;	
	lno=0;
	do {
		itread=DFread(dff,raw,(long)readsize);	/* block read in imcomp compressed image */
		p=raw;
		endp=raw + itread;

/* take each imcomp compressed line and uncompress it */

		while(p<endp && lno<(ydim/4)){
			unimcomp(xdim,1,p,bigstore);
			for (i=0;i<4 ;i++)
				memcpy(store[lno*4+i],&bigstore[i*xdim],xdim);
			p += xdim;
			lno++;
		  } /* end while */
	} while (lno<(ydim/4));
} /* end readipic() */

/**********************************************************************
*  Function	: read_pic
*  Purpose	: Reads in the raw image in big blocks from an HDF file
*				Performs decompression and store it in array 'store'
*  Parameters	:
*	xdim,ydim  - x and y dimension of image
*  Returns	: none
*  Calls	: DFaccess(), DFread(), unimcomp(), choose_rgb()
*  Called by	: main()
**********************************************************************/
void read_pic(xdim,ydim)
int xdim, ydim;	/* x & y dimensions of the image to be read in */
{
	int i,j,k,cnt,	/* more local counting variables */
		readline,	/* the number of lines the storage array can hold */
		readsize,	/* the size of the block to be read in */
		nlines;		/* the current line count into the image */
	char *p;		/* character pointer to the beginning of the array read in */
	unsigned char *out,		/* character pointer to the unimcomp compressed lines */
					 color; /* color value for a pixel */
	void unimcomp();	/* routine to uncompress imcomp line compression */
	int choose_rgb();	/* routine to get 6 bit color values from 24 bit palettes */

	for (j=0; j<64; j++)	/* clear out the frequency count array */
		count[j]=0;
	
/* read in image */

	DFaccess( dff, ddstr.tag, ddstr.ref, "r");

	readline=RAWSIZE / xdim - 5;
	readsize=readline * xdim;
	out=(unsigned char *)malloc(4*xdim);
	nlines=0;
	do {
		cnt=DFread(dff,raw,(long)readsize);	/* get a chunk of the image */
	
/* count the frequency of colors */

		for (i=0; i<cnt; i=i+4)
		   for (j=HI; j<=LO; j++) {
			   color=raw[i+j];
			   k=3 * color;
			   count[choose_rgb(pal[k],pal[k+1],pal[k+2])]++;	/* get the correct color setting and increment it */
			  } /* end of for j */
		
/* decompress the raw image */

		for (j=0; j<readline; j++) {
			unimcomp(xdim,1,&(raw[xdim*j]),out);	/* uncompress each compressed line into four normal lines */
			p=out;
			for (i=0; i< 4 && nlines < ydim; i++) {	/* copy the four lines into memory */
				memcpy(store[nlines],p,xdim);
				nlines++;
				p=p + xdim;
	   		 }	/* end of for i */
		  }	/* end of for j */
	} while (nlines < ydim);
} /* end of read_pic() */

/**********************************************************************
*  Function	:	palloc
*  Purpose	:	allocate room in dynamic memory for a 256 byte palette
*  Parameters	:	
*			x - the number of the palette to try to allocate
*  Returns	:
*			1 if a palette was allocated
*			0 if no memory
*  Calls	:	none
*  Called by	:	loadpal(), findpal(), newpal()
**********************************************************************/
int palloc(x)
int x;	/* the number of the palette to try to allocate */
{
	if(x<16){	/* the legal number of palettes in memory */
		rpal[x]=malloc(256);
		gpal[x]=malloc(256);
		bpal[x]=malloc(256);

		if (rpal[x]==NULL || gpal[x]==NULL || bpal[x]==NULL)	/* if any of the palettes were not able to be allocated then return 0 */
			return(0);
		else{				/* otherwise, copy in the current palette */
			memcpy(rpal[x],rmap,256);
			memcpy(gpal[x],gmap,256);
			memcpy(bpal[x],bmap,256);
			return(1);
		  }	/* end else */
	  }	/* end if */
	else
		return(0);				/* if too many palettes then return 0 */
} /* end palloc() */

/**********************************************************************
*  Function	:	palloce
*  Purpose	:	allocate room for an ega palette and copy the current
*			one into that memory
*  Parameters	:
*			x - the number of the palette to allocate memory for
*  Returns	:
*			1 if the memory was allocated ok
*			0 if the memory was not available
*  Calls	:	none
*  Called by	:	loadega(), findpal(), newpal()
**********************************************************************/
int palloce(x)
int x;	/* the number of the palette to be allocated */
{
	if(x<16){	/* if it is a legal palette value */
		egapals[x]=malloc(16);
	
		if (egapals[x]==NULL)	/* if no memory available, then return 0 */
			return(0);
		else{					/* otherwise, return 1 and copy the palette into the new memory */
			memcpy(egapals[x],regrs,16);
			return(1);
		  }	/* end else */
	  } /* end if */
	else
		return(0);				/* return 0 if too many palettes */
} /* end palloce() */

/**********************************************************************
*  Function	:	loadpal
*  Purpose	:	load in a palette from an HDF file and set the vga or
*			no. 9 palette to it.
*  Parameters	:	none
*  Returns	:	none
*  Calls	:	DFsetfind(), DFfind, DFgetelement(), palloc(), putmap9(),
*			 putmapv()
*  Called by	:	initpal()
**********************************************************************/
void loadpal()
{
	int i;	/* local counting variable */
	char *pi;	/* pointer to the chracter array read in */

	DFgetelement( dff, DFTG_IP8, imref, pal);	/* get palette associated with the image */

	pi=pal;
	for (i=0; i<256; i++) {
		rmap[i]=*pi++;
		gmap[i]=*pi++;
		bmap[i]=*pi++;
	} /* end for */

	palnum=0;
	palmax=0;
	if(!palloc(palmax)) {	/* allocate room for another palette */
		palmax=-1;		/* bad allocation */
		displayerr("No Room For Another Palette");
	  }	/* end if */
	else				/* ok allocation for palette */
		switch (mode) {		/* switch routine to put the correct palette */
			case VGA:
				putmapv(&rmap[0],&gmap[0],&bmap[0]);
				break;

			case NO9:
				putmap9(&rmap[0],&gmap[0],&bmap[0]);
				break;
		  }	/* end switch */
} /* end loadpal() */

/**********************************************************************
*  Function	:	loadega
*  Purpose	:	load in the ega palette from an HDF file
*  Parameters	:	none
*  Returns	:	none
*  Calls	:	DFsetfind(), DFfind(), DFgetelement(), select_pal(),
*			palloce()
*  Called by	:	initpal()
**********************************************************************/
void loadega()
{
	int	i;	/* local counting variable */

	DFgetelement( dff, DFTG_IP8, imref, pal);	/* get palette associated with the image */

	palnum=0;
	palmax=0;
	select_pal(xdim,ydim,1);	/* perform a frequency count on it */
	if(!palloce(palmax)) {	/* allocate room for the first palette */
		palmax=-1;
		displayerr("No Room For Another Palette");
	  }	/* end if */
	else 
		for(i=0; i<16; i++)
			egapal(i,(int)regrs[i]);
} /* end loadega() */

/**********************************************************************
*  Function	:	unrleit
*  Purpose	:	decompress run length encoding of a line of an image
*  Parameters	:
*			buf - the character string to be unencoded
*			bufto - the character string to be unencoded into
*			outlen - the length of the final, unencoded string
*  Returns	:	the length of the encoded line
*  Calls	:	none
*  Called by	:	readcpic()
**********************************************************************/
long unrleit(buf,bufto,outlen)
long outlen;	/* the long value of the final unencoded line length */
unsigned char *buf,*bufto;	/* the character pointers to the initial and final character buffers */
{
	register int cnt;
	register unsigned char *p,*q;
	unsigned char *endp;
	static unsigned char save[255], *savestart=NULL, *saveend=NULL;
				/* save has a list of decompressed bytes not returned in
					previous call.  savestart and saveend specify the position
					at which this list starts and ends in the array save */
	
	p=buf;
	endp=bufto+outlen;
	q=bufto;
	while((saveend>savestart) && (q<endp))			/* copy saved stuff */
		*q++=*savestart++;
	if(savestart>=saveend)
		savestart=saveend=save;		/* all copied */
	while(q<endp) {
		cnt=*p++;			/* count field */
		if(!(cnt&128))	/* is set of uniques */
			while(cnt--)
				if(q<endp)
					*q++=*p++;	/* copy unmodified */
				else
					*saveend++=*p++;
		else {
			cnt&=127;			/* strip high bit */
			while(cnt--)
				if(q<endp)
					*q++=*p;	/* copy unmodified */
				else
					*saveend++=*p;
			p++;				/* skip that character */
		  }	/* end else */
	  }	/* end while */
	return((long)(p-buf));
}	/* end unrleit() */

/************************************************************************
*  Function	: unimcomp
*  Purpose	: 'Decompresses' the compressed image
*  Parameter	:
*	xdim	   - x dimensions of image
*	lines	  - number of lines of compressed image
*	in, out	- Input buffer and output buffer. Size of input buffer
*		   is xdim*lines. Size of output buffer is 4 times
*		   that. It 'restores' images into seq-type files
*  Returns  	: none
*  Called by   : readipic(), read_pic()
*  Calls	   : none
************************************************************************/
void unimcomp(xdim,lines,in,out)
int xdim,	/* width of the image */
	lines;	/* number of lines of the compressed image */
unsigned char in[], /* input buffer */
			out[];	/* output buffer (4 times as large as the input buffer) */
{
  int bitmap,	/* integer value of two side-by-side pixels */
		temp;	/* temporary var. to hold working stuff */
  int i, j, k,	/* local counting variables */
		x, y;	/* counting variables for the x & y coor. of the image */
  unsigned char hi_color,	/* value of the highest color */
				lo_color;	/* value of the lowest color */

  /* go over the compressed image */
  for (y=0; y<lines; y++)
	for (x=0; x<xdim; x=x+4) {
	  k=y*xdim + x;
	  hi_color=in[k+2]; 
	  lo_color=in[k+3];

	  bitmap=(in[k] << 8) | in[k+1];

	  /* store in the out buffer */
	  for (i=(y*4); i<(y*4+4); i++) {
		temp=bitmap >> (3 + y*4 - i)*4;
		for (j=x; j<(x+4); j++) {
	 	  if ((temp & 8)==8)
			out[i*xdim+j]=hi_color;
		  else
			out[i*xdim+j]=lo_color;
		  temp=temp << 1;
		} /* end of for j */
	  }	/* end of for i */
	} /* end of for x */
} /* end of unimcomp() */

/************************************************************************
*  Function   : select_pal
*  Purpose	: Selects a palette of 16 colors out of 256 colors.
*			   Each of the 256 original colors are 24 bit-rgb values
*			   The routine truncates the 24 bit values to 6 bits and
*			   selects the most popular 16 colors
*  Parameters :
*	xdim,ydim - x and y dimension of image
*	mode	  - '1' implies program will count the frequency of colors
*				'0' implies the frequency count has alreay been done
*  Returns	: none
*  Called By  : showega()
*  Calls	  : choose_rgb(), map()
************************************************************************/
void select_pal(xdim,ydim,mode)
int xdim,ydim,	/* x & y dimensions */
		mode;	/* whether or not to perform frequency count */
{
	int i,j,k,	/* local counting variables */
		x,y,	/* variables for x & y dimensions */
		indx;	/* index to the current maximum value in the frequency table */
	long maxfreq;	/* the current highest frequency */
	unsigned char color;	/* the color of a pixel */

	int choose_rgb();	/* routine to choose a corresponding color from a mixture of red, green, and blue palettes */
	int map();	/* routine to map from 16 colors into the 256 color vga table */

	/* count the frequency of each color used */

	textmode();
	printf("Performing Frequency Count on The Image Data, Please be Patient\n");
	if (mode==1) {	/* if mode!=1 then count has already been performed, so no need to do it again */
 		for (i=0; i<64; i++)	/* clear out the count array */
			count[i]=0;
	  	for (y=0; y<ydim; y++)
			for (x=0; x<xdim; x++) {
				color=store[y][x];
				j=3 * color;
				k=choose_rgb(pal[j],pal[j+1],pal[j+2]);
				count[k]++;
			 }	/* end of for x */
	  }	/* end of if mode==1 */

/* select the 16 most frequently used colors */

	for (i=0; i<16; i++) {
		maxfreq=count[0];
		indx=0;
		for (j=1; j<64; j++)
			if (maxfreq < count[j]) {
				maxfreq=count[j];
				indx=j;
			  }	/* end of for j */
		count[indx]=0;
		regrs[i]=indx;
		egapal(i,indx);
	  }	/* end of for i */

/*  set up translation table */

	for (i=0; i<768; i=i+3) {
		j=choose_rgb(pal[i],pal[i+1],pal[i+2]);
		trans[i/3]=map(regrs,j);
	  }	/* end of for i */
	grafmode();
} /* end of select_pal() */

/************************************************************************
*  Function   : map
*  Purpose	: Maps a 6 bit rgb value to one of the 16 colors chosen
*			   Selects the one with the least bit difference
*  Parameters :
*	regrs	 - stores the 16 colors chosen
*	color	 - the color to be mapped
*  Returns	: register with nearest color
*  Called By  : select_pal()
*  Calls	  : none
************************************************************************/
int map(regrs,color)
char regrs[16];	/* array of the current ega palette values */
int color;	/* the color to map into the large 256 color palette */
{
	int i,j,	/* counting variables */
		minval,	/* the smallest value in the 256 color palette which correspond to the color chosen */
		temp,	/* temporary variable */
		diff,	/* the amount of difference between a color and the ega palette value */
		reg;	/* the register number of the ega palette which is closest to the color wanted */

	minval=999;
	for (i=0; i<16; i++) {	/* check through all the registers in the ega palette */
		diff=0;
		temp=1;
		for (j=0; j<6; j++) {	/* check through all the bits in the color */
			if ((temp & color) != (regrs[i] & temp))	/* if the bits don't match then increment the difference variable */
				diff++;
			temp=temp * 2;
		  }	/* end for j */
		if (minval > diff) {
			reg=i;
			minval=diff;
		  }	/* end if */
	  }	/* end for i */
	return reg;	/* return the corresponding register value to the color given */
} /* end of map() */

/************************************************************************
*  Function   : choose_rgb
*  Purpose	: Selects a 6 bit rgb value for a 24 bit number. Takes
*			   the 2 most sign. bit of each 8 bit component
*  Parameters :
*	r,g,b	- rgb components
*  Returns	: 6 bit rgb value
*  Called By  : select_pal()
*  Calls	  : none
************************************************************************/
int choose_rgb(r,g,b)
int r,g,b;	/* red, green, and blue components for the 24 bit value */
{
	int color;	/* 6 bit color value */

	color=((r & 128) >> 5) | ((r & 64) >> 1) |
			((g & 128) >> 6) | ((g & 64) >> 2) |
			((b & 128) >> 7) | ((b & 64) >> 3);

	return color;	/* return the 6 bit color value */
} /* end choose_rgb() */

/**********************************************************************
*  Function	:	newpal
*  Purpose	:	read a new palette from a binary file and switch to it
*  Parameters	:
*			s - name of a file
*  Returns	:	none
*  Calls	:	palloc(), palloce(), select_pal()
*  Called by	:	main(), options()
**********************************************************************/
void newpal(s)
char *s;	/* pointer to a file name */
{
	FILE *fp;	/* file pointer for the palette */
	
	if (NULL==(fp=fopen(s,"rb")))	/* open the palette file */
		makepal();
	else {	/* read in the palettes */
		fread(rmap,1,256,fp);
		fread(gmap,1,256,fp);
		fread(bmap,1,256,fp);
		fclose(fp);

/* attempt to allocate room for the palette and switch to it */

		palmax++;
		if(mode!=EGA) {
			if(!palloc(palmax)) {	/*allocate the new palette memory */
				palmax--;			/* bad allocation, fix old palette */
				displayerr("No Room For Another Palette");
				memcpy(rmap,rpal[palnum],256);
				memcpy(gmap,gpal[palnum],256);
				memcpy(bmap,bpal[palnum],256);
			  } /* end if */
			else 
				palnum=palmax;	/* good allocation, set palnum to new palette */
		  } /* end if */
		else {
			for(i=0; i<256; i++) {	/* put individual palettes into the big one */
				pal[i*3]=rmap[i];
				pal[i*3+1]=gmap[i];
				pal[i*3+2]=bmap[i];
			  } /* end for */
			select_pal(xdim,ydim,1);	/* do a frequency count on it */
			if(!palloce(palmax)) {
				displayerr("No Room For Another Palette");
				palmax--;
				memcpy(regrs,egapals[palnum],16);
			  } /* end if */
			else 
				palnum=palmax;
	  	} /* end else */
	  } /* end else */	
} /* end newpal() */

/**********************************************************************
*  Function	:	textmode
*  Purpose	:	switch into text mode
*  Parameters	:	none
*  Returns	:	none
*  Calls	:	resetega(), vgamode(3)
*  Called by	:	main(), options()
**********************************************************************/
void textmode()
{
	switch(mode){	/* depending on the monitor type, switch to text display mode */
		case VGA:
			vgamode(3);
			break;

		case NO9:
			vgamode(3);
			break;

		case EGA:
		default:
			resetega();
			break;
	  } /* end switch */
} /* end textmode() */

/**********************************************************************
*  Function	:	grafmode
*  Purpose	:	switch into correct graphics mode
*  Parameters	:	none
*  Returns	:	none
*  Calls	:	vgamode(), initega(), putpal()
*  Called by	:	main(), options()
**********************************************************************/
void grafmode()
{
	switch (mode){	/* depending on the monitor type, switch to graphics display mode */
		case VGA:
			vgamode(19);
			break;
/*
		case TARGA:
			GraphInit(16);
			break;
*/
		case NO9:
			RG9clrscr();
			break;

		case EGA:
		default:
			vgamode(16);
#ifdef QAK
			initega();
#endif
			break;
	  }	/* end switch */
	putpal();	/* replace the palette */
} /* end grafmode() */

/**********************************************************************
*  Function	:	putpal
*  Purpose	:	renew the palette on the graphics card with the current
*			palette in memory
*  Parameters	:	none
*  Returns	:	none
*  Calls	:	putmapv(), putmap9(), egapal(),
*  Called by	:	grafmode(), options()
**********************************************************************/
void putpal()
{
	switch (mode){		/* different calls for different monitor types */
		case VGA:
			putmapv(rmap,gmap,bmap);
			break;

		case NO9:
			putmap9(rmap,gmap,bmap);
			break;

		case EGA:
		default:
			for(i=0; i<16; i++)
				egapal(i,(int)regrs[i]);
			settrans(trans);
			break;
	  } /* end switch */
} /* end putpal() */

/**********************************************************************
*  Function	:	showpic
*  Purpose	:	display the current portion of the image
*  Parameters	:	none
*  Returns	:	none
*  Calls	:	vgaline(), egaline(), no9line()
*  Called by	:	main(), options()
**********************************************************************/
void showpic()
{
	switch(mode){		/* output to screen differently for each different type of monitor */
		case VGA:
			for(i=0; (i+ywhere)<ydim && (i+ywhere)<200; i++)
				LINEVGA;
			break;

		case NO9:
			for(i=0; (i+ywhere)<ydim && (i+ywhere)<500; i++)
				LINENO9;
			break;
/*
 		case TARGA:
 			for(i=0; (i+ywhere)<ydim && (i+ywhere)<500; i++)
 				LINET16;
 			break;			
*/
		case EGA:
		default:
			for (i=0; (i+ywhere)<ydim && (i+ywhere)<350; i++)		   /* display the image */
				LINEEGA;
			break;
	  }	/* end switch */
} /* end showpic() */

/**********************************************************************
*  Function	:	initpal
*  Purpose	:	to load in the first palette for the image
*  Parameters	:	none
**  Returns	:	none
*  Calls	:	loadpal(), loadega()
*  Called by	:	main()
**********************************************************************/
void initpal()
{
		switch(mode){		/* VGA and No9 use 256 byte palettes and EGA uses 16 byte palettes */
			case VGA:
			case NO9:
				loadpal();
				break;

 			case TARGA:
 				loadpal();
 				break;

			case EGA:
			default:
				loadega();
				break;
		  }	/* end switch(mode) */
} /* end initpal() */

/**********************************************************************
*  Function	:	makepal
*  Purpose	:	make a grey scale palette as the first palette
*  Parameters	:	none
*  Returns	:	none
*  Calls	:	select_pal(), palloc(), palloce(), putpal9(), putpalv(),
*				memcpy()
*  Called by	:	newpal()
**********************************************************************/
void makepal()
{
	if(mode!=EGA) {		/* for vga and no9 palettes */
		for (i=0; i<256; i++)		/* make a grey scale palette */
			rmap[i]=gmap[i]=bmap[i]=i;

		palnum=0;
		palmax=0;
		if(!palloc(palmax)) {	/* allocate room for another palette */
			palmax=-1;
			displayerr("No Room For Another Palette");
		  }	/* end if */
		else				/* load the grey scale data into the arrays */
			switch (mode) {		/* switch routine to put the correct palette */
				case VGA:
					putmapv(&rmap[0],&gmap[0],&bmap[0]);
					break;

				case NO9:
					putmap9(&rmap[0],&gmap[0],&bmap[0]);
					break;
			  }	/* end switch */
	  }	/* end if */
	else {		/* for ega palettes */
		for(i=0; i<256; i++)	/* make an ega grey scale big palette */
			pal[i*3]=pal[i*3+1]=pal[i*3+2]=i;
		palnum=0;
		palmax=0;
		select_pal(xdim,ydim,1);	/* perform a frequency count on it */
		if(!palloce(palmax)) {	/* allocate room for the first palette */
			palmax=-1;
			displayerr("No Room For Another Palette");
		  }	/* end if */
		else 
			for(i=0; i<16; i++)
				egapal(i,(int)regrs[i]);
	  }	/* end else */
	if(palmax==-1)			/* grey scale not loaded properly */
		displayerr("Palette Not Specified, No Room For Any Palettes");
	else						/* successful grey scale load */		
		displayerr("Palette Not Specified, Grey Scale Palette Loaded");
}	/* end makepal() */

/**********************************************************************
*  Function	:	displayerr
*  Purpose	:	display a string in textmode, wait for keypress and
*				to graphics mode
*  Parameters	:
*			errstr -	the string to be displayed on the screen
*  Returns	:	none
*  Calls	:	textmode, updatescrn()
*  Called by	:	everywhere...
**********************************************************************/
void displayerr(errstr)
char *errstr;
{
	if(mouse && mode==NO9)
		makecur9(mx,my);
	textmode();
	printf("%s\n",errstr);
	printf("Hit any key to continue\n");
	waitq();
	grafmode();
	updatescrn();
}	/* end displayerr() */

/**********************************************************************
*  Function	:	debug
*  Purpose	:	print debugging variables
*  Parameters	:
*			s1,s2,s3,s4 -	names of variables printed
*			d1,d2,d3,d4 -	variables to print
*  Returns	:	none
*  Calls	:	none
*  Called by	:	anywhere...
**********************************************************************/
void debug(s1,d1,s2,d2,s3,d3,s4,d4)
char *s1,*s2,*s3,*s4;
int	d1,d2,d3,d4;		/* variables to display */
{
	if(mouse && mode==NO9)
		makecur9(mx,my);
	textmode();
	printf("%s=%d\n",s1,d1);
	printf("%s=%d\n",s2,d2);
	printf("%s=%d\n",s3,d3);
	printf("%s=%d\n",s4,d4);
	printf("Hit any key to continue\n");
	waitq();
	grafmode();
	updatescrn();
}	/* end debug() */

/**********************************************************************
*  Function	:	usage
*  Purpose	:	print the command line parameters
*  Parameters	:	none
*  Returns	:	none
*  Calls	:	none
*  Called by	:	main()
**********************************************************************/
void usage()
{
	printf("Command line options are as follows:\n");
	printf("\t-b xdim ydim\t: The dimensions of the binary file, and specifies\n");
	printf("\t\t\tbinary file type of data\n");
	printf("\t-m mapfile\t: The name of a palette for a binary file\n");
	printf("\t-v\t: Sets VGA display mode\n");
	printf("\t-e\t: Sets EGA display mode (default)\n");
	printf("\t-9\t: Sets Number 9 display mode\n");
	printf("\t-h\t: Specifies reading from an HDF file (default)\n");
	printf("\t-c\t: Center the image on the screen\n");
	printf("\t-p xwhere ywhere  : Specify an x & y position for the upper left hand\n");
	printf("\t\t\tcorner of the screen\n");
	printf("\t-a\t: Set animation mode\n");
	printf("\t-A\t: Set animation mode and specify animation of multiple\n");
	printf("\t\t\timages from only one hdf file\n");
	printf("\t-s\t: Specifies only one binary image and name is filename\n");
	printf("\tfilename\t: The file containing a list of binary images or\n");
	printf("\t\t\tan HDF file containing images\n\n");
	printf("Note:  for binary file usage, both the -b xdim ydim and the -m mapfile\n");
	printf("\toptions must be used for the correct displaying of the image.\n");
	printf("\tThe file name at the end of the command line is a mandatory command\n");
	printf("\tline parameter, the rest of the command line parameters are optional.\n");
}

#ifdef FUTURE 
/**********************************************************************
*  Function	:	t16line
*  Purpose	:	Convert Image to Targa format and display
*  Parameters	:
*			x,y	-	x & y coor. for the position of the line
*			store -	the pointer for the image
*			xoff - 	offset into the line
*			len -	length of a line of the image
*  Returns	:	none
*  Calls	:	pline()
*  Called by	:	showpic()
**********************************************************************/
void t16line(x,y,store,xoff,len)
int x,y,xoff,len;
unsigned char *store;
{
	short int i,		/* counter variable */
			v,			/* variable to keep track of the color for the targa */
			ind;		/* data from the image line */
 	unsigned short int *ip;	/* pointer to the current targa image line */
 
 	ip=l16;

	for (i=0; i<len; i++) {
		ind=*(store+i);		/* get the data from image in memory */
		v=bmap[ind]>>3;		/* convert into targa form */
		v |= (gmap[ind]>>3)<<5;
 		v |= (rmap[ind]>>3)<<10;
 		*ip++=v;				/* store in targa line */
	  }	/* end for */
 	pline(x,485-y,l16,len);		/* call targa line routine */
}
#endif

void NO9setup()
/* prepare variables for use in other functions */
{
	NO9ram=(char *)0xA0000;
	NO9bank=(int *)0xC0705;
}


void clrbuf(bank)
unsigned int bank;
{
	*NO9bank=bank;
	memset(NO9ram,0,0xFFFF);
	NO9ram[0xFFFF]=0;
}


void RG9gmode()
/* go into NO9 graphics mode -- not yet implemented */
{
	clrbuf(0x0000);
	clrbuf(0x00ff);
	clrbuf(0xff00);
	clrbuf(0xffff);
}

void RG9clrscr()
/* 
	Clear the screen.
*/
{
		NO9setup();
		RG9gmode();
}
