/*
 *			D M - R A T . C
 *
 *  MGED display manager for the Raster Technology Model One/180
 *  display or Model One/380 display WITHOUT the displaylist capability.
 *  This version only works over the Gould MP bus parallel interface
 *  with the standard Gould UNIX driver.
 *
 *  Authors -
 *	Charles M. Kennedy
 *	Phil Dykstra
 *	Michael John Muuss
 *  
 *  Source -
 *	SECAD/VLD Computing Consortium, Bldg 394
 *	The U. S. Army Ballistic Research Laboratory
 *	Aberdeen Proving Ground, Maryland  21005
 *  
 *  Copyright Notice -
 *	This software is Copyright (C) 1985 by the United States Army.
 *	All rights reserved.
 */
#ifndef lint
static char RCSid[] = "@(#)$Header: dm-rat.c,v 2.7 86/01/15 23:03:23 mike Exp $ (BRL)";
#endif

#include <stdio.h>
#include <string.h>
#include "./machine.h"	/* special copy */
#include "../h/vmath.h"
#include "ged.h"
#include "dm.h"
#include "solid.h"
#include "../h/mater.h"

extern void	perror();
extern unsigned	sleep();

typedef unsigned char u_char;

/* Display Manager package interface */

#define RATBOUND	1000.0	/* ?? Max magnification in Rot matrix */
int	Rat_open();
void	Rat_close();
int	Rat_input();
void	Rat_prolog(), Rat_epilog();
void	Rat_normal(), Rat_newrot();
void	Rat_update();
void	Rat_puts(), Rat_2d_line(), Rat_light();
int	Rat_object();
unsigned Rat_cvtvecs(), Rat_load();
void	Rat_statechange(), Rat_viewchange(), Rat_colorchange();
void	Rat_window(), Rat_debug();

struct dm dm_Rat = {
	Rat_open, Rat_close,
	Rat_input,
	Rat_prolog, Rat_epilog,
	Rat_normal, Rat_newrot,
	Rat_update,
	Rat_puts, Rat_2d_line,
	Rat_light,
	Rat_object,
	Rat_cvtvecs, Rat_load,
	Rat_statechange,
	Rat_viewchange,
	Rat_colorchange,
	Rat_window, Rat_debug,
	0,				/* No displaylist */
	RATBOUND,			/* ??? */
	"rat", "Raster Tech One/80"
};

struct timeval	{			/* needed for select() */
	long	tv_sec;			/* seconds */
	long	tv_usec;		/* microseconds */
};

extern struct device_values dm_values;	/* values read from devices */

static int	rat_debug;
static vect_t	clipmin, clipmax;		/* for vector clipping */

static int second_fd;		/* fd of RasterTech if not /dev/tty */
static FILE *outfp;		/* RasterTech device to output on */
static int mousefd;		/* fd of mouse input */

/*
 * Display coordinate conversion:
 *  RasterTech is using -512..+511
 *  GED is using -2048..+2047
 *  It *would* just be /4 and *4 but in interlace mode the RaT
 *  can't actually display all its lines, thus it's scaled down
 *  to +506...-507.  This hurts in the x direction where we have
 *  loads of pixles (and the monitor doesn't seem to show this square).
 *
 * For the dual-display trick, Raster Tech is using (-507..0),(0..+506)
 */
/* Dual display trick puts frames on top of each other */
#define HALF_SCREEN	510	/* Rat coord., must be multiple of 2 */
static int frame = 0;

static int prev_status = 0;	/* previous value of rat_debug */
#define DUALDISPLAY	(rat_debug == 0)	/* auto flipping */
#define HIRES		(rat_debug == 1)	/* no flipping, 1kX1k */
#define SHOWBOTH	(rat_debug == 2)	/* flipping, show both */

#define XSCREEN_OFFSET	260	/* must be multiple of 20 */
#define	GEDX_TO_RAT(x)	(HIRES ? \
	(((x) / 4) * 507 / 512) : \
	(((x) / 8) * 507 / 512 - XSCREEN_OFFSET ) )

#define YSCREEN_OFFSET	252	/* must be multiple of 2 */
#define	GEDY_TO_RAT(x)	(HIRES ? \
	(((x) / 4) * 507 / 512) : \
	(((x) / 8) * 507 / 512 + (frame ? \
	HALF_SCREEN-YSCREEN_OFFSET : -YSCREEN_OFFSET ) ) )

