/* Original Author:         Andrew Trevorrow
   Implementation: Modula-2 under VAX/UNIX 4.2 BSD
   Date Started:   June, 1986

   Description:
   Implements the InitAED512()procedure that initializes the generic VDU
   routines and parameters used in DVItoVDU.
   The AED512 screen is 483 or 512 pixels high (depending on monitor) and
   512 pixels wide.  The variable screenht will be set to 512 for the AED512
   and 483 for the AED483 (see InitVDUInterface().
   The bottom left pixel is the point (x=0,y=0); x coordinates
   increase to the right and y coordinates increase up the screen.
   DVItoVDU uses a coordinate scheme in which horizontal (=h) coordinates
   also increase to the right but vertical (=v) coordinates increase DOWN the
   screen, i.e. the top left pixel on the screen is the point (h=0,v=0).
   This means that the AED512 routines will have to do a
   simple translation of the vertical coordinates passed by DVItoVDU.
   DVItoVDU assumes text lines on the screen start at 1 and increase downwards.

   This version converted to C and ported to BSD and System V UNIX by
   some chaps at Kernel Technology up to September 1989.  Contact
   mjh@uk.co.kernel (Mark J. Hewitt) with bug fixes etc.

   Involved were:	Mark J. Hewitt
   			Dave Dixon
			Marc Hadley
*/

#include "def.h"

static char *sccsid[] = "@(#)aed512vdu.c	1.1";

void InitAED512 ();
Void AED512StartText ();
Void AED512MoveToTextLine ();
Void SendXY ();
Void SelectAlphaFont ();
Void AED512ClearTextLine ();
Void AED512ClearScreen ();
Void AED512StartGraphics ();
Void AED512LoadFont ();
Void AED512ShowChar ();
Void AED512ShowRectangle ();
Void AED512ResetVDU ();

#define  ALPHA  '\1'		/* SOH = enter Alpha mode */
#define  INTER  ESC		/* ESC = enter Interpreter mode */
#define  ERASE  FF		/* form feed to erase screen */
#define  SAP    '^'		/* select Alpha parameters for char size */
#define  MOV    'Q'		/* move CAP to absolute x,y position; CAP = Current
				   Access Position */
#define  DVA    'A'		/* draw vector from CAP to absolute x,y pos */
#define  DFR    'o'		/* draw filled rectangle with one corner at CAP nd
				   opposite corner at absolute x,y position */
#define  SEC    'C'		/* set current writing colour */
#define  SBC    '['		/* set background colour */
#define  GREEN  '\2'		/* my writing colour; better than default red */
#define  BLACK  '\0'		/* my background colour; also the default */
#define  LINEHT 9		/* height in pixels of my default text line */

#define  CHARWIDTH1  6		/* 5*8 fnt for dialogue region; 85 chs per lne */
#define  CHARWIDTH2  8		/* normal 7*12 font; 64 chars per line */
#define  CHARWIDTH3  12		/* double 5*8 font; 42 chars per line */
#define  CHARWIDTH4  16		/* double 7*12 font; 32 chars per line */


int   screenht = 512;		/* AED screen can be 512 or 483 pixels high */

typedef short xycoords;

unsigned int  maxy,		/* screenht - 1 */
              loadedwidth,	/* remember charwidth set by last LoadFont */
              charwidth;	/* used to select Alpha font */

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

/* The dialogue region will be the top 4 text lines in Alpha mode.
   The window region will be the remaining screen area.
*/

