/* Driver for Linux VGA mode 
    Rob Malouf, 4-Sep-1993   
    Rob Malouf, 16-Nov-1993 : Use vgagl 
    Rob Malouf, 28-May-1994 : Set colors from environment variable (thanks to 
                               Sylvio Levy) 
    Rob Malouf, 9-Sep-1994  : Handle scrolling more efficiently 
    Rob Malouf, 23-Jun-1995 : Don't use vgagl, so it'll work in monochrome */

#ifdef __linux__

#include "config.h"
#include "screenio.h" 
#include "unixio.h"
#include "vdu.h"
#include "linuxvdu.h"
#include <vga.h>
#include <string.h>
#include <unistd.h>

#ifdef NOGL
#define WIDTH vga_getxdim()
#define HEIGHT vga_getydim()
#else
#include <vgagl.h>
#endif /* NOGL */

Static int currx, curry; /* Current position for text output */

#define FORE_COLOR 1
#define BACK_COLOR 0

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

#ifdef __STDC__
Void LINUXScrollRegion(int x1, int y1, int w, int h, int x2, int y2)
#else
Void LINUXScrollRegion(x1, y1, w, h, x2, y2)
     int x1, y1, w, h, x2, y2;
#endif
{
#ifdef NOGL
 /* do nothing */
#else
  gl_copybox(x1, y1, w, h, x2, y2);
#endif /* NOGL */
}

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

#ifdef __STDC__
Void LINUXClearRegion(int x1, int y1, int x2, int y2)
#else
Void LINUXClearRegion(x1, y1, x2, y2)
     int x1, y1, x2, y2;
#endif
{
#ifdef NOGL
  int i;

  vga_setcolor(BACK_COLOR);
  for (i = y1; i < y2; i++)
    vga_drawline(x1, i, x2, i);
#else
  gl_fillbox(x1, y1, x2 - x1, y2 - y1, BACK_COLOR);
#endif /* NOGL */
}

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

Void LINUXDoNothing (VOID)
{
  /* Dummy routine */
}  /* LINUXDoNothing */


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

#ifdef __STDC__
Void LINUXShowRectangle (int screenh, int screenv, int width, int height, 
                         Char ch)
#else
Void LINUXShowRectangle (screenh, screenv, width, height)
    int screenh, screenv, width, height;
Char ch;
#endif
{
#ifdef NOGL
  int i;

  vga_setcolor(FORE_COLOR);
  for (i = 0; i < height; i++)
    vga_drawline(screenh, screenv + i, screenh + width - 1, screenv + i);
#else
  gl_fillbox(screenh, screenv, width, height, FORE_COLOR);
#endif /* NOGL */
}  /* LINUXShowRectangle */


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

#ifdef __STDC__
Void LINUXMoveToTextLine (int line)
#else
Void LINUXMoveToTextLine (line)
    int line;
#endif
{

  /* Move current position to start of given line. */
  currx = 0;
  curry = line * FONT_LINES;

}  /* LINUXMoveToTextLine */


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

#ifdef __STDC__
Void LINUXClearTextLine (int line)
#else
Void LINUXClearTextLine (line)
    int line;
#endif
{
#ifdef NOGL
  int i;

  vga_setcolor(BACK_COLOR);
  for (i = -FONT_LINES; i < 0; i++)
    vga_drawline(0, (line*FONT_LINES) + i, windowwd, (line*FONT_LINES) + i);
#else
  gl_fillbox(0,(line*FONT_LINES)-(FONT_LINES),windowwd,FONT_LINES,BACK_COLOR);
#endif /* NOGL */
}  /* LINUXClearTextLine */

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

Void LINUXClearScreen (VOID)
{
#ifdef NOGL
  vga_clear();
#else
  gl_clearscreen(BACK_COLOR);
#endif /* NOGL */
}  /* LINUXClearScreen */


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

#ifdef __STDC__
Void LINUXLoadFont (Char *fontname, int fontsize, double mag, double hscale,
                    double vscale)
#else
Void LINUXLoadFont (fontname, fontsize, mag, hscale, vscale)
    Char *fontname;
    int fontsize;
    double mag, hscale, double vscale;
#endif
{
  /* only one character size available, so do nothing */
}  /* LINUXLoadFont */

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

#ifdef __STDC__
Static Void PutTextChar (int h, int v, Char chr)
#else
Static Void PutTextChar (h, v, chr)
    int h, v;
    Char chr;
