1 /* SCCS Id: @(#)vidvga.c 3.4 1996/02/16 */
2 /* Copyright (c) NetHack PC Development Team 1995 */
3 /* NetHack may be freely redistributed. See license for details. */
5 * vidvga.c - VGA Hardware video support
10 #ifdef SCREEN_VGA /* this file is for SCREEN_VGA only */
24 /*=========================================================================
25 * VGA Video supporting routines (for tiles).
27 * The following routines carry out the lower level video functions required
28 * to make PC NetHack work with VGA graphics.
30 * - The binary files NetHack1.tib and NetHacko.tib must be in your
31 * game directory. Currently, unpredictable results may occur if they
32 * aren't since the code hasn't been tested with it missing (yet).
36 * - Cursor emulation on the map is now implemented. The input routine
37 * in msdos.c calls the routine to display the cursor just before
38 * waiting for input, and hides the cursor immediately after satisfying
41 * - A check for a VGA adapter is implemented.
43 * - With 640 x 480 resolution, the use of 16 x 16 icons allows only 40
44 * columns for the map display. This makes it necessary to support the
45 * TTY CLIPPING code. The right/left scrolling with this can be
46 * a little annoying. Feel free to rework the routines.
48 * - NetHack1.tib is built from text files derived from bitmap files
49 * provided by Warwick Allison, using routines developed and supplied
50 * by Janet Walz. The icons are very well done and thanks to
51 * Warwick Allison for an excellent effort!
53 * - The text fonts that this is using while in graphics mode come from
54 * the Video BIOS ROM on board the VGA adapter. Code in vga_WriteChar
55 * copies the appropriate pixels from the video ROM to the Video buffer.
57 * - Currently, most of the routines are in an ifdef OVLB.
58 * If you change that, you may have to muck with some of the
59 * variable declarations which now assume this. This is not a
60 * problem in a non-overlaid environment (djgpp for example).
62 * - VGA 640 by 480, 16 colour mode (0x12) uses an odd method to
63 * represent a colour value from the palette. There are four
64 * planes of video memory, all overlaid at the same memory location.
65 * For example, if a pixel has the colour value 7:
74 * - VGA write mode 2 requires that a read be done before a write to
75 * set some latches on the card. The value read had to be placed
76 * into a variable declared 'volatile' to prevent djgpp from
77 * optimizing away the entire instruction (the value was assigned
78 * to a variable which was never used). This corrects the striping
79 * problem that was apparent with djgpp.
81 * - A check for valid mode switches has been added.
83 * - No tiles are displayed on the Rogue Level in keeping with the
84 * original Rogue. The display adapter remains in graphics mode
87 * - Added handling for missing NetHackX.tib files, and resort to using
88 * video:default and tty if one of them can't be located.
92 * - Nothing prior to release.
93 *=========================================================================
97 # if defined(_MSC_VER)
99 #pragma warning(disable:4018) /* signed/unsigned mismatch */
100 #pragma warning(disable:4127) /* conditional expression is constant */
101 #pragma warning(disable:4131) /* old style declarator */
102 #pragma warning(disable:4305) /* prevents complaints with MK_FP */
103 #pragma warning(disable:4309) /* initializing */
105 #pragma warning(disable:4759) /* prevents complaints with MK_FP */
111 /* STATIC_DCL void FDECL(vga_NoBorder, (int)); */
112 void FDECL(vga_gotoloc, (int,int)); /* This should be made a macro */
113 void NDECL(vga_backsp);
115 STATIC_DCL void FDECL(vga_scrollmap,(BOOLEAN_P));
117 STATIC_DCL void FDECL(vga_redrawmap,(BOOLEAN_P));
118 void FDECL(vga_cliparound,(int, int));
119 STATIC_OVL void FDECL(decal_planar,(struct planar_cell_struct *, unsigned));
122 STATIC_DCL void NDECL(positionbar);
123 static void FDECL(vga_special,(int, int, int));
126 extern int clipx, clipxmax; /* current clipping column from wintty.c */
127 extern boolean clipping; /* clipping on? from wintty.c */
128 extern int savevmode; /* store the original video mode */
129 extern int curcol,currow; /* current column and row */
130 extern int g_attribute;
131 extern int attrib_text_normal; /* text mode normal attribute */
132 extern int attrib_gr_normal; /* graphics mode normal attribute */
133 extern int attrib_text_intense; /* text mode intense attribute */
134 extern int attrib_gr_intense; /* graphics mode intense attribute */
135 extern boolean inmap; /* in the map window */
141 STATIC_VAR unsigned char __far *font;
142 STATIC_VAR char *screentable[SCREENHEIGHT];
144 STATIC_VAR char *paletteptr;
145 STATIC_VAR struct map_struct {
150 } map[ROWNO][COLNO]; /* track the glyphs */
152 # define vga_clearmap() { int x,y; for (y=0; y < ROWNO; ++y) \
153 for (x=0; x < COLNO; ++x) { map[y][x].glyph = cmap_to_glyph(S_stone); \
154 map[y][x].ch = S_stone; map[y][x].attr = 0; map[y][x].special = 0;} }
155 # define TOP_MAP_ROW 1
157 STATIC_VAR int vgacmap[CLR_MAX] = {0,3,5,9,4,8,12,14,11,2,6,7,1,8,12,13};
158 STATIC_VAR int viewport_size = 40;
159 /* STATIC_VAR char masktable[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; */
160 /* STATIC_VAR char bittable[8]= {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; */
162 STATIC_VAR char defpalette[] = { /* Default VGA palette */
182 # ifndef ALTERNATE_VIDEO_METHOD
183 int vp[SCREENPLANES] = {8,4,2,1};
185 int vp2[SCREENPLANES] = {1,2,4,8};
187 extern int vgacmap[CLR_MAX];
188 extern int viewport_size;
189 extern char masktable[8];
190 extern char bittable[8];
191 extern char defpalette[];
192 # ifndef ALTERNATE_VIDEO_METHOD
193 extern int vp[SCREENPLANES];
195 extern int vp2[SCREENPLANES];
198 STATIC_VAR struct planar_cell_struct *planecell;
199 STATIC_VAR struct overview_planar_cell_struct *planecell_O;
201 # if defined(USE_TILES)
202 STATIC_VAR struct tibhdr_struct tibheader;
203 /* extern FILE *tilefile; */ /* Not needed in here most likely */
206 /* STATIC_VAR int g_attribute; */ /* Current attribute to use */
226 col = curcol; /* Character cell row and column */
229 if (col > 0) col = col-1;
230 vga_gotoloc(col,row);
237 vga_clear_screen(colour)
247 for (y=0; y < SCREENHEIGHT; ++y) {
248 pch = screentable[y];
249 for (j=0; j < SCREENBYTES; ++j) {
252 a = READ_ABSOLUTE(pch); /* Must read , then write */
253 WRITE_ABSOLUTE(pch, (char)colour);
259 if (iflags.tile_view) vga_clearmap();
260 vga_gotoloc(0,0); /* is this needed? */
264 vga_cl_end(col,row) /* clear to end of line */
270 * This is being done via character writes.
271 * This should perhaps be optimized for speed by using VGA write
272 * mode 2 methods as did clear_screen()
274 for (count = col; count < (CO-1); ++count) {
275 vga_WriteChar(' ',count,row,BACKGROUND_VGA_COLOR);
280 vga_cl_eos(cy) /* clear to end of screen */
287 for (count = 0; count < (CO-1); ++count) {
288 vga_WriteChar(' ',count,cy,
289 BACKGROUND_VGA_COLOR);
302 vga_clear_screen(BACKGROUND_VGA_COLOR);
303 vga_SwitchMode(MODETEXT);
308 vga_tty_startup(wid, hgt)
312 /* code to sense display adapter is required here - MJA */
320 attrib_gr_normal = ATTRIB_VGA_NORMAL;
321 attrib_gr_intense = ATTRIB_VGA_INTENSE;
322 g_attribute = attrib_gr_normal; /* Give it a starting value */
327 * Screen output routines (these are heavily used).
329 * These are the 3 routines used to place information on the screen
330 * in the VGA PC tty port of NetHack. These are the routines
331 * that get called by the general interface routines in video.c.
333 * vga_xputs -Writes a c null terminated string at the current location.
335 * vga_xputc -Writes a single character at the current location. Since
336 * various places in the code assume that control characters
337 * can be used to control, we are forced to interpret some of
338 * the more common ones, in order to keep things looking correct.
340 * vga_xputg -This routine is used to display a graphical representation of a
341 * NetHack glyph (a tile) at the current location. For more
342 * information on NetHack glyphs refer to the comments in
354 if (s != (char *)0) {
355 vga_WriteStr((char *)s,strlen(s),col,row,g_attribute);
360 vga_xputc(ch,attr) /* write out character (and attribute) */
375 vga_WriteChar((unsigned char)ch,col,row,attr);
376 if (col < (CO -1 )) ++col;
379 vga_gotoloc(col,row);
382 # if defined(USE_TILES)
384 vga_xputg(glyphnum,ch, special) /* Place tile represent. a glyph at current location */
387 unsigned special; /* special feature: corpse, invis, detected, pet, ridden - hack.h */
395 if ((col < 0 || col >= COLNO) ||
396 (row < TOP_MAP_ROW || row >= (ROWNO + TOP_MAP_ROW))) return;
397 ry = row - TOP_MAP_ROW;
398 map[ry][col].glyph = glyphnum;
399 map[ry][col].ch = ch;
400 map[ry][col].special = special;
401 attr = (g_attribute == 0) ? attrib_gr_normal : g_attribute;
402 map[ry][col].attr = attr;
403 if (iflags.traditional_view) {
404 vga_WriteChar((unsigned char)ch,col,row,attr);
405 } else if (!iflags.over_view) {
406 if ((col >= clipx) && (col <= clipxmax)) {
407 if (!ReadPlanarTileFile(glyph2tile[glyphnum], &planecell)) {
408 if (map[ry][col].special) decal_planar(planecell, special);
409 vga_DisplayCell(planecell,
412 pline("vga_xputg: Error reading tile (%d,%d) from file",
413 glyphnum,glyph2tile[glyphnum]);
416 if (!ReadPlanarTileFile_O(glyph2tile[glyphnum], &planecell_O))
417 vga_DisplayCell_O(planecell_O, col, row);
419 pline("vga_xputg: Error reading tile (%d,%d) from file",
420 glyphnum,glyph2tile[glyphnum]);
422 if (col < (CO - 1 )) ++col;
423 vga_gotoloc(col,row);
425 # endif /* USE_TILES */
428 * Cursor location manipulation, and location information fetching
432 * vga_gotoloc(x,y) - Moves the "cursor" on screen to the specified x
433 * and y character cell location. This routine
434 * determines the location where screen writes
435 * will occur next, it does not change the location
436 * of the player on the NetHack level.
443 curcol = min(col,CO - 1); /* protection from callers */
444 currow = min(row,LI - 1);
447 # if defined(USE_TILES) && defined(CLIPPING)
452 extern boolean restoring;
455 if (!iflags.tile_view || iflags.over_view || iflags.traditional_view)
459 clipx = max(0, x - (viewport_size / 2));
460 clipxmax = clipx + (viewport_size - 1);
462 else if (x > clipxmax - 5) {
463 clipxmax = min(COLNO - 1, x + (viewport_size / 2));
464 clipx = clipxmax - (viewport_size - 1);
467 if (on_level(&u.uz0, &u.uz) && !restoring)
468 /* (void) doredraw(); */
474 vga_redrawmap(clearfirst)
482 /* y here is in pixel rows */
485 t = TOP_MAP_ROW * ROWS_PER_CELL;
486 for (y = t; y < (ROWNO * ROWS_PER_CELL) + t; ++y) {
487 pch = screentable[y];
488 for (j=0; j < SCREENBYTES; ++j) {
491 /* On VGA mode2, must read first, then write */
492 a = READ_ABSOLUTE(pch);
493 WRITE_ABSOLUTE(pch, (char)BACKGROUND_VGA_COLOR);
500 /* y here is in screen rows*/
502 for (y = 0; y < ROWNO; ++y)
503 for (x = clipx; x <= clipxmax; ++x) {
505 for (x = clipx; x <= clipxmax; ++x)
506 for (y = 0; y < ROWNO; ++y) {
508 if (iflags.traditional_view) {
509 if (!(clearfirst && map[y][x].ch == S_stone))
511 (unsigned char)map[y][x].ch,
512 x,y + TOP_MAP_ROW,map[y][x].attr);
515 if (!(clearfirst && t == cmap_to_glyph(S_stone))) {
516 if (!iflags.over_view) {
517 if (!ReadPlanarTileFile(glyph2tile[t],
519 if (map[y][x].special)
520 decal_planar(planecell, map[y][x].special);
521 vga_DisplayCell(planecell,
522 x - clipx, y + TOP_MAP_ROW);
524 pline("vga_redrawmap: Error reading tile (%d,%d)",
527 if (!ReadPlanarTileFile_O(glyph2tile[t],
529 vga_DisplayCell_O(planecell_O,
532 pline("vga_redrawmap: Error reading tile (%d,%d)",
539 # endif /* USE_TILES && CLIPPING */
549 /* pline("Into userpan"); */
550 if (iflags.over_view || iflags.traditional_view) return;
552 x = min(COLNO - 1, clipxmax + 10);
554 x = max(0, clipx - 10);
555 vga_cliparound(x, 10); /* y value is irrelevant on VGA clipping */
561 void vga_overview(on)
564 /* vga_HideCursor(); */
566 iflags.over_view = TRUE;
570 iflags.over_view = FALSE;
571 clipx = max(0, (curcol - viewport_size / 2));
572 if (clipx > ((CO - 1) - viewport_size))
573 clipx = (CO - 1) - viewport_size;
574 clipxmax = clipx + (viewport_size - 1);
578 void vga_traditional(on)
581 /* vga_HideCursor(); */
583 /* switch_graphics(ASCII_GRAPHICS); */
584 iflags.traditional_view = TRUE;
588 iflags.traditional_view = FALSE;
589 if (!iflags.over_view) {
590 clipx = max(0, (curcol - viewport_size / 2));
591 if (clipx > ((CO - 1) - viewport_size))
592 clipx = (CO - 1) - viewport_size;
593 clipxmax = clipx + (viewport_size - 1);
611 int i,pixx,pixy,x1,y1,x2,y2;
612 int byteoffset, vplane;
615 unsigned char source[SCREENPLANES][80];
616 unsigned char first,second;
619 pixy = row2y(TOP_MAP_ROW); /* convert to pixels */
628 /* read each row, all columns but the one to be replaced */
629 for(i = 0;i < (ROWNO-1) * ROWS_PER_CELL; ++i) {
630 tmp1 = screentable[i + pixy];
632 for(vplane=0; vplane < SCREENPLANES; ++vplane) {
633 egareadplane(vplane);
634 for (byteoffset = 0; byteoffset < 20; ++byteoffset) {
635 tmp2 = tmp1 + byteoffset;
636 source[vplane][byteoffset] = READ_ABSOLUTE(tmp2);
639 tmp1 = screentable[i + pixy];
641 for(vplane=0; vplane < SCREENPLANES; ++vplane) {
642 egawriteplane(vp2[vplane]);
643 for (byteoffset = 0; byteoffset < 20; ++byteoffset) {
644 tmp2 = tmp1 + byteoffset;
645 WRITE_ABSOLUTE(tmp2,source[vplane][byteoffset]);
658 for (y = 0; y < ROWNO; ++y) {
659 for (x = i; x < j; x += 2) {
661 if (!ReadPlanarTileFile(glyph2tile[t], &planecell))
662 if (map[y][x].special) decal_planar(planecell, map[y][x].special);
663 vga_DisplayCell(planecell, x - clipx, y + TOP_MAP_ROW);
665 pline("vga_shiftmap: Error reading tile (%d,%d)",
670 # endif /* SCROLLMAP */
675 decal_planar(gp, special)
676 struct planar_cell_struct *gp;
679 if (special & MG_CORPSE) {
680 } else if (special & MG_INVIS) {
681 } else if (special & MG_DETECT) {
682 } else if (special & MG_PET) {
683 } else if (special & MG_RIDDEN) {
689 * initialize the SCREEN, switch it to graphics mode,
690 * initialize the pointers to the fonts, clear
701 * Attempt to open the required tile files. If we can't
702 * don't perform the video mode switch, use TTY code instead.
705 if (OpenTileFile(NETHACK_PLANAR_TILEFILE, FALSE)) tilefailure |= 1;
706 if (OpenTileFile(NETHACK_OVERVIEW_TILEFILE, TRUE)) tilefailure |= 2;
707 if (ReadTileFileHeader(&tibheader, FALSE)) tilefailure |= 4;
710 raw_printf("Reverting to TTY mode, tile initialization failure (%d).",
714 iflags.tile_view = FALSE;
715 iflags.over_view = FALSE;
718 /* clear_screen() */ /* not vga_clear_screen() */
724 for (i=0; i < SCREENHEIGHT; ++i) {
725 screentable[i]=MK_PTR(VIDEOSEG, (i * SCREENBYTES));
728 vga_SwitchMode(MODE640x480);
729 windowprocs.win_cliparound = vga_cliparound;
730 /* vga_NoBorder(BACKGROUND_VGA_COLOR); */ /* Not needed after palette mod */
732 paletteptr = tibheader.palette;
733 iflags.tile_view = TRUE;
734 iflags.over_view = FALSE;
736 paletteptr = defpalette;
738 vga_SetPalette(paletteptr);
739 g_attribute = attrib_gr_normal;
740 font = vga_FontPtrs();
743 clipxmax = clipx + (viewport_size - 1);
747 * Switches modes of the video card.
749 * If mode == MODETEXT (0x03), then the card is placed into text
750 * mode. If mode == 640x480, then the card is placed into vga
751 * mode (video mode 0x12). No other modes are currently supported.
754 void vga_SwitchMode(unsigned int mode)
758 if ((mode == MODE640x480) || (mode == MODETEXT)) {
759 if (iflags.usevga && (mode == MODE640x480)) {
765 (void) int86(VIDEO_BIOS, ®s, ®s);
767 iflags.grmode = 0; /* force text mode for error msg */
768 regs.x.ax = MODETEXT;
769 (void) int86(VIDEO_BIOS, ®s, ®s);
770 g_attribute = attrib_text_normal;
771 impossible("vga_SwitchMode: Bad video mode requested 0x%X",
777 * This allows grouping of several tasks to be done when
778 * switching back to text mode. This is a public (extern) function.
781 void vga_Finish(void)
785 vga_SwitchMode(MODETEXT);
786 windowprocs.win_cliparound = tty_cliparound;
787 g_attribute = attrib_text_normal;
788 iflags.tile_view = FALSE;
793 * Turn off any border colour that might be enabled in the VGA card
796 * I disabled this after modifying tile2bin.c to remap black & white
797 * to a more standard values - MJA 94/04/23.
805 regs.h.ah = (char)0x10;
806 regs.h.al = (char)0x01;
807 regs.h.bh = (char)bc;
809 (void) int86(VIDEO_BIOS, ®s, ®s);
815 * Returns a far pointer (or flat 32 bit pointer under djgpp) to the
816 * location of the appropriate ROM font for the _current_ video mode
817 * (so you must place the card into the desired video mode before
818 * calling this function).
820 * This function takes advantage of the video BIOS loading the
821 * address of the appropriate character definition table for
822 * the current graphics mode into interrupt vector 0x43 (0000:010C).
824 char __far *vga_FontPtrs(void)
829 tmp = (USHORT __far *)MK_PTR(((USHORT)FONT_PTR_SEGMENT),
830 ((USHORT)FONT_PTR_OFFSET));
831 foff = READ_ABSOLUTE_WORD(tmp);
833 fseg = READ_ABSOLUTE_WORD(tmp);
834 retval = (char __far *)MK_PTR(fseg,foff);
839 * This will verify the existance of a VGA adapter on the machine.
840 * Video function call 0x1a returns 0x1a in AL if successful, and
841 * returns the following values in BL for the active display:
843 * 0=no display, 1=MDA, 2=CGA, 4=EGA(color-monitor),
844 * 5=EGA(mono-monitor), 6=PGA, 7=VGA(mono-monitor), 8=VGA(color-monitor),
845 * 0xB=MCGA(mono-monitor), 0xC=MCGA(color-monitor), 0xFF=unknown)
853 (void) int86(VIDEO_BIOS, ®s, ®s);
857 * printf("vga_detect returned al=%02x, bh=%02x, bl=%02x\n",
858 * (int)regs.h.al, (int)regs.h.bh, (int)regs.h.bl);
861 if ((int)regs.h.al == 0x1a) {
862 if (((int)regs.h.bl == 8) || ((int)regs.h.bl == 7)) {
870 * Write character 'ch', at (x,y) and
871 * do it using the colour 'colour'.
875 vga_WriteChar(chr,col,row,colour)
876 int chr,col,row,colour;
883 unsigned char __far *fp = font;
885 int actual_colour = vgacmap[colour];
888 x = min(col,(CO-1)); /* min() used protection from callers */
889 pixy = min(row,(LI-1)) * 16; /* assumes 8 x 16 char set */
890 /* if (chr < ' ') chr = ' '; */ /* assumes ASCII set */
896 for (i=0; i < MAX_ROWS_PER_CELL; ++i) {
897 cp = screentable[pixy+i] + x;
898 fnt = READ_ABSOLUTE((fp + chr + i));
901 tc = READ_ABSOLUTE(cp); /* wrt mode 2, must read, then write */
902 WRITE_ABSOLUTE(cp, (char)actual_colour);
904 outportb(0x3cf,~fnt);
905 tc = READ_ABSOLUTE(cp); /* wrt mode 2, must read, then write */
906 WRITE_ABSOLUTE(cp, (char)BACKGROUND_VGA_COLOR);
915 * This is the routine that displays a high-res "cell" pointed to by 'gp'
916 * at the desired location (col,row).
918 * Note: (col,row) in this case refer to the coordinate location in
919 * NetHack character grid terms, (ie. the 40 x 25 character grid),
920 * not the x,y pixel location.
924 vga_DisplayCell(gp,col,row)
925 struct planar_cell_struct *gp;
929 char __far *tmp_s; /* source pointer */
930 char __far *tmp_d; /* destination pointer */
933 pixy = row2y(row); /* convert to pixels */
935 for(vplane=0; vplane < SCREENPLANES; ++vplane) {
936 egawriteplane(vp[vplane]);
937 for(i=0;i < ROWS_PER_CELL; ++i) {
938 tmp_d = screentable[i+pixy];
941 * memcpy((void *)tmp,(void *)gp->plane[vplane].image[i],
944 tmp_s = gp->plane[vplane].image[i];
945 WRITE_ABSOLUTE(tmp_d, (*tmp_s));
947 WRITE_ABSOLUTE(tmp_d, (*tmp_s));
954 vga_DisplayCell_O(gp,col,row)
955 struct overview_planar_cell_struct *gp;
959 char __far *tmp_s; /* source pointer */
960 char __far *tmp_d; /* destination pointer */
963 pixy = row2y(row); /* convert to pixels */
965 for(vplane=0; vplane < SCREENPLANES; ++vplane) {
966 egawriteplane(vp[vplane]);
967 for(i=0;i < ROWS_PER_CELL; ++i) {
968 tmp_d = screentable[i+pixy];
971 * memcpy((void *)tmp,(void *)gp->plane[vplane].image[i],
974 tmp_s = gp->plane[vplane].image[i];
975 WRITE_ABSOLUTE(tmp_d, (*tmp_s));
982 * Write the character string pointed to by 's', whose maximum length
983 * is 'len' at location (x,y) using the 'colour' colour.
987 vga_WriteStr(s,len,col,row,colour)
989 int len,col,row,colour;
994 /* protection from callers */
995 if (row > (LI-1)) return;
998 us = (unsigned char *)s;
999 while( (*us != 0) && (i < len) && (col < (CO - 1))) {
1000 vga_WriteChar(*us,col,row,colour);
1012 * Initialize the VGA palette with the desired colours. This
1013 * must be a series of 48 bytes for use with a card in
1014 * 16 colour mode at 640 x 480.
1024 outportb(0x3c6,0xff);
1025 for(i=0;i < COLORDEPTH; ++i) {
1027 outportb(0x3c9,(*p++) >> 2);
1028 outportb(0x3c9,(*p++) >> 2);
1029 outportb(0x3c9,(*p++) >> 2);
1032 for(i=0;i < COLORDEPTH; ++i) {
1034 (void) int86(VIDEO_BIOS,®s,®s);
1035 regs.x.bx += 0x0101;
1039 /*static unsigned char colorbits[]={0x01,0x02,0x04,0x08}; */ /* wrong */
1040 static unsigned char colorbits[]={0x08,0x04,0x02,0x01};
1044 #define PBAR_ROW (LI - 4)
1045 #define PBAR_COLOR_ON 15 /* slate grey background colour of tiles */
1046 #define PBAR_COLOR_OFF 12 /* bluish grey, used in old style only */
1047 #define PBAR_COLOR_STAIRS 9 /* brown */
1048 #define PBAR_COLOR_HERO 14 /* creamy white */
1050 static unsigned char pbar[COLNO];
1053 vga_update_positionbar(posbar)
1057 if (posbar) while (*posbar) *p++ = *posbar++;
1064 char *posbar = pbar;
1066 int k, y, colour, row;
1071 boolean nowhere = FALSE;
1072 int pixy = (PBAR_ROW * MAX_ROWS_PER_CELL);
1075 if (!iflags.grmode || !iflags.tile_view) return;
1076 if ((clipx < 0) || (clipxmax <= 0) || (clipx >= clipxmax))
1080 pline("Would have put bar using %d - %d.",clipx,clipxmax);
1087 for (y=pixy; y < (pixy + MAX_ROWS_PER_CELL); ++y) {
1088 pch = screentable[y];
1089 for (k=0; k < SCREENBYTES; ++k) {
1090 if ((k < clipx) || (k > clipxmax)) {
1091 colour = PBAR_COLOR_OFF;
1092 } else colour = PBAR_COLOR_ON;
1094 outportb(0x3cf,255);
1095 a = READ_ABSOLUTE(pch); /* Must read , then write */
1096 WRITE_ABSOLUTE(pch, (char)colour);
1103 colour = PBAR_COLOR_ON;
1106 for (y=pixy, row = 0; y < (pixy + MAX_ROWS_PER_CELL); ++y, ++row) {
1107 pch = screentable[y];
1108 if ((!row) || (row == (ROWS_PER_CELL-1))) {
1110 stopk = SCREENBYTES;
1115 for (k=0; k < SCREENBYTES; ++k) {
1116 if ((k < startk) || (k > stopk))
1117 colour = BACKGROUND_VGA_COLOR;
1119 colour = PBAR_COLOR_ON;
1121 outportb(0x3cf,255);
1122 a = READ_ABSOLUTE(pch); /* Must read , then write */
1123 WRITE_ABSOLUTE(pch, (char)colour);
1132 while (*posbar != 0) {
1133 feature = *posbar++;
1136 vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS);
1139 vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS);
1142 ucol = (int)*posbar++;
1143 vga_special(feature, ucol, PBAR_COLOR_HERO);
1145 default: /* unanticipated symbols */
1146 vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS);
1151 # ifdef SIMULATE_CURSOR
1154 if ((tmp != ucol) && (curcol >= 0))
1155 vga_special('_', tmp, PBAR_COLOR_HERO);
1161 vga_special(chr,col,color)
1165 char __far *tmp_d; /* destination pointer */
1168 char bits[SCREENPLANES][ROWS_PER_CELL];
1170 pixy = PBAR_ROW * MAX_ROWS_PER_CELL;
1171 for(vplane=0; vplane < SCREENPLANES; ++vplane) {
1172 egareadplane(vplane);
1174 for(i=0;i < ROWS_PER_CELL; ++i) {
1175 tmp_d = screentable[y++] + col;
1176 bits[vplane][i] = READ_ABSOLUTE(tmp_d);
1177 fnt = READ_ABSOLUTE((font + ((chr<<4) + i)));
1178 if (colorbits[vplane] & color)
1179 bits[vplane][i] |= fnt;
1181 bits[vplane][i] &= ~fnt;
1184 for(vplane=0; vplane < SCREENPLANES; ++vplane) {
1185 egawriteplane(vp[vplane]);
1187 for(i=0;i < ROWS_PER_CELL; ++i) {
1188 tmp_d = screentable[y++] + col;
1189 WRITE_ABSOLUTE(tmp_d, (bits[vplane][i]));
1197 # ifdef SIMULATE_CURSOR
1199 static struct planar_cell_struct undercursor;
1200 static struct planar_cell_struct cursor;
1205 int i,pixx,pixy,x,y,p;
1208 unsigned char first,second;
1209 /* char on[2] = {0xFF,0xFF}; */
1210 /* char off[2] = {0x00,0x00}; */
1211 #ifdef REINCARNATION
1212 boolean isrogue = Is_rogue_level(&u.uz);
1213 boolean singlebyte = (isrogue || iflags.over_view
1214 || iflags.traditional_view || !inmap);
1216 boolean singlebyte = (iflags.over_view
1217 || iflags.traditional_view || !inmap);
1221 if (!cursor_type && inmap) return; /* CURSOR_INVIS - nothing to do */
1223 x = min(curcol,(CO - 1)); /* protection from callers */
1224 y = min(currow,(LI - 1)); /* protection from callers */
1225 if (!singlebyte && ((x < clipx) || (x > clipxmax))) return;
1226 pixy = row2y(y); /* convert to pixels */
1230 pixx = col2x((x-clipx));
1232 for(i=0;i < ROWS_PER_CELL; ++i) {
1233 tmp1 = screentable[i+pixy];
1237 /* memcpy(undercursor.plane[3].image[i],tmp1,BYTES_PER_CELL); */
1238 undercursor.plane[3].image[i][0] = READ_ABSOLUTE(tmp1);
1240 undercursor.plane[3].image[i][1] = READ_ABSOLUTE(tmp2);
1243 /* memcpy(undercursor.plane[2].image[i],tmp1,BYTES_PER_CELL); */
1244 undercursor.plane[2].image[i][0] = READ_ABSOLUTE(tmp1);
1246 undercursor.plane[2].image[i][1] = READ_ABSOLUTE(tmp2);
1249 /* memcpy(undercursor.plane[1].image[i],tmp1,BYTES_PER_CELL); */
1250 undercursor.plane[1].image[i][0] = READ_ABSOLUTE(tmp1);
1252 undercursor.plane[1].image[i][1] = READ_ABSOLUTE(tmp2);
1255 /* memcpy(undercursor.plane[0].image[i],tmp1,BYTES_PER_CELL); */
1256 undercursor.plane[0].image[i][0] = READ_ABSOLUTE(tmp1);
1258 undercursor.plane[0].image[i][1] = READ_ABSOLUTE(tmp2);
1262 * Now we have a snapshot of the current cell.
1263 * Make a copy of it, then manipulate the copy
1264 * to include the cursor, and place the tinkered
1265 * version on the display.
1268 cursor = undercursor;
1269 if (inmap) curtyp = cursor_type;
1270 else curtyp = CURSOR_UNDERLINE;
1275 for(i = 0; i < 2; ++i) {
1277 if (singlebyte) first = 0xC3;
1281 if (singlebyte) first = 0x81;
1285 for (p=0; p < 4; ++p) {
1286 if (cursor_color & colorbits[p]) {
1287 cursor.plane[p].image[i][0] |= first;
1289 cursor.plane[p].image[i][1] |= second;
1291 cursor.plane[p].image[i][0] &= ~first;
1293 cursor.plane[p].image[i][1] &= ~second;
1298 for(i = ROWS_PER_CELL - 2; i < ROWS_PER_CELL; ++i) {
1299 if (i != (ROWS_PER_CELL-1)) {
1300 if (singlebyte) first = 0x81;
1304 if (singlebyte) first = 0xC3;
1308 for (p=0; p < SCREENPLANES; ++p) {
1309 if (cursor_color & colorbits[p]) {
1310 cursor.plane[p].image[i][0] |= first;
1312 cursor.plane[p].image[i][1] |= second;
1314 cursor.plane[p].image[i][0] &= ~first;
1316 cursor.plane[p].image[i][1] &= ~second;
1322 case CURSOR_UNDERLINE:
1324 i = ROWS_PER_CELL - 1;
1327 for (p=0; p < SCREENPLANES; ++p) {
1328 if (cursor_color & colorbits[p]) {
1329 cursor.plane[p].image[i][0] |= first;
1331 cursor.plane[p].image[i][1] |= second;
1333 cursor.plane[p].image[i][0] &= ~first;
1335 cursor.plane[p].image[i][1] &= ~second;
1345 for(i = 0; i < ROWS_PER_CELL; ++i) {
1347 if ((i == 0) || (i == (ROWS_PER_CELL-1))) {
1351 if (singlebyte) first = 0x81;
1355 for (p=0; p < SCREENPLANES; ++p) {
1356 if (cursor_color & colorbits[p]) {
1357 cursor.plane[p].image[i][0] |= first;
1359 cursor.plane[p].image[i][1] |= second;
1361 cursor.plane[p].image[i][0] &= ~first;
1363 cursor.plane[p].image[i][1] &= ~second;
1371 * Place the new cell onto the display.
1375 for(i=0;i < ROWS_PER_CELL; ++i) {
1376 tmp1 = screentable[i+pixy];
1380 /* memcpy(tmp1,cursor.plane[3].image[i],BYTES_PER_CELL); */
1381 WRITE_ABSOLUTE(tmp1,cursor.plane[3].image[i][0]);
1383 WRITE_ABSOLUTE(tmp2,cursor.plane[3].image[i][1]);
1386 /* memcpy(tmp1,cursor.plane[2].image[i],BYTES_PER_CELL); */
1387 WRITE_ABSOLUTE(tmp1,cursor.plane[2].image[i][0]);
1389 WRITE_ABSOLUTE(tmp2,cursor.plane[2].image[i][1]);
1392 /* memcpy(tmp1,cursor.plane[1].image[i],BYTES_PER_CELL); */
1393 WRITE_ABSOLUTE(tmp1,cursor.plane[1].image[i][0]);
1395 WRITE_ABSOLUTE(tmp2,cursor.plane[1].image[i][1]);
1398 /* memcpy(tmp1,cursor.plane[0].image[i],BYTES_PER_CELL); */
1399 WRITE_ABSOLUTE(tmp1,cursor.plane[0].image[i][0]);
1401 WRITE_ABSOLUTE(tmp2,cursor.plane[0].image[i][1]);
1405 if (inmap) positionbar();
1413 int i,pixx,pixy,x,y;
1416 #ifdef REINCARNATION
1417 boolean isrogue = Is_rogue_level(&u.uz);
1418 boolean singlebyte = (isrogue || iflags.over_view
1419 || iflags.traditional_view || !inmap);
1421 boolean singlebyte = (iflags.over_view
1422 || iflags.traditional_view || !inmap);
1426 if (inmap && !cursor_type) return; /* CURSOR_INVIS - nothing to do */
1427 /* protection from callers */
1428 x = min(curcol,(CO - 1));
1429 y = min(currow,(LI-1));
1430 if (!singlebyte && ((x < clipx) || (x > clipxmax))) return;
1432 pixy = row2y(y); /* convert to pixels */
1436 pixx = col2x((x-clipx));
1438 if (inmap) curtyp = cursor_type;
1439 else curtyp = CURSOR_UNDERLINE;
1441 if (curtyp == CURSOR_UNDERLINE) /* optimization for uline */
1442 i = ROWS_PER_CELL - 1;
1446 for(;i < ROWS_PER_CELL; ++i) {
1447 tmp1 = screentable[i+pixy];
1451 /* memcpy(tmp,undercursor.plane[3].image[i],BYTES_PER_CELL); */
1452 WRITE_ABSOLUTE(tmp1,undercursor.plane[3].image[i][0]);
1454 WRITE_ABSOLUTE(tmp2,undercursor.plane[3].image[i][1]);
1457 /* memcpy(tmp,undercursor.plane[2].image[i],BYTES_PER_CELL); */
1458 WRITE_ABSOLUTE(tmp1,undercursor.plane[2].image[i][0]);
1460 WRITE_ABSOLUTE(tmp2,undercursor.plane[2].image[i][1]);
1463 /* memcpy(tmp,undercursor.plane[1].image[i],BYTES_PER_CELL); */
1464 WRITE_ABSOLUTE(tmp1,undercursor.plane[1].image[i][0]);
1466 WRITE_ABSOLUTE(tmp2,undercursor.plane[1].image[i][1]);
1469 /* memcpy(tmp,undercursor.plane[0].image[i],BYTES_PER_CELL); */
1470 WRITE_ABSOLUTE(tmp1,undercursor.plane[0].image[i][0]);
1472 WRITE_ABSOLUTE(tmp2,undercursor.plane[0].image[i][1]);
1476 # endif /* SIMULATE_CURSOR */
1478 #endif /* SCREEN_VGA */