#define RAT_TO_GED(x)	(((x + YSCREEN_OFFSET) * 512 / 507) * 8)

/*
 *  Pseudo-Color Table - maps 0-15 into RaT colors.
 */
char	rat_colors[16][3] = {
	{   0,   0,   0 },	/* 0 MUST BE Black */
	{ 255,   0,   0 },	/* 1 Red */
	{   0,   0, 255 },	/* 2 Blue */
	{ 255, 255,   0 },	/* 3 Yellow */
#define FIRSTFREESLOT	4	/* all entries here to 14 are user-filled */
	{   0, 255,   0 },	/* 4 Green */
	{ 255,   0, 255 },	/* 5 Magenta */
	{   0, 255, 255 },	/* 6 Cyan */
	{ 192, 160,  64 },	/* 7 Orange */
	{  64, 192, 160 },	/* 8 ??? */
	{ 160,  64, 192 },	/* 9 Purple */
	{ 255, 128,   0 },	/* 10 Doug's Orange */
	{ 128, 255,   0 },	/* 11 Doug's ??? */
	{ 128,   0, 255 },	/* 12 Doug's Purple */
	{ 255, 128, 128 },	/* 13 Pink */
	{ 100, 100, 100 },	/* 14 Gray */
	{ 255, 255, 255 }	/* 15 MUST BE White */
};
#define NSLOTS		(15-FIRSTFREESLOT)	/* Saves 0..3, 15 */

#define RATC_BLACK	0
#define RATC_RED	1		/* same as DM_RED */
#define RATC_BLUE	2
#define RATC_YELLOW	3
#define RATC_WHITE	15		/* NOT the same as DM_WHITE */

/*
 *			R A T _ O P E N
 *
 * Fire up the display manager, and the display processor.
 *   Opens the Raster Tech, enters graphics mode,
 *     turn on 24 bit color, sets interlace on.
 *
 */
Rat_open()
{
#define OBUFSZ	(32*1024)
	static char ttybuf[OBUFSZ];
	static char firstcmds[] = {
		0x10,			/* reset */
		0x04,			/* Enter Graphics mode */
		0xFD			/* COLD Start */
	};
	static char buff[] = {
		0x10,			/* reset? */
		0x04,			/* Enter Graphics mode */
		0x08, 0, 1,		/* VIDFORM Interlace ON */
		0x4E, 1			/* RGBTRU ON */
	};
	char line[64], line2[64];

	/* Protect ourselves */
	sync();

	(void)printf("Output tty [/dev/rt0]? ");
	(void)gets( line );		/* Null terminated */
	if( feof(stdin) )  quit();
	if( line[0] != '\0' )  {
		if( (outfp = fopen(line,"r+w")) == NULL )  {
			(void)sprintf( line2, "/dev/tty%s%c", line, '\0' );
			if( (outfp = fopen(line2,"r+w")) == NULL )  {
				perror(line);
				return(1);	/* BAD */
			}
		}
		second_fd = fileno(outfp);
	} else {
		if( (outfp = fopen("/dev/rt0","r+w")) == NULL )
			return(1);		/* BAD */
		second_fd = 0;		/* no second filedes */
	}
#ifdef BSD42
	setbuffer( outfp, ttybuf, OBUFSZ );		/* BSD 4.2 */
#else
/**	(void)setvbuf( outfp, ttybuf, _IOFBF, OBUFSZ );	/* Sys V */
#endif

/*
	(void)fwrite( firstcmds, sizeof(firstcmds), 1, outfp );
	(void)fflush( outfp );
	(void)sleep(3);
*/
	(void)fwrite( buff, sizeof(buff), 1, outfp );
	/*
	 * We need to do this incredible kludge since the RaT actually
	 *  displays x,+511 at the bottom of the screen.
	 */
/*	ratscrorg( 0, 1 );	What's one pixel anyway... */
	(void)fflush( outfp );
	(void)printf("Rat opened\n");
	return(0);		/* OK */
}

/*
 *  			R A T _ C L O S E
 *  
 *  Gracefully release the display.
 *    Issue quit command, and close connection.
 */
void
Rat_close()
{
	(void)putc( 0xFF, outfp );	/* QUIT - Exit Graphics */
	(void)fflush( outfp );
	fclose( outfp );
}