void InitAED512 ()
{
  DVIstatusl = 1;		/* DVItoVDU assumes top text line = 1 */
  windowstatusl = 2;
  messagel = 3;
  commandl = 4;
  maxy = ((unsigned) screenht) - 1;
  bottoml = screenht / LINEHT;	/* number of text lines on AED512 screen */
  windowv = 4 * LINEHT + 5;	/* height in pixels of dialogue region */
  windowh = 0;
  windowht = screenht - windowv;
  windowwd = 512;

  ClearTextLine = AED512ClearTextLine;
  MoveToTextLine = AED512MoveToTextLine;
  ClearScreen = AED512ClearScreen;
  StartText = AED512StartText;
  StartGraphics = AED512StartGraphics;
  LoadFont = AED512LoadFont;
  ShowChar = AED512ShowChar;
  ShowRectangle = AED512ShowRectangle;
  ResetVDU = AED512ResetVDU;

  Write (INTER);

  Write (SBC);			/* make sure black is the background colour */
  Write (BLACK);
  Write (SEC);			/* change writing colour to green; easier to read
				   than red */
  Write (GREEN);

  Write ('(');			/* programmable option */
  Write (((char) 06));
  Write (((char) 01));		/* override any overlapping TEK4010 commands,
				   regardless of option switch 4! */

  charwidth = CHARWIDTH1;	/* font for dialogue region */
  loadedwidth = charwidth;	/* for first StartGraphics call */
  SelectAlphaFont ();
}

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

Void AED512StartText ()
{
  Write (ALPHA);
}

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

Void AED512MoveToTextLine (line)
unsigned int  line;
{
/* Move to start of given text line; at the end of this routine we must
   be ready to display default Alpha characters.
*/

  Write (INTER);
  Write (MOV);
  SendXY (0, (short) (maxy - (line * LINEHT)));
  charwidth = CHARWIDTH1;	/* use default Alpha font */
  SelectAlphaFont ();
}

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

Void SendXY (x, y)
xycoords x, y;
{
/* Assuming non-mnemonic 8-bit encoding (the default),
   send the 3 bytes representing the given x,y address.
*/

  Write ((char) ((x / 256) * 16 + (y / 256)));/* x11,x10,x9,x8,y11,y10,y9,y8 */
  Write ((char) (x % 256));	/* x7 ,x6 ,   ...          ,x0 */
  Write ((char) (y % 256));	/* y7 ,y6 ,   ...          ,y0 */
}

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

Void SelectAlphaFont ()
{
/* Select a new Alpha font depending on the current value of charwidth
   and prepare to display Alpha text.
   charwidth is CHARWIDTH1 initially; changed in MoveToTextLine and LoadFont.
*/

  Write (INTER);
  Write (SAP);			/* select Alpha parameters */
  switch (charwidth)
  {
    case CHARWIDTH1: 
      {
	Write ('1');		/* normal sized */
	Write ('5');		/* 5*8 font */
	Write ((char) (CHARWIDTH1));/* default hspace */
	Write ((char) (LINEHT));/* default vspace */
	break;
      }
    case CHARWIDTH2: 
      {
	Write ('1');		/* normal sized */
	Write ('7');		/* 7*12 font    */
	Write ((char) (CHARWIDTH2));
	Write ((char) 015);	/* vspace = 13  */
	break;
      }
    case CHARWIDTH3: 
      {
	Write ('2');		/* double sized */
	Write ('5');		/* 5*8 font */
	Write ((char) (CHARWIDTH3));
	Write ((char) 022);	/* vspace = 18 */
	break;
      }
    case CHARWIDTH4: 
      {
	Write ('2');		/* double sized */
	Write ('7');		/* 7*12 font */
	Write ((char) (CHARWIDTH4));
	Write ((char) 032);	/* vspace = 26 */
	break;
      }
    default: 
      WriteString ("Bug in AED512VDU! Illegal charwidth!");
  }
  Write ('L');			/* Alpha cursor position identical with CAP */
  Write (ALPHA);
}

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

Void AED512ClearTextLine (line)
unsigned int  line;
{
/* Erase given text line; note that DVItoVDU does not assume anything about
   the location of the cursor after this routine is called.
*/

  Write (INTER);
  Write (SEC);
  Write (BLACK);		/* set writing colour to background temporarily */
  Write (MOV);
  SendXY (0, (short) (maxy - (line * LINEHT) - 2));
				/* ensure g,j,p... descenders are erased */
  Write (DFR);			/* draw filled rectangle to top right corner */
  SendXY (511, (short) (maxy - (line * LINEHT) + (LINEHT - 3)));
  Write (SEC);
  Write (GREEN);		/* back to green */
  Write (ALPHA);		/* safer to leave in Alpha mode */
}

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

