/* This module is a minimum extenal hooks tek 4010 emulation, the
 * function InitTek() must be called before any of the others, it
 * assumes that gfx, intuition are open. Tek() returns true if it
 * uses the input stream else false. It must be called before any 
 * character parsing or you could get into trouble. CloseTek() Frees
 * up all resources used by this module */

/* I had to invent a few commands for area fill reset screen, and
 * color setting. Any one who knows the correct commands please let me
 * know  the line drawing and color index selection are standard commands.
 * I have vax software to drive the 640x400 mode, and it works really well.
 * the 1024x790 mode is not quite as clear, but works ok.
 * The author of this software can be contacted as:
 * T.Whelan
 * Dept. of Physics & Astronomy
 * University of Iowa
 * Iowa City
 * IA 52244
 * and on span at IOWA::WHELAN

 * on the "to do" list, are graphis input mode and run time selection
 * of the screen resoultion. */


/*  compiler directives to fetch the necessary header files */
#include "vt100.h"
#include "graphics/display.h"

/* this varaible conditionally compiles in one of 2 modes,
 * if TS =  1 you get a 16 color 640x400 screen, the system can not
 * manage to draw sucessfully at 19200 bps in this mode, and the screen
 * on the Amiga 1080 monitor flickers like crazy. (any one know a better
 * monitor for interlace, i.e. one with longer persistance)
 * TS = 2 gives 320x200 32 color screen. It would be simple to put in
 * 6 bit planes to allow extra half bright, but for displaying color
 * graphs that mode is not usefull. This mode runs at 19200 bps. */

#define TS 1

/* global pointers, used only in this code module */
struct Screen	   *TekScreen;
struct Window      *TekWindow;
int *TekFillRas;
extern int * AllocRaster();
/* macros... */
#define mrp TekWindow->RPort
#define COLOR(i, j, k, l) SetRGB4(&TekScreen->ViewPort, i, j, k, l)


/* this macro puts the tek screen at the back
 * and sets things so that the user gets the
 * non-tek mode of operation, there are some problems here
 * as we do not use intuition to control window positions */
#define TekOFF() {TekMode = FALSE; \
		  ScreenToBack(TekScreen); }

#define clear() SetRast(mrp, 0); /* set the screen to color Zero */

/* the screen size */
#define xmin 0
#define ymin 0 
#define xmax (640/TS)
#define ymax (400/TS)

struct NewScreen TekNewScreen = { 
   xmin, ymin,
   xmax, ymax, 3 + TS,
   0, 1,
#if TS == 2
   NULL , 
#else
   HIRES|INTERLACE,
#endif
   CUSTOMSCREEN,
   NULL,
   NULL,
   NULL,
   NULL
   };

struct NewWindow TekNewWindow = {
   xmin, ymin,
   xmax, ymax,
   -1, -1,
   RAWKEY, 	/* No IDCMP flags */
   BORDERLESS|NOCAREREFRESH|SMART_REFRESH,
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   0, 0,
   0, 0,
   CUSTOMSCREEN
   };

/* initalise the window and screen needed for this mode
 * inituition and gfx are assumed open */
InitTek(HisPort)
struct MsgPort *HisPort;
{  
static struct AreaInfo ai;
static WORD buffer[250];
static struct TmpRas tr;

TekScreen = (struct Screen *)OpenScreen(&TekNewScreen);
if (TekScreen == NULL) return TRUE;

TekNewWindow.Screen = TekScreen;
TekWindow = (struct Window *)OpenWindow(&TekNewWindow);
if (TekWindow == NULL) return TRUE;

/* make HisPort the User Port for this window, so that his
 * read routines will work when my screen is active
 */
TekWindow->UserPort = HisPort;
ModifyIDCMP(TekWindow, RAWKEY|MENUPICK);

/* allow for area fill */
InitArea (ai, buffer, 100);
mrp->AreaInfo = &ai;
TekFillRas = AllocRaster(xmax, ymax);
mrp->TmpRas = InitTmpRas(&tr, TekFillRas, RASSIZE(xmax, ymax));

reset();

TekScale = 1;
TekOFF();
return FALSE; /* no errors detected */
}


CloseTek()
{
 TekMode = FALSE;
 FreeRaster(TekFillRas, xmax, ymax);
 TekWindow->UserPort = NULL; /* I will not close his port */
 CloseWindow(TekWindow);
 CloseScreen(TekScreen);
}


/*************************************************
* Function to do tek 4010 graphics and mode
* switching, the function returns false if it
* uses the character else the
* character can be used for something else
*************************************************/