#endif
{
#ifdef NOGL
  int i,j, bits;

  vga_setcolor(FORE_COLOR);
  for (i = 0; i < FONT_LINES; i++) {
    bits = font_bits[chr*FONT_LINES+i];
    for (j = 0; j < 8; j++) {
      if (bits & 0x80)
	vga_drawpixel(j + h, i + v - FONT_LINES);
      bits = bits << 1;
    }
  }
#else
  gl_writen(h, v - FONT_LINES, 1, &chr);
#endif /* NOGL */

} /* PutTextChar */
 
/******************************************************************************/

#ifdef __STDC__
Void LINUXWriteTextChar (Char ch)
#else
Void LINUXWriteTextChar (ch)
    Char ch;
#endif
{
  switch (ch) {
  case '\n':
    currx = 0;
    curry = curry + FONT_LINES;
    break;
  case '\b':
  case 127:
    break;
  default:
    PutTextChar(currx, curry, ch);
    currx += 8;
    break;
  } 
} /* LINUXWriteTextChar */


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

#ifdef __STDC__
Void LINUXReadTextString (Char *s)
#else
Void LINUXReadTextString (s)
    Char *s;
#endif
{
  Char ch;
  int i = 0;

  while (1) {
    ReadChar(&ch);
    switch (ch) {
    case '\n':
      s[i] = '\0';      
      return;
    case '\b':
    case 127:
      if (i > 0) {
	currx -= 8;
#ifdef NOGL
	{
	  int l;
	  
	  vga_setcolor(BACK_COLOR);
	  for (l = curry-FONT_LINES; l < curry; l++)
	    vga_drawline(currx, l, currx+8, l);
	}
#else
	gl_fillbox(currx, curry - FONT_LINES, 8, FONT_LINES, BACK_COLOR);
#endif /* NOGL */
	i--;
      }
      break;
    default:
      s[i++] = ch;
      break;
    }
  }
} /* LINUXReadTextString */

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

#ifdef __STDC__
Void LINUXShowChar (int screenh, int screenv, Char ch)
#else
Void LINUXShowChar (screenh, screenv, ch)
    int screenh, screenv; 
    Char ch;
#endif
{
  Char newch;   /* = TeXtoASCII[ch] */
  int v;

  v = screenv + 5; /* Match characters with TeX baseline */
  newch = TeXtoASCII[ch - NUL];   /* convert TeX ch to ASCII */
  if (newch != '?') {
    PutTextChar(screenh, v, newch);
  } else {
    switch (ch) {
    case 0x00: /* Gamma */
      PutTextChar(screenh, v, 226);
      break;
    case 0x02: /* Theta */
      PutTextChar(screenh, v, 233);
      break;
    case 0x05: /* Pi */
      PutTextChar(screenh, v, 227);
      break;
    case 0x06: /* Sigma */
      PutTextChar(screenh, v, 228);
      break;
    case 0x08: /* Phi */
      PutTextChar(screenh, v, 232);
      break;
    case 0x0a: /* Omega */
      PutTextChar(screenh, v, 233);
      break;
    case 0x0b: /* ff */
      PutTextChar(screenh, v, 'f');
      PutTextChar(screenh+8, v, 'f');
      break;
    case 0x0c: /* fi */
      PutTextChar(screenh, v, 'f');
      PutTextChar(screenh+8, v, 'i');
      break;
    case 0x0d: /* fl */
      PutTextChar(screenh, v, 'f');
      PutTextChar(screenh+8, v, 'l');
      break;
    case 0x0e: /* ffi */
      PutTextChar(screenh, v, 'f');
      PutTextChar(screenh+8, v, 'f');
      PutTextChar(screenh+8, v, 'i');
      break;
    case 0x0f: /* ffl */
      PutTextChar(screenh, v, 'f');
      PutTextChar(screenh+8, v, 'f');
      PutTextChar(screenh+16, v, 'l');
      break;
    case 0x17: /* Degree mark */
      PutTextChar(screenh, v, 248);
      break;
    case 0x19: /* German sharp S */
      PutTextChar(screenh, v, 225);
      break;
/*    case 0x19:*/ /* German sharp S */
/*      PutTextChar(screenh, v, 237);
      break; */
    case 0x1a: /* ae */
      PutTextChar(screenh, v, 145);
      break;
    case 0x1b: /* oe */
      PutTextChar(screenh, v, 'o');
      PutTextChar(screenh+8, v, 'e');
      break;
    case 0x1d: /* AE */
      PutTextChar(screenh, v, 146);
      break;
    case 0x1e: /* OE */
      PutTextChar(screenh, v, 'O');
      PutTextChar(screenh+8, v, 'E');
      break;
    case 0x3c: /* ! */
      PutTextChar(screenh, v, 173);
      break;
    case 0x3e: /* ? */
      PutTextChar(screenh, v, 168);
      break;
    default:
      PutTextChar(screenh+8, v, '?');
      break;
    }
  }
}  /* LINUXShowChar */


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

