/*
	SCCS id:	@(#) fb_buf.c	1.17
	Last edit: 	3/14/86 at 12:10:29
	Retrieved: 	6/12/86 at 10:52:10
	SCCS archive:	/vld/src/libfb/s.fb_buf.c

	Authors:	Mike J. Muuss
			Douglas P. Kingston III
			Gary S. Moss
			U. S. Army Ballistic Research Laboratory
			Aberdeen Proving Ground
			Maryland 21005-5066
*/
#if ! defined( lint )
static
char	sccsTag[] = "@(#) fb_buf.c	1.17	last edit 3/14/86 at 12:10:29";
#endif
/*
	F B _ B U F . C
	Buffered frame buffer IO routines
 */
#include <stdio.h>
#include <fb.h>
#define HIDDEN
extern int	_fbfd;
extern int	_fbsize;
extern int	_fbtype;
extern Pixel	_fbbackground;

static int	fbpage;		/* Current 'page' in memory.		*/
static int	fbpgref;	/* 'referenced' flag.			*/
#if defined( vax )
#define PAGE_PIXELS	(1024*16)
#else
#define PAGE_PIXELS	(1024*4)
#endif
#define PAGE_SCANS	(PAGE_PIXELS/_fbsize)
extern char	*malloc();
static Pixel	*page = NULL;
static Pixel	*curp;		/* Current pointer into page buffer.	*/
static Pixel	*endp;		/* End of page buffer.			*/
static unsigned	page_sz = 0;	/* Sizeof page buffer (bytes).		*/
static long	curpos;		/* Pixel number.			*/
HIDDEN void	erase();
HIDDEN	int	pagein(), pageout();
void		fbioinit(), fbtell();

/*	f b i o i n i t ( )
	This initialization routine must be called before any buffered
	I/O routines in this file are used.
 */
void
fbioinit()
	{
	fbpage = -1;	/* Force pagein() initially.			*/
	curpos = 0L;	/* Initialize pixel number.			*/
	if( page_sz == 0 )	/* Only allocate buffer once.		*/
		{
		page_sz = PAGE_PIXELS * sizeof(Pixel);	/* Bytes/page.	*/
		if( (page = (Pixel *) malloc( page_sz )) == (Pixel *) NULL)
			{
			(void) fprintf( stderr,
			"Malloc() failed, fatal error (libfb.a:fbioinit)\n" );
			exit( 1 );
			}
		}
	curp = page;	/* Initialize pixel pointer.			*/
	endp = (Pixel *)((char *)(&page[0]) + page_sz);
	return;
	}

/*	f b s e e k ( )							*/
fbseek(x, y)
int	x, y;
	{	long	pos;
		long	pagepos;

#ifdef DEBUG
	(void) fprintf( stderr, "fbseek( %d, %d )\n", x, y );
#endif
	if( x < 0 || y < 0 || x > 1024 || y > 4096 )
		{
		(void) fprintf( stderr,
				"(libfb.a):fbseek(%d,%d) illegal address!\n",
				x, y
				);
		return	-1;
		}
	pos = (((long)y * (long)_fbsize)+x) * (long)(sizeof (Pixel));
	pagepos = (long)fbpage * (long)page_sz;
	if (pos < pagepos || pos >= (pagepos+page_sz))
		{
		if (fbpgref)
			if( pageout() == - 1 )
				return	-1;
		if( pagein ((int)(pos / (long)page_sz)) == -1 )
			return	-1;
		}
	curpos = ((long)y*(long)_fbsize)+x;
	/* Compute new pixel pointer into page.				*/
	curp = page + (curpos%(PAGE_PIXELS));
	return	0;
	}

void
fbtell(xp, yp)
int	*xp, *yp;
	{
	*yp = (int)(curpos/_fbsize);
	*xp = (int)(curpos%_fbsize);
	return;
	}

/*	f b w p i x e l ( )						*/
fbwpixel(pp)
Pixel *pp;
	{
	if (fbpage == -1)
		if( pagein (curpos/PAGE_PIXELS) == -1 )
			return	-1;
	*(curp++) = *pp;
	fbpgref = 1;
	curpos++;
	if(curp >= endp)
		{
		if( pageout() == - 1 )
			return	-1;
		fbpage = -1;
		}
	return	0;
	}

/*	f b r p i x e l ( )						*/
fbrpixel(pp)
Pixel *pp;
	{
	if (fbpage == -1)
		if( pagein(curpos/PAGE_PIXELS) == -1 )
			return	-1;
	*pp = *(curp++);
	curpos++;
	if(curp >= endp)
		{
		if( pageout() == -1 )
			return	-1;
		fbpage = -1;
		}
	return	0;
	}

/*	f b f l u s h ( )						*/
fbflush()
	{
	if (fbpgref)
		if( pageout() == -1 )
			return	-1;
	fbpgref = 0;
	return	0;
	}

HIDDEN
pageout()
	{
#ifdef DEBUG
	(void) fprintf( stderr, "pageout(%d)\n", fbpage );
#endif
	if (fbpage < 0)	/* Already paged out, return 1.			*/
		return	1;
	if( _fbtype == FB_RASTER_TECH )
		return	_rat_write( 0, fbpage*PAGE_SCANS, page, PAGE_PIXELS );
	if( _fbtype == FB_PTTY )
		{	int	ct = _fbsize * _fbsize;
		ct = ct > PAGE_PIXELS ? PAGE_PIXELS : ct;
		return	_ptty_write( 0, fbpage*PAGE_SCANS, page, ct );
		}
	if (lseek (_fbfd, (long)fbpage * (long)page_sz, 0) == -1L)
		{
		perror ("fb pageout seek");
		return	-1;
		}
	if (write (_fbfd, page, page_sz) != page_sz)
		{
		perror("fb pageout write");
		return	-1;
		}
	return	0;
	}

HIDDEN
pagein (pageno)
int	pageno;
	{
	int	nread;

	curp = page;	/* Set pixel pointer to beginning of pg.	*/
	fbpage = pageno;
#ifdef DEBUG
	(void) fprintf( stderr, "pagein(%d)\n", pageno );
#endif
	fbpgref = 0; 
	if( _fbtype == FB_RASTER_TECH )
		return	_rat_read( 0, fbpage * PAGE_SCANS, page, PAGE_PIXELS );
	if( _fbtype == FB_PTTY )
		return	_ptty_read( 0, fbpage * PAGE_SCANS, page, PAGE_PIXELS );

	if( lseek( _fbfd, (long)pageno * (long)page_sz, 0 ) == -1L )
		{
		perror ("fb pagein seek");
		return	-1;
		}

	if ((nread = read (_fbfd, page, page_sz)) == page_sz)
		return	0;

	if (nread < 0 || _fbtype == FB_IKONAS)
		{
		perror ("fb pagein read");
		return	-1;
		}

	/* FB_FILE, fill with background.				*/
	nread = (nread/sizeof(Pixel));
	erase (page + nread, PAGE_PIXELS - nread);
	return	0;
	}

HIDDEN void
erase (pp, cnt)
Pixel	*pp;
register int	cnt;
	{
	while (cnt--)
		*pp++ = _fbbackground;
	return;
	}
