Logo Search packages:      
Sourcecode: jnethack version File versions  Download package

vidvga.c

/*   SCCS Id: @(#)vidvga.c   3.2     96/02/16                   */
/*   Copyright (c) NetHack PC Development Team 1995                 */
/*   NetHack may be freely redistributed.  See license for details. */
/*
 * vidvga.c - VGA Hardware video support
 */

#include "hack.h"

#ifdef SCREEN_VGA       /* this file is for SCREEN_VGA only    */
#include "pcvideo.h"
#include "tile.h"
#include "pctiles.h"

#include <dos.h>
#include <ctype.h>
#include "wintty.h"

# ifdef __GO32__
#include <pc.h>
#include <unistd.h>
# endif

/*=========================================================================
 * VGA Video supporting routines (for tiles).
 *
 * The following routines carry out the lower level video functions required
 * to make PC NetHack work with VGA graphics.
 *
 *   - The binary files NetHack1.tib and NetHacko.tib must be in your
 *     game directory.  Currently, unpredictable results may occur if they 
 *     aren't since the code hasn't been tested with it missing (yet).
 *
 * Notes (96/02/16):
 *
 *   - Cursor emulation on the map is now implemented.  The input routine
 *     in msdos.c calls the routine to display the cursor just before
 *     waiting for input, and hides the cursor immediately after satisfying 
 *     the input request.
 *
 *   - A check for a VGA adapter is implemented.
 *
 *   - With 640 x 480 resolution, the use of 16 x 16 icons allows only 40
 *     columns for the map display.  This makes it necessary to support the
 *     TTY CLIPPING code.  The right/left scrolling with this can be
 *     a little annoying.  Feel free to rework the routines.
 *
 *   - NetHack1.tib is built from text files derived from bitmap files 
 *     provided by Warwick Allison, using routines developed and supplied 
 *     by Janet Walz.  The icons are very well done and thanks to 
 *     Warwick Allison for an excellent effort!
 *
 *   - The text fonts that this is using while in graphics mode come from
 *     the Video BIOS ROM on board the VGA adapter.  Code in vga_WriteChar
 *     copies the appropriate pixels from the video ROM to the Video buffer.
 *
 *   - Currently, most of the routines are in an ifdef OVLB.
 *     If you change that, you may have to muck with some of the 
 *     variable declarations which now assume this.  This is not a 
 *     problem in a non-overlaid environment (djgpp for example).
 *
 *   - VGA 640 by 480, 16 colour mode (0x12) uses an odd method to 
 *     represent a colour value from the palette. There are four 
 *     planes of video memory, all overlaid at the same memory location.
 *     For example, if a pixel has the colour value 7:
 *
 *           0 1 1 1
 *            \ \ \ \
 *             \ \ \ plane 0 
 *              \ \ plane 1
 *               \ plane 2
 *                plane 3
 *
 *   - VGA write mode 2 requires that a read be done before a write to
 *     set some latches on the card.  The value read had to be placed
 *     into a variable declared 'volatile' to prevent djgpp from
 *     optimizing away the entire instruction (the value was assigned
 *     to a variable which was never used).  This corrects the striping
 *     problem that was apparent with djgpp.
 *
 *   - A check for valid mode switches has been added.
 *
 *   - No tiles are displayed on the Rogue Level in keeping with the
 *     original Rogue.  The display adapter remains in graphics mode 
 *     however.
 *
 *   - Added handling for missing NetHackX.tib files, and resort to using
 *     video:default and tty if one of them can't be located.
 *
 * ToDo (96/02/17):
 *
 *   - Nothing prior to release.
 *=========================================================================
 */


# if defined(_MSC_VER)
#  if _MSC_VER >= 700
#pragma warning(disable:4018) /* signed/unsigned mismatch */
#pragma warning(disable:4127) /* conditional expression is constant */
#pragma warning(disable:4131) /* old style declarator */
#pragma warning(disable:4305) /* prevents complaints with MK_FP */
#pragma warning(disable:4309) /* initializing */
#    if _MSC_VER > 700
#pragma warning(disable:4759) /* prevents complaints with MK_FP */
#    endif
#  endif
# include <conio.h>
# endif

/* STATIC_DCL void FDECL(vga_NoBorder, (int)); /* */
void FDECL(vga_gotoloc, (int,int));  /* This should be made a macro */
void NDECL(vga_backsp);
#ifdef SCROLLMAP
STATIC_DCL void FDECL(vga_scrollmap,(BOOLEAN_P));
#endif
STATIC_DCL void FDECL(vga_redrawmap,(BOOLEAN_P));
void FDECL(vga_cliparound,(int, int));

#ifdef POSITIONBAR
STATIC_DCL void NDECL(positionbar);
static void FDECL(vga_special,(int, int, int));
#endif

extern int clipx, clipxmax;   /* current clipping column from wintty.c */
extern boolean clipping;      /* clipping on? from wintty.c */
extern int savevmode;         /* store the original video mode */
extern int curcol,currow;     /* current column and row        */
extern int g_attribute;
extern int attrib_text_normal;      /* text mode normal attribute */
extern int attrib_gr_normal;  /* graphics mode normal attribute */
extern int attrib_text_intense;     /* text mode intense attribute */
extern int attrib_gr_intense; /* graphics mode intense attribute */
extern boolean inmap;         /* in the map window */

/*
 * Global Variables
 */ 

STATIC_VAR unsigned char __far *font;
STATIC_VAR char *screentable[SCREENHEIGHT];
STATIC_VAR char tmp[SCREENWIDTH];
STATIC_VAR char *paletteptr;
STATIC_VAR struct map_struct {
      int glyph;
      int ch;
      int attr;
}  map[ROWNO][COLNO];   /* track the glyphs */

# define vga_clearmap() { int x,y; for (y=0; y < ROWNO; ++y) \
      for (x=0; x < COLNO; ++x) { map[y][x].glyph = cmap_to_glyph(S_stone); \
      map[y][x].ch = S_stone; map[y][x].attr = 0;} }
