/*
 * Fast video support for IBM PC like displays.
 * Use with pcio.c and FASTVIDEO.
 * For faster display speed, use pcfv.asm instead of this file.
 * Routines:
 *   fv_init()
 *   putline(row,buf,attr) int row,attr; char *buf;
 *   void t_move(row,col) int row, col;
 *   void t_eeol()
 * Notes:
 *   The stuff in this file is C versions of the code in pcfv.asm.
 *   The only routine that will really speed things up is putline().  I
 *     don't think the other stuff is called enough to have much effect.
 *   
 * C Durland	Public Domain
 * J Burnell	C for some of the asm routines.  3/92
 */

extern int t_ncol, t_nrow;	/* in pcio.c */

int tcolor = 7, mcolor = 96;	/* text, modeline color defaults */

static char *video_addr;
static int BIOS_color;
static int phys_cols;		/* Because t_ncol can change */


void putline(row, buf, attr)	/* note: row is 0 relative */
  int row,attr; char *buf;
{
  register int n = t_ncol;
  register char *display = video_addr +2*row*phys_cols;

  while (n--)
  {
    *display++ = *buf++;	/* character */
    *display++ = attr;		/* attribute */
  }
}

#include <dos.h>

void t_move(row,col) int row, col;	/* move cursor to (row,col) */
{
  union REGS rg;

  rg.h.ah = 2;		/* set cursor position function code */
  rg.h.dl = col;
  rg.h.dh = row;
  rg.h.bh = 0;		/* set screen page number */
  int86(0x10, &rg, &rg);
}

void fv_init()
{
  union REGS x;

	/* Try and figure out addr of video */
  x.h.ah = 0xF; int86(0x10,&x,&x);
  if (x.h.al == 7) video_addr = (char *)0xB0000000L;	/* mono */
  else video_addr = (char *)0xB8000000L;		/* color */

	/* Figure out the BIOS color.  I'll use that to write the message
	 *   line.
	 */
  t_move(0,0);
  t_putchar(' ');	/* Let the BIOS write a character and attr */
  t_move(0,0);
	/* read character attr */
  x.h.ah = 0x8;
  int86(0x10,&x,&x);
  BIOS_color = x.h.ah;
  if (BIOS_color == 0) BIOS_color = 7;	/* make sure cursor displays */

	/* Figure out the number of columns (BIOS 40:4A == columns) */
  t_ncol = phys_cols = *((unsigned char *)0x0040004AL);

	/* Figure out the number of rows.
	 * For EGA type displays, the number of rows is in ram.  For CGA, it
	 *   is fixed.
	 */
  t_nrow = 24;		/* default */

  x.x.ax = 0x1200;
  x.x.bx = 0x0010;
  x.x.cx = 0xFFFF;
  int86(0x10,&x,&x);
  if (x.x.cx != 0xFFFF)		/* is at least EGA */
    t_nrow = *((unsigned char *)0x00400084L);		/* 40:84 == rows-1 */
}

#define NCOL  140	/* maximum number of columns */
#define SPACE ' '

void t_eeol()		/* erase to end of line */
{
  register int n = t_ncol;
  int CurCol;		/* current column cursor */
  int CurRow;		/*	   row	*/
  union REGS rg;
  register char *ScreenAddr;		/* address to write to */

	/* find the current cursor position */
  rg.h.ah = 3;	
  rg.h.bh = 0;		/* current page */
  int86(0x10, &rg, &rg);
  CurCol = rg.h.dl;
  CurRow = rg.h.dh;

  ScreenAddr = video_addr + CurRow*phys_cols*2 + CurCol*2;

	/* Note:  You could probably save time by writing
	 *   (SPACE | (BIOS_color << 8)) to a short int pointer but I don't
	 *   think it will make any difference.
	 */
  for (n = phys_cols -CurCol; n--; )
  {
    *ScreenAddr++ = SPACE;	/* character */
    *ScreenAddr++ = BIOS_color;	/* attribute */
  }
}
