/*
	SCCS id:	@(#) fb_rat.c	1.10
	Last edit: 	10/8/85 at 12:16:24	G S M
	Retrieved: 	6/12/86 at 10:53:16
	SCCS archive:	/vld/src/libfb/s.fb_rat.c

	Modified for libfb :

			Gary S. Moss
			U. S. Army Ballistic Research Laboratory
			Aberdeen Proving Ground
			Maryland 21005-5066
			(301)278-6647 or AV-298-6647

	Original author :
			Phil Dykstra, BRL, 18 Jan 85.
*/
#if ! defined( lint )
static
char	sccsTag[] = "@(#) fb_rat.c	1.10	last edit 10/8/85 at 12:16:24";
#endif
#include <stdio.h>
#include <fb.h>
#include "./fb_ik.h"
extern char		*malloc();
typedef unsigned char	u_char;
#ifdef WRONG_JUMPERS
/* In case bytes are swapped because board is jumpered wrong.		*/
#define SWAB(s1,s2,ct)	swab(s1,s2,ct)
#else
#define SWAB(s1,s2,ct)
#endif
#define Max( a, b )	((a) < (b) ? (b) : (a))
#define Min( a, b )	((a) > (b) ? (b) : (a))
#define Rat_Cvt( x, y )	x -= _fbsize / 2, y = _fbsize/2 - y
#define Rat_Write( cmd, buff, ct ) \
	{ \
	SWAB( buff, buff, ct ); \
	if( write( _fbfd, buff, ct ) == -1 ) \
		{ \
		(void) fprintf( stderr, "%s : write failed!\n", cmd ); \
		return	0; \
		} \
	}
#define Round_N( a, n )	{ register int f = a%n; a = f<10 ? a-f : a+(n-f); }
#define PAD		0xA
#define	MAX_RAT_BUFF	((MAX_IK_DMA/4)*3)
#define	MAX_RAT_READ	1024
int		rat_debug = 0;
static u_char	*buff = NULL;	/* I/O buffer for raster tech. comm.	*/
static int	zoom_factor = 1;

static int	cload(), cursor(),
		debug(), entergraphics(), flood(), lutrmp(), lut8(),
		memsel(), movabs(), pixels(), quit(),
		rdmask(), rdmode(), rdpixr(), readf(), readw(), readvr(),
		rgbtru(), rmsk16(),
		scrorg(), value(), vidform(),
		warm(), wrmask(), xhair(), zoom();

/*	c o l o r s e l
	Write enable ONLY the chosen color.
 */
colorsel( color )
int color;
	{
	switch( color )
		{
	case 0 :
		return	wrmask( 255, 4 );	/* Red */
	case 1 :
		return	wrmask( 255, 2 );	/* Green */
	case 2 :
		return	wrmask( 255, 1 );	/* Blue */
	default :
		return	0;
		}
	}

/*	_ r a t _ o p e n ( )
	Opens the Raster Tech.
 */
_rat_open()
	{
	return	_fbfd;
	}

/*	_ r a t _ i n i t ( )
	This routine must be called before any others in this file to allocate
	the I/O buffer.
	Reset, enter graphics mode, set interlace on, turn on 24 bit color.
	Set origin and zoom factor.
 */
_rat_init()
	{
	if( buff == NULL )
		if( (buff = (u_char *) malloc( MAX_RAT_BUFF+6 )) == (u_char *) NULL )
			{
			(void) fprintf( stderr,
			"Malloc() failed, fatal error (libfb.a:_rat_init)\n"
					);
			exit( 1 );
			}
	if(	debug( rat_debug )
	    &&	warm()
	    &&	entergraphics()
	    &&	vidform( 0, 1 )
	    &&	memsel( 0 )
	    &&	rgbtru( 1 )
	    &&	wrmask( 255, 7 )	/* enable all bits & channels.	*/
	    &&	rdmask( 255 )		/* enable for reading.		*/
	    &&	readf( 0 )
	    &&	rdmode( 1 )
	    &&	_rat_zoom( 1, 1 ) == 0
	    &&	scrorg( 0, 0 )
		)
		return	0;
	else
		return	-1;
	}

/*	_ r a t _ c l o s e ( )
	Issue quit command, and close connection.
 */
_rat_close()
	{
	if(  !	quit()
	    ||	close( _fbfd ) == -1
		)
		{
		(void) fprintf( stderr, "_rat_close() close failed!\n" );
		return	-1;
		}
	return	0;
	}