# define TOP_MAP_ROW 1
#  if defined(OVLB)
STATIC_VAR int vgacmap[CLR_MAX] = {0,3,5,9,4,8,12,14,11,2,6,7,1,8,12,13};
STATIC_VAR int viewport_size = 40;
STATIC_VAR char masktable[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
STATIC_VAR char bittable[8]= {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
STATIC_VAR char defpalette[] = {    /* Default VGA palette         */
      0x00, 0x00, 0x00,
      0x00, 0x00, 0xaa,
      0x00, 0xaa, 0x00,
      0x00, 0xaa, 0xaa,
      0xaa, 0x00, 0x00,
      0xaa, 0x00, 0xaa,
      0xaa, 0xaa, 0x00,
      0xaa, 0xaa, 0xaa,
      0x55, 0x55, 0x55,
      0xcc, 0xcc, 0xcc,
      0x00, 0x00, 0xff,
      0x00, 0xff, 0x00,
      0xff, 0x00, 0x00,
      0xff, 0xff, 0x00,
      0xff, 0x00, 0xff,
      0xff, 0xff, 0xff
      };
#   ifndef ALTERNATE_VIDEO_METHOD
int vp[SCREENPLANES] = {8,4,2,1};
#   endif
int vp2[SCREENPLANES] = {1,2,4,8};
#  else
extern int vgacmap[CLR_MAX];
extern int viewport_size;
extern char masktable[8];
extern char bittable[8];
extern char defpalette[];
#   ifndef ALTERNATE_VIDEO_METHOD
extern int vp[SCREENPLANES];
#   endif
extern int vp2[SCREENPLANES];
#  endif /* OVLB */

STATIC_VAR struct planar_cell_struct *planecell;
STATIC_VAR struct overview_planar_cell_struct *planecell_O;

# if defined(USE_TILES)
STATIC_VAR struct tibhdr_struct tibheader;
/* extern FILE *tilefile; /* Not needed in here most likely */
# endif

/* STATIC_VAR int  g_attribute;           /* Current attribute to use */

#ifdef OVLB
void
vga_get_scr_size()
{
      CO = 80;
      LI = 29;
}
#endif /*OVLB*/



# ifdef OVLB

void
vga_backsp()
{
      int col,row;

      col = curcol;           /* Character cell row and column */
      row = currow;

      if (col > 0) col = col-1;
      vga_gotoloc(col,row);
      vga_xputc(' ',g_attribute);
      vga_gotoloc(col,row);
}

# endif /* OVLB */
# ifdef OVL0

void
vga_clear_screen(colour)
int colour;
{
      char __far *pch;
      int y,j;
      char volatile a;

      outportb(0x3ce,5);
      outportb(0x3cf,2);

      for (y=0; y < SCREENHEIGHT; ++y) {
            pch = screentable[y];
            for (j=0; j < SCREENBYTES; ++j) {
                  outportb(0x3ce,8);
                  outportb(0x3cf,255);
                  a = READ_ABSOLUTE(pch); /* Must read , then write */
                  WRITE_ABSOLUTE(pch, (char)colour);
                  ++pch;
            }
      }
      outportb(0x3ce,5);
      outportb(0x3cf,0);
      if (iflags.tile_view) vga_clearmap();
      vga_gotoloc(0,0); /* is this needed? */
}

void
vga_cl_end(col,row)     /* clear to end of line */
int col,row;
{
      int count;

      /*
       * This is being done via character writes.
       * This should perhaps be optimized for speed by using VGA write
       * mode 2 methods as did clear_screen()
       */
      for (count = col; count < (CO-1); ++count) {
            vga_WriteChar(' ',count,row,BACKGROUND_VGA_COLOR);
      }
}

void
vga_cl_eos(cy)    /* clear to end of screen */
int cy;
{
      int count;

      cl_end();
      while(cy <= LI-2) {
            for (count = 0; count < (CO-1); ++count) {
                  vga_WriteChar(' ',count,cy,
                        BACKGROUND_VGA_COLOR);
            }
            cy++;
      }
}


# endif /* OVL0 */

# ifdef OVLB
void
vga_tty_end_screen()
{
      vga_clear_screen(BACKGROUND_VGA_COLOR);
      vga_SwitchMode(MODETEXT);
}


void
vga_tty_startup(wid, hgt)
    int *wid, *hgt;
{

      /* code to sense display adapter is required here - MJA */

      vga_get_scr_size();
      if (CO && LI) {
            *wid = CO;
            *hgt = LI;
      }

      attrib_gr_normal    = ATTRIB_VGA_NORMAL;
      attrib_gr_intense   = ATTRIB_VGA_INTENSE;
      g_attribute         = attrib_gr_normal;   /* Give it a starting value */
}
# endif /* OVLB */

/*
 * Screen output routines (these are heavily used).
 *
 * These are the 3 routines used to place information on the screen
 * in the VGA PC tty port of NetHack.  These are the routines
 * that get called by the general interface routines in video.c.
 *
 * vga_xputs -Writes a c null terminated string at the current location.
 *
 * vga_xputc -Writes a single character at the current location. Since
 *            various places in the code assume that control characters
 *            can be used to control, we are forced to interpret some of
 *            the more common ones, in order to keep things looking correct.
 *
 * vga_xputg -This routine is used to display a graphical representation of a
 *            NetHack glyph (a tile) at the current location.  For more
 *            information on NetHack glyphs refer to the comments in
 *            include/display.h.
 *
 */

# ifdef OVL0
void
vga_xputs(s,col,row)
const char *s;
int col,row;
{
      if (s != (char *)0) {
            vga_WriteStr((char *)s,strlen(s),col,row,g_attribute);
      }
}
void
vga_xputc2(ch, ch2, attr)
char ch;
char ch2;
int attr;
{
  int col, row;

  col = curcol;
  row = currow;

  vga_WriteChar2((unsigned char)ch,(unsigned char)ch2,col,row,attr);
  if (col < (CO -2 )) col+=2;
  vga_gotoloc(col,row);
}

void
vga_xputc(ch,attr)      /* write out character (and attribute) */
char ch;
int attr;
{
      int col,row;

      col = curcol;
      row = currow;

      switch(ch) {
          case '\n':    
                  col = 0;
                  ++row;
                  break;
          default:
                  vga_WriteChar((unsigned char)ch,col,row,attr);
                  if (col < (CO -1 )) ++col;
                  break;
      } /* end switch */
      vga_gotoloc(col,row);
}

#  if defined(USE_TILES)
void
vga_xputg(glyphnum,ch)  /* Place tile represent. a glyph at current location */
int glyphnum;
int ch;
{
      int col,row;
      int attr;

      row = currow;
      col = curcol;
      if ((col < 0 || col >= COLNO) ||
          (row < TOP_MAP_ROW || row >= (ROWNO + TOP_MAP_ROW))) return;
      map[row - TOP_MAP_ROW][col].glyph = glyphnum;
      map[row - TOP_MAP_ROW][col].ch = ch;
      attr = (g_attribute == 0) ? attrib_gr_normal : g_attribute;
      map[row - TOP_MAP_ROW][col].attr = attr;
      if (iflags.traditional_view) {
          vga_WriteChar((unsigned char)ch,col,row,attr);
      } else if (!iflags.over_view) {
          if ((col >= clipx) && (col <= clipxmax)) {
            if (!ReadPlanarTileFile(glyph2tile[glyphnum], &planecell))
                  vga_DisplayCell(planecell, 
                              col - clipx, row);
            else
                  pline("vga_xputg: Error reading tile (%d,%d) from file",
                              glyphnum,glyph2tile[glyphnum]);
          }
      } else {
          if (!ReadPlanarTileFile_O(glyph2tile[glyphnum], &planecell_O))
                  vga_DisplayCell_O(planecell_O, col, row);
          else
                  pline("vga_xputg: Error reading tile (%d,%d) from file",
                              glyphnum,glyph2tile[glyphnum]);
      }
      if (col < (CO - 1 )) ++col;
      vga_gotoloc(col,row);
}
#  endif /* USE_TILES */

/*
 * Cursor location manipulation, and location information fetching
 * routines.
 * These include:
 *
 * vga_gotoloc(x,y)     - Moves the "cursor" on screen to the specified x
 *                 and y character cell location.  This routine
 *                       determines the location where screen writes
 *                       will occur next, it does not change the location
 *                       of the player on the NetHack level.
 */
 
void
vga_gotoloc(col,row)
int col,row;
{
      curcol = min(col,CO - 1); /* protection from callers */
      currow = min(row,LI - 1);
/*JP*/
      txt_gotoxy(col, row);
}

#  if defined(USE_TILES) && defined(CLIPPING)
void
vga_cliparound(x, y)
int x, y;
{
      extern boolean restoring;
      int oldx = clipx;

      if (!iflags.tile_view || iflags.over_view || iflags.traditional_view)
            return;

      if (x < clipx + 5) {
            clipx = max(0, x - (viewport_size / 2));
            clipxmax = clipx + (viewport_size - 1);
      }
      else if (x > clipxmax - 5) {
            clipxmax = min(COLNO - 1, x + (viewport_size / 2));
            clipx = clipxmax - (viewport_size - 1);
      }
      if (clipx != oldx) {
          if (on_level(&u.uz0, &u.uz) && !restoring)
            /* (void) doredraw(); */
            vga_redrawmap(1);
      }
}

STATIC_OVL void
vga_redrawmap(clearfirst)
boolean clearfirst;
{
      int j,x,y,t;
      char __far *pch;
      char volatile a;

      if (clearfirst) {
            /* y here is in pixel rows */
            outportb(0x3ce,5);
            outportb(0x3cf,2);
            t = TOP_MAP_ROW * ROWS_PER_CELL;
            for (y = t; y < (ROWNO * ROWS_PER_CELL) + t; ++y) {
                  pch = screentable[y];
                  for (j=0; j < SCREENBYTES; ++j) {
                        outportb(0x3ce,8);
                        outportb(0x3cf,255);
                         /* On VGA mode2, must read first, then write */
                        a = READ_ABSOLUTE(pch);
                        WRITE_ABSOLUTE(pch, (char)BACKGROUND_VGA_COLOR);
                        ++pch;
                  }
            }
            outportb(0x3ce,5);
            outportb(0x3cf,0);
      }
      /* y here is in screen rows*/
#    ifdef ROW_BY_ROW
      for (y = 0; y < ROWNO; ++y)
            for (x = clipx; x <= clipxmax; ++x) {
#    else
      for (x = clipx; x <= clipxmax; ++x)
            for (y = 0; y < ROWNO; ++y) {
#    endif
                if (iflags.traditional_view) {
                  if (!(clearfirst && map[y][x].ch == S_stone))
                        vga_WriteChar(
                              (unsigned char)map[y][x].ch,
                              x,y + TOP_MAP_ROW,map[y][x].attr);
                } else {
                  t = map[y][x].glyph;
                  if (!(clearfirst && t == cmap_to_glyph(S_stone))) {
                  if (!iflags.over_view) {
                        if (!ReadPlanarTileFile(glyph2tile[t], 
                            &planecell)) {
                              vga_DisplayCell(planecell,
                                    x - clipx, y + TOP_MAP_ROW);
                        } else
                        pline("vga_redrawmap: Error reading tile (%d,%d)",
                               t,glyph2tile[t]);
                  } else {
                        if (!ReadPlanarTileFile_O(glyph2tile[t], 
                             &planecell_O)) {
                              vga_DisplayCell_O(planecell_O,
                                    x, y + TOP_MAP_ROW);
                        } else
                       pline("vga_redrawmap: Error reading tile (%d,%d)",
                              t,glyph2tile[t]);
                  }
                  }
                }
            }
}
#  endif /* USE_TILES && CLIPPING */
# endif /* OVL0 */
# ifdef OVL2

void
vga_userpan(left)
boolean left;
{
      int x;

/*    pline("Into userpan"); */
      if (iflags.over_view || iflags.traditional_view) return;
      if (left)
            x = min(COLNO - 1, clipxmax + 10);
      else 
            x = max(0, clipx - 10);
      vga_cliparound(x, 10);  /* y value is irrelevant on VGA clipping */
      positionbar();
      vga_DrawCursor();
}


void vga_overview(on)
boolean on;
{
/*    vga_HideCursor(); */
      if (on) {
            iflags.over_view = TRUE;
            clipx = 0;
            clipxmax = CO - 1;
      } else {
            iflags.over_view = FALSE;
            clipx = max(0, (curcol - viewport_size / 2));
            if (clipx > ((CO - 1) - viewport_size)) 
                  clipx = (CO - 1) - viewport_size;
            clipxmax = clipx + (viewport_size - 1);
      }
}

void vga_traditional(on)
boolean on;
{
/*    vga_HideCursor(); */
      if (on) {
/*          switch_graphics(ASCII_GRAPHICS); */
            iflags.traditional_view = TRUE;
            clipx = 0;
            clipxmax = CO - 1;
      } else {
            iflags.traditional_view = FALSE;
            if (!iflags.over_view) {
                  clipx = max(0, (curcol - viewport_size / 2));
                  if (clipx > ((CO - 1) - viewport_size)) 
                        clipx = (CO - 1) - viewport_size;
                  clipxmax = clipx + (viewport_size - 1);
            }
      }
}

void vga_refresh()
{
      positionbar();
      vga_redrawmap(1);
      vga_DrawCursor();
}

#  ifdef SCROLLMAP
STATIC_OVL void
vga_scrollmap(left)
boolean left;
{
      int j,x,y,t;
      int i,pixx,pixy,x1,y1,x2,y2;
      int byteoffset, vplane;
      char __far *tmp1;
      char __far *tmp2;
      unsigned char source[SCREENPLANES][80];
      unsigned char first,second;

      
      pixy = row2y(TOP_MAP_ROW);            /* convert to pixels */
      pixx = col2x(x1);
      if (left) {
            x1 = 20;
            x2 = 0;
      } else {
            x1 = 0;
            x2 = 20;
      }
      /* read each row, all columns but the one to be replaced */
      for(i = 0;i < (ROWNO-1) * ROWS_PER_CELL; ++i) {
          tmp1 = screentable[i + pixy];
          tmp1 += x1;
          for(vplane=0; vplane < SCREENPLANES; ++vplane) {
            egareadplane(vplane);
            for (byteoffset = 0; byteoffset < 20; ++byteoffset) {
                  tmp2 = tmp1 + byteoffset;
                  source[vplane][byteoffset] = READ_ABSOLUTE(tmp2);
            }
          }
          tmp1 = screentable[i + pixy];
          tmp1 += x2;
          for(vplane=0; vplane < SCREENPLANES; ++vplane) {
            egawriteplane(vp2[vplane]);
            for (byteoffset = 0; byteoffset < 20; ++byteoffset) {
                  tmp2 = tmp1 + byteoffset;
                  WRITE_ABSOLUTE(tmp2,source[vplane][byteoffset]);
            }
          }
          egawriteplane(15);
      }

      if (left) {
            i = clipxmax - 1;
            j = clipxmax;
      } else {
            i = clipx;
            j = clipx + 1;
      }
      for (y = 0; y < ROWNO; ++y) {
          for (x = i; x < j; x += 2) {
            t = map[y][x].glyph;
            if (!ReadPlanarTileFile(glyph2tile[t], &planecell)) 
                  vga_DisplayCell(planecell, x - clipx, y + TOP_MAP_ROW);
            else
                  pline("vga_shiftmap: Error reading tile (%d,%d)",
                        t, glyph2tile[t]);            
          }
      }
}
#   endif /* SCROLLMAP */
# endif /* OVL2 */

# ifdef OVLB

/*
 * Open tile files,
 * initialize the SCREEN, switch it to graphics mode,
 * initialize the pointers to the fonts, clear
 * the screen.
 *
 */
void vga_Init(void)
{
     int i, c;

#   ifdef USE_TILES
     int tilefailure = 0;
/*
 * Attempt to open the required tile files. If we can't
 * don't perform the video mode switch, use TTY code instead.
 *
 */
     if (OpenTileFile(NETHACK_PLANAR_TILEFILE, FALSE)) tilefailure |= 1;
     if (OpenTileFile(NETHACK_OVERVIEW_TILEFILE, TRUE)) tilefailure |= 2;           
     if (ReadTileFileHeader(&tibheader, FALSE)) tilefailure |= 4;

     if (tilefailure) {
      raw_printf("Reverting to TTY mode, tile initialization failure (%d).",
            tilefailure);
      wait_synch();
      iflags.usevga = 0;
      iflags.tile_view = FALSE;
      iflags.over_view = FALSE;
      CO = 80;
      LI = 25;
/*    clear_screen()    /* not vga_clear_screen() */
      return;
     }
#   endif

     if (iflags.usevga) {
      for (i=0; i < SCREENHEIGHT; ++i) {
            screentable[i]=MK_PTR(VIDEOSEG, (i * SCREENBYTES));
      }
     }
     vga_SwitchMode(MODE640x480);
     windowprocs.win_cliparound = vga_cliparound;
/*     vga_NoBorder(BACKGROUND_VGA_COLOR);   /* Not needed after palette mod */
#   ifdef USE_TILES
     paletteptr = tibheader.palette;
     iflags.tile_view = TRUE;
     iflags.over_view = FALSE;
#   else
     paletteptr = defpalette;
#   endif
     vga_SetPalette(paletteptr);
     g_attribute  = attrib_gr_normal;
     font = vga_FontPtrs();
     clear_screen();
     clipx = 0;
     clipxmax = clipx + (viewport_size - 1);
}

/*
 * Switches modes of the video card.
 *
 * If mode == MODETEXT (0x03), then the card is placed into text
 * mode.  If mode == 640x480, then the card is placed into vga
 * mode (video mode 0x12). No other modes are currently supported.
 *
 */
void vga_SwitchMode(unsigned int mode)
{
      union REGS regs;

      if ((mode == MODE640x480) || (mode == MODETEXT)) {
            if (iflags.usevga && (mode == MODE640x480)) {
                  iflags.grmode = 1;
            } else {
                  iflags.grmode = 0;
            }
            regs.x.ax = mode;
            (void) int86(VIDEO_BIOS, &regs, &regs);
      } else {
            iflags.grmode = 0;      /* force text mode for error msg */
            regs.x.ax = MODETEXT;
            (void) int86(VIDEO_BIOS, &regs, &regs);
            g_attribute  = attrib_text_normal;
            impossible("vga_SwitchMode: Bad video mode requested 0x%X",
                  mode);
      }
}

/*
 * This allows grouping of several tasks to be done when
 * switching back to text mode. This is a public (extern) function.
 *
 */
void vga_Finish(void)
{
     CloseTileFile(0);
     CloseTileFile(1);
     vga_SwitchMode(MODETEXT);
     windowprocs.win_cliparound = tty_cliparound;
     g_attribute  = attrib_text_normal;
     iflags.tile_view = FALSE;
}

#if 0
/*
 * Turn off any border colour that might be enabled in the VGA card
 * register.
 *
 * I disabled this after modifying tile2bin.c to remap black & white
 * to a more standard values - MJA 94/04/23.
 *
 */
STATIC_OVL void 
vga_NoBorder(int bc)
{
      union REGS regs;

      regs.h.ah = (char)0x10;
      regs.h.al = (char)0x01;
      regs.h.bh = (char)bc;
      regs.h.bl = 0;
      (void) int86(VIDEO_BIOS, &regs, &regs);   
}
#endif

/*
 * 
 * Returns a far pointer (or flat 32 bit pointer under djgpp) to the
 * location of the appropriate ROM font for the _current_ video mode
 * (so you must place the card into the desired video mode before
 * calling this function).
 *
 * This function takes advantage of the video BIOS loading the
 * address of the appropriate character definition table for
 * the current graphics mode into interrupt vector 0x43 (0000:010C).
 */
char __far  *vga_FontPtrs(void)
{
      USHORT  __far *tmp;
      char __far *retval;
      USHORT fseg, foff;
      tmp  = (USHORT __far *)MK_PTR(((USHORT)FONT_PTR_SEGMENT),
                              ((USHORT)FONT_PTR_OFFSET));
      foff = READ_ABSOLUTE_WORD(tmp);
      ++tmp;
      fseg = READ_ABSOLUTE_WORD(tmp);
      retval = (char __far *)MK_PTR(fseg,foff);
      return retval;
}

/*
 * This will verify the existance of a VGA adapter on the machine.
 * Video function call 0x1a returns 0x1a in AL if successful, and
 * returns the following values in BL for the active display:
 *
 * 0=no display, 1=MDA, 2=CGA, 4=EGA(color-monitor), 
 * 5=EGA(mono-monitor), 6=PGA, 7=VGA(mono-monitor), 8=VGA(color-monitor),
 * 0xB=MCGA(mono-monitor), 0xC=MCGA(color-monitor), 0xFF=unknown)
 */
int vga_detect()
{
      union REGS regs;
      
      regs.h.al = 0;
      regs.h.ah = 0x1a;
      (void) int86(VIDEO_BIOS, &regs, &regs);
/*
 * debug
 *
 *    printf("vga_detect returned al=%02x, bh=%02x, bl=%02x\n",
 *                (int)regs.h.al, (int)regs.h.bh, (int)regs.h.bl);
 *    getch();
 */
      if ((int)regs.h.al == 0x1a) { 
            if (((int)regs.h.bl == 8) || ((int)regs.h.bl == 7)) {
                  return 1;
            }
      }
      return 0;
}

void
vga_WriteChar2(chr, chr2, col, row, colour)
int chr, chr2, col, row, colour;
{
  int saved_col, saved_row;

  saved_col = curcol;
  saved_row = currow;

  vga_gotoloc(col, row);
  txt_xputc2(chr, chr2, 14);

  curcol = saved_col;
  currow = saved_row;
}

void
vga_WriteChar(chr, col, row, colour)
int chr, col, row, colour;
{
  int saved_col, saved_row;

  saved_col = curcol;
  saved_row = currow;

  vga_gotoloc(col, row);
  txt_xputc(chr, 14);

  curcol = saved_col;
  currow = saved_row;
}

#if 0 /*JP*/
/*
 * Write character 'ch', at (x,y) and
 * do it using the colour 'colour'.
 *
 */
void 
vga_WriteChar(chr,col,row,colour)
int chr,col,row,colour;
{
      int i;
      int x,pixy;
      int floc;
      char volatile tc;
      char __far *cp;
      unsigned char __far *fp = font;
      unsigned char fnt;
      int actual_colour = vgacmap[colour];


      x = min(col,(CO-1));           /* min() used protection from callers */
      pixy = min(row,(LI-1)) * 16; /* assumes 8 x 16 char set */
/*    if (chr < ' ') chr = ' ';    /* assumes ASCII set */

      outportb(0x3ce,5);
      outportb(0x3cf,2);
                  
      chr = chr<<4;
      for (i=0; i < MAX_ROWS_PER_CELL; ++i) {
            cp = screentable[pixy+i] + x;
            fnt = READ_ABSOLUTE((fp + chr + i));
            outportb(0x3ce,8);
            outportb(0x3cf,fnt);
            tc = READ_ABSOLUTE(cp); /* wrt mode 2, must read, then write */
            WRITE_ABSOLUTE(cp, (char)actual_colour);
            outportb(0x3ce,8);
            outportb(0x3cf,~fnt);
            tc = READ_ABSOLUTE(cp); /* wrt mode 2, must read, then write */
            WRITE_ABSOLUTE(cp, (char)BACKGROUND_VGA_COLOR);
      }
      outportb(0x3ce,5);
      outportb(0x3cf,0);
      outportb(0x3ce,8);
      outportb(0x3cf,255);
}
#endif

/*
 * This is the routine that displays a high-res "cell" pointed to by 'gp'
 * at the desired location (col,row).
 *
 * Note: (col,row) in this case refer to the coordinate location in
 * NetHack character grid terms, (ie. the 40 x 25 character grid),
 * not the x,y pixel location.
 *
 */
void
vga_DisplayCell(gp,col,row)
struct planar_cell_struct *gp;
int col,row;
{
      int i,pixx,pixy;
      char __far *tmp_s;      /* source pointer */
      char __far *tmp_d;      /* destination pointer */
      int vplane;

      pixy = row2y(row);            /* convert to pixels */
      pixx = col2x(col);
      for(vplane=0; vplane < SCREENPLANES; ++vplane) {
            egawriteplane(vp[vplane]);
            for(i=0;i < ROWS_PER_CELL; ++i) {
                  tmp_d = screentable[i+pixy];
                  tmp_d += pixx;
            /*
             * memcpy((void *)tmp,(void *)gp->plane[vplane].image[i],
             *         BYTES_PER_CELL);
             */
                  tmp_s = gp->plane[vplane].image[i];
                  WRITE_ABSOLUTE(tmp_d, (*tmp_s));
                  ++tmp_s; ++tmp_d;
                  WRITE_ABSOLUTE(tmp_d, (*tmp_s));
            }
      }
      egawriteplane(15);
}

void
vga_DisplayCell_O(gp,col,row)
struct overview_planar_cell_struct *gp;
int col,row;
{
      int i,pixx,pixy;
      char __far *tmp_s;      /* source pointer */
      char __far *tmp_d;      /* destination pointer */
      int vplane;

      pixy = row2y(row);            /* convert to pixels */
      pixx = col;
      for(vplane=0; vplane < SCREENPLANES; ++vplane) {
            egawriteplane(vp[vplane]);
            for(i=0;i < ROWS_PER_CELL; ++i) {
                  tmp_d = screentable[i+pixy];
                  tmp_d += pixx;
            /*
             * memcpy((void *)tmp,(void *)gp->plane[vplane].image[i],
             *         BYTES_PER_CELL);
             */
                  tmp_s = gp->plane[vplane].image[i];
                  WRITE_ABSOLUTE(tmp_d, (*tmp_s));
            }
      }
      egawriteplane(15);
}

/*
 * Write the character string pointed to by 's', whose maximum length
 * is 'len' at location (x,y) using the 'colour' colour.
 *
 */
void 
vga_WriteStr(s,len,col,row,colour)
char *s;
int len,col,row,colour;
{
/*JP*/
  int i = 0;

  g_attribute = 14;

  if(s)
    while(*s && i<len){
      vga_gotoloc(col, row);
      jputchar(*s);
      ++col;
      ++s;
      ++i;
    }
/*JP*/
#if 0
      unsigned char *us;
      int i = 0;

      /* protection from callers */
      if (row > (LI-1)) return;

      i  = 0;
      us = (unsigned char *)s;
      while( (*us != 0) && (i < len) && (col < (CO - 1))) {
            vga_WriteChar(*us,col,row,colour);
            ++us;
            ++i;
            ++col;
      }
#endif
}

# endif /* OVLB */


# ifdef OVLB
/*
 * Initialize the VGA palette with the desired colours. This
 * must be a series of 48 bytes for use with a card in
 * 16 colour mode at 640 x 480.
 *
 */
void
vga_SetPalette(p)
      char *p;
{
      union REGS regs;
      int i;

      outportb(0x3c6,0xff);
      for(i=0;i < COLORDEPTH; ++i) {
            outportb(0x3c8,i);
            outportb(0x3c9,(*p++) >> 2);
            outportb(0x3c9,(*p++) >> 2);
            outportb(0x3c9,(*p++) >> 2);
      }
      regs.x.bx = 0x0000;
      for(i=0;i < COLORDEPTH; ++i) {
            regs.x.ax = 0x1000;
            (void) int86(VIDEO_BIOS,&regs,&regs);
            regs.x.bx += 0x0101;
      }
}

/*static unsigned char colorbits[]={0x01,0x02,0x04,0x08}; /* wrong */
static unsigned char colorbits[]={0x08,0x04,0x02,0x01}; 

#ifdef POSITIONBAR

#define PBAR_ROW (LI - 4)
#define PBAR_COLOR_ON     15  /* slate grey background colour of tiles */
#define PBAR_COLOR_OFF    12  /* bluish grey, used in old style only */
#define PBAR_COLOR_STAIRS  9  /* brown */
#define PBAR_COLOR_HERO   14  /* creamy white */

static unsigned char pbar[COLNO];

void 
vga_update_positionbar(posbar)
char *posbar;
{
      char *p = pbar;
      if (posbar) while (*posbar) *p++ = *posbar++;
      *p = 0;
}

STATIC_OVL void 
positionbar()
{
      char *posbar = pbar;
      int feature, ucol;
      int k, y, colour, row;
      char __far *pch;
      char bitblock;
      int startk, stopk;
      char volatile a;
      boolean nowhere = FALSE;
      int pixy = (PBAR_ROW * MAX_ROWS_PER_CELL);
      int tmp;

      if (!iflags.grmode || !iflags.tile_view) return;
      if ((clipx < 0)  || (clipxmax <= 0) || (clipx >= clipxmax)) 
            nowhere = TRUE;
      if (nowhere) {
#ifdef DEBUG
            pline("Would have put bar using %d - %d.",clipx,clipxmax);
#endif
            return;
        }
#ifdef OLD_STYLE
      outportb(0x3ce,5);
      outportb(0x3cf,2);
      for (y=pixy; y < (pixy + MAX_ROWS_PER_CELL); ++y) {
            pch = screentable[y];
            for (k=0; k < SCREENBYTES; ++k) {
                  if ((k < clipx) || (k > clipxmax)) {
                        colour = PBAR_COLOR_OFF;                  
                  } else colour = PBAR_COLOR_ON;
                  outportb(0x3ce,8);
                  outportb(0x3cf,255);
                  a = READ_ABSOLUTE(pch); /* Must read , then write */
                  WRITE_ABSOLUTE(pch, (char)colour);
                  ++pch;
            }
      }
      outportb(0x3ce,5);
      outportb(0x3cf,0);
#else
      colour = PBAR_COLOR_ON;
      outportb(0x3ce,5);
      outportb(0x3cf,2);
      for (y=pixy, row = 0; y < (pixy + MAX_ROWS_PER_CELL); ++y, ++row) {
            pch = screentable[y];
            if ((!row) || (row == (ROWS_PER_CELL-1))) {
                  startk = 0;
                  stopk  = SCREENBYTES;
            } else {
                  startk = clipx;
                  stopk  = clipxmax;
            }
            for (k=0; k < SCREENBYTES; ++k) {
                  if ((k < startk) || (k > stopk))
                        colour = BACKGROUND_VGA_COLOR;
                  else
                        colour = PBAR_COLOR_ON;
                  outportb(0x3ce,8);
                  outportb(0x3cf,255);
                  a = READ_ABSOLUTE(pch); /* Must read , then write */
                  WRITE_ABSOLUTE(pch, (char)colour);
                  ++pch;
            }
      }
      outportb(0x3ce,5);
      outportb(0x3cf,0);
#endif
      ucol = 0;
      if (posbar) {
          while (*posbar != 0) {
            feature = *posbar++;
            switch (feature) {
                case '>':
                  vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS);
                  break;
                case '<':
                  vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS);
                  break;
                case '@':
                  ucol = (int)*posbar++;
                  vga_special(feature, ucol, PBAR_COLOR_HERO);
                  break;
                default: /* unanticipated symbols */
                  vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS);
                  break;
            }
          }
      }
#  ifdef SIMULATE_CURSOR
      if (inmap) {
            tmp = curcol + 1;
            if ((tmp != ucol) && (curcol >= 0)) 
                  vga_special('_', tmp, PBAR_COLOR_HERO);
      }
#  endif
}