/*
 *			R A T _ P R O L O G
 *
 * There are global variables which are parameters to this routine.
 */
void
Rat_prolog()
{

	if( !dmaflag )
		return;

	/* If debug mode has changed, clear screen */
	if( prev_status != rat_debug )  {
		prev_status = rat_debug;
		raterase();		/* clear it all out */
	}
	ratcolor(DM_WHITE);	/* Make things visible again! */

	/* Put the center point up */
	ratpoint( 0, 0 );
}

/*
 *			R A T _ E P I L O G
 */
void
Rat_epilog()
{
	if( !dmaflag )
		return;
	ratmove( TITLE_XBASE, SOLID_YBASE );
}

/*
 *  			R A T _ N E W R O T
 *  Stub.
 */
/* ARGSUSED */
void
Rat_newrot(mat)
mat_t mat;
{
	return;
}

/*
 *  			R A T _ O B J E C T
 *  
 *  Set up for an object, transformed as indicated, and with an
 *  object center as specified.  The ratio of object to screen size
 *  is passed in as a convienience.
 *
 *  Returns 0 if object could be drawn, !0 if object was omitted.
 */
/* ARGSUSED */
int
Rat_object( sp, mat, ratio, white )
register struct solid *sp;
mat_t mat;
double ratio;
{
	static vect_t last;
	register struct veclist *vp;
	int nvec;
	int useful = 0;
	char colorbuf[3];

	ratlinemod( sp->s_soldash );	/* Solid or Dashed */
#ifdef NEVER
	ratcolor( white ? RATC_WHITE : ((ndrawn>>2)%13)+2 );
#else
	if( white || sp->s_materp == (char *)0 )
		ratcolor( RATC_WHITE );
	else
		ratcolor( ((struct mater *)sp->s_materp)->mt_dm_int );
#endif
	nvec = sp->s_vlen;
	for( vp = sp->s_vlist; nvec-- > 0; vp++ )  {
		/* Viewing region is from -1.0 to +1.0 */
		if( vp->vl_pen == PEN_UP )  {
			/* Move, not draw */
			MAT4X3PNT( last, mat, vp->vl_pnt );
		}  else  {
			static vect_t fin;
			static vect_t start;
			/* draw */
			MAT4X3PNT( fin, mat, vp->vl_pnt );
			VMOVE( start, last );
			VMOVE( last, fin );
			if(
#ifdef later
				/* sqrt(1+1) */
				(ratio >= 0.7071)  &&
#endif
				vclip( start, fin, clipmin, clipmax ) == 0
			)  continue;

			ratmove(	(int)( start[0] * 2047 ),
				(int)( start[1] * 2047 ) );
			ratdraw(	(int)( fin[0] * 2047 ),
				(int)( fin[1] * 2047 ) );
			useful = 1;
		}
	}
	return(useful);
}

/*
 *			R A T _ N O R M A L
 *
 * Restore the display processor to a normal mode of operation
 * (ie, not scaled, rotated, displaced, etc).
 * Turns off windowing.
 */
void
Rat_normal()
{
	return;
}

/*
 *			R A T _ U P D A T E
 *
 * Switch to just-drawn portion of display.
 */
void
Rat_update()
{
	/* Display crosshair cursor */
	ratcursor(
		GEDX_TO_RAT(dm_values.dv_xpen),
		GEDY_TO_RAT(dm_values.dv_ypen),
		1 );

	if( !dmaflag )
		return;

	if( SHOWBOTH || HIRES )  {
		/* "rat_debug", show full screen all the time */
		(void)putc( 0x34, outfp );	/* ZOOM */
		(void)putc( 0x01, outfp );	/*   1  */
		ratscrorg( 0, 0 );
	} else {
		/* Normal:  Flip back and forth */
		(void)putc( 0x34, outfp );		/* ZOOM */
		(void)putc( 0x02, outfp );		/*   2  */
		ratscrorg(
			-XSCREEN_OFFSET,
			frame ?
				258 :		/* magic */
				-YSCREEN_OFFSET
		);		/* SCRORG */
	}
	(void)fflush(outfp);

	if( HIRES )  {
		raterase();
		/* DO NOT flush;  it will leave image up longer */
		return;
	}

	/* Dual display:  Clear other half of the screen */
	frame ^= 1;		/* flip frame number */
	ratcolor( DM_BLACK );
	(void)putc( 0x1F, outfp );	/* PRMFIL */
	(void)putc( 0x01, outfp );	/*   1 (ON) */
	ratmove( -2048, -2048);
	ratrectan( 2047, 2047 );
	(void)fflush( outfp );
}