int Tek(c)
char c;
{
#define dx 8
#define dy 10

static short x = xmin, xl;
static short y = ymin + dy, yl;
static int last, escmode = FALSE, boxmode = FALSE;
static short loy, hix, hiy;
static enum {alpha, line, move, point} mode;
static colormode = NULL, index, red, green;
#define COLORSET  1024
static int tk4100 = NULL;
static int ic = 1;

if (TekMode) goto top;
if (c == 29) {
    TekMode = TRUE;
    ScreenToFront(TekScreen);
    mode = move;
    }
return TekMode; /* i.e. if c== 29 we used it and can leave */
top:
if (escmode)
	{
	if (colormode != NULL) {
	   c = c - 48;
	   colormode++;
	   if (colormode == 2)
	      index = c;
	   else if (colormode == 3)
	      red = c;
	   else if (colormode == 4)
	      green = c;
	   else if (colormode == 5) {
	   	COLOR(index, red, green, c);
	   	colormode = NULL;
	   	escmode = FALSE;
		}
	   return TekMode;
	}
	switch (c)
	{
	case '2':    /* Selanar Compatable graphics termiante */
          TekOFF();
          boxmode = FALSE;
	break;
/* I do not know what the tek 4100 area fill commands are so I made-up
   my own, this will not harm the line drawing mode. */
	case 'A':
	   boxmode = TRUE;
	break;
	case 'B':
	  boxmode = FALSE;
	break;
	case 'Q':
	  colormode = 1;
	return TekMode;
/* another one of my own commands */
	case 'R':   /* reset to default then clear screen */
	    reset();
	    ic = 1;
	case 12:     /* clear page */
             x = xmin;
             y = ymin + dy;
	    mode = alpha;
	    tk4100 = NULL;
	    clear();
	break;
	case 'M':  /* looks like a 4100 command */
	     tk4100 = 'M';
	break;
	}
	escmode = FALSE;
	}
else if (tk4100 != NULL)
	{
	if (tk4100 == COLORSET)
	   ic = c - 48;
	   SetAPen(mrp, ic);
	  
	if (tk4100 == 'M' && c == 'L')  
	   tk4100 = COLORSET;
	else
	    tk4100 = NULL;
	}
else if (c >= 32)
	if (mode == alpha)
	  {
	  SetAPen(mrp, 1);
	  Move(mrp,xl,yl);
	  Text(mrp,&c,1);
	  SetAPen(mrp, ic);
	  xl += dx;
	  if (xl > xmax) xl = xmax;
	  }
	else
	  {
		/* a note here about 4014 graphics, If your graphics software
		   drives a Tek 4014 then this will work perfecly well, you
		   just will not be able to use the 4096 pixel resolution
		   that that big storage tube device offers */
	  register int tag, data, x, y;
	  tag = c/32;
	  data = c - tag*32;
	  switch (tag)
	  {
	  case 1:
	    if (last == 3)
	        hix = data*32;
	    else
	        hiy = data*32;
	  break;
	  case 2:
	     x = hix + data;   /* low x always sent so don't save it */
	     y = hiy + loy;
	     if (TekScale == 0)
	       {
	       x = (x*xmax)/1024;
	       y = (y*ymax)/780;
	       }
	       x = x/TS;
	       y = ((ymax-1) -  y/TS);
	     switch (mode)
	     {
	     case move:
	     	mode = line;
	     	Move(mrp, x, y);
	     break;
	     case line:
	        if (boxmode)
		  RectFill(mrp, 
		     min(xl, x), min(yl, y), max(xl, x), max(yl, y));
	        else
	     	  Draw(mrp, x, y);
	     break;
	     case point:
	        WritePixel(mrp, x, y);
	      break;
	      }
	  xl = x;
	  yl = y;
	  break;
	  case 3:
	     loy = data;
	  break;
	  }
	  last = tag; 
	  }
else    switch(c)
	{
	case 7:     /* bell */
	     DisplayBeep(NULL);
	break;
	case 8:   /* backspace */
           x -= dx;
           if (x < xmin) x = xmin;
        break;
	case 9:  /* cursor right */
	   x += dx;
	   if (x > xmax) x = xmax;
	break;
	case 10: /* NL */
	     y += dy;
	     if (y > ymax) y = ymax;
	break;
	case 11: /* cursor up */
	     y -= dy;
	     if (y < ymin+dy) y = ymin+dy;
	break;
	case 13:  /* CR */
             x = xmin;
	break;
	case 24:  /* CAN */
	    TekOFF();
	    boxmode = FALSE;
	break;
	case 27:  /* ESC */
	     escmode = TRUE;
	break;
	case 28:  /* FS (point-plot) */
	     mode = point;
	break;
	case 29:  /* GS vector */
	     mode = move;
	break;
	case 31: /* alpha mode */
	     mode = alpha;
	break;
	default:
	break;
      } /* end of switch */
      return TRUE;
}
reset()
{
/* mess up the colors */
COLOR(0, 00, 00, 00);
COLOR(1, 15, 15, 15);
COLOR(2, 15, 00, 00);
COLOR(3, 00, 15, 00);
COLOR(4, 00, 00, 15);
COLOR(5, 00, 15, 15);
COLOR(6, 15, 00, 15);
COLOR(7, 15, 15, 00);
COLOR(8, 15, 08, 00);
COLOR(9, 08, 15, 00);
COLOR(10,00, 15, 08);
COLOR(11,00, 08, 15);
COLOR(12,08, 00, 15);
COLOR(13,15, 00, 08);
COLOR(14,05, 05, 05);
COLOR(15,10, 10, 10);

clear();
SetAPen(mrp, 1); 
}