void
vga_special(chr,col,color)
int chr,col,color;
{
      int i,y,pixx,pixy;
      char __far *tmp_d;      /* destination pointer */
      int vplane;
      char fnt;
      char bits[SCREENPLANES][ROWS_PER_CELL];

      pixy = PBAR_ROW * MAX_ROWS_PER_CELL;
      for(vplane=0; vplane < SCREENPLANES; ++vplane) {
            egareadplane(vplane);
            y = pixy;
            for(i=0;i < ROWS_PER_CELL; ++i) {
                  tmp_d = screentable[y++] + col;
                  bits[vplane][i] = READ_ABSOLUTE(tmp_d);
                  fnt = READ_ABSOLUTE((font + ((chr<<4) + i)));
                  if (colorbits[vplane] & color)
                        bits[vplane][i] |= fnt;
                  else
                        bits[vplane][i] &= ~fnt;
            }
      }
      for(vplane=0; vplane < SCREENPLANES; ++vplane) {
            egawriteplane(vp[vplane]);
            y = pixy;
            for(i=0;i < ROWS_PER_CELL; ++i) {
                  tmp_d = screentable[y++] + col;
                  WRITE_ABSOLUTE(tmp_d, (bits[vplane][i]));
            }
      }
      egawriteplane(15);
}