Void LINUXResetVDU (VOID)
{
  vga_setmode(TEXT);
}  /* LINUXResetVDU */


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

Void InitLINUX (VOID)
{
  int vgamode, i;
  void *font;
  vga_modeinfo *modeinfo;
  int fg_red = 180, fg_green = 180, fg_blue = 180,
      bg_red = 0, bg_green = 0, bg_blue = 0;

  restore_init_tty();
  
  /* Get SVGA mode */
  setreuid(geteuid(),getuid()); /* Temporarily give up privs */
  setregid(getegid(),getgid());

  vga_init();
  vgamode = vga_getdefaultmode();

#ifndef NOGL
  if (vga_hasmode(vgamode)) {
    modeinfo = vga_getmodeinfo(vgamode);
    if (modeinfo->bytesperpixel < 1) {
      fprintf(stderr, "vgagl requires linear resolution - using 640x480x256 mode!\n");
      vgamode = G640x480x256; 
    }
  } else {
    fprintf(stderr, "Unavailable graphics mode - using 640x480x256 mode!\n");
    vgamode = G640x480x256;
  }
#endif /* NOGL */

  if (!vga_hasmode(vgamode)) {
    fprintf(stderr, "Unavailable graphics mode - please check GSVGAMODE setting!\n");
    exit (1);
  } 

  /* Get foreground and background colors */
  if (getenv("DV_LINUX_FG")) {
    fg_red = atoi(strtok(getenv("DV_LINUX_FG"), ","));
    fg_green = atoi(strtok(NULL, ","));
    fg_blue = atoi(strtok(NULL, ","));
  }
  if (getenv("DV_LINUX_BG")) {
    bg_red = atoi(strtok(getenv("DV_LINUX_BG"), ","));
    bg_green = atoi(strtok(NULL, ","));
    bg_blue = atoi(strtok(NULL, ","));
  }
  
  /* Initialize SVGAlib */
  vga_setmode(vgamode);
  vga_setpalette(BACK_COLOR,bg_red,bg_green,bg_blue);
  vga_setpalette(FORE_COLOR,fg_red,fg_green,fg_blue);
  vga_setcolor(FORE_COLOR);
  
#ifndef NOGL
  /* Initialize gl */
  gl_setcontextvga(vgamode);
  gl_setwritemode(WRITEMODE_OVERWRITE);
  gl_disableclipping();
  
  /* Set up font */
  font = malloc(256 * 8 * FONT_LINES * BYTESPERPIXEL);
  gl_expandfont(8, FONT_LINES, FORE_COLOR, font_bits, font);
  gl_setfont(8, FONT_LINES, font);
#endif /* NOGL */
  
  /* The dialogue region is the top 4 lines.
     The window region is the remaining area of the screen.
     */
  DVIstatusl = 1;
  windowstatusl = 2;
  messagel = 3;
  commandl = 4;
  bottoml = 24;
  windowh = 0;
  windowv = 64; /* (FONT_LINES * 4) */
  windowwd = WIDTH;
  windowht = HEIGHT - windowv; 
  
  MoveToTextLine = LINUXMoveToTextLine;
  ClearTextLine  = LINUXClearTextLine;
  ClearScreen    = LINUXClearScreen;
  StartText      = LINUXDoNothing;
  StartGraphics  = LINUXDoNothing;
  LoadFont       = LINUXLoadFont;
  ShowChar       = LINUXShowChar;
  ShowRectangle  = LINUXShowRectangle;
  ResetVDU       = LINUXResetVDU;
  WriteTextChar  = LINUXWriteTextChar;
  ReadTextString = LINUXReadTextString;
  ScrollRegion   = LINUXScrollRegion;
  ClearRegion    = LINUXClearRegion;
  
  vdu_unixio = 0; /* We do our own I/O */
  
#ifndef NOGL
  vdu_scroll = 1; /* We can do scrolling to minimize screen updates */
#endif /* NOGL */
  
#if 0
  vdu_bitmap = 1; /* We prefer bitmaps to lots of rectangles */
#endif
  
  currx = 0;
  curry = 0;
}  /*InitLINUX */

#endif /* linux */
/* End. */