/*	_ r a t _ c l e a r ( )
	Clear the Raster Tech. to the background color.
 */
_rat_clear()
	{
	if(	value(	_fbbackground.red,
			_fbbackground.green,
			_fbbackground.blue
			)
	    &&	flood()
		)
		return	0;
	else
		return	-1;
	}
				
/*	_ r a t _ w m a p ( )
	Load the color map into the frame buffer.
 */
_rat_wmap( map )
ColorMap	*map;
	{
	register int	i;
	
	/* If map is NULL, write standard map.				*/
	if( map == (ColorMap *) NULL )
		if( ! lutrmp( 7, 0, 255, 0, 255 ) )
			return	-1;
		else
			return	0;
	else
		{
		for( i = 0; i < 256; i++ )
			if( ! lut8(	i,
					map->cm_red[i], 
					map->cm_green[i],
					map->cm_blue[i]
					)
				)
				return	-1;
		}
	return	0;
	}

/*	_ r a t _ r m a p ( )
	Fetch the color map from the frame buffer.
 */
_rat_rmap( map )
ColorMap	*map;
	{
	return	0;
	}

/*	_ r a t _ w r i t e ( )						*/
_rat_write( x, y, addr, ct )
int	x, y;
register Pixel	*addr;
register int	ct;
	{
	register int	nrows;
	int		ncols;

	/* If first scanline is a partial, output it seperately.	*/
	if( x > 0 || x + ct <= _fbsize )
		{	register int	bytes, i;
			register u_char	*p = buff+5;
		if( ! movabs( x, y ) )
			return	-1;
		if( x + ct <= _fbsize )
			ncols = i = ct;	/* Only 1 scanline is involved.	*/
		else			/* First scan is a partial.	*/
			ncols = i = _fbsize - x;
		y++;
		for( bytes = 0; i > 0; i--, addr++, bytes += 3, ct-- )
			{
			*p++ = addr->red;
			*p++ = addr->green;
			*p++ = addr->blue;
			}
		if( ! pixels( 1, ncols, buff, bytes ) )
			return	-1;
		}
	/* Do all full scanlines.					*/
	while( (nrows = ct / _fbsize) != 0 )
		{	register int	bytes, i;
			register u_char	*p = buff+5;
		if( ! movabs( 0, y ) )
			return	-1;
		if( nrows * _fbsize * 3 > MAX_RAT_BUFF )
			nrows = MAX_RAT_BUFF / (_fbsize * 3);
		y += nrows;
		for(	i = nrows * _fbsize, bytes = 0;
			i > 0;
			i--, addr++, bytes += 3, ct--
			)
			{
			*p++ = addr->red;
			*p++ = addr->green;
			*p++ = addr->blue;
			}
		if( ! pixels( nrows, _fbsize, buff, bytes ) )
			return	-1;
		}
	/* If partial scanline remains, finish up.			*/
	if( ct > 0 )
		{	register int	bytes, i;
			register u_char	*p = buff+5;
		if( ! movabs( 0, y ) )
			return	-1;
		ncols = ct;
		for( bytes = 0; ct > 0; addr++, bytes += 3, ct-- )
			{
			*p++ = addr->red;
			*p++ = addr->green;
			*p++ = addr->blue;
			}
		if( ! pixels( 1, ncols, buff, bytes ) )
			return	-1;
		}
	return	0;
	}

/*	_ r a t _ r e a d ( )
 */