/*
 *			R A T _ P U T S
 *
 * Output a string into the displaylist.
 * The starting position of the beam is as specified.
 */
void
Rat_puts( str, x, y, size, color )
register u_char *str;
{
	static	char	sizbuf[4] = { 0x092, 0, 0, 0 };	/* TEXTC cmd */
	int	len;

	ratmove(x,y);
	/* This handles out-of-range, plus DM_WHITE != RATC_WHITE */
	if( color < RATC_BLACK || color > RATC_YELLOW ) color = RATC_WHITE;
	ratcolor(color);

	switch( size ) {
	case 0:	sizbuf[1] = 23;
		break;
	case 1:	sizbuf[1] = 30;
		break;
	case 2:	sizbuf[1] = 55;
		break;
	case 3:	sizbuf[1] = 100;
		break;
	}
	if( DUALDISPLAY || SHOWBOTH )
		sizbuf[1] /= 2;
	(void)fwrite( sizbuf, sizeof(sizbuf), 1, outfp );	/* set size */

	len = strlen(str);
	if (len > 255) {	/* incredible temporary cop-out */
		fprintf(stderr, "STRING TOO LONG!\n");
		return;
	}

	(void)putc(0x090, outfp);	/* TEXT1 cmd */
	(void)putc((char)len, outfp);

	for( ; *str; str++ )
		(void)putc((int)*str,outfp);
}


/*
 *			R A T _ 2 D _ G O T O
 *
 * Do it in yellow.
 */
void
Rat_2d_line( x1, y1, x2, y2, dashed )
int x1, y1;
int x2, y2;
int dashed;
{
	/* Color ? */
	ratcolor( DM_YELLOW );
	ratlinemod( dashed );
	ratmove( x1, y1 );
	ratdraw( x2, y2 );
	/* Should we change it back to solid? */
}

/*
 *			G E T _ C U R S O R
 *  
 *  Read the RasterTech cursor.  The RasterTech sends
 *  6 bytes:  The key the user struck, 4 bytes of
 *  encoded position, and a return (newline).
 *  Note this is is complicated if the user types
 *  a return or linefeed.
 *  (The terminal is assumed to be in cooked mode)
 */
static get_cursor()
{
	register char *cp;
	char ibuf[64];
	register int i;
	int hix, hiy, lox, loy;

	/* ASSUMPTION:  Input is line buffered (tty cooked) */
	i = read( second_fd, ibuf, sizeof(ibuf) );
	/* The LAST 6 chars are the string from the tektronix */
	if( i < 6 )  {
		(void)printf("short read of %d\n", i);
		return;		/* Fails if he hits RETURN */
	}
	cp = &ibuf[i-6];
	if( cp[5] != '\n' )  {
		(void)printf("cursor synch?\n");
		(void)printf("saw:%c%c%c%c%c%c\n",
			cp[0], cp[1], cp[2], cp[3], cp[4], cp[5] );
		return;
	}

	/* cp[0] is what user typed, followed by 4pos + NL */
	hix = ((int)cp[1]&037)<<7;
	lox = ((int)cp[2]&037)<<2;
	hiy = ((int)cp[3]&037)<<7;
	loy = ((int)cp[4]&037)<<2;

	/* Rat positioning is -512..+512,
	 * The desired range is -2048 <= x,y <= +2048.
	 */
	dm_values.dv_xpen = RAT_TO_GED(hix|lox);
	dm_values.dv_ypen = RAT_TO_GED(hiy|loy);
	if( dm_values.dv_xpen < -2048 || dm_values.dv_xpen > 2048 )
		dm_values.dv_xpen = 0;
	if( dm_values.dv_ypen < -2048 || dm_values.dv_ypen > 2048 )
		dm_values.dv_ypen = 0;

	switch(cp[0])  {
	case 'Z':
		(void)printf("x=%d,y=%d\n", dm_values.dv_xpen, dm_values.dv_ypen);
		break;		/* NOP */
	case 'b':
		dm_values.dv_penpress = DV_INZOOM;
		break;
	case 's':
		dm_values.dv_penpress = DV_OUTZOOM;
		break;
	case '.':
		dm_values.dv_penpress = DV_SLEW;
		break;
	default:
		(void)printf("s=smaller, b=bigger, .=slew, space=pick/slew\n");
		return;
	case ' ':
		dm_values.dv_penpress = DV_PICK;
		break;
	}
}

