/*
 *	NOTE: mgif can now display flicker files, too. i used t his before
 *	that was added and thought it might be useful standalone...
 */

#undef FULL_SCREEN

/*
 *	showfl - display a flicker-mode .FL file
 *
 *	file consists of:
 *
 *	offset	size	item
 *	------	----	---------------------------------
 *	0	10	magic (FLICKER91a)
 *	10	256	header
 *		2	w (in pixels, NOT bytes)
 *		2	h (in pixels, NOT bytes)
 *		252	reserved (should be 0 for FLICKER91a)
 *	266	n	pixel data (3 "screens" holding bytes, 8 pixels
 *			per byte). for widths not evenly divisible by 8,
 *			a partial byte is used. so:
 *
 *				if (w % 8)
 *					nbytes = ((w + 8) / 8);
 *				else
 *					nbytes = (w / 8);
 *			and
 *
 *				nlines = h;
 *
 *			n will be 3 * nbytes * nlines. for a 320x200 image,
 *			n is 24000 (similar GIF is 25k to 50k bytes).
 */

static char *sccsid = "@(#) showfl 1.0 91/6/6 rosenkra\0\0                 ";
char        *myname = "showfl\0\0\0\0\0\0";
char        *version = "showfl 1.0 91/6/6 rosenkra\0\0\0                   ";


#include <stdio.h>
#include <osbind.h>

#define reg_t		register
#define DBG(x)		/*printf x*/

#define SCRNSPACE	48256L	/* buffer size for 3 screens (words) */
				/* leave extra to word-align */

/*
 *	globals:
 */
int	_Width;			/* image size */
int    	_Hight;
int	_ScrnBuf[SCRNSPACE];	/* enuf for 3 screens... */
int    *_Scrn;			/* -> first screen */
int	montage = 0;

/*
 *	local functions
 */
int	read_fl ();
int	showfl ();


/*------------------------------*/
/*	main			*/
/*------------------------------*/
main (argc, argv)
int	argc;
char   *argv[];
{
	reg_t long	ii;
	reg_t int      *pscrn;
	int		count;


	/*
	 *   align to page boundary
	 */
	_Scrn = (int *) (((long) _ScrnBuf + 256L) & 0xFFFFFF00L);



	/*
	 *   parse args...
	 */
	for (argc--, argv++; (argc && **argv == '-'); argc--, argv++)
	{
		switch (*(*argv+1))
		{
		case 'v':
			printf ("%s\n", version);
			exit (0);			/* NO RETURN */

		case 'h':
			usage (0);			/* NO RETURN */

		case 'm':
			montage++;
			break;

		default:
			break;
		}
	}



	/*
	 *   make sure we have at least one file...
	 */
	if (argc < 1)
		usage (1);				/* NO RETURN */



	if (montage)
	{
		/*
		 *   for either 4 320x200 images or 6 200x200 images. first
		 *   read them. note changing ptr into screen buffers...
		 */
		pscrn = _Scrn;
		count = 0;
		while (argc--)
		{
			printf ("Reading %s\n", *argv);
			if (!read_fl (*argv, pscrn, &_Width, &_Hight))
			{
				fprintf (stderr, "read_fl failed for %s\n", *argv);
				exit (1);
			}
			count++;
			argv++;
			if ((_Width <= 320) && (_Width > 200)
			&& (_Hight <= 400) && (_Hight > 200))
			{
				/*
				 *   2 320x400 images...
				 */
				if (count == 1)
					pscrn = (int *) ((long) _Scrn + 40L);
				else
					break;
			}
			else if ((_Width <= 320) && (_Width > 200)
			&& (_Hight <= 200))
			{
				/*
				 *   4 320x200 images...
				 */
				if (count == 1)
					pscrn = (int *) ((long) _Scrn + 40L);
				else if (count == 2)
					pscrn = (int *) ((long) _Scrn + 16000L);
				else if (count == 3)
					pscrn = (int *) ((long) _Scrn + 16040L);
				else
					break;
			}
			else if ((_Width <= 200) && (_Hight <= 200))
			{
				/*
				 *   6 200x200 images...
				 */
				if (count == 1)
					pscrn = (int *) ((long) _Scrn + 25L);
				else if (count == 2)
					pscrn = (int *) ((long) _Scrn + 50L);
				else if (count == 3)
					pscrn = (int *) ((long) _Scrn + 16000L);
				else if (count == 4)
					pscrn = (int *) ((long) _Scrn + 16025L);
				else if (count == 5)
					pscrn = (int *) ((long) _Scrn + 16050L);
				else
					break;
			}
			else
				break;
		}


		/*
		 *   show them all...
		 */
		showfl (_Scrn);
	}
	else
	{
		/*
		 *   loop on files
		 */
		while (argc--)
		{
			/*
			 *   read file. if ok, display...
			 */
			printf ("Reading %s\n", *argv);
			if (read_fl (*argv, _Scrn, &_Width, &_Hight))
				showfl (_Scrn);


			/*
			 *   clear screen buffer for next image if there
			 *   is one...
			 */
			if (argc)
			{
				pscrn = _ScrnBuf;
				for (ii = 0L; ii < SCRNSPACE; ii++)
					*pscrn++ = 0;
				argv++;
			}
		}
	}

	exit (0);
}




/*------------------------------*/
/*	read_fl			*/
/*------------------------------*/

