#define		MAIN
#include	<msdos.cf>
#include	"gif386.h"

_far char      *screen;			/* pointer to display memory */
int	SWidth,SHeight;

_packed struct	dta	{
	char		ff_reserved[21];
	char		ff_attrib;
	unsigned short	ff_ftime;
	unsigned short	ff_fdate;
	long		ff_fsize;
	char		ff_name[13];
} DTA ;

main(int argc,char **argv)	{
extern	char *Image;
char	fn[65];
int	bDone = 0;
int	device;

	if (argc == 1)	{
		fprintf(stderr,"usage: gif386 [device] giffile\n");
		fprintf(stderr,"where	device =\n");
		fprintf(stderr,"o	orchid\n");
		fprintf(stderr,"e	everex\n");
		fprintf(stderr,"v	video7\n");
		fprintf(stderr,"p	paradise\n");
		fprintf(stderr,"g	generic (default)\n");
		exit(1);
	}

	findfirst(fn,argv[argc - 1]);

	LoadGIF(fn);

	if (argc == 3)
		device = set_device(argv[1][0]);
	else
		device = set_device('g');		

	while (1)	{
		bDone = !DoDisplay(Image,device);

		if (bDone)	
			break;

		findnext(fn,argv[argc - 1]);

		LoadGIF(fn);
	}

	restore_palette();
	restore_screen();
}


int	restore_palette()	{

}

int	restore_screen()	{

	Registers.AX.LH.H = 0;
	Registers.AX.LH.L = 0x03;
	callint(0x10);	
}

int	set_device(char d)	{
int	device;
	
	/*
	 * 0x1c is the Phar Lap DOS|Extender selector for the screen.
	 */
	 
	((struct overlay *) &screen)->seg = 0x1c;
	((struct overlay *) &screen)->off = 0;

/*	
	Registers.AX.LH.H = 0x10;
	Registers.AX.LH.L = 0x13;	
	Registers.BX.W    = 0;
	callint(0x10);
*/	

	switch(d)	{
		case 'o':
			SWidth = HWIDTH;
			SHeight= HHEIGHT;
		   	Registers.AX.LH.H = 0;
			Registers.AX.LH.L = 0x30; /* 800 X 600 X 256 mode */
			callint(0x10);
			device = TSENG;
		break;			

		default:
			SWidth = LWIDTH;
			SHeight= LHEIGHT;
		   	Registers.AX.LH.H = 0;
			Registers.AX.LH.L = 0x13; /* 320 X 200 X 256 mode */
			callint(0x10);
			device = GENERIC;
		break;					
	}

	return device;
}	

setup_palette()	{
extern	byte Red[256],Green[256],Blue[256],used[256];
extern  int	numused;
register int	color;
double	R,G,B;
byte	r,g,b;

	for (color = 0;color < 256;color++)	{
		if (used[color])	{

		   	Registers.AX.LH.H = 0x10;
		   	Registers.AX.LH.L = 0x10;
			Registers.BX.W    = (short)color;

			R = 63.0 * ((double)Red[color] / 255.0);
			r = (byte)R;

			G = 63.0 * ((double)Green[color] / 255.0);
			g = (byte)G;

			B = 63.0 * ((double)Blue[color] / 255.0);
			b = (byte)B;		

			Registers.DX.LH.H = r;
			Registers.CX.LH.H = g;
			Registers.CX.LH.L = b;

			callint(0x10);
		}
	}
}

DoDisplay(char *image,int device)	{
extern	int	Width,Height;
int	x,y,bQuit,bDontDraw,bNext;

	x = 0;
	y = 0;
	bQuit = 0;
	bDontDraw = 0;
	bNext = 0;
	
	setup_palette();

	while(1)	{
		if (!bDontDraw)
			BitBlt(SWidth,SHeight,x,y,Width,Height,image,device);

		bDontDraw = 0;	

		/* get key */
		Registers.AX.LH.H = 0;
		callint(0x16);

		if (Registers.AX.LH.L == 0)	
		switch(Registers.AX.LH.H)	{
			case 72:	y--; break;
			case 80:	y++; break;
			case 77:	x++; break;
			case 75:	x--; break;			

			case 73:	y-=10; break;
			case 81:	y+=10; break;
			case 116:	x+=10; break;
			case 115:	x-=10; break;
			case 82:	changepalette(1); bDontDraw = 1; break;
			case 83:	changepalette(-1); bDontDraw = 1; break;
			case 60:	pan(x,y,image,device); break;
		}
		else
			switch(Registers.AX.LH.L)	{
				case 'q':
				case 27:	bQuit = 1; break;
				case 'n':	bNext = 1; break;
				case 'g':	grayscalesum(); bDontDraw = 1; break;
				case 's':	smooth(Width,Height,image);
			}

		if (x < 0)	x = 0;
		if (y < 0)	y = 0;
		if (y > (Height - SHeight)) y = Height - SHeight;
		
		if (bQuit || bNext)
			break;

	}

	return bNext;	
}