/*
 *			R A T _ I N P U T
 *
 * Execution must suspend in this routine until a significant event
 * has occured on either the command stream, or a device event has
 * occured, unless "noblock" is set.
 *
 * The GED "generic input" structure is filled in.
 *
 * Returns:
 *	0 if no command waiting to be read,
 *	1 if command is waiting to be read.
 */
Rat_input( cmd_fd, noblock )
{
	static long readfds;
	static struct timeval timeout;

	/*
	 * Check for input on the keyboard or on the polled registers.
	 *
	 * Suspend execution until either
	 *  1)  User types a full line
	 *  2)  A change in peripheral status occurs
	 *  3)  The timelimit on SELECT has expired
	 *
	 * If a RATE operation is in progress (zoom, rotate, slew)
	 * in which the peripherals (rate setting) may not be changed,
	 * but we still have to update the display,
	 * do not suspend execution.
	 */
	if( noblock )
		timeout.tv_sec = 0;
	else
		timeout.tv_sec = 30*60;		/* 30 MINUTES for Rat */
	timeout.tv_usec = 0;

	readfds = (1<<cmd_fd);
#ifdef never
	if( second_fd )
		readfds |= (1<<second_fd);
#endif
	(void)select( 32, &readfds, 0L, 0L, &timeout );

	dm_values.dv_penpress = 0;
	if( second_fd && readfds & (1<<second_fd) )
		get_cursor();

	if( readfds & (1<<cmd_fd) )
		return(1);		/* command awaits */
	else
		return(0);		/* just peripheral stuff */
}

/* 
 *			R A T _ L I G H T
 */
/* ARGSUSED */
void
Rat_light( cmd, func )
int cmd;
int func;			/* BE_ or BV_ function */
{
	return;
}

/* ARGSUSED */
unsigned
Rat_cvtvecs( sp )
struct solid *sp;
{
	return( 0 );
}

/*
 * Loads displaylist
 */
/* ARGSUSED */
unsigned
Rat_load( addr, count )
unsigned addr, count;
{
	(void)printf("Rat_load?\n");
	return( 0 );
}

void
Rat_statechange()
{
}

void
Rat_viewchange()
{
}

/*
 *  			R A T _ C O L O R C H A N G E
 *  
 *  Go through the mater table, and compute nearest match to availible
 *  display manager colors.
 *  Sometime in the future, this probably should be a cluster analysis,
 *  given that we only have 16 colors to play with, and 5 pre-defined.
 */
static int slotsused;
void
Rat_colorchange()
{
	register struct mater *mp;

	slotsused = 0;
	for( mp = MaterHead; mp != MATER_NULL; mp = mp->mt_forw )
		rat_colorit( mp );

	color_soltab();		/* apply colors to the solid table */
}

static int
rat_near(a,b)
int a,b;
{
	register int d;

	d = a-b;
	if( !d || d == (-1) || d == 1 )
		return(1);
	return(0);
}