#define NCHUNK		400		/* size of chuck to read */
#define FL3MAGSZ	10		/* size of magic (chars) */
#define FL3HDRSZ	256		/* size of header */
#define MAGIC_FL3	"FLICKER91a"	/* magic string */

int read_fl (fname, pscrn, w, h)
char   *fname;				/* file name (in) */
int    *pscrn;				/* where to put screen data (out) */
int    *w;				/* size of image, pixels (out) */
int    *h;
{

/*
 *	read the flicker file. return 0 if error else 1.
 */

	reg_t char     *pbuf;
	reg_t int      *pint;
	reg_t int	nbytes;
	reg_t int	nlines;
	reg_t long	ii;
	int		fd;
	FILE	       *stream;
	char		magic[FL3MAGSZ+10];
	char		header[FL3HDRSZ+10];
	char	       *pheader;


	DBG (("enter read_fl...\n"));

	/*
	 *   open the .fl file, binary...
	 */
	if ((stream = fopenb (fname, "r")) == (FILE *) NULL)
	{
		printf ("Error openning %s.\n", fname);
		return (0);
	}
	fd = fileno (stream);



	/*
	 *   read .fl magic
	 */
	read (fd, magic, (int) FL3MAGSZ);
	if (strncmp (magic, MAGIC_FL3, 10))
	{
		printf ("Bad magic here...\n");
		fclose (stream);
		return (0);
	}



	/*
	 *   read .fl header:
	 *
	 *	offset	size	item
	 *	------	----	-----------------------------------------
	 *	0	2	width (pixels)
	 *	2	2	height (pixels)
	 */
	if (header & 1)		pheader = (char *) (&header[1]);
	else			pheader = (char *) (&header[0]);

	read (fd, pheader, (int) FL3HDRSZ);

	pint = &pheader[0];	*w = *pint;
	pint = &pheader[2];	*h = *pint;



#ifdef FULL_SCREEN
	/*
	 *   read the screens, sequentially. each screen is 32000 and there
	 *   are 3 screens for a total of 96000 bytes. work with NCHUNK bytes
	 *   at a time.
	 */
	pbuf = (char *) pscrn;
	for (ii = 0L; ii < 96000L/NCHUNK; ii++)	/* number of reads */
	{
		read (fd, pbuf, (int) NCHUNK);

		pbuf += (long) NCHUNK;
	}
#else
	/*
	 *   this is space-saver version. we only need the actual pixels,
	 *   not the whole screen saved. find actual byte count for files
	 *   with w not evenly divisible by 8.
	 */
	if ((int) *w % 8)
		nbytes = ((*w + 8) >> 3);
	else
		nbytes = (*w >> 3);
	nlines = *h;

	/* screen 1 */
	for (pbuf = (char *) pscrn, ii = 0L; ii < nlines; ii++)
	{
		read (fd, pbuf, nbytes);
		pbuf += 80L;		/* 640x400 screen has 80 bytes/line */
	}

	/* screen 2 */
	for (pbuf = (char *) ((long) pscrn + 32000L), ii = 0L; ii < nlines; ii++)
	{
		read (fd, pbuf, nbytes);
		pbuf += 80L;
	}

	/* screen 3 */
	for (pbuf = (char *) ((long) pscrn + 64000L), ii = 0L; ii < nlines; ii++)
	{
		read (fd, pbuf, nbytes);
		pbuf += 80L;
	}
#endif


	/*
	 *   done. return success...
	 */
	fclose (stream);
	DBG (("read_fl returning...\n"));

	return (1);
}




/*------------------------------*/
/*	showfl			*/
/*------------------------------*/
int showfl (s0)
int    *s0;
{

/*
 *	show a flicker image already in memory. for 640x400 ONLY!!!
 *	returns char read to stop the display as low byte of int.
 */

	reg_t long	ii;
	reg_t char     *ps1;
	reg_t char     *ps2;
	char	       *old1;
	char	       *old2;
	int	       *s1, *s2, *s3;
	long		ret;


	DBG (("enter showfl...\n"));

	/*
	 *   remember old screen
	 */
	old1 = Logbase ();
	old2 = Physbase ();



	/*
	 *   clear these (phys and logical)
	 */
	ps1 = old1;
	ps2 = old2;
	for (ii = 0L; ii < 32000L; ii++)
	{
		*ps1++ = 0;
		*ps2++ = 0;
	}



	/*
	 *   set phys screen to first screen
	 */
	Setscreen (old2, s0, -1);



	/*
	 *   set pointers
	 */
	s1 = (int *) Physbase ();
	s2 = (int *) ((long) s1 + 32000L);
	s3 = (int *) ((long) s2 + 32000L);



	/*
	 *   display until a key is pressed
	 */
	do
	{
		Setscreen (old2, s1, -1);	Vsync ();
		Setscreen (old2, s2, -1);	Vsync ();
		Setscreen (old2, s3, -1);	Vsync ();

	} while (!Bconstat (2));



	/*
	 *   get the key...
	 */
	ret = Bconin (2) & 0x000000ffL;



	/*
	 *   reset screen
	 */
	Setscreen (old1, old2, -1);



	/*
	 *   clear keypresses
	 */
	while (Bconstat (2))
		Bconin (2);


	/*
	 *   done.
	 */
	return ((int) ret);
}




/*------------------------------*/
/*	usage			*/
/*------------------------------*/
usage (excode)
int	excode;
{
	printf ("Usage: %s [-m] file.fl ...\n", myname);
	exit (excode);
}