BitBlt(int swidth,int sheight,int ix,int iy,int iwidth,int iheight,char *image,int device) {
register int pixel,count,scan,ioffset;
int	width,height;
short	bank;

	width = (iwidth < swidth) ? iwidth : swidth;
	height= (iheight< sheight)? iheight: sheight;

	count = 0;
	bank  = 0;
	ioffset = iy * iwidth + ix;
	SetBank(device,bank);
	
	for (scan = 0;scan < height;scan++)	{
		for (pixel = 0;pixel < swidth;pixel++)	{
			screen[count++] =
				(pixel < width) ?
				image[ioffset + pixel] :
				0;
				
			if (count & 0x10000)	{
				SetBank(device,++bank);
				count = 0;
			}
		}

		ioffset += iwidth;
	}
}

changepalette(int amount)	{
register int	color;
extern byte	used[256];
int	r,g,b;

	/* set up palette */

	for (color = 0;color < 256;color++)	{
		if (used[color])	{
		
			r = Red[color];
			g = Green[color];
			b = Blue[color];

			r += amount;
			g += amount;
			b += amount;

			if (r > 255)	r = 255;
			if (g > 255)	g = 255;
			if (b > 255)	b = 255;

			if (r < 0)	r = 0;
			if (g < 0)	g = 0;
			if (b < 0)	b = 0;
			
			Red[color] = r;
			Green[color]=g;
			Blue[color]=b;
		}
	}
	setup_palette();
}

grayscalesum()	{
	Registers.AX.LH.H = 0x10;
	Registers.AX.LH.L = 0x1b;
	Registers.BX.W    = 0;
	Registers.CX.W    = 256;
	callint(0x10);
}


smooth(int width,int height,char *image)	{
register int	row,col,val,offset;

	for (row = 1;row < height - 1;row++)	{
		offset = row * width;
		
		for (col = 1;col < width - 1;col++)	{
			val =
				image[offset + col - 1] +	
				image[offset + col + 1] +
				image[offset - width + col - 1] +
				image[offset - width + col + 1] +
				image[offset - width + col] +
				image[offset + width + col + 1] +
				image[offset + width + col - 1] +
				image[offset + width + col];

			image[offset + col] = val >> 3;				
		}
	}
}

pan(int x,int y,char *image,int device)	{
register int i;
extern 	int Width,Height;	

	for (i = y;i <= (Height - SHeight);i++)
	BitBlt(SWidth,SHeight,x,i,Width,Height,image,device);
	for (;i >= 0;i--)
	BitBlt(SWidth,SHeight,x,i,Width,Height,image,device);
	for (;i <= y;i++)	
	BitBlt(SWidth,SHeight,x,i,Width,Height,image,device);
}


findfirst(char *fn,char *fs)	{
char	temp[64];
char	*ptr;
		
	Registers.AX.LH.H = 0x1A;
	Registers.DX.R = (unsigned int)(&DTA);
	Registers.DS.R = 0x14;
	
	callint(0x21);

	Registers.AX.LH.H = 0x4E;
	Registers.CX.W    = 0;
	Registers.DS.R = 0x14;
	Registers.DX.R = (unsigned int)fs;

	callint(0x21);

	strcpy(temp,fs);
	ptr = (char *)strrchr(temp,'\\');

	if (ptr != NULL)	{
		*(ptr + 1) = '\0';
		strcat(temp,DTA.ff_name);
		strcpy(fn,temp);
	} else 
		strcpy(fn,DTA.ff_name);	
}


findnext(char *fn,char *fs)	{
char	temp[64];
char	*ptr;

	Registers.AX.LH.H = 0x4F;
	Registers.DS.R = 0x14;

	callint(0x21);
	strcpy(fn,DTA.ff_name);

	strcpy(temp,fs);
	ptr = (char *)strrchr(temp,'\\');

	if (ptr != NULL)	{
		*(ptr + 1) = '\0';
		strcat(temp,DTA.ff_name);
		strcpy(fn,temp);
	} else 
		strcpy(fn,DTA.ff_name);	
	
}