_rat_read( x, y, addr, ct )
int	x, y;
register Pixel	*addr;
register int	ct;
	{
	register int	nrows;
	register int	bytes;
	register int	load;
	register u_char	*p;

	/* If first scanline is a partial, input it seperately.		*/
	if( x > 0 || x + ct <= _fbsize )
		{	register int	i;
		if( ! movabs( x, y ) )
			return	-1;
		y++;
		if( x + ct <= _fbsize )
			i = ct;		/* Only 1 scanline is involved.	*/
		else
			i = _fbsize - x; /* First scan is a partial.	*/
		if( ! readw( 1, i, 1 ) )
			return	-1;
		for(	bytes = i * 3, p = buff;
			bytes > 0;
			bytes -= load, p += load
			)
			{
			if( bytes > MAX_RAT_READ )
				load = MAX_RAT_READ;
			else
				load = bytes;		
			if( read( _fbfd, p, load ) < load )
				{
				(void) fprintf( stderr,
						"_rat_read() read failed\n"
						);
				return	-1;
				}
			}
		SWAB( buff, buff, i * 3 );
		for( p = buff; i > 0; i--, addr++, ct-- )
			{
			addr->red = *p++;
			addr->green = *p++;
			addr->blue = *p++;
			}
		}
	/* Do all full scanlines.					*/
	while( (nrows = ct / _fbsize) != 0 )
		{	register int	i;
		if( ! movabs( 0, y ) )
			return	-1;
		if( nrows * _fbsize * 3 > MAX_RAT_BUFF )
			nrows = MAX_RAT_BUFF / (_fbsize * 3);
		i = nrows * _fbsize;
		y += nrows;
		if( ! readw( nrows, _fbsize, 1 ) )
			return	-1;
		for(	bytes = i * 3, p = buff;
			bytes > 0;
			bytes -= load, p += load
			)
			{
			if( bytes > MAX_RAT_READ )
				load = MAX_RAT_READ;
			else
				load = bytes;		
			{ register int	ii;
			for( ii = 0; ii < load; ii++ )
				p[ii] = 100;
			}
			if( read( _fbfd, p, load ) < load )
				{
				(void) fprintf( stderr,
						"_rat_read() read failed\n"
						);
				return	-1;
				}
			}
		SWAB( buff, buff, i * 3 );
		for(	p = buff;
			i > 0;
			i--, addr++, ct--
			)
			{
			addr->red = *p++;
			addr->green = *p++;
			addr->blue = *p++;
			}
		}
	if( ct > 0 )
		{ /* Do partial scanline.				*/
			register int	i;
			register u_char	*p = buff;

		/*(void) fprintf( stderr, "doing partial scan at end\n" );*/
		if(   !	movabs( 0, y )
		   || ! readw( 1, ct, 1 )
			)
			return	-1;
		for(	bytes = ct * 3, p = buff;
			bytes > 0;
			bytes -= load, p += load
			)
			{
			if( bytes > MAX_RAT_READ )
				load = MAX_RAT_READ;
			else
				load = bytes;		
			if( read( _fbfd, p, load ) < load )
				{
				(void) fprintf( stderr,
						"_rat_read() read failed\n"
						);
				return	-1;
				}
			}
		SWAB( buff, buff, ct * 3 );
		for( p = buff; ct > 0; addr++, ct-- )
			{
			addr->red = *p++;
			addr->green = *p++;
			addr->blue = *p++;
			}
		}
	return	0;
	}

/*	_ r a t _ r p i x e l ( )					*/
_rat_rpixel( x, y, pixel )
int	x, y;
Pixel	*pixel;
	{
	if(   !	movabs( x, y )
	   || !	rdpixr( 7 )
	   || ! readvr( 7 )
		)
		return	-1;
	if( read( _fbfd, buff, 4 ) != 4 )
		{
		(void) fprintf( stderr, "_rat_rpixel() read failed!\n" );
		return	-1;
		}
	SWAB( buff, buff, 4 );
	pixel->red = buff[0];
	pixel->green = buff[1];
	pixel->blue = buff[2];
	return	0;
	}

/*	_ r a t _ s e t _ c u r s o r ( )
 */
_rat_set_cursor()
	{
	return	0;
	}

/*	_ r a t _ c u r s o r ( )
 */
_rat_cursor( mode, x, y )
int	mode, x, y;
	{
	if(   !	cload( 5, x, y )
	   || ! xhair( 0, mode )
/*	if(   !	cload( 17, x, y )
	   || ! cursor( 0, mode )*/
		)
		return	-1;
	return	0;
	}

/*	_ r a t _ z o o m ( )
 */
/*ARGSUSED*/
_rat_zoom( x, y )
int	x, y;
	{
	/* The Raster Tech does not scale independently in x and y.
		Also addressing is the same in low and high res. so
		must zoom twice for low res.
	 */
	zoom_factor = Max( x, y );
	zoom_factor = Min( zoom_factor, 16 );
	zoom_factor = Max( zoom_factor, 1 );
	return	zoom(	_fbsize == 512 && zoom_factor < 16 ?
			zoom_factor * 2 :
			zoom_factor
			) ? 0 : -1;
	}

/*	_ r a t _ w i n d o w ( )
	This routine takes advantage of the fact that there is only 1
	scaling parameter available (equal scaling in x and y).
 */