Void AED512ClearScreen ()
{
  Write (INTER);
  Write (ERASE);			/* erase screen and return cursor to home position;
				   also exits Interpreter */
/* preferable to ERS = '~' which has some problems with setting x,y origin */
}

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

Void AED512StartGraphics ()
{
  if (charwidth != loadedwidth)
  {
  /* graphics mode was interrupted */
    charwidth = loadedwidth;
    SelectAlphaFont ();		/* restore font selected in last LoadFont */
  }
  Write (INTER);
}

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

/* AED512 uses the given information to select an appropriate character size
   (based on horizontal scaling only!) for future calls of ShowChar.
   DVItoVDU only calls this routine in graphics mode.  */

/*ARGSUSED*/
Void AED512LoadFont (fontname, fontsize, localmag, hscale, vscale)
char  fontname[];
unsigned int  fontsize;
float   localmag, hscale, vscale;
{
  unsigned int  newwidth;

/* convert fontsize into scaled screen pixels using localmag and hscale */

  fontsize = (int) (((float) fontsize) * localmag * hscale + 0.5);

/* Chooose one of the 4 Alpha mode character sizes based on fontsize:
   charwidth    max chars/line      fontsize range
       1             85                0..20
       2             64               21..40
       3             42               41..60
       4             32               61...
   The fontsize ranges were chosen by trial and error.
*/

  if (fontsize < 21)
    newwidth = CHARWIDTH1;
  else
    if (fontsize < 41)
      newwidth = CHARWIDTH2;
    else
      if (fontsize < 61)
	newwidth = CHARWIDTH3;
      else
	newwidth = CHARWIDTH4;

  loadedwidth = newwidth;	/* remember for ShowChar */
  if (charwidth != newwidth)	/* change needed */
  {
    charwidth = newwidth;
    SelectAlphaFont ();
  }
  Write (INTER);		/* must exit in graphics mode */
}

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

/* We show the given character (mapping TeX text character to ASCII) using
   the given reference point and the charwidth selected by the last LoadFont.
   DVItoVDU only uses this routine in a Terse display.
   Note that Alpha characters g,j,p,q,y have descenders that fall below their
   reference point; when baselines appear near the bottom of the screen the
   descenders will wrap to the top. */

