/*
*
*  Raster image display program for the IBM PC  
*
*    This program takes 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, each image is read from the file 
*  with block reads, then displayed in the specified position on the screen.
*  Portions of the image that do not fit on the screen are clipped.
*
*  example use:    rev  256 256 -c -m pal.pal list.dat
*     the file 'list.dat' must contain a list of file names of the images
*     that are to be displayed in sequence.
*
*  The space bar pauses and restarts the display.  Return exits after any
*  image.
*
*  the mapfile is a sequence of bytes from 0 - 255.  There are 256 red values
*  followed by 256 green values followed by 256 blue values.  They are
*  divided by 16 before use because the PGA only has 16 intensities per gun.
*
*
*  National Center for Supercomputing Applications, University of Illinois
*  153 Water Resources Building
*  605 E. Springfield Ave.
*  Champaign, IL  61820     (217)244-0072
*
*  Tim Krauskopf            July 1986
*
*/
#include "stdio.h"
#include "fcntl.h"

#define USAGE  printf("\nUsage: %s xdim ydim [-c][-p xwhere ywhere][-m mapfile] fileofnames\n",argv[0])

#define RAWSIZE 32000
#define SCRX 640
#define SCRY 480
#define LINEPUT    pgalinea(xwhere,ywhere+i,store[i],xshow,1)


FILE *fp;
int		i,j,c,xdim,ydim,file,xshow,xwhere=0,ywhere=0;

unsigned char raw[RAWSIZE],             /* for file buffering */
	rmap[256],gmap[256],bmap[256];		/* color map, if specified */
unsigned char filename[128];
unsigned char palfile[128] = {0,0}; 	/* starts out = NULL */


char *store[1024],      		/* one per line of image */
	*malloc(),*p;  

main(argc,argv)
	int argc;
	char *argv[];
	{
	if (argc < 4 ) {       		/*  requires at least 2 parameters */
		USAGE;
		exit(1);
	}

	xdim = atoi(argv[1]);       /* required parms of x and y dimensions */
	if (xdim > SCRX)
		xshow = SCRX;           /* screen limits  */
	else
		xshow = xdim;

	ydim = atoi(argv[2]);

	if (xdim < 10 || ydim < 10) {
		puts("\n Huh? ");
		exit(1);
	}

	for (i=3; i<argc; i++) {      /* look at each parm */
		if (*argv[i] == '-') 
			switch ( *(argv[i]+1)) {
				case 'c':                	/*  centering  */
					xwhere = (SCRX-xdim)/2;
					ywhere = (SCRY-ydim)/2;
					if (xwhere < 0) 
						xwhere = 0;			/* if larger than screen, */
					if (ywhere < 0)			/* don't center it */
						ywhere = 0;
					break;
				case 'p':                	/* special position */
					xwhere = atoi(argv[++i]);
					ywhere = atoi(argv[++i]);
					if (xwhere > SCRX || ywhere > SCRY) {
						puts("\n Invalid position ");
						USAGE;
						exit(1);
					}
					break;
				case 'm':   				/* color map definition */
					strcpy(palfile,argv[i+1]);
					break;
				default:
					USAGE;
					exit(1);
			}
	}

/*
*  allocate memory for the image, if not enough, then error
*/
	if (enoughspace(xdim,ydim)) {
		puts("\n Not enough memory for image to be stored");
		exit(1);
	}

/*
*  open file with list of file names to display
*/
	if ( NULL == (fp = fopen(argv[argc-1],"ra" ))) {
		printf("\n%s: Error opening %s",argv[0],argv[3]);
		exit(1);
	}

/*
*  graphics initialization
*/
	initpga();

	if (*palfile)    					/* if there is a palette specified */
		loadpal(palfile);


/*
*  cycle through all of the file names
*/
	*filename = '\0';

	while (NULL != fgets(filename,100,fp)) {     /* while there are files */

		if (*filename < 33)
			break;               /* exit the program if end of list */

		p = filename;

		while (*p > 32)          /*  find the first non printable char or sp*/
			p++;
		*p = '\0';               /*  truncate the file name for use by open */


		if ( 0 > (file = open(filename,O_RDONLY | O_RAW))) {
			printf("\n%s: Error opening image file: %s",argv[0],filename);
			restpga();
			exit(1);
		}

		readpic(file,xdim,ydim);        /* block read from disk */

		close(file);

		for (i=0; i<ydim; i++)          /* display the image */
			LINEPUT;

/*
*  see if we should pause because of keypress
*/
		if (kbhit()) {                 	/* if key(s) is pressed */
			while (kbhit())		
				c = getch();            /* empty backlog */

			if (c == ' ') {
				while (!kbhit()) ;      /* wait for another to restart */
				c = getch();            /* clear buffer */
			}

			if (c != ' ') {             /* RETURN will exit program */
				fclose(fp);
				restpga();
				exit(0);
			}
		}

    }

	fclose(fp);
	restpga();
	exit(0);
}

/*************************************************************************/
/*  readpic
*
*      block read the file and copy to main memory storage
*   Block reading the hard disk (or floppy) saves enough time to pay for
*   the extra memory-to-memory move and then some.
*
*/
readpic(file,len,lines)
	int file,len,lines;
	{
	int i,lno,readsize,readfact;
	char *p;

	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++) {
			movmem(p,store[lno++],len);
			p += len;
		}

	} while (lno < lines);

}
		
/**********************************************************************/
/*  enoughspace
*
*   make enough room for maximum row,col size
*
*   Image memory is allocated line by line because of 64K data limitation
*   of the PC.  
*
*   returns error code of 1 if not enough memory
*/
enoughspace(c,l)
	int l,c;
    {
	int i;

   	for (i=0; i < l; i++) {				/* allocate each line separately */
		store[i] = malloc(c);

		if (store[i] == NULL)   		/* malloc returned not enough */
			return(1);
	}

	return(0);                     		/* successful return */

}



loadpal(s)
	char *s;
	{
	int i;
	FILE *pfp;

    if (NULL == (pfp = fopen(s,"rb"))) {        puts("Error on palette file open ");
		restpga();        exit(2);    }
    for (i=0; i < 256 ; i++) {        fread(rmap,1,256,pfp);        fread(gmap,1,256,pfp);        fread(bmap,1,256,pfp);   }
   fclose(pfp);
/*
*  divide by 16 to fit PGA
*/

	for (i=0; i< 256; i++) {
		mapcolor(i,rmap[i]>>4,gmap[i]>>4,bmap[i]>>4);
	}


}