_rat_window( x, y )
int	x, y;
	{
	Rat_Cvt( x, y );
	Round_N( x, 20 );
	return	scrorg( x, y ) ? 0 : -1;
	}

static int
cload( creg, x, y )
int	creg, x, y;
	{
	Rat_Cvt( x, y );
	buff[0] = 0xA0;
	buff[1] = creg;
	buff[2] = (x>>8)&0x0FF;		/* high_x, low_x.	*/
	buff[3] = x&0x0FF;
	buff[4] = (y>>8)&0x0FF;		/* high_y, low_y.	*/
	buff[5] = y&0x0FF;
	Rat_Write( "cload", buff, 6 );
	return	1;
	}

static int
cursor( num, flag )
int	num, flag;
	{
	buff[0] = 0x4A;
	buff[1] = num;
	buff[2] = flag;
	buff[3] = PAD;
	Rat_Write( "cursor", buff, 4 );
	return	1;
	}

static int
debug( flag )
int	flag;
	{
	buff[0] = 0xA8;
	buff[1] = flag;
	Rat_Write( "debug", buff, 2 );
	return	1;
	}

static int
entergraphics()
	{
	buff[0] = 0x04;
	buff[1] = PAD;
	Rat_Write( "entergraphics", buff, 2 );
	return	1;
	}

static int
flood()
	{
	buff[0] = 0x07;
	buff[1] = PAD;
	Rat_Write( "flood", buff, 2 );
	return	1;
	}

static int
lutrmp( code, sind, eind, sval, eval )
int	code, sind, eind, sval, eval;
	{
	buff[0] = 0x01d;
	buff[1] = code;
	buff[2] = sind;
	buff[3] = eind;
	buff[4] = sval;
	buff[5] = eval;
	Rat_Write( "lutrmp", buff, 6 );
	return	1;
	}

static int
lut8( index, r, g, b )
int	index;
u_char	r, g, b;
	{
	buff[0] = 0x01c;
	buff[1] = index;
	buff[2] = r;
	buff[3] = g;
	buff[4] = b;
	buff[5] = PAD;
	Rat_Write( "lut8", buff, 6 );
	return	1;
	}

/*	m e m s e l ( )
	Select a memory unit.
	Since the RLE format splits up the colors running in RGBTRU OFF
	and selecting the unit for each color is the easiest way to go.
 */
static int
memsel( unit )
int	unit;
	{
	buff[0] = 0x48;
	buff[1] = unit;
	Rat_Write( "memsel", buff, 2 );
	return	1;
	}

/*	m o v a b s ( )
	Set the current position (CREG 0) to (x, y).
	The generic device has its origin in the upper left corner (modeled
	after the Ikonas or a UNIX file)...


	(0,      0)..................(_fbsize,       0)
	.                                             .
	.                                             .
	.                                             .
	.                                             .
	.                                             .
	.                                             .
	.                                             .
	(0, _fbsize).................(_fbsize, _fbsize)


	The Raster Tech. is a 4-quadrant cartesian device, so its origin is at
	screen center...


	(-_fbsize/2, _fbsize/2)......(_fbsize/2, _fbsize/2)
	.                                                 .
	.                                                 .
	.                                                 .
	.                      (0, 0)                     .
	.                                                 .
	.                                                 .
	.                                                 .
	(-_fbsize/2, -_fbsize/2).....(_fbsize/2, -_fbsize/2)
 */
static int
movabs( x, y )
register int	x, y;
	{
	Rat_Cvt( x, y );
	buff[0] = 0x1;
	buff[1] = (x>>8)&0x0FF;		/* high_x, low_x.	*/
	buff[2] = x&0x0FF;
	buff[3] = (y>>8)&0x0FF;		/* high_y, low_y.	*/
	buff[4] = y&0x0FF;
	buff[5] = PAD;
	Rat_Write( "movabs", buff, 6 );
	return	1;
	}

static int
pixels( rows, cols, buff, bytes )
int		rows, cols;
register u_char	*buff;
int		bytes;
	{
	register int	ct;

	debug( 0 );
	ct = bytes & 1 ? 5 + bytes : 6 + bytes; /* Insure even count.	*/
	buff[0] = 0x28;
	buff[1] = rows>>8 & 0xFF;
	buff[2] = rows & 0xFF;
	buff[3] = cols>>8 & 0xFF;
	buff[4] = cols & 0xFF;
	SWAB( buff, buff, ct );
	if( write( _fbfd, buff, ct ) == -1 )
		{
		(void) fprintf( stderr, "pixels : write failed!\n" );
		return	0;
		}
	debug( rat_debug );
	return	1;
	}