Void AED512ShowChar (screenh, screenv, ch)
unsigned int  screenh, screenv;
char  ch;
{
  char  newch;			/* = TeXtoASCII[ch] */

/* shift character left if it will overlap right edge of screen */

  if ((screenh + charwidth) > 511)
    screenh = 511 - charwidth;

/* DVItoVDU only calls ShowChar in graphics mode */

  Write (MOV);
  SendXY ((short) (screenh), (short) (maxy - screenv));
				/* move cursor to reference point */

/* We use TeXtoASCII to map ch into a comparable ASCII character, apart
   from most of the ? characters which we attempt to simulate.
*/

  Write (ALPHA);
  newch = TeXtoASCII[ch];
  if (newch != '?')		/* newch is similar to TeX ch */
  {
    Write (newch);
  }
  else				/* attempt to display something other than ? */
  {
    switch (ch)
    {
      case '\13': 
      case '\14': 
      case '\15': 
      case '\16': 
      case '\17': 		/* ff, fi, fl, ffi, ffl */
	{
	  Write ('f');
	/* only simulate rest of ligature if room at right edge */
	  if (screenh + 2 * charwidth - (charwidth / 2) <= 511)
	  {
	    Write (INTER);
	    Write (MOV);
	    SendXY ((short) (screenh + charwidth - (charwidth / 2)), (short) (maxy - screenv));
	    Write (ALPHA);
	    switch (ch)
	    {
	      case 13: 
		Write ('f');
		break;
	      case 14: 
		Write ('i');
		break;
	      case 5: 
		Write ('l');
		break;
	      case 16: 
	      case 17: 
		{
		  Write ('f');
		  if (screenh + 3 * charwidth - 2 * (charwidth / 2) <= 511)
		  {
		    Write (INTER);
		    Write (MOV);
		    SendXY ((short) (screenh + 2 * charwidth - 2 * (charwidth / 2)), (short) (maxy - screenv));
		    Write (ALPHA);
		    if (ch == 016)
		      Write ('i');
		    else
		      Write ('l');
		  }
		}
	    }
	  }
	  break;
	}
      case 31: 
	Write ('B');
	break;			/* German sharp S */
      case 32: 
      case 33: 
      case 35: 
      case 36: 			/* diphthongs: ae, oe, AE, OE */
	{
	  switch (ch)
	  {
	    case 32: 
	      Write ('a');
	      break;
	    case 33: 
	      Write ('o');
	      break;
	    case 35: 
	      Write ('A');
	      break;
	    case 36: 
	      Write ('O');
	      break;
	  }
	  if (screenh + 2 * charwidth - (charwidth / 2) <= 511)
	  {
	    Write (INTER);
	    Write (MOV);
	    SendXY ((short) (screenh + charwidth - (charwidth / 2)), (short) (maxy - screenv));
	    Write (ALPHA);
	    switch (ch)
	    {
	      case 32: 
	      case 33: 
		{
		  Write ('e');
		  break;
		}
	      case 35: 
	      case 36: 
		{
		  Write ('E');
		}
	    }
	  }
	  break;
	}
      case 40: 
	{
	  Write ('\'');
	  break;		/* Polish suppressed l and L */
	}
      default: 
	Write ('?');
    }
  }
  Write (INTER);		/* must exit in graphics mode */
}

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

/* Display the given rectangle without using the given black pixel character.
   We assume that the top left position is correct and that the given
   dimensions do not go beyond the screen edges.
   We assume DVItoVDU is in graphics mode.
*/

/*ARGSUSED*/
Void AED512ShowRectangle (screenh, screenv, width, height, ch)/* black pixel */
unsigned int  screenh, screenv, width, height;
char  ch;
{
  unsigned int  pos;

  if (height == 1)
  {				/* show row vector */
    pos = maxy - screenv;
    Write (MOV);
    SendXY ((short) (screenh), (short) (pos));/* move cursor to start of row */
    Write (DVA);
    SendXY ((short) (screenh + width - 1), (short) (pos));
				/* draw vector to end of row */
  }
  else
    if (width == 1)
    {				/* show column vector */
      Write (MOV);
      SendXY ((short) (screenh), (short) (maxy - screenv));
				/* move cursor to start of column */
      Write (DVA);
      SendXY ((short) (screenh), (short) (maxy - (screenv + height - 1)));
				/* draw vector to end of column */
    }
    else			/* assume height and width > 1 *//* draw filled
				   rectangle */
    {
      Write (MOV);
      SendXY ((short) (screenh), (short) (maxy - screenv));
				/* CAP to top left corner */
      Write (DFR);
      SendXY ((short) (screenh + width - 1), (short) (maxy - (screenv + height - 1)));
				/* fill to bottom right corner */
    }
}

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

Void AED512ResetVDU ()
{

/* We DON'T reset AED512 to power-up state; we leave AED using green as the
   writing colour and set font back to power-up values.
   Such decisions may not please other AED sites, but I was talked into them
   by our AED users (all 2 of them!).
*/

  Write (INTER);
  Write (SAP);			/* select Alpha parameters */
  Write ('1');			/* normal sized */
  Write ('7');			/* 7*12 font */
  Write ((char) 010);		/* hspace = 8 */
  Write ((char) 14);		/* vspace = 12 */
  Write ('L');			/* Alpha cursor position identical with CAP */
  Write (ALPHA);		/* exit in Alpha mode */
}

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


/* screenht changed in InitVDUInterface() to 483 for the AED483 */