int
rat_colorit( mp )
register struct mater *mp;
{
	register int i;
	register char r,g,b;

	/* Limit values to 0,MINVAL..15 */
#define MINVAL		4
#define FOLD(x)		((x)>>4)
	if( (r = FOLD(mp->mt_r)) < MINVAL )  r = 0;
	if( (g = FOLD(mp->mt_g)) < MINVAL )  g = 0;
	if( (b = FOLD(mp->mt_b)) < MINVAL )  b = 0;
	if(rat_debug) (void)printf("%d,%d,%d mapped to %d,%d,%d: ", mp->mt_r, mp->mt_g, mp->mt_b, r,g,b);

	if( (r == 15 && g == 15 && b == 15) ||
	    (r == 0 && g == 0 && b == 0) )  {
		if(rat_debug) (void)printf("WHITE\n");
		mp->mt_dm_int = RATC_WHITE;
		return;
	}

	/* First, see if this matches an existing color map entry */
	for( i = 0; i < FIRSTFREESLOT+slotsused; i++ )  {
		if( rat_colors[i][0] == r &&
		    rat_colors[i][1] == g &&
		    rat_colors[i][2] == b )  {
			if(rat_debug) (void)printf("matches [%d]\n", i);
			mp->mt_dm_int = i;
			return;
		}
	}

	/* Now try for "loose" match to an existing color */
	for( i = 0; i < FIRSTFREESLOT+slotsused; i++ )  {
		if( rat_near(rat_colors[i][0], r) &&
		    rat_near(rat_colors[i][1], g) &&
		    rat_near(rat_colors[i][2], b) )  {
			if(rat_debug) (void)printf("nearly %d\n", i);
			 mp->mt_dm_int = i;
			 return;
		}
	}

	/* If slots left, create a new color map entry, first-come basis */
	if( slotsused < NSLOTS )  {
		rat_colors[i=(FIRSTFREESLOT+slotsused++)][0] = mp->mt_r;
		rat_colors[i][1] = mp->mt_g;
		rat_colors[i][2] = mp->mt_b;
		mp->mt_dm_int = i;
		if(rat_debug) (void)printf("new slot %d\n", i);
		return;
	}

	/* Default color */
	mp->mt_dm_int = RATC_YELLOW;
	if(rat_debug) (void)printf("defaults to yellow\n");
}



/**************************************************************************/

/* Raster Tech Routines */

ratpoint(xi,yi){
	/* Hack */
	ratmove(xi,yi);
	ratdraw(xi+1,yi+1);
}

/*
 *  R A T M O V E
 *  Set the current position (CREG 0) to (xpos, ypos).
 */
ratmove(xpos, ypos)
int xpos, ypos;
{
	static char buff[6] = { 0xA0, 0 };	/* CLOAD 0 */

	xpos = GEDX_TO_RAT( xpos );
	ypos = GEDY_TO_RAT( ypos );

/*	buff[1] = 0; */
	buff[2] = (xpos>>8) & 0x0FF;
	buff[3] = xpos & 0x0FF;
	buff[4] = (ypos>>8) & 0x0FF;
	buff[5] = ypos & 0x0FF;

	(void)fwrite( buff, sizeof(buff), 1, outfp );
}

/*
 *  R A T R E C T A N
 *  Draw rectangle from current pos to (x,y)
 */
ratrectan(xpos, ypos)
int xpos, ypos;
{
	static	char	buff[5] = { 0x8E };	/* RECTAN */

	xpos = GEDX_TO_RAT( xpos );
	ypos = GEDY_TO_RAT( ypos );

	buff[1] = (xpos>>8) & 0x0FF;
	buff[2] = xpos & 0x0FF;
	buff[3] = (ypos>>8) & 0x0FF;
	buff[4] = ypos & 0x0FF;

	(void)fwrite( buff, sizeof(buff), 1, outfp );
}

/*
 *  R A T D R A W	- Draw from current point to (x, y).
 */
ratdraw(xpos, ypos)
int xpos, ypos;
{
	static	char	buff[5] = { 0x081 };	/* DRWABS cmd */

	xpos = GEDX_TO_RAT( xpos );
	ypos = GEDY_TO_RAT( ypos );

	buff[1] = (xpos>>8) & 0x0FF;
	buff[2] = xpos & 0x0FF;
	buff[3] = (ypos>>8) & 0x0FF;
	buff[4] = ypos & 0x0FF;

	(void)fwrite( buff, sizeof(buff), 1, outfp );
}


/*
 *  R A T E R A S E  - fill the screen with the background color
 */
raterase()
{
	ratcolor( DM_BLACK );
	(void)putc( 0x07, outfp );	/* FLOOD command */
}

/*
 *  R A T C O L O R	- Map GED colors into Rat values
 */
ratcolor(color)
int color;
{
	(void)putc( 0x06, outfp );			/* VALUE cmd */
	(void)fwrite( rat_colors[color], 3, 1, outfp );	/* Pseudo-Color */
}

/*
 *  L I N E M O D
 *     Select solid or dashed line.
 */
ratlinemod(type)
int type;
{
	char	buff[3];

	buff[0] = 0x02E;	/* VECPAT cmd */
	if (type == 0) {
		/* solid */
		buff[1] = 0x0FF;
		buff[2] = 0x0FF;
	} else {
		/* dashed */
		buff[1] = 0x0F0;
		buff[2] = 0x0F0;
	}

	(void)fwrite( buff, sizeof(buff), 1, outfp );
}