static int
quit()
	{
	buff[0] = 0xFF;
	buff[1] = PAD;
	Rat_Write( "quit", buff, 2 );
	return	1;
	}

/*	r d m a s k ( )
	Set read mask.
 */
static int
rdmask( bitm )
int	bitm;
	{
	buff[0] = 0x9E;
	buff[1] = bitm;
	Rat_Write( "rdmask", buff, 2 );
	return	1;
	}

/*	r d m o d e ( )
 */
static int
rdmode( flag )
int	flag;
	{
	buff[0] = 0xD3;
	buff[1] = flag;
	Rat_Write( "rdmode", buff, 2 );
	return	1;
	}

static int
rdpixr( vreg )
int	vreg;
	{
	buff[0] = 0xAF;
	buff[1] = vreg;
	Rat_Write( "rdpixr", buff, 2 );
	return	1;
	}

static int
readf( func )
int	func;
	{
	buff[0] = 0x27;
	buff[1] = func;
	Rat_Write( "readf", buff, 2 );
	return	1;
	}
	
static int
readvr( vreg )
int	vreg;
	{
	buff[0] = 0x99;
	buff[1] = vreg;
	Rat_Write( "readvr", buff, 2 );
	return	1;
	}

static int
readw( rows, cols, bf )
int	rows, cols, bf;
	{
	buff[0] = 0x96;
	buff[1] = rows>>8 & 0xFF;
	buff[2] = rows & 0xFF;
	buff[3] = cols>>8 & 0xFF;
	buff[4] = cols & 0xFF;
	buff[5] = bf;
	Rat_Write( "readw", buff, 6 );
	return	1;
	}

static int
rgbtru( flag )
int	flag;
	{
	buff[0] = 0x4e;
	buff[1] = flag;
	Rat_Write( "rgbtru", buff, 2 );
	return	1;
	}

static int
rmsk16( mask )
int	mask;
	{
	buff[0] = 0x43;
	buff[1] = mask;
	Rat_Write( "rmsk16", buff, 2 );
	return	1;
	}

/*	s c r o r g ( )
	Set the screen-center coordinate (CREG 4) to (x, y).
 */
static int
scrorg( x, y )
int	x, y;
	{
	buff[0] = 0x36;
	buff[1] = (x>>8) & 0x0FF;		/* high_x, low_x.	*/
	buff[2] = x & 0x0FF;
	buff[3] = (y>>8) & 0x0FF;		/* high_y, low_y.	*/
	buff[4] = y & 0x0FF;
	buff[5] = PAD;
	Rat_Write( "scrorg", buff, 6 );
	return	1;
	}

static int
value( red, green, blue )
u_char	red, green, blue;
	{
	buff[0] = 0x06;
	buff[1] = red;
	buff[2] = green;
	buff[3] = blue;
	Rat_Write( "value", buff, 4 );
	return	1;
	}

static int
vidform( mode, flag )
int	mode, flag;
	{
	buff[0] = 0x08;
	buff[1] = mode;
	buff[2] = flag;
	buff[3] = PAD;
	Rat_Write( "vidform", buff, 4 );
	return	1;
	}

static int
warm()
	{
	buff[0] = 0xFE;
	buff[1] = PAD;
	Rat_Write( "warm", buff, 2 );
	return	1;
	}

/*	w r m a s k ( )
	Set write mask.
 */
static int
wrmask( bitm, bankm )
int	bitm, bankm;
	{
	buff[0] = 0x9D;
	buff[1] = bitm;
	buff[2] = bankm;
	buff[3] = PAD;
	Rat_Write( "wrmask", buff, 4 );
	return	1;
	}

static int
xhair( num, flag )
int	num, flag;
	{
	buff[0] = 0x9C;
	buff[1] = num;
	buff[2] = flag;
	buff[3] = PAD;
	Rat_Write( "xhair", buff, 4 );
	return	1;
	}

static int
zoom( factor )
int	factor;
	{
	buff[0] = 0x34;
	buff[1] = factor;
	Rat_Write( "zoom", buff, 2 );
	return	1;
	}

