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. */
4 /*
5  * vidvga.c - VGA Hardware video support
6  */
7 
8 #include "hack.h"
9 
10 #ifdef SCREEN_VGA		/* this file is for SCREEN_VGA only    */
11 #include "pcvideo.h"
12 #include "tile.h"
13 #include "pctiles.h"
14 
15 #include <dos.h>
16 #include <ctype.h>
17 #include "wintty.h"
18 
19 # ifdef __GO32__
20 #include <pc.h>
21 #include <unistd.h>
22 # endif
23 
24 /*=========================================================================
25  * VGA Video supporting routines (for tiles).
26  *
27  * The following routines carry out the lower level video functions required
28  * to make PC NetHack work with VGA graphics.
29  *
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).
33  *
34  * Notes (96/02/16):
35  *
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
39  *     the input request.
40  *
41  *   - A check for a VGA adapter is implemented.
42  *
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.
47  *
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!
52  *
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.
56  *
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).
61  *
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:
66  *
67  *           0 1 1 1
68  *            \ \ \ \
69  *             \ \ \ plane 0
70  *              \ \ plane 1
71  *               \ plane 2
72  *                plane 3
73  *
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.
80  *
81  *   - A check for valid mode switches has been added.
82  *
83  *   - No tiles are displayed on the Rogue Level in keeping with the
84  *     original Rogue.  The display adapter remains in graphics mode
85  *     however.
86  *
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.
89  *
90  * ToDo (96/02/17):
91  *
92  *   - Nothing prior to release.
93  *=========================================================================
94  */
95 
96 
97 # if defined(_MSC_VER)
98 #  if _MSC_VER >= 700
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 */
104 #    if _MSC_VER > 700
105 #pragma warning(disable:4759)	/* prevents complaints with MK_FP */
106 #    endif
107 #  endif
108 # include <conio.h>
109 # endif
110 
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);
114 #ifdef SCROLLMAP
115 STATIC_DCL void FDECL(vga_scrollmap,(BOOLEAN_P));
116 #endif
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));
120 
121 #ifdef POSITIONBAR
122 STATIC_DCL void NDECL(positionbar);
123 static void FDECL(vga_special,(int, int, int));
124 #endif
125 
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 */
136 
137 /*
138  * Global Variables
139  */
140 
141 STATIC_VAR unsigned char __far *font;
142 STATIC_VAR char *screentable[SCREENHEIGHT];
143 
144 STATIC_VAR char *paletteptr;
145 STATIC_VAR struct map_struct {
146 	int glyph;
147 	int ch;
148 	int attr;
149 	unsigned special;
150 }  map[ROWNO][COLNO];	/* track the glyphs */
151 
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
156 #  if defined(OVLB)
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}; */
161 #if 0
162 STATIC_VAR char defpalette[] = {	/* Default VGA palette         */
163 	0x00, 0x00, 0x00,
164 	0x00, 0x00, 0xaa,
165 	0x00, 0xaa, 0x00,
166 	0x00, 0xaa, 0xaa,
167 	0xaa, 0x00, 0x00,
168 	0xaa, 0x00, 0xaa,
169 	0xaa, 0xaa, 0x00,
170 	0xaa, 0xaa, 0xaa,
171 	0x55, 0x55, 0x55,
172 	0xcc, 0xcc, 0xcc,
173 	0x00, 0x00, 0xff,
174 	0x00, 0xff, 0x00,
175 	0xff, 0x00, 0x00,
176 	0xff, 0xff, 0x00,
177 	0xff, 0x00, 0xff,
178 	0xff, 0xff, 0xff
179 	};
180 #endif
181 
182 #   ifndef ALTERNATE_VIDEO_METHOD
183 int vp[SCREENPLANES] = {8,4,2,1};
184 #   endif
185 int vp2[SCREENPLANES] = {1,2,4,8};
186 #  else
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];
194 #   endif
195 extern int vp2[SCREENPLANES];
196 #  endif /* OVLB */
197 
198 STATIC_VAR struct planar_cell_struct *planecell;
199 STATIC_VAR struct overview_planar_cell_struct *planecell_O;
200 
201 # if defined(USE_TILES)
202 STATIC_VAR struct tibhdr_struct tibheader;
203 /* extern FILE *tilefile; */ /* Not needed in here most likely */
204 # endif
205 
206 /* STATIC_VAR int  g_attribute;	*/	/* Current attribute to use */
207 
208 #ifdef OVLB
209 void
vga_get_scr_size()210 vga_get_scr_size()
211 {
212 	CO = 80;
213 	LI = 29;
214 }
215 #endif /*OVLB*/
216 
217 
218 
219 # ifdef OVLB
220 
221 void
vga_backsp()222 vga_backsp()
223 {
224 	int col,row;
225 
226 	col = curcol; 		/* Character cell row and column */
227 	row = currow;
228 
229 	if (col > 0) col = col-1;
230 	vga_gotoloc(col,row);
231 }
232 
233 # endif /* OVLB */
234 # ifdef OVL0
235 
236 void
vga_clear_screen(colour)237 vga_clear_screen(colour)
238 int colour;
239 {
240 	char __far *pch;
241 	int y,j;
242 	char volatile a;
243 
244 	outportb(0x3ce,5);
245 	outportb(0x3cf,2);
246 
247 	for (y=0; y < SCREENHEIGHT; ++y) {
248 		pch = screentable[y];
249 		for (j=0; j < SCREENBYTES; ++j) {
250 			outportb(0x3ce,8);
251 			outportb(0x3cf,255);
252 			a = READ_ABSOLUTE(pch); /* Must read , then write */
253 			WRITE_ABSOLUTE(pch, (char)colour);
254 			++pch;
255 		}
256 	}
257 	outportb(0x3ce,5);
258 	outportb(0x3cf,0);
259 	if (iflags.tile_view) vga_clearmap();
260 	vga_gotoloc(0,0);	/* is this needed? */
261 }
262 
263 void
vga_cl_end(col,row)264 vga_cl_end(col,row)	/* clear to end of line */
265 int col,row;
266 {
267 	int count;
268 
269 	/*
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()
273 	 */
274 	for (count = col; count < (CO-1); ++count) {
275 		vga_WriteChar(' ',count,row,BACKGROUND_VGA_COLOR);
276 	}
277 }
278 
279 void
vga_cl_eos(cy)280 vga_cl_eos(cy)	/* clear to end of screen */
281 int cy;
282 {
283 	int count;
284 
285 	cl_end();
286 	while(cy <= LI-2) {
287 		for (count = 0; count < (CO-1); ++count) {
288 			vga_WriteChar(' ',count,cy,
289 				BACKGROUND_VGA_COLOR);
290 		}
291 		cy++;
292 	}
293 }
294 
295 
296 # endif /* OVL0 */
297 
298 # ifdef OVLB
299 void
vga_tty_end_screen()300 vga_tty_end_screen()
301 {
302 	vga_clear_screen(BACKGROUND_VGA_COLOR);
303 	vga_SwitchMode(MODETEXT);
304 }
305 
306 
307 void
vga_tty_startup(wid,hgt)308 vga_tty_startup(wid, hgt)
309     int *wid, *hgt;
310 {
311 
312 	/* code to sense display adapter is required here - MJA */
313 
314 	vga_get_scr_size();
315 	if (CO && LI) {
316 		*wid = CO;
317 		*hgt = LI;
318 	}
319 
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 */
323 }
324 # endif /* OVLB */
325 
326 /*
327  * Screen output routines (these are heavily used).
328  *
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.
332  *
333  * vga_xputs -Writes a c null terminated string at the current location.
334  *
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.
339  *
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
343  *            include/display.h.
344  *
345  */
346 
347 # ifdef OVL0
348 void
vga_xputs(s,col,row)349 vga_xputs(s,col,row)
350 const char *s;
351 int col,row;
352 {
353 
354 	if (s != (char *)0) {
355 		vga_WriteStr((char *)s,strlen(s),col,row,g_attribute);
356 	}
357 }
358 
359 void
vga_xputc(ch,attr)360 vga_xputc(ch,attr)	/* write out character (and attribute) */
361 char ch;
362 int attr;
363 {
364 	int col,row;
365 
366 	col = curcol;
367 	row = currow;
368 
369 	switch(ch) {
370 	    case '\n':
371 			col = 0;
372 			++row;
373 			break;
374 	    default:
375 			vga_WriteChar((unsigned char)ch,col,row,attr);
376 			if (col < (CO -1 )) ++col;
377 			break;
378 	} /* end switch */
379 	vga_gotoloc(col,row);
380 }
381 
382 #  if defined(USE_TILES)
383 void
vga_xputg(glyphnum,ch,special)384 vga_xputg(glyphnum,ch, special)	/* Place tile represent. a glyph at current location */
385 int glyphnum;
386 int ch;
387 unsigned special;	/* special feature: corpse, invis, detected, pet, ridden - hack.h */
388 {
389 	int col,row;
390 	int attr;
391 	int ry;
392 
393 	row = currow;
394 	col = curcol;
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,
410 					col - clipx, row);
411 		} else
412 			pline("vga_xputg: Error reading tile (%d,%d) from file",
413 					glyphnum,glyph2tile[glyphnum]);
414 	    }
415 	} else {
416 	    if (!ReadPlanarTileFile_O(glyph2tile[glyphnum], &planecell_O))
417 			vga_DisplayCell_O(planecell_O, col, row);
418 	    else
419 			pline("vga_xputg: Error reading tile (%d,%d) from file",
420 					glyphnum,glyph2tile[glyphnum]);
421 	}
422 	if (col < (CO - 1 )) ++col;
423 	vga_gotoloc(col,row);
424 }
425 #  endif /* USE_TILES */
426 
427 /*
428  * Cursor location manipulation, and location information fetching
429  * routines.
430  * These include:
431  *
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.
437  */
438 
439 void
vga_gotoloc(col,row)440 vga_gotoloc(col,row)
441 int col,row;
442 {
443 	curcol = min(col,CO - 1); /* protection from callers */
444 	currow = min(row,LI - 1);
445 }
446 
447 #  if defined(USE_TILES) && defined(CLIPPING)
448 void
vga_cliparound(x,y)449 vga_cliparound(x, y)
450 int x, y;
451 {
452 	extern boolean restoring;
453 	int oldx = clipx;
454 
455 	if (!iflags.tile_view || iflags.over_view || iflags.traditional_view)
456 		return;
457 
458 	if (x < clipx + 5) {
459 		clipx = max(0, x - (viewport_size / 2));
460 		clipxmax = clipx + (viewport_size - 1);
461 	}
462 	else if (x > clipxmax - 5) {
463 		clipxmax = min(COLNO - 1, x + (viewport_size / 2));
464 		clipx = clipxmax - (viewport_size - 1);
465 	}
466 	if (clipx != oldx) {
467 	    if (on_level(&u.uz0, &u.uz) && !restoring)
468 		/* (void) doredraw(); */
469 		vga_redrawmap(1);
470 	}
471 }
472 
473 STATIC_OVL void
vga_redrawmap(clearfirst)474 vga_redrawmap(clearfirst)
475 boolean clearfirst;
476 {
477 	int j,x,y,t;
478 	char __far *pch;
479 	char volatile a;
480 
481 	if (clearfirst) {
482 		/* y here is in pixel rows */
483 		outportb(0x3ce,5);
484 		outportb(0x3cf,2);
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) {
489 				outportb(0x3ce,8);
490 				outportb(0x3cf,255);
491 				 /* On VGA mode2, must read first, then write */
492 				a = READ_ABSOLUTE(pch);
493 				WRITE_ABSOLUTE(pch, (char)BACKGROUND_VGA_COLOR);
494 				++pch;
495 			}
496 		}
497 		outportb(0x3ce,5);
498 		outportb(0x3cf,0);
499 	}
500 	/* y here is in screen rows*/
501 #    ifdef ROW_BY_ROW
502 	for (y = 0; y < ROWNO; ++y)
503 		for (x = clipx; x <= clipxmax; ++x) {
504 #    else
505 	for (x = clipx; x <= clipxmax; ++x)
506 		for (y = 0; y < ROWNO; ++y) {
507 #    endif
508 		    if (iflags.traditional_view) {
509 			if (!(clearfirst && map[y][x].ch == S_stone))
510 				vga_WriteChar(
511 					(unsigned char)map[y][x].ch,
512 					x,y + TOP_MAP_ROW,map[y][x].attr);
513 		    } else {
514 		      t = map[y][x].glyph;
515 		      if (!(clearfirst && t == cmap_to_glyph(S_stone))) {
516 			if (!iflags.over_view) {
517 			  	if (!ReadPlanarTileFile(glyph2tile[t],
518 				    &planecell)) {
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);
523 		  	  	} else
524 			      pline("vga_redrawmap: Error reading tile (%d,%d)",
525 					 t,glyph2tile[t]);
526 		     	} else {
527 				if (!ReadPlanarTileFile_O(glyph2tile[t],
528 				     &planecell_O)) {
529 					vga_DisplayCell_O(planecell_O,
530 						x, y + TOP_MAP_ROW);
531 		  	  	} else
532 			     pline("vga_redrawmap: Error reading tile (%d,%d)",
533 					t,glyph2tile[t]);
534 		  	}
535 		      }
536 		    }
537 		}
538 }
539 #  endif /* USE_TILES && CLIPPING */
540 # endif /* OVL0 */
541 # ifdef OVL2
542 
543 void
vga_userpan(left)544 vga_userpan(left)
545 boolean left;
546 {
547 	int x;
548 
549 /*	pline("Into userpan"); */
550 	if (iflags.over_view || iflags.traditional_view) return;
551 	if (left)
552 		x = min(COLNO - 1, clipxmax + 10);
553 	else
554 		x = max(0, clipx - 10);
555 	vga_cliparound(x, 10);	/* y value is irrelevant on VGA clipping */
556 	positionbar();
557 	vga_DrawCursor();
558 }
559 
560 
vga_overview(on)561 void vga_overview(on)
562 boolean on;
563 {
564 /*	vga_HideCursor(); */
565 	if (on) {
566 		iflags.over_view = TRUE;
567 		clipx = 0;
568 		clipxmax = CO - 1;
569 	} else {
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);
575 	}
576 }
577 
vga_traditional(on)578 void vga_traditional(on)
579 boolean on;
580 {
581 /*	vga_HideCursor(); */
582 	if (on) {
583 /*		switch_graphics(ASCII_GRAPHICS); */
584 		iflags.traditional_view = TRUE;
585 		clipx = 0;
586 		clipxmax = CO - 1;
587 	} else {
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);
594 		}
595 	}
596 }
597 
vga_refresh()598 void vga_refresh()
599 {
600 	positionbar();
601 	vga_redrawmap(1);
602 	vga_DrawCursor();
603 }
604 
605 #  ifdef SCROLLMAP
606 STATIC_OVL void
vga_scrollmap(left)607 vga_scrollmap(left)
608 boolean left;
609 {
610 	int j,x,y,t;
611 	int i,pixx,pixy,x1,y1,x2,y2;
612 	int byteoffset, vplane;
613 	char __far *tmp1;
614 	char __far *tmp2;
615 	unsigned char source[SCREENPLANES][80];
616 	unsigned char first,second;
617 
618 
619 	pixy = row2y(TOP_MAP_ROW);		  /* convert to pixels */
620 	pixx = col2x(x1);
621 	if (left) {
622 		x1 = 20;
623 		x2 = 0;
624 	} else {
625 		x1 = 0;
626 		x2 = 20;
627 	}
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];
631 	    tmp1 += x1;
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);
637 		}
638 	    }
639 	    tmp1 = screentable[i + pixy];
640 	    tmp1 += x2;
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]);
646 		}
647 	    }
648 	    egawriteplane(15);
649 	}
650 
651 	if (left) {
652 		i = clipxmax - 1;
653 		j = clipxmax;
654 	} else {
655 		i = clipx;
656 		j = clipx + 1;
657 	}
658 	for (y = 0; y < ROWNO; ++y) {
659 	    for (x = i; x < j; x += 2) {
660 		t = map[y][x].glyph;
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);
664 		else
665 			pline("vga_shiftmap: Error reading tile (%d,%d)",
666 				t, glyph2tile[t]);
667 	    }
668 	}
669 }
670 #   endif /* SCROLLMAP */
671 # endif /* OVL2 */
672 
673 # ifdef OVLB
674 STATIC_OVL void
decal_planar(gp,special)675 decal_planar(gp, special)
676 struct planar_cell_struct *gp;
677 unsigned special;
678 {
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) {
684     }
685 }
686 
687 /*
688  * Open tile files,
689  * initialize the SCREEN, switch it to graphics mode,
690  * initialize the pointers to the fonts, clear
691  * the screen.
692  *
693  */
vga_Init(void)694 void vga_Init(void)
695 {
696      int i;
697 
698 #   ifdef USE_TILES
699      int tilefailure = 0;
700 /*
701  * Attempt to open the required tile files. If we can't
702  * don't perform the video mode switch, use TTY code instead.
703  *
704  */
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;
708 
709      if (tilefailure) {
710 	raw_printf("Reverting to TTY mode, tile initialization failure (%d).",
711 		tilefailure);
712 	wait_synch();
713 	iflags.usevga = 0;
714 	iflags.tile_view = FALSE;
715 	iflags.over_view = FALSE;
716 	CO = 80;
717 	LI = 25;
718 /*	clear_screen()	*/ /* not vga_clear_screen() */
719 	return;
720      }
721 #   endif
722 
723      if (iflags.usevga) {
724 	for (i=0; i < SCREENHEIGHT; ++i) {
725 		screentable[i]=MK_PTR(VIDEOSEG, (i * SCREENBYTES));
726 	}
727      }
728      vga_SwitchMode(MODE640x480);
729      windowprocs.win_cliparound = vga_cliparound;
730 /*     vga_NoBorder(BACKGROUND_VGA_COLOR); */  /* Not needed after palette mod */
731 #   ifdef USE_TILES
732      paletteptr = tibheader.palette;
733      iflags.tile_view = TRUE;
734      iflags.over_view = FALSE;
735 #   else
736      paletteptr = defpalette;
737 #   endif
738      vga_SetPalette(paletteptr);
739      g_attribute  = attrib_gr_normal;
740      font = vga_FontPtrs();
741      clear_screen();
742      clipx = 0;
743      clipxmax = clipx + (viewport_size - 1);
744 }
745 
746 /*
747  * Switches modes of the video card.
748  *
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.
752  *
753  */
vga_SwitchMode(unsigned int mode)754 void vga_SwitchMode(unsigned int mode)
755 {
756 	union REGS regs;
757 
758 	if ((mode == MODE640x480) || (mode == MODETEXT)) {
759 		if (iflags.usevga && (mode == MODE640x480)) {
760      			iflags.grmode = 1;
761 		} else {
762 	        	iflags.grmode = 0;
763 		}
764 		regs.x.ax = mode;
765 		(void) int86(VIDEO_BIOS, &regs, &regs);
766 	} else {
767 		iflags.grmode = 0;	/* force text mode for error msg */
768 		regs.x.ax = MODETEXT;
769 		(void) int86(VIDEO_BIOS, &regs, &regs);
770 		g_attribute  = attrib_text_normal;
771 		impossible("vga_SwitchMode: Bad video mode requested 0x%X",
772 			mode);
773 	}
774 }
775 
776 /*
777  * This allows grouping of several tasks to be done when
778  * switching back to text mode. This is a public (extern) function.
779  *
780  */
vga_Finish(void)781 void vga_Finish(void)
782 {
783      CloseTileFile(0);
784      CloseTileFile(1);
785      vga_SwitchMode(MODETEXT);
786      windowprocs.win_cliparound = tty_cliparound;
787      g_attribute  = attrib_text_normal;
788      iflags.tile_view = FALSE;
789 }
790 
791 #if 0
792 /*
793  * Turn off any border colour that might be enabled in the VGA card
794  * register.
795  *
796  * I disabled this after modifying tile2bin.c to remap black & white
797  * to a more standard values - MJA 94/04/23.
798  *
799  */
800 STATIC_OVL void
801 vga_NoBorder(int bc)
802 {
803 	union REGS regs;
804 
805 	regs.h.ah = (char)0x10;
806 	regs.h.al = (char)0x01;
807 	regs.h.bh = (char)bc;
808 	regs.h.bl = 0;
809 	(void) int86(VIDEO_BIOS, &regs, &regs);
810 }
811 #endif
812 
813 /*
814  *
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).
819  *
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).
823  */
vga_FontPtrs(void)824 char __far  *vga_FontPtrs(void)
825 {
826 	USHORT  __far *tmp;
827 	char __far *retval;
828 	USHORT fseg, foff;
829 	tmp  = (USHORT __far *)MK_PTR(((USHORT)FONT_PTR_SEGMENT),
830 					((USHORT)FONT_PTR_OFFSET));
831 	foff = READ_ABSOLUTE_WORD(tmp);
832 	++tmp;
833 	fseg = READ_ABSOLUTE_WORD(tmp);
834 	retval = (char __far *)MK_PTR(fseg,foff);
835 	return retval;
836 }
837 
838 /*
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:
842  *
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)
846  */
vga_detect()847 int vga_detect()
848 {
849 	union REGS regs;
850 
851 	regs.h.al = 0;
852 	regs.h.ah = 0x1a;
853 	(void) int86(VIDEO_BIOS, &regs, &regs);
854 /*
855  * debug
856  *
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);
859  *	getch();
860  */
861 	if ((int)regs.h.al == 0x1a) {
862 		if (((int)regs.h.bl == 8) || ((int)regs.h.bl == 7)) {
863 			return 1;
864 		}
865 	}
866 	return 0;
867 }
868 
869 /*
870  * Write character 'ch', at (x,y) and
871  * do it using the colour 'colour'.
872  *
873  */
874 void
vga_WriteChar(chr,col,row,colour)875 vga_WriteChar(chr,col,row,colour)
876 int chr,col,row,colour;
877 {
878 	int i;
879 	int x,pixy;
880 
881 	char volatile tc;
882 	char __far *cp;
883 	unsigned char __far *fp = font;
884 	unsigned char fnt;
885 	int actual_colour = vgacmap[colour];
886 
887 
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 */
891 
892 	outportb(0x3ce,5);
893 	outportb(0x3cf,2);
894 
895 	chr = chr<<4;
896 	for (i=0; i < MAX_ROWS_PER_CELL; ++i) {
897 		cp = screentable[pixy+i] + x;
898 		fnt = READ_ABSOLUTE((fp + chr + i));
899 		outportb(0x3ce,8);
900 		outportb(0x3cf,fnt);
901 		tc = READ_ABSOLUTE(cp);	/* wrt mode 2, must read, then write */
902 		WRITE_ABSOLUTE(cp, (char)actual_colour);
903 		outportb(0x3ce,8);
904 		outportb(0x3cf,~fnt);
905 		tc = READ_ABSOLUTE(cp);	/* wrt mode 2, must read, then write */
906 		WRITE_ABSOLUTE(cp, (char)BACKGROUND_VGA_COLOR);
907 	}
908 	outportb(0x3ce,5);
909 	outportb(0x3cf,0);
910 	outportb(0x3ce,8);
911 	outportb(0x3cf,255);
912 }
913 
914 /*
915  * This is the routine that displays a high-res "cell" pointed to by 'gp'
916  * at the desired location (col,row).
917  *
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.
921  *
922  */
923 void
vga_DisplayCell(gp,col,row)924 vga_DisplayCell(gp,col,row)
925 struct planar_cell_struct *gp;
926 int col,row;
927 {
928 	int i,pixx,pixy;
929 	char __far *tmp_s;	/* source pointer */
930 	char __far *tmp_d;	/* destination pointer */
931 	int vplane;
932 
933 	pixy = row2y(row);		/* convert to pixels */
934 	pixx = col2x(col);
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];
939  			tmp_d += pixx;
940 		/*
941 		 * memcpy((void *)tmp,(void *)gp->plane[vplane].image[i],
942 		 *         BYTES_PER_CELL);
943 		 */
944 			tmp_s = gp->plane[vplane].image[i];
945 			WRITE_ABSOLUTE(tmp_d, (*tmp_s));
946 			++tmp_s; ++tmp_d;
947 			WRITE_ABSOLUTE(tmp_d, (*tmp_s));
948 		}
949 	}
950 	egawriteplane(15);
951 }
952 
953 void
vga_DisplayCell_O(gp,col,row)954 vga_DisplayCell_O(gp,col,row)
955 struct overview_planar_cell_struct *gp;
956 int col,row;
957 {
958 	int i,pixx,pixy;
959 	char __far *tmp_s;	/* source pointer */
960 	char __far *tmp_d;	/* destination pointer */
961 	int vplane;
962 
963 	pixy = row2y(row);		/* convert to pixels */
964 	pixx = col;
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];
969  			tmp_d += pixx;
970 		/*
971 		 * memcpy((void *)tmp,(void *)gp->plane[vplane].image[i],
972 		 *         BYTES_PER_CELL);
973 		 */
974 			tmp_s = gp->plane[vplane].image[i];
975 			WRITE_ABSOLUTE(tmp_d, (*tmp_s));
976 		}
977 	}
978 	egawriteplane(15);
979 }
980 
981 /*
982  * Write the character string pointed to by 's', whose maximum length
983  * is 'len' at location (x,y) using the 'colour' colour.
984  *
985  */
986 void
vga_WriteStr(s,len,col,row,colour)987 vga_WriteStr(s,len,col,row,colour)
988 char *s;
989 int len,col,row,colour;
990 {
991 	unsigned char *us;
992 	int i = 0;
993 
994 	/* protection from callers */
995 	if (row > (LI-1)) return;
996 
997 	i  = 0;
998 	us = (unsigned char *)s;
999 	while( (*us != 0) && (i < len) && (col < (CO - 1))) {
1000 		vga_WriteChar(*us,col,row,colour);
1001 		++us;
1002 		++i;
1003 		++col;
1004 	}
1005 }
1006 
1007 # endif /* OVLB */
1008 
1009 
1010 # ifdef OVLB
1011 /*
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.
1015  *
1016  */
1017 void
vga_SetPalette(p)1018 vga_SetPalette(p)
1019 	char *p;
1020 {
1021 	union REGS regs;
1022 	int i;
1023 
1024 	outportb(0x3c6,0xff);
1025 	for(i=0;i < COLORDEPTH; ++i) {
1026 		outportb(0x3c8,i);
1027 		outportb(0x3c9,(*p++) >> 2);
1028 		outportb(0x3c9,(*p++) >> 2);
1029 		outportb(0x3c9,(*p++) >> 2);
1030 	}
1031 	regs.x.bx = 0x0000;
1032 	for(i=0;i < COLORDEPTH; ++i) {
1033 		regs.x.ax = 0x1000;
1034 		(void) int86(VIDEO_BIOS,&regs,&regs);
1035 		regs.x.bx += 0x0101;
1036 	}
1037 }
1038 
1039 /*static unsigned char colorbits[]={0x01,0x02,0x04,0x08}; */ /* wrong */
1040 static unsigned char colorbits[]={0x08,0x04,0x02,0x01};
1041 
1042 #ifdef POSITIONBAR
1043 
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 */
1049 
1050 static unsigned char pbar[COLNO];
1051 
1052 void
vga_update_positionbar(posbar)1053 vga_update_positionbar(posbar)
1054 char *posbar;
1055 {
1056 	char *p = pbar;
1057 	if (posbar) while (*posbar) *p++ = *posbar++;
1058 	*p = 0;
1059 }
1060 
1061 STATIC_OVL void
positionbar()1062 positionbar()
1063 {
1064 	char *posbar = pbar;
1065 	int feature, ucol;
1066 	int k, y, colour, row;
1067 	char __far *pch;
1068 
1069 	int startk, stopk;
1070 	char volatile a;
1071 	boolean nowhere = FALSE;
1072 	int pixy = (PBAR_ROW * MAX_ROWS_PER_CELL);
1073 	int tmp;
1074 
1075 	if (!iflags.grmode || !iflags.tile_view) return;
1076 	if ((clipx < 0)  || (clipxmax <= 0) || (clipx >= clipxmax))
1077 		nowhere = TRUE;
1078 	if (nowhere) {
1079 #ifdef DEBUG
1080 		pline("Would have put bar using %d - %d.",clipx,clipxmax);
1081 #endif
1082 		return;
1083         }
1084 #ifdef OLD_STYLE
1085 	outportb(0x3ce,5);
1086 	outportb(0x3cf,2);
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;
1093 			outportb(0x3ce,8);
1094 			outportb(0x3cf,255);
1095 			a = READ_ABSOLUTE(pch); /* Must read , then write */
1096 			WRITE_ABSOLUTE(pch, (char)colour);
1097 			++pch;
1098 		}
1099 	}
1100 	outportb(0x3ce,5);
1101 	outportb(0x3cf,0);
1102 #else
1103 	colour = PBAR_COLOR_ON;
1104 	outportb(0x3ce,5);
1105 	outportb(0x3cf,2);
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))) {
1109 			startk = 0;
1110 			stopk  = SCREENBYTES;
1111 		} else {
1112 			startk = clipx;
1113 			stopk  = clipxmax;
1114 		}
1115 		for (k=0; k < SCREENBYTES; ++k) {
1116 			if ((k < startk) || (k > stopk))
1117 				colour = BACKGROUND_VGA_COLOR;
1118 			else
1119 				colour = PBAR_COLOR_ON;
1120 			outportb(0x3ce,8);
1121 			outportb(0x3cf,255);
1122 			a = READ_ABSOLUTE(pch); /* Must read , then write */
1123 			WRITE_ABSOLUTE(pch, (char)colour);
1124 			++pch;
1125 		}
1126 	}
1127 	outportb(0x3ce,5);
1128 	outportb(0x3cf,0);
1129 #endif
1130 	ucol = 0;
1131 	if (posbar) {
1132 	    while (*posbar != 0) {
1133 		feature = *posbar++;
1134 		switch (feature) {
1135 		    case '>':
1136 			vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS);
1137 			break;
1138 		    case '<':
1139 			vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS);
1140 			break;
1141 		    case '@':
1142 			ucol = (int)*posbar++;
1143 			vga_special(feature, ucol, PBAR_COLOR_HERO);
1144 			break;
1145 		    default: /* unanticipated symbols */
1146 			vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS);
1147 			break;
1148 		}
1149 	    }
1150 	}
1151 #  ifdef SIMULATE_CURSOR
1152 	if (inmap) {
1153 		tmp = curcol + 1;
1154 		if ((tmp != ucol) && (curcol >= 0))
1155 			vga_special('_', tmp, PBAR_COLOR_HERO);
1156 	}
1157 #  endif
1158 }
1159 
1160 void
vga_special(chr,col,color)1161 vga_special(chr,col,color)
1162 int chr,col,color;
1163 {
1164 	int i,y,pixy;
1165 	char __far *tmp_d;	/* destination pointer */
1166 	int vplane;
1167 	char fnt;
1168 	char bits[SCREENPLANES][ROWS_PER_CELL];
1169 
1170 	pixy = PBAR_ROW * MAX_ROWS_PER_CELL;
1171 	for(vplane=0; vplane < SCREENPLANES; ++vplane) {
1172 		egareadplane(vplane);
1173 		y = pixy;
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;
1180 			else
1181 				bits[vplane][i] &= ~fnt;
1182 		}
1183 	}
1184 	for(vplane=0; vplane < SCREENPLANES; ++vplane) {
1185 		egawriteplane(vp[vplane]);
1186 		y = pixy;
1187 		for(i=0;i < ROWS_PER_CELL; ++i) {
1188 			tmp_d = screentable[y++] + col;
1189 			WRITE_ABSOLUTE(tmp_d, (bits[vplane][i]));
1190 		}
1191      	}
1192 	egawriteplane(15);
1193 }
1194 
1195 #  endif POSITIONBAR
1196 
1197 #  ifdef SIMULATE_CURSOR
1198 
1199 static struct planar_cell_struct undercursor;
1200 static struct planar_cell_struct cursor;
1201 
1202 void
vga_DrawCursor()1203 vga_DrawCursor()
1204 {
1205 	int i,pixx,pixy,x,y,p;
1206 	char __far *tmp1;
1207 	char __far *tmp2;
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);
1215 #else
1216 	boolean singlebyte = (iflags.over_view
1217 			      || iflags.traditional_view || !inmap);
1218 #endif
1219 	int curtyp;
1220 
1221 	if (!cursor_type && inmap) return;	/* CURSOR_INVIS - nothing to do */
1222 
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 */
1227 	    if (singlebyte)
1228 		    pixx = x;
1229 	    else
1230 		    pixx = col2x((x-clipx));
1231 
1232 	    for(i=0;i < ROWS_PER_CELL; ++i) {
1233 		tmp1 = screentable[i+pixy];
1234  		tmp1 += pixx;
1235  		tmp2 = tmp1 + 1;
1236 		egareadplane(3);
1237 		/* memcpy(undercursor.plane[3].image[i],tmp1,BYTES_PER_CELL); */
1238 		undercursor.plane[3].image[i][0] = READ_ABSOLUTE(tmp1);
1239 		if (!singlebyte)
1240 			undercursor.plane[3].image[i][1] = READ_ABSOLUTE(tmp2);
1241 
1242 		egareadplane(2);
1243 		/* memcpy(undercursor.plane[2].image[i],tmp1,BYTES_PER_CELL); */
1244 		undercursor.plane[2].image[i][0] = READ_ABSOLUTE(tmp1);
1245 		if (!singlebyte)
1246 			undercursor.plane[2].image[i][1] = READ_ABSOLUTE(tmp2);
1247 
1248 		egareadplane(1);
1249 		/* memcpy(undercursor.plane[1].image[i],tmp1,BYTES_PER_CELL); */
1250 		undercursor.plane[1].image[i][0] = READ_ABSOLUTE(tmp1);
1251 		if (!singlebyte)
1252 			undercursor.plane[1].image[i][1] = READ_ABSOLUTE(tmp2);
1253 
1254 		egareadplane(0);
1255 		/* memcpy(undercursor.plane[0].image[i],tmp1,BYTES_PER_CELL); */
1256 		undercursor.plane[0].image[i][0] = READ_ABSOLUTE(tmp1);
1257 		if (!singlebyte)
1258 			undercursor.plane[0].image[i][1] = READ_ABSOLUTE(tmp2);
1259 	    }
1260 
1261 	    /*
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.
1266              */
1267 
1268 	    cursor = undercursor;
1269 	    if (inmap) curtyp = cursor_type;
1270 	    else curtyp = CURSOR_UNDERLINE;
1271 
1272 	    switch(curtyp) {
1273 
1274 		case CURSOR_CORNER:
1275 		    for(i = 0; i < 2; ++i) {
1276 			if (!i) {
1277 				if (singlebyte) first = 0xC3;
1278 				else first  = 0xC0;
1279 				second = 0x03;
1280 			} else {
1281 				if (singlebyte) first = 0x81;
1282 				else first  = 0x80;
1283 				second = 0x01;
1284 			}
1285 			for (p=0; p < 4; ++p) {
1286 				if (cursor_color & colorbits[p]) {
1287 					cursor.plane[p].image[i][0] |= first;
1288 					if (!singlebyte)
1289 					cursor.plane[p].image[i][1] |= second;
1290 				} else {
1291 					cursor.plane[p].image[i][0] &= ~first;
1292 					if (!singlebyte)
1293 					cursor.plane[p].image[i][1] &= ~second;
1294 				}
1295 			}
1296 		    }
1297 
1298 		    for(i = ROWS_PER_CELL - 2; i < ROWS_PER_CELL; ++i) {
1299 			if (i != (ROWS_PER_CELL-1)) {
1300 				if (singlebyte) first = 0x81;
1301 				else first  = 0x80;
1302 				second = 0x01;
1303 			} else {
1304 				if (singlebyte) first = 0xC3;
1305 				else first  = 0xC0;
1306 				second = 0x03;
1307 			}
1308 			for (p=0; p < SCREENPLANES; ++p) {
1309 				if (cursor_color & colorbits[p]) {
1310 					cursor.plane[p].image[i][0] |= first;
1311 					if (!singlebyte)
1312 					cursor.plane[p].image[i][1] |= second;
1313 				} else {
1314 					cursor.plane[p].image[i][0] &= ~first;
1315 					if (!singlebyte)
1316 					cursor.plane[p].image[i][1] &= ~second;
1317 				}
1318 			}
1319 		    }
1320 		    break;
1321 
1322 		case CURSOR_UNDERLINE:
1323 
1324 		    i = ROWS_PER_CELL - 1;
1325 		    first  = 0xFF;
1326 		    second = 0xFF;
1327 		    for (p=0; p < SCREENPLANES; ++p) {
1328 			if (cursor_color & colorbits[p]) {
1329 				cursor.plane[p].image[i][0] |= first;
1330 				if (!singlebyte)
1331 				cursor.plane[p].image[i][1] |= second;
1332 			} else {
1333 				cursor.plane[p].image[i][0] &= ~first;
1334 				if (!singlebyte)
1335 				cursor.plane[p].image[i][1] &= ~second;
1336 			}
1337 		    }
1338 		    break;
1339 
1340 		case CURSOR_FRAME:
1341 
1342 		    /* fall through */
1343 
1344 		default:
1345 		    for(i = 0; i < ROWS_PER_CELL; ++i) {
1346 
1347 			if ((i == 0) || (i == (ROWS_PER_CELL-1))) {
1348 				first  = 0xFF;
1349 				second = 0xFF;
1350 			} else {
1351 				if (singlebyte) first = 0x81;
1352 				else first  = 0x80;
1353 				second = 0x01;
1354 			}
1355 			for (p=0; p < SCREENPLANES; ++p) {
1356 				if (cursor_color & colorbits[p]) {
1357 					cursor.plane[p].image[i][0] |= first;
1358 					if (!singlebyte)
1359 					cursor.plane[p].image[i][1] |= second;
1360 				} else {
1361 					cursor.plane[p].image[i][0] &= ~first;
1362 					if (!singlebyte)
1363 					cursor.plane[p].image[i][1] &= ~second;
1364 				}
1365 			}
1366 		    }
1367 		    break;
1368 	    }
1369 
1370 	   /*
1371             * Place the new cell onto the display.
1372             *
1373             */
1374 
1375 	    for(i=0;i < ROWS_PER_CELL; ++i) {
1376  		tmp1 = screentable[i+pixy];
1377  		tmp1 += pixx;
1378  		tmp2 = tmp1 + 1;
1379 		egawriteplane(8);
1380 		/* memcpy(tmp1,cursor.plane[3].image[i],BYTES_PER_CELL); */
1381 		WRITE_ABSOLUTE(tmp1,cursor.plane[3].image[i][0]);
1382 		if (!singlebyte)
1383 		WRITE_ABSOLUTE(tmp2,cursor.plane[3].image[i][1]);
1384 
1385 		egawriteplane(4);
1386 		/* memcpy(tmp1,cursor.plane[2].image[i],BYTES_PER_CELL); */
1387 		WRITE_ABSOLUTE(tmp1,cursor.plane[2].image[i][0]);
1388 		if (!singlebyte)
1389 		WRITE_ABSOLUTE(tmp2,cursor.plane[2].image[i][1]);
1390 
1391 		egawriteplane(2);
1392 		/* memcpy(tmp1,cursor.plane[1].image[i],BYTES_PER_CELL); */
1393 		WRITE_ABSOLUTE(tmp1,cursor.plane[1].image[i][0]);
1394 		if (!singlebyte)
1395 		WRITE_ABSOLUTE(tmp2,cursor.plane[1].image[i][1]);
1396 
1397 		egawriteplane(1);
1398 		/* memcpy(tmp1,cursor.plane[0].image[i],BYTES_PER_CELL); */
1399 		WRITE_ABSOLUTE(tmp1,cursor.plane[0].image[i][0]);
1400 		if (!singlebyte)
1401 		WRITE_ABSOLUTE(tmp2,cursor.plane[0].image[i][1]);
1402 	    }
1403 	    egawriteplane(15);
1404 #ifdef POSITIONBAR
1405 	    if (inmap) positionbar();
1406 #endif
1407 }
1408 
1409 void
vga_HideCursor()1410 vga_HideCursor()
1411 {
1412 
1413 	int i,pixx,pixy,x,y;
1414 	char __far *tmp1;
1415 	char __far *tmp2;
1416 #ifdef REINCARNATION
1417 	boolean isrogue = Is_rogue_level(&u.uz);
1418 	boolean singlebyte = (isrogue || iflags.over_view
1419 			      || iflags.traditional_view || !inmap);
1420 #else
1421 	boolean singlebyte = (iflags.over_view
1422 			      || iflags.traditional_view || !inmap);
1423 #endif
1424 	int curtyp;
1425 
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;
1431 
1432 	    pixy = row2y(y);		/* convert to pixels */
1433 	    if (singlebyte)
1434 		    pixx = x;
1435 	    else
1436 		    pixx = col2x((x-clipx));
1437 
1438 	    if (inmap) curtyp = cursor_type;
1439 	    else curtyp = CURSOR_UNDERLINE;
1440 
1441 	    if (curtyp == CURSOR_UNDERLINE)  /* optimization for uline */
1442 		i = ROWS_PER_CELL - 1;
1443 	    else
1444 		i = 0;
1445 
1446 	    for(;i < ROWS_PER_CELL; ++i) {
1447 		tmp1 = screentable[i+pixy];
1448  		tmp1 += pixx;
1449  		tmp2 = tmp1 + 1;
1450 		egawriteplane(8);
1451 		/* memcpy(tmp,undercursor.plane[3].image[i],BYTES_PER_CELL); */
1452 		WRITE_ABSOLUTE(tmp1,undercursor.plane[3].image[i][0]);
1453 		if (!singlebyte)
1454 		WRITE_ABSOLUTE(tmp2,undercursor.plane[3].image[i][1]);
1455 
1456 		egawriteplane(4);
1457 		/* memcpy(tmp,undercursor.plane[2].image[i],BYTES_PER_CELL); */
1458 		WRITE_ABSOLUTE(tmp1,undercursor.plane[2].image[i][0]);
1459 		if (!singlebyte)
1460 		WRITE_ABSOLUTE(tmp2,undercursor.plane[2].image[i][1]);
1461 
1462 		egawriteplane(2);
1463 		/* memcpy(tmp,undercursor.plane[1].image[i],BYTES_PER_CELL); */
1464 		WRITE_ABSOLUTE(tmp1,undercursor.plane[1].image[i][0]);
1465 		if (!singlebyte)
1466 		WRITE_ABSOLUTE(tmp2,undercursor.plane[1].image[i][1]);
1467 
1468 		egawriteplane(1);
1469 		/* memcpy(tmp,undercursor.plane[0].image[i],BYTES_PER_CELL); */
1470 		WRITE_ABSOLUTE(tmp1,undercursor.plane[0].image[i][0]);
1471 		if (!singlebyte)
1472 		WRITE_ABSOLUTE(tmp2,undercursor.plane[0].image[i][1]);
1473 	    }
1474 	    egawriteplane(15);
1475 }
1476 #  endif /* SIMULATE_CURSOR */
1477 # endif /* OVLB */
1478 #endif /* SCREEN_VGA  */
1479 
1480 /* vidvga.c */
1481