/*
 *  R A T C U R S O R
 *   Enables or disables "crosshair 0" and sets its position.
 *   Perhaps the turning on should only be done once??
 *   Note that there is a second crosshair register and full screen
 *    cursor to play with and the colors of all can be set.
 */
ratcursor(x, y, onoff)
{
	static	char	curson[3] = { 0x4A, 0, 1 };	/* CURSOR cmd */
	static	char	cursoff[3] = { 0x4A, 0, 0 };
	char	buff[6];

	if ( onoff == 0 ) {
		/* Turn cursor off */
		(void)fwrite( cursoff, sizeof(cursoff), 1, outfp );
		return;		/* don't bother with position */
	}

	/* Set it's position */
	buff[0] = 0xA0;			/* CLOAD cmd */
	buff[1] = 17;			/* cursor position reg */
	buff[2] = (x>>8) & 0x0FF;
	buff[3] = x & 0x0FF;
	buff[4] = (y>>8) & 0x0FF;
	buff[5] = y & 0x0FF;

	(void)fwrite( buff, sizeof(buff), 1, outfp );	/* write its position */
	(void)fwrite( curson, sizeof(curson), 1, outfp );	/* turn it on */
}

/*
 *  Set the screen-center coordinate (CREG 4) to (xpos, ypos).
 */
ratscrorg(x, y)
int x, y;
{
	char	buff[5];

	buff[0] = 0x036;	/* SCRORG cmd */
	buff[1] = (x>>8) & 0x0FF;
	buff[2] = x & 0x0FF;
	buff[3] = (y>>8) & 0x0FF;
	buff[4] = y & 0x0FF;

	(void)fwrite( buff, sizeof(buff), 1, outfp );
}


#ifdef NEVER
/*
 *  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.
 */
memsel(unit)
int unit;
{
	char	buff[2];

	buff[0] = 0x048;	/* MEMSEL */
	buff[1] = unit;

	(void)fwrite( buff, sizeof(buff), 1, outfp );
}

/*
 *  Set the coordinate origin (CREG 3) to (xpos, ypos).
 */
cororg(x, y)
int x, y;
{
	char	buff[5];

	buff[0] = 0x037;	/* CORORG cmd */
	buff[1] = (x>>8) & 0x0FF;
	buff[2] = x & 0x0FF;
	buff[3] = (y>>8) & 0x0FF;
	buff[4] = y & 0x0FF;

	(void)fwrite( buff, sizeof(buff), 1, outfp );
}
#endif

#ifdef NEVER
/*
 *  R T Z O O M
 *     Note:  This trusts that  1 <= factor <= 16.
 */
rtzoom(factor)
int factor;
{
	char	buff[2];

	buff[0] = 0x034;	/* ZOOM cmd */
	buff[1] = factor;

	(void)fwrite( buff, sizeof(buff), 1, outfp );
}

/*
 *  Load the given color maps into the framebuffer.
 */
load_map(r, g, b)
short r[256], g[256], b[256];
{
	char	buff[5];
	int	i;

	buff[0] = 0x01c;	/* LUT8 cmd */
	for (i = 0; i < 256; i++) {
		buff[1] = i;
		buff[2] = r[i];
		buff[3] = g[i];
		buff[4] = b[i];
		(void)fwrite( buff, sizeof(buff), 1, outfp );
	}
}
#endif

/*
 * Set all color maps to standard 0-255 values
 */
std_map()
{
	/* LUTRMP 7 0 255 0 255 */
	static char buff[6] = { 0x1D, 7, 0, 255, 0, 255 };
	
	(void)fwrite( buff, sizeof(buff), 1, outfp );
}

void
Rat_debug(lvl)
{
	rat_debug = lvl;
}

void
Rat_window(w)
register int w[];
{
	/* Compute the clipping bounds */
	clipmin[0] = w[1] / 2048.;
	clipmin[1] = w[3] / 2048.;
	clipmin[2] = w[5] / 2048.;
	clipmax[0] = w[0] / 2047.;
	clipmax[1] = w[2] / 2047.;
	clipmax[2] = w[4] / 2047.;
}