#  endif POSITIONBAR

#  ifdef SIMULATE_CURSOR

static struct planar_cell_struct undercursor;
static struct planar_cell_struct cursor;

void
vga_DrawCursor()
{
      int i,pixx,pixy,x,y,p;
      char __far *tmp1;
      char __far *tmp2;
      unsigned char first,second;
/*    char on[2] =  {0xFF,0xFF}; */
/*    char off[2] = {0x00,0x00}; */
      boolean isrogue = Is_rogue_level(&u.uz);
      boolean singlebyte = (isrogue || iflags.over_view
                        || iflags.traditional_view || !inmap);
      int curtyp;

      if (!cursor_type && inmap) return;  /* CURSOR_INVIS - nothing to do */

      x = min(curcol,(CO - 1)); /* protection from callers */
      y = min(currow,(LI - 1));             /* protection from callers */
      if (!singlebyte && ((x < clipx) || (x > clipxmax))) return;
          pixy = row2y(y);            /* convert to pixels */
          if (singlebyte)
                pixx = x;
          else
                pixx = col2x((x-clipx));

          for(i=0;i < ROWS_PER_CELL; ++i) {
            tmp1 = screentable[i+pixy];
            tmp1 += pixx;
            tmp2 = tmp1 + 1;
            egareadplane(3);
            /* memcpy(undercursor.plane[3].image[i],tmp1,BYTES_PER_CELL); */
            undercursor.plane[3].image[i][0] = READ_ABSOLUTE(tmp1);
            if (!singlebyte)
                  undercursor.plane[3].image[i][1] = READ_ABSOLUTE(tmp2);

            egareadplane(2);
            /* memcpy(undercursor.plane[2].image[i],tmp1,BYTES_PER_CELL); */
            undercursor.plane[2].image[i][0] = READ_ABSOLUTE(tmp1);
            if (!singlebyte)
                  undercursor.plane[2].image[i][1] = READ_ABSOLUTE(tmp2);

            egareadplane(1);
            /* memcpy(undercursor.plane[1].image[i],tmp1,BYTES_PER_CELL); */
            undercursor.plane[1].image[i][0] = READ_ABSOLUTE(tmp1);
            if (!singlebyte)
                  undercursor.plane[1].image[i][1] = READ_ABSOLUTE(tmp2);

            egareadplane(0);
            /* memcpy(undercursor.plane[0].image[i],tmp1,BYTES_PER_CELL); */
            undercursor.plane[0].image[i][0] = READ_ABSOLUTE(tmp1);
            if (!singlebyte)
                  undercursor.plane[0].image[i][1] = READ_ABSOLUTE(tmp2);
          }

          /*
             * Now we have a snapshot of the current cell.
             * Make a copy of it, then manipulate the copy
             * to include the cursor, and place the tinkered
             * version on the display.
             */ 

          cursor = undercursor;
          if (inmap) curtyp = cursor_type;
          else curtyp = CURSOR_UNDERLINE;

          switch(curtyp) {

            case CURSOR_CORNER:
                for(i = 0; i < 2; ++i) {
                  if (!i) {
                        if (singlebyte) first = 0xC3;
                        else first  = 0xC0;
                        second = 0x03;
                  } else {
                        if (singlebyte) first = 0x81;
                        else first  = 0x80;
                        second = 0x01;
                  }
                  for (p=0; p < 4; ++p) {
                        if (cursor_color & colorbits[p]) {
                              cursor.plane[p].image[i][0] |= first;
                              if (!singlebyte)
                              cursor.plane[p].image[i][1] |= second;
                        } else {
                              cursor.plane[p].image[i][0] &= ~first;
                              if (!singlebyte)
                              cursor.plane[p].image[i][1] &= ~second;
                        }
                  }
                }

                for(i = ROWS_PER_CELL - 2; i < ROWS_PER_CELL; ++i) {
                  if (i != (ROWS_PER_CELL-1)) {
                        if (singlebyte) first = 0x81;
                        else first  = 0x80;
                        second = 0x01;
                  } else {
                        if (singlebyte) first = 0xC3;
                        else first  = 0xC0;
                        second = 0x03;
                  }
                  for (p=0; p < SCREENPLANES; ++p) {
                        if (cursor_color & colorbits[p]) {
                              cursor.plane[p].image[i][0] |= first;
                              if (!singlebyte)
                              cursor.plane[p].image[i][1] |= second;
                        } else {
                              cursor.plane[p].image[i][0] &= ~first;
                              if (!singlebyte)
                              cursor.plane[p].image[i][1] &= ~second;
                        }
                  }
                }
                break;

            case CURSOR_UNDERLINE:

                i = ROWS_PER_CELL - 1;
                first  = 0xFF;
                second = 0xFF;
                for (p=0; p < SCREENPLANES; ++p) {
                  if (cursor_color & colorbits[p]) {
                        cursor.plane[p].image[i][0] |= first;
                        if (!singlebyte)
                        cursor.plane[p].image[i][1] |= second;
                  } else {
                        cursor.plane[p].image[i][0] &= ~first;
                        if (!singlebyte)
                        cursor.plane[p].image[i][1] &= ~second;
                  }
                }
                break;

            case CURSOR_FRAME:

                /* fall through */

            default:                
                for(i = 0; i < ROWS_PER_CELL; ++i) {

                  if ((i == 0) || (i == (ROWS_PER_CELL-1))) {
                        first  = 0xFF;
                        second = 0xFF;
                  } else {
                        if (singlebyte) first = 0x81;
                        else first  = 0x80;
                        second = 0x01;
                  }
                  for (p=0; p < SCREENPLANES; ++p) {
                        if (cursor_color & colorbits[p]) {
                              cursor.plane[p].image[i][0] |= first;
                              if (!singlebyte)
                              cursor.plane[p].image[i][1] |= second;
                        } else {
                              cursor.plane[p].image[i][0] &= ~first;
                              if (!singlebyte)
                              cursor.plane[p].image[i][1] &= ~second;
                        }
                  }
                }
                break;
          }

         /*
            * Place the new cell onto the display.
            *
            */
          
          for(i=0;i < ROWS_PER_CELL; ++i) {
            tmp1 = screentable[i+pixy];
            tmp1 += pixx;
            tmp2 = tmp1 + 1;
            egawriteplane(8);
            /* memcpy(tmp1,cursor.plane[3].image[i],BYTES_PER_CELL); */
            WRITE_ABSOLUTE(tmp1,cursor.plane[3].image[i][0]);
            if (!singlebyte)
            WRITE_ABSOLUTE(tmp2,cursor.plane[3].image[i][1]);

            egawriteplane(4);
            /* memcpy(tmp1,cursor.plane[2].image[i],BYTES_PER_CELL); */
            WRITE_ABSOLUTE(tmp1,cursor.plane[2].image[i][0]);
            if (!singlebyte)
            WRITE_ABSOLUTE(tmp2,cursor.plane[2].image[i][1]);

            egawriteplane(2);
            /* memcpy(tmp1,cursor.plane[1].image[i],BYTES_PER_CELL); */
            WRITE_ABSOLUTE(tmp1,cursor.plane[1].image[i][0]);
            if (!singlebyte)
            WRITE_ABSOLUTE(tmp2,cursor.plane[1].image[i][1]);

            egawriteplane(1);
            /* memcpy(tmp1,cursor.plane[0].image[i],BYTES_PER_CELL); */
            WRITE_ABSOLUTE(tmp1,cursor.plane[0].image[i][0]);
            if (!singlebyte)
            WRITE_ABSOLUTE(tmp2,cursor.plane[0].image[i][1]);
          }
          egawriteplane(15);
#ifdef POSITIONBAR
          if (inmap) positionbar();
#endif
}

void
vga_HideCursor()
{

      int i,pixx,pixy,x,y;
      char __far *tmp1;
      char __far *tmp2;
      boolean isrogue = Is_rogue_level(&u.uz);
      boolean singlebyte = (isrogue || iflags.over_view
                        || iflags.traditional_view || !inmap);
      int curtyp;
      
      if (inmap && !cursor_type) return;  /* CURSOR_INVIS - nothing to do */
      /* protection from callers */
      x = min(curcol,(CO - 1)); 
      y = min(currow,(LI-1));
      if (!singlebyte && ((x < clipx) || (x > clipxmax))) return;

          pixy = row2y(y);          /* convert to pixels */
          if (singlebyte)
                pixx = x;
          else
                pixx = col2x((x-clipx));

          if (inmap) curtyp = cursor_type;
          else curtyp = CURSOR_UNDERLINE;

          if (curtyp == CURSOR_UNDERLINE)  /* optimization for uline */
            i = ROWS_PER_CELL - 1;
          else
            i = 0;

          for(;i < ROWS_PER_CELL; ++i) {
            tmp1 = screentable[i+pixy];
            tmp1 += pixx;
            tmp2 = tmp1 + 1;
            egawriteplane(8);
            /* memcpy(tmp,undercursor.plane[3].image[i],BYTES_PER_CELL); */
            WRITE_ABSOLUTE(tmp1,undercursor.plane[3].image[i][0]);
            if (!singlebyte)
            WRITE_ABSOLUTE(tmp2,undercursor.plane[3].image[i][1]);

            egawriteplane(4);
            /* memcpy(tmp,undercursor.plane[2].image[i],BYTES_PER_CELL); */
            WRITE_ABSOLUTE(tmp1,undercursor.plane[2].image[i][0]);
            if (!singlebyte)
            WRITE_ABSOLUTE(tmp2,undercursor.plane[2].image[i][1]);

            egawriteplane(2);
            /* memcpy(tmp,undercursor.plane[1].image[i],BYTES_PER_CELL); */
            WRITE_ABSOLUTE(tmp1,undercursor.plane[1].image[i][0]);
            if (!singlebyte)
            WRITE_ABSOLUTE(tmp2,undercursor.plane[1].image[i][1]);

            egawriteplane(1);
            /* memcpy(tmp,undercursor.plane[0].image[i],BYTES_PER_CELL); */
            WRITE_ABSOLUTE(tmp1,undercursor.plane[0].image[i][0]);
            if (!singlebyte)
            WRITE_ABSOLUTE(tmp2,undercursor.plane[0].image[i][1]);
          }
          egawriteplane(15);
}
#  endif /* SIMULATE_CURSOR */
# endif /* OVLB */
#endif /* SCREEN_VGA  */

/* vidvga.c */

Generated by  Doxygen 1.6.0   Back to index