NHDT->ANH, nethack->anethack, nhdat->anhdat
[aNetHack.git] / sys / msdos / vidvesa.c
blob483118fed3512de5717eef2d30739d0e2c8e6995
1 /* Copyright (c) aNetHack PC Development Team 1995 */
2 /* VESA BIOS functions copyright (c) Ray Chason 2016 */
3 /* aNetHack may be freely redistributed. See license for details. */
4 /*
5 * vidvesa.c - VGA Hardware video support with VESA BIOS Extensions
6 */
8 #include "hack.h"
10 #ifdef SCREEN_VESA /* this file is for SCREEN_VESA only */
11 #include <dpmi.h>
13 #include "pcvideo.h"
14 #include "tile.h"
15 #include "pctiles.h"
16 #include "vesa.h"
17 #include "wintty.h"
18 #include "tileset.h"
20 #define BACKGROUND_VESA_COLOR 1
21 #define FIRST_TEXT_COLOR 240
23 static unsigned long FDECL(vesa_SetWindow, (int window, unsigned long offset));
24 static unsigned long FDECL(vesa_ReadPixel32, (unsigned x, unsigned y));
25 static void FDECL(vesa_WritePixel32, (unsigned x, unsigned y,
26 unsigned long color));
27 static void FDECL(vesa_WritePixel, (unsigned x, unsigned y, unsigned color));
28 static unsigned long FDECL(vesa_MakeColor, (unsigned r, unsigned g, unsigned b));
29 static void FDECL(vesa_GetRGB, (
30 unsigned long color,
31 unsigned char *rp, unsigned char *gp, unsigned char *bp));
32 static void FDECL(vesa_FillRect, (
33 unsigned left, unsigned top,
34 unsigned width, unsigned height,
35 unsigned color));
37 static void NDECL(vesa_redrawmap);
38 static void FDECL(vesa_cliparound, (int, int));
39 static void FDECL(decal_packed, (const struct TileImage *tile, unsigned special));
40 static void FDECL(vesa_SwitchMode, (unsigned mode));
41 static boolean FDECL(vesa_SetPalette, (const struct Pixel *));
42 static boolean FDECL(vesa_SetHardPalette, (const struct Pixel *));
43 static boolean FDECL(vesa_SetSoftPalette, (const struct Pixel *));
44 static void FDECL(vesa_DisplayCell, (const struct TileImage *tile, int, int));
45 static void FDECL(vesa_DisplayCellInMemory, (const struct TileImage *tile,
46 int, char buf[TILE_Y][640*2]));
47 static unsigned FDECL(vesa_FindMode, (unsigned long mode_addr, unsigned bits));
48 static void FDECL(vesa_WriteChar, (int, int, int, int, BOOLEAN_P));
49 static void FDECL(vesa_WriteCharInMemory, (int, int, char buf[TILE_Y][640*2],
50 int));
51 static void FDECL(vesa_WriteStr, (const char *, int, int, int, int));
52 static char __far *NDECL(vesa_FontPtrs);
54 #ifdef POSITIONBAR
55 static void NDECL(positionbar);
56 #endif
58 extern int clipx, clipxmax; /* current clipping column from wintty.c */
59 extern int curcol, currow; /* current column and row */
60 extern int g_attribute;
61 extern int attrib_text_normal; /* text mode normal attribute */
62 extern int attrib_gr_normal; /* graphics mode normal attribute */
63 extern int attrib_gr_intense; /* graphics mode intense attribute */
64 extern boolean inmap; /* in the map window */
65 extern boolean restoring;
68 * Global Variables
71 static unsigned char __far *font;
73 static struct map_struct {
74 int glyph;
75 int ch;
76 int attr;
77 unsigned special;
78 } map[ROWNO][COLNO]; /* track the glyphs */
80 #define vesa_clearmap() \
81 { \
82 int x, y; \
83 for (y = 0; y < ROWNO; ++y) \
84 for (x = 0; x < COLNO; ++x) { \
85 map[y][x].glyph = cmap_to_glyph(S_stone); \
86 map[y][x].ch = S_stone; \
87 map[y][x].attr = 0; \
88 map[y][x].special = 0; \
89 } \
91 #define TOP_MAP_ROW 1
93 static int viewport_size = 40;
95 static const struct Pixel defpalette[] = { /* Colors for text and the position bar */
96 { 0x18, 0x18, 0x18, 0xff }, /* CLR_BLACK */
97 { 0xaa, 0x00, 0x00, 0xff }, /* CLR_RED */
98 { 0x00, 0xaa, 0x00, 0xff }, /* CLR_GREEN */
99 { 0x99, 0x40, 0x00, 0xff }, /* CLR_BROWN */
100 { 0x00, 0x00, 0xaa, 0xff }, /* CLR_BLUE */
101 { 0xaa, 0x00, 0xaa, 0xff }, /* CLR_MAGENTA */
102 { 0x00, 0xaa, 0xaa, 0xff }, /* CLR_CYAN */
103 { 0xaa, 0xaa, 0xaa, 0xff }, /* CLR_GRAY */
104 { 0x55, 0x55, 0x55, 0xff }, /* NO_COLOR */
105 { 0xff, 0x90, 0x00, 0xff }, /* CLR_ORANGE */
106 { 0x00, 0xff, 0x00, 0xff }, /* CLR_BRIGHT_GREEN */
107 { 0xff, 0xff, 0x00, 0xff }, /* CLR_YELLOW */
108 { 0x00, 0x00, 0xff, 0xff }, /* CLR_BRIGHT_BLUE */
109 { 0xff, 0x00, 0xff, 0xff }, /* CLR_BRIGHT_MAGENTA */
110 { 0x00, 0xff, 0xff, 0xff }, /* CLR_BRIGHT_CYAN */
111 { 0xff, 0xff, 0xff, 0xff } /* CLR_WHITE */
114 /* Information about the selected VESA mode */
115 static unsigned short vesa_mode = 0xFFFF; /* Mode number */
116 static unsigned short vesa_x_res; /* X resolution */
117 static unsigned short vesa_y_res; /* Y resolution */
118 static unsigned short vesa_x_center; /* X centering offset */
119 static unsigned short vesa_y_center; /* Y centering offset */
120 static unsigned short vesa_scan_line; /* Bytes per scan line */
121 static int vesa_read_win; /* Select the read window */
122 static int vesa_write_win; /* Select the write window */
123 static unsigned long vesa_win_pos[2]; /* Window position */
124 static unsigned long vesa_win_addr[2]; /* Window physical address */
125 static unsigned long vesa_win_size; /* Window size */
126 static unsigned long vesa_win_gran; /* Window granularity */
127 static unsigned char vesa_pixel_size;
128 static unsigned char vesa_pixel_bytes;
129 static unsigned char vesa_red_pos;
130 static unsigned char vesa_red_size;
131 static unsigned char vesa_green_pos;
132 static unsigned char vesa_green_size;
133 static unsigned char vesa_blue_pos;
134 static unsigned char vesa_blue_size;
135 static unsigned long vesa_palette[256];
137 struct OldModeInfo {
138 unsigned mode;
140 unsigned short XResolution; /* horizontal resolution in pixels or characters */
141 unsigned short YResolution; /* vertical resolution in pixels or characters */
142 unsigned char BitsPerPixel; /* bits per pixel */
143 unsigned char MemoryModel; /* memory model type */
146 static const struct OldModeInfo old_mode_table[] = {
147 { 0x0101, 640, 480, 8, 4 },
148 { 0x0103, 800, 600, 8, 4 },
149 { 0x0105, 1024, 768, 8, 4 },
150 { 0x0107, 1280, 1024, 8, 4 },
151 { 0x0110, 640, 480, 15, 6 },
152 { 0x0111, 640, 480, 16, 6 },
153 { 0x0112, 640, 480, 24, 6 },
154 { 0x0113, 800, 600, 15, 6 },
155 { 0x0114, 800, 600, 16, 6 },
156 { 0x0115, 800, 600, 24, 6 },
157 { 0x0116, 1024, 768, 15, 6 },
158 { 0x0117, 1024, 768, 16, 6 },
159 { 0x0118, 1024, 768, 24, 6 },
160 { 0x0119, 1280, 1024, 15, 6 },
161 { 0x011A, 1280, 1024, 16, 6 },
162 { 0x011B, 1280, 1024, 24, 6 },
165 /* Retrieve the mode info block */
166 static boolean
167 vesa_GetModeInfo(mode, info)
168 unsigned mode;
169 struct ModeInfoBlock *info;
171 int mode_info_sel = -1; /* custodial */
172 int mode_info_seg;
173 __dpmi_regs regs;
175 mode_info_seg = __dpmi_allocate_dos_memory(
176 (sizeof(*info) + 15) / 16,
177 &mode_info_sel);
178 if (mode_info_seg < 0) goto error;
180 memset(info, 0, sizeof(*info));
181 dosmemput(info, sizeof(*info), mode_info_seg * 16L);
183 memset(&regs, 0, sizeof(regs));
184 regs.x.ax = 0x4F01;
185 regs.x.cx = mode;
186 regs.x.di = 0;
187 regs.x.es = mode_info_seg;
188 (void) __dpmi_int(VIDEO_BIOS, &regs);
190 if (regs.x.ax != 0x004F) goto error;
191 dosmemget(mode_info_seg * 16L, sizeof(*info), info);
192 if (!(info->ModeAttributes & 0x0001)) goto error;
194 if (!(info->ModeAttributes & 0x0002)) {
195 /* Older VESA BIOS that did not return certain mode properties, but
196 that has fixed mode numbers; search the table to find the right
197 mode properties */
199 unsigned i;
201 for (i = 0; i < SIZE(old_mode_table); ++i) {
202 if (mode == old_mode_table[i].mode) {
203 break;
206 if (i >= SIZE(old_mode_table)) goto error;
208 info->XResolution = old_mode_table[i].XResolution;
209 info->YResolution = old_mode_table[i].YResolution;
210 info->NumberOfPlanes = 1;
211 info->BitsPerPixel = old_mode_table[i].BitsPerPixel;
212 info->NumberOfBanks = 1;
213 info->MemoryModel = old_mode_table[i].MemoryModel;
216 __dpmi_free_dos_memory(mode_info_sel);
217 return TRUE;
219 error:
220 if (mode_info_sel != -1) __dpmi_free_dos_memory(mode_info_sel);
221 return FALSE;
224 /* Set the memory window and return the offset */
225 static unsigned long
226 vesa_SetWindow(window, offset)
227 int window;
228 unsigned long offset;
230 /* If the desired offset is already within the window, leave the window
231 as it is and return the address based on the current window position.
232 This minimizes the use of the window switch function.
234 On the first call to the function, vesa_win_pos[window] == 0xFFFFFFFF,
235 the offset will always be less than this, and the BIOS will always be
236 called. */
238 unsigned long pos = vesa_win_pos[window];
239 if (offset < pos || pos + vesa_win_size <= offset) {
240 __dpmi_regs regs;
242 memset(&regs, 0, sizeof(regs));
243 regs.x.ax = 0x4F05;
244 regs.h.bh = 0x00;
245 regs.h.bl = window;
246 regs.x.dx = offset / vesa_win_gran;
247 pos = regs.x.dx * vesa_win_gran;
248 (void) __dpmi_int(VIDEO_BIOS, &regs);
249 vesa_win_pos[window] = pos;
252 offset = offset - vesa_win_pos[window] + vesa_win_addr[window];
253 /* Keep from crashing the system if some malfunction gives us a bad
254 offset */
255 if (offset < 0xA0000 || offset > 0xBFFFF) {
256 vesa_SwitchMode(MODETEXT);
257 fprintf(stderr, "Abort: offset=%08lX\n", offset);
258 exit(1);
260 return offset;
263 static unsigned long
264 vesa_ReadPixel32(x, y)
265 unsigned x, y;
267 unsigned long offset = y * vesa_scan_line + x * vesa_pixel_bytes;
268 unsigned long addr, color;
269 unsigned i;
271 switch (vesa_pixel_size) {
272 case 8:
273 addr = vesa_SetWindow(vesa_read_win, offset);
274 color = _farpeekb(_dos_ds, addr);
275 break;
277 case 15:
278 case 16:
279 addr = vesa_SetWindow(vesa_read_win, offset);
280 color = _farpeekw(_dos_ds, addr);
281 break;
283 case 24:
284 /* Pixel may cross a window boundary */
285 color = 0;
286 for (i = 0; i < 3; ++i) {
287 addr = vesa_SetWindow(vesa_read_win, offset + i);
288 color |= (unsigned long) _farpeekb(_dos_ds, addr) << (i * 8);
290 break;
292 case 32:
293 addr = vesa_SetWindow(vesa_read_win, offset);
294 color = _farpeekl(_dos_ds, addr);
295 break;
297 return color;
300 static void
301 vesa_WritePixel32(x, y, color)
302 unsigned x, y;
303 unsigned long color;
305 unsigned long offset = y * vesa_scan_line + x * vesa_pixel_bytes;
306 unsigned long addr;
307 unsigned i;
309 switch (vesa_pixel_size) {
310 case 8:
311 addr = vesa_SetWindow(vesa_write_win, offset);
312 _farpokeb(_dos_ds, addr, color);
313 break;
315 case 15:
316 case 16:
317 addr = vesa_SetWindow(vesa_write_win, offset);
318 _farpokew(_dos_ds, addr, color);
319 break;
321 case 24:
322 /* Pixel may cross a window boundary */
323 for (i = 0; i < 3; ++i) {
324 addr = vesa_SetWindow(vesa_read_win, offset + i);
325 _farpokeb(_dos_ds, addr, (unsigned char) (color >> (i * 8)));
327 break;
329 case 32:
330 addr = vesa_SetWindow(vesa_write_win, offset);
331 _farpokel(_dos_ds, addr, color);
332 break;
336 static void
337 vesa_WritePixel(x, y, color)
338 unsigned x, y;
339 unsigned color;
341 if (vesa_pixel_size == 8) {
342 vesa_WritePixel32(x, y, color);
343 } else {
344 vesa_WritePixel32(x, y, vesa_palette[color & 0xFF]);
348 static unsigned long
349 vesa_MakeColor(r, g, b)
350 unsigned r, g, b;
352 r = (r & 0xFF) >> (8 - vesa_red_size);
353 g = (g & 0xFF) >> (8 - vesa_green_size);
354 b = (b & 0xFF) >> (8 - vesa_blue_size);
355 return ((unsigned long) r << vesa_red_pos)
356 | ((unsigned long) g << vesa_green_pos)
357 | ((unsigned long) b << vesa_blue_pos);
360 static void
361 vesa_GetRGB(color, rp, gp, bp)
362 unsigned long color;
363 unsigned char *rp, *gp, *bp;
365 unsigned r, g, b;
367 r = color >> vesa_red_pos;
368 g = color >> vesa_green_pos;
369 b = color >> vesa_blue_pos;
370 r <<= 8 - vesa_red_size;
371 g <<= 8 - vesa_green_size;
372 b <<= 8 - vesa_blue_size;
373 *rp = (unsigned char) r;
374 *gp = (unsigned char) g;
375 *bp = (unsigned char) b;
378 static void
379 vesa_FillRect(left, top, width, height, color)
380 unsigned left, top, width, height, color;
382 unsigned x, y;
384 for (y = 0; y < height; ++y) {
385 for (x = 0; x < width; ++x) {
386 vesa_WritePixel(left + x, top + y, color);
391 void
392 vesa_get_scr_size()
394 CO = 80;
395 LI = 29;
398 void
399 vesa_backsp()
401 int col, row;
403 col = curcol; /* Character cell row and column */
404 row = currow;
406 if (col > 0)
407 col = col - 1;
408 vesa_gotoloc(col, row);
411 void
412 vesa_clear_screen(colour)
413 int colour;
415 vesa_FillRect(0, 0, vesa_x_res, vesa_y_res, colour);
416 if (iflags.tile_view)
417 vesa_clearmap();
418 vesa_gotoloc(0, 0); /* is this needed? */
421 /* clear to end of line */
422 void
423 vesa_cl_end(col, row)
424 int col, row;
426 unsigned left = vesa_x_center + col * 8;
427 unsigned top = vesa_y_center + row * 16;
428 unsigned width = (CO - 1 - col) * 8;
429 unsigned height = 16;
431 vesa_FillRect(left, top, width, height, BACKGROUND_VESA_COLOR);
434 /* clear to end of screen */
435 void
436 vesa_cl_eos(cy)
437 int cy;
439 int count;
441 cl_end();
442 if (cy < LI - 1) {
443 unsigned left = vesa_x_center;
444 unsigned top = vesa_y_center + cy * 16;
445 unsigned width = 640;
446 unsigned height = (LI - 1 - cy) * 16;
448 vesa_FillRect(left, top, width, height, BACKGROUND_VESA_COLOR);
452 void
453 vesa_tty_end_screen()
455 vesa_clear_screen(BACKGROUND_VESA_COLOR);
456 vesa_SwitchMode(MODETEXT);
459 void
460 vesa_tty_startup(wid, hgt)
461 int *wid, *hgt;
463 /* code to sense display adapter is required here - MJA */
465 vesa_get_scr_size();
466 if (CO && LI) {
467 *wid = CO;
468 *hgt = LI;
471 attrib_gr_normal = ATTRIB_VGA_NORMAL;
472 attrib_gr_intense = ATTRIB_VGA_INTENSE;
473 g_attribute = attrib_gr_normal; /* Give it a starting value */
477 * Screen output routines (these are heavily used).
479 * These are the 3 routines used to place information on the screen
480 * in the VGA PC tty port of aNetHack. These are the routines
481 * that get called by the general interface routines in video.c.
483 * vesa_xputs -Writes a c null terminated string at the current location.
485 * vesa_xputc -Writes a single character at the current location. Since
486 * various places in the code assume that control characters
487 * can be used to control, we are forced to interpret some of
488 * the more common ones, in order to keep things looking correct.
490 * vesa_xputg -This routine is used to display a graphical representation of a
491 * aNetHack glyph (a tile) at the current location. For more
492 * information on aNetHack glyphs refer to the comments in
493 * include/display.h.
497 void
498 vesa_xputs(s, col, row)
499 const char *s;
500 int col, row;
502 if (s != NULL) {
503 vesa_WriteStr(s, strlen(s), col, row, g_attribute);
507 /* write out character (and attribute) */
508 void
509 vesa_xputc(ch, attr)
510 char ch;
511 int attr;
513 int col, row;
515 col = curcol;
516 row = currow;
518 switch (ch) {
519 case '\n':
520 col = 0;
521 ++row;
522 break;
523 default:
524 vesa_WriteChar((unsigned char) ch, col, row, attr, FALSE);
525 if (col < (CO - 1))
526 ++col;
527 break;
528 } /* end switch */
529 vesa_gotoloc(col, row);
532 #if defined(USE_TILES)
533 /* Place tile represent. a glyph at current location */
534 void
535 vesa_xputg(glyphnum, ch,
536 special)
537 int glyphnum;
538 int ch;
539 unsigned special; /* special feature: corpse, invis, detected, pet, ridden -
540 hack.h */
542 int col, row;
543 int attr;
544 int ry;
545 const struct TileImage *packcell;
547 row = currow;
548 col = curcol;
549 if ((col < 0 || col >= COLNO)
550 || (row < TOP_MAP_ROW || row >= (ROWNO + TOP_MAP_ROW)))
551 return;
552 ry = row - TOP_MAP_ROW;
553 map[ry][col].glyph = glyphnum;
554 map[ry][col].ch = ch;
555 map[ry][col].special = special;
556 attr = (g_attribute == 0) ? attrib_gr_normal : g_attribute;
557 map[ry][col].attr = attr;
558 if (iflags.traditional_view) {
559 vesa_WriteChar((unsigned char) ch, col, row, attr, FALSE);
560 } else {
561 if ((col >= clipx) && (col <= clipxmax)) {
562 packcell = get_tile(glyph2tile[glyphnum]);
563 if (!iflags.over_view && map[ry][col].special)
564 decal_packed(packcell, special);
565 vesa_DisplayCell(packcell, col - clipx, row);
568 if (col < (CO - 1))
569 ++col;
570 vesa_gotoloc(col, row);
572 #endif /* USE_TILES */
575 * Cursor location manipulation, and location information fetching
576 * routines.
577 * These include:
579 * vesa_gotoloc(x,y) - Moves the "cursor" on screen to the specified x
580 * and y character cell location. This routine
581 * determines the location where screen writes
582 * will occur next, it does not change the location
583 * of the player on the aNetHack level.
586 void
587 vesa_gotoloc(col, row)
588 int col, row;
590 curcol = min(col, CO - 1); /* protection from callers */
591 currow = min(row, LI - 1);
594 #if defined(USE_TILES) && defined(CLIPPING)
595 static void
596 vesa_cliparound(x, y)
597 int x, y;
599 int oldx = clipx;
601 if (!iflags.tile_view || iflags.over_view || iflags.traditional_view)
602 return;
604 if (x < clipx + 5) {
605 clipx = max(0, x - (viewport_size / 2));
606 clipxmax = clipx + (viewport_size - 1);
607 } else if (x > clipxmax - 5) {
608 clipxmax = min(COLNO - 1, x + (viewport_size / 2));
609 clipx = clipxmax - (viewport_size - 1);
611 if (clipx != oldx) {
612 if (on_level(&u.uz0, &u.uz) && !restoring)
613 /* (void) doredraw(); */
614 vesa_redrawmap();
618 static void
619 vesa_redrawmap()
621 int x, y, t;
622 const struct TileImage *packcell;
624 /* y here is in screen rows*/
625 /* Build each row in local memory, then write, to minimize use of the
626 window switch function */
627 for (y = 0; y < ROWNO; ++y) {
628 char buf[TILE_Y][640*2];
630 for (x = clipx; x <= clipxmax; ++x) {
631 if (iflags.traditional_view) {
632 vesa_WriteCharInMemory((unsigned char) map[y][x].ch, x,
633 buf, map[y][x].attr);
634 } else {
635 t = map[y][x].glyph;
636 packcell = get_tile(glyph2tile[t]);
637 if (!iflags.over_view && map[y][x].special)
638 decal_packed(packcell, map[y][x].special);
639 vesa_DisplayCellInMemory(packcell, x - clipx, buf);
642 if (iflags.over_view && vesa_pixel_size != 8) {
643 for (t = 0; t < TILE_Y; ++t) {
644 for (x = 0; x < 640; ++x) {
645 unsigned long c1 = vesa_palette[buf[t][x * 2 + 0]];
646 unsigned long c2 = vesa_palette[buf[t][x * 2 + 1]];
647 unsigned char r1, r2, g1, g2, b1, b2;
649 vesa_GetRGB(c1, &r1, &g1, &b1);
650 vesa_GetRGB(c2, &r2, &g2, &b2);
651 r1 = (r1 + r2) / 2;
652 g1 = (g1 + g2) / 2;
653 b1 = (b1 + b2) / 2;
654 vesa_WritePixel32(x, (y + TOP_MAP_ROW) * TILE_Y + t,
655 vesa_MakeColor(r1, g1, b1));
658 } else {
659 for (t = 0; t < TILE_Y; ++t) {
660 for (x = 0; x < 640; ++x) {
661 vesa_WritePixel(x, (y + TOP_MAP_ROW) * TILE_Y + t, buf[t][x]);
667 #endif /* USE_TILES && CLIPPING */
669 void
670 vesa_userpan(left)
671 boolean left;
673 int x;
675 /* pline("Into userpan"); */
676 if (iflags.over_view || iflags.traditional_view)
677 return;
678 if (left)
679 x = min(COLNO - 1, clipxmax + 10);
680 else
681 x = max(0, clipx - 10);
682 vesa_cliparound(x, 10); /* y value is irrelevant on VGA clipping */
683 positionbar();
684 vesa_DrawCursor();
687 void
688 vesa_overview(on)
689 boolean on;
691 /* vesa_HideCursor(); */
692 if (on) {
693 iflags.over_view = TRUE;
694 clipx = 0;
695 clipxmax = CO - 1;
696 } else {
697 iflags.over_view = FALSE;
698 clipx = max(0, (curcol - viewport_size / 2));
699 if (clipx > ((CO - 1) - viewport_size))
700 clipx = (CO - 1) - viewport_size;
701 clipxmax = clipx + (viewport_size - 1);
705 void
706 vesa_traditional(on)
707 boolean on;
709 /* vesa_HideCursor(); */
710 if (on) {
711 /* switch_symbols(FALSE); */
712 iflags.traditional_view = TRUE;
713 clipx = 0;
714 clipxmax = CO - 1;
715 } else {
716 iflags.traditional_view = FALSE;
717 if (!iflags.over_view) {
718 clipx = max(0, (curcol - viewport_size / 2));
719 if (clipx > ((CO - 1) - viewport_size))
720 clipx = (CO - 1) - viewport_size;
721 clipxmax = clipx + (viewport_size - 1);
726 void
727 vesa_refresh()
729 positionbar();
730 vesa_redrawmap();
731 vesa_DrawCursor();
734 static void
735 decal_packed(gp, special)
736 const struct TileImage *gp;
737 unsigned special;
739 /* FIXME: the tile array is fixed in memory and should not be changed;
740 if we ever implement this, we'll have to copy the pixels */
741 if (special & MG_CORPSE) {
742 } else if (special & MG_INVIS) {
743 } else if (special & MG_DETECT) {
744 } else if (special & MG_PET) {
745 } else if (special & MG_RIDDEN) {
750 * Open tile files,
751 * initialize the SCREEN, switch it to graphics mode,
752 * initialize the pointers to the fonts, clear
753 * the screen.
756 void
757 vesa_Init(void)
759 const struct Pixel *paletteptr;
760 #ifdef USE_TILES
761 const char *tile_file;
762 int tilefailure = 0;
764 * Attempt to open the required tile files. If we can't
765 * don't perform the video mode switch, use TTY code instead.
768 tile_file = iflags.wc_tile_file;
769 if (tile_file == NULL || tile_file == '\0') {
770 tile_file = "nhtiles.bmp";
772 if (!read_tiles(tile_file, FALSE))
773 tilefailure |= 1;
774 if (get_palette() == NULL)
775 tilefailure |= 4;
777 if (tilefailure) {
778 raw_printf("Reverting to TTY mode, tile initialization failure (%d).",
779 tilefailure);
780 wait_synch();
781 iflags.usevga = 0;
782 iflags.tile_view = FALSE;
783 iflags.over_view = FALSE;
784 CO = 80;
785 LI = 25;
786 /* clear_screen() */ /* not vesa_clear_screen() */
787 return;
789 #endif
791 if (vesa_mode == 0xFFFF) {
792 vesa_detect();
794 vesa_SwitchMode(vesa_mode);
795 windowprocs.win_cliparound = vesa_cliparound;
796 #ifdef USE_TILES
797 paletteptr = get_palette();
798 iflags.tile_view = TRUE;
799 iflags.over_view = FALSE;
800 #else
801 paletteptr = defpalette;
802 #endif
803 vesa_SetPalette(paletteptr);
804 g_attribute = attrib_gr_normal;
805 font = vesa_FontPtrs();
806 clear_screen();
807 clipx = 0;
808 clipxmax = clipx + (viewport_size - 1);
812 * Switches modes of the video card.
814 * If mode == MODETEXT (0x03), then the card is placed into text
815 * mode. Otherwise, the card is placed in the mode selected by
816 * vesa_detect. Supported modes are those with packed 8 bit pixels.
819 static void
820 vesa_SwitchMode(mode)
821 unsigned mode;
823 __dpmi_regs regs;
825 if (mode == MODETEXT) {
826 iflags.grmode = 0;
827 regs.x.ax = mode;
828 (void) __dpmi_int(VIDEO_BIOS, &regs);
829 } else if (mode >= 0x100) {
830 iflags.grmode = 1;
831 regs.x.ax = 0x4F02;
832 regs.x.bx = mode & 0x81FF;
833 (void) __dpmi_int(VIDEO_BIOS, &regs);
834 /* Record that the window position is unknown */
835 vesa_win_pos[0] = 0xFFFFFFFF;
836 vesa_win_pos[1] = 0xFFFFFFFF;
837 } else {
838 iflags.grmode = 0; /* force text mode for error msg */
839 regs.x.ax = MODETEXT;
840 (void) __dpmi_int(VIDEO_BIOS, &regs);
841 g_attribute = attrib_text_normal;
842 impossible("vesa_SwitchMode: Bad video mode requested 0x%X", mode);
847 * This allows grouping of several tasks to be done when
848 * switching back to text mode. This is a public (extern) function.
851 void
852 vesa_Finish(void)
854 free_tiles();
855 vesa_SwitchMode(MODETEXT);
856 windowprocs.win_cliparound = tty_cliparound;
857 g_attribute = attrib_text_normal;
858 iflags.tile_view = FALSE;
863 * Returns a far pointer (or flat 32 bit pointer under djgpp) to the
864 * location of the appropriate ROM font for the _current_ video mode
865 * (so you must place the card into the desired video mode before
866 * calling this function).
868 * This function takes advantage of the video BIOS loading the
869 * address of the appropriate character definition table for
870 * the current graphics mode into interrupt vector 0x43 (0000:010C).
872 static char __far *
873 vesa_FontPtrs(void)
875 USHORT __far *tmp;
876 char __far *retval;
877 USHORT fseg, foff;
878 tmp = (USHORT __far *) MK_PTR(((USHORT) FONT_PTR_SEGMENT),
879 ((USHORT) FONT_PTR_OFFSET));
880 foff = READ_ABSOLUTE_WORD(tmp);
881 ++tmp;
882 fseg = READ_ABSOLUTE_WORD(tmp);
883 retval = (char __far *) MK_PTR(fseg, foff);
884 return retval;
888 * This will verify the existance of a VGA adapter on the machine.
889 * Video function call 0x4F00 returns 0x004F in AX if successful, and
890 * returns a VbeInfoBlock describing the features of the VESA BIOS.
893 vesa_detect()
895 int vbe_info_sel = -1; /* custodial */
896 int vbe_info_seg;
897 struct VbeInfoBlock vbe_info;
898 __dpmi_regs regs;
899 unsigned long mode_addr;
900 struct ModeInfoBlock mode_info;
902 vbe_info_seg = __dpmi_allocate_dos_memory(
903 (sizeof(vbe_info) + 15) / 16,
904 &vbe_info_sel);
905 if (vbe_info_seg < 0) goto error;
907 /* Request VBE 2.0 information if it is available */
908 memset(&vbe_info, 0, sizeof(vbe_info));
909 memcpy(vbe_info.VbeSignature, "VBE2", 4);
910 dosmemput(&vbe_info, sizeof(vbe_info), vbe_info_seg * 16L);
912 /* Request VESA BIOS information */
913 regs.x.ax = 0x4F00;
914 regs.x.di = 0;
915 regs.x.es = vbe_info_seg;
916 (void) __dpmi_int(VIDEO_BIOS, &regs);
918 /* Check for successful completion of function: is VESA BIOS present? */
919 if (regs.x.ax != 0x004F) goto error;
920 dosmemget(vbe_info_seg * 16L, sizeof(vbe_info), &vbe_info);
921 if (memcmp(vbe_info.VbeSignature, "VESA", 4) != 0) goto error;
923 /* Get the address of the mode list */
924 /* The mode list may be within the DOS memory area allocated above.
925 That area must remain allocated and must not be rewritten until
926 we're done here. */
927 mode_addr = (vbe_info.VideoModePtr >> 16) * 16L
928 + (vbe_info.VideoModePtr & 0xFFFF);
930 /* Scan the mode list for an acceptable mode */
931 vesa_mode = vesa_FindMode(mode_addr, 32);
932 if (vesa_mode == 0xFFFF)
933 vesa_mode = vesa_FindMode(mode_addr, 24);
934 if (vesa_mode == 0xFFFF)
935 vesa_mode = vesa_FindMode(mode_addr, 16);
936 if (vesa_mode == 0xFFFF)
937 vesa_mode = vesa_FindMode(mode_addr, 15);
938 if (vesa_mode == 0xFFFF)
939 vesa_mode = vesa_FindMode(mode_addr, 8);
940 if (vesa_mode == 0xFFFF)
941 goto error;
943 /* Set up the variables for the pixel functions */
944 vesa_GetModeInfo(vesa_mode, &mode_info);
945 vesa_x_res = mode_info.XResolution;
946 vesa_y_res = mode_info.YResolution;
947 vesa_x_center = (vesa_x_res - 640) / 2;
948 vesa_y_center = (vesa_y_res - 480) / 2;
949 vesa_scan_line = mode_info.BytesPerScanLine;
950 vesa_win_size = mode_info.WinSize * 1024L;
951 vesa_win_gran = mode_info.WinGranularity * 1024L;
952 vesa_pixel_size = mode_info.BitsPerPixel;
953 vesa_pixel_bytes = (vesa_pixel_size + 7) / 8;
954 if (vbe_info.VbeVersion >= 0x0300) {
955 vesa_red_pos = mode_info.RedFieldPosition;
956 vesa_red_size = mode_info.RedMaskSize;
957 vesa_green_pos = mode_info.GreenFieldPosition;
958 vesa_green_size = mode_info.GreenMaskSize;
959 vesa_blue_pos = mode_info.BlueFieldPosition;
960 vesa_blue_size = mode_info.BlueMaskSize;
961 } else {
962 switch (vesa_pixel_size) {
963 case 15:
964 vesa_blue_pos = 0;
965 vesa_blue_size = 5;
966 vesa_green_pos = 5;
967 vesa_green_size = 5;
968 vesa_red_pos = 10;
969 vesa_red_size = 5;
970 break;
972 case 16:
973 vesa_blue_pos = 0;
974 vesa_blue_size = 5;
975 vesa_green_pos = 5;
976 vesa_green_size = 6;
977 vesa_red_pos = 11;
978 vesa_red_size = 5;
979 break;
981 case 24:
982 case 32:
983 vesa_blue_pos = 0;
984 vesa_blue_size = 8;
985 vesa_green_pos = 8;
986 vesa_green_size = 8;
987 vesa_red_pos = 16;
988 vesa_red_size = 8;
989 break;
992 vesa_win_addr[0] = mode_info.WinASegment * 16L;
993 vesa_win_addr[1] = mode_info.WinBSegment * 16L;
994 vesa_win_pos[0] = 0xFFFFFFFF; /* position unknown */
995 vesa_win_pos[1] = 0xFFFFFFFF;
996 /* Read window */
997 if (mode_info.WinAAttributes & 0x2) {
998 vesa_read_win = 0;
999 } else if (mode_info.WinBAttributes & 0x2) {
1000 vesa_read_win = 1;
1001 } else {
1002 goto error; /* Shouldn't happen */
1004 /* Write window */
1005 if (mode_info.WinAAttributes & 0x4) {
1006 vesa_write_win = 0;
1007 } else if (mode_info.WinBAttributes & 0x4) {
1008 vesa_write_win = 1;
1009 } else {
1010 goto error; /* Shouldn't happen */
1013 __dpmi_free_dos_memory(vbe_info_sel);
1014 return TRUE;
1016 error:
1017 if (vbe_info_sel != -1) __dpmi_free_dos_memory(vbe_info_sel);
1018 return FALSE;
1021 static unsigned
1022 vesa_FindMode(mode_addr, bits)
1023 unsigned long mode_addr;
1024 unsigned bits;
1026 unsigned selected_mode;
1027 struct ModeInfoBlock mode_info0, mode_info;
1028 unsigned model = (bits == 8) ? 4 : 6;
1030 memset(&mode_info, 0, sizeof(mode_info));
1031 selected_mode = 0xFFFF;
1032 while (1) {
1033 unsigned mode = _farpeekw(_dos_ds, mode_addr);
1034 if (mode == 0xFFFF) break;
1035 mode_addr += 2;
1037 /* Query the mode info; skip to next if not in fact supported */
1038 if (!vesa_GetModeInfo(mode, &mode_info0)) continue;
1040 /* Check that the mode is acceptable */
1041 if (mode_info0.XResolution < 640) continue;
1042 if (mode_info0.YResolution < 480) continue;
1043 if (mode_info0.NumberOfPlanes != 1) continue;
1044 if (mode_info0.BitsPerPixel != bits) continue;
1045 if (mode_info0.NumberOfBanks != 1) continue;
1046 if (mode_info0.MemoryModel != model) continue;
1047 if (mode_info0.ModeAttributes & 0x40) continue;
1049 /* The mode is OK. Accept it if it is smaller than any previous mode
1050 or if no previous mode is accepted. */
1051 if (selected_mode == 0xFFFF
1052 || mode_info0.XResolution * mode_info0.YResolution
1053 < mode_info.XResolution * mode_info.YResolution) {
1054 selected_mode = mode;
1055 mode_info = mode_info0;
1059 return selected_mode;
1063 * Write character 'ch', at (x,y) and
1064 * do it using the colour 'colour'.
1067 static void
1068 vesa_WriteChar(chr, col, row, colour, transparent)
1069 int chr, col, row, colour;
1070 boolean transparent;
1072 int i, j;
1073 int pixx, pixy;
1075 unsigned char __far *fp = font;
1076 unsigned char fnt;
1078 pixx = min(col, (CO - 1)) * 8; /* min() protects from callers */
1079 pixy = min(row, (LI - 1)) * 16; /* assumes 8 x 16 char set */
1080 pixx += vesa_x_center;
1081 pixy += vesa_y_center;
1083 for (i = 0; i < MAX_ROWS_PER_CELL; ++i) {
1084 fnt = READ_ABSOLUTE((fp + chr * 16 + i));
1085 for (j = 0; j < 8; ++j) {
1086 if (fnt & (0x80 >> j)) {
1087 vesa_WritePixel(pixx + j, pixy + i, colour + FIRST_TEXT_COLOR);
1088 } else if (!transparent) {
1089 vesa_WritePixel(pixx + j, pixy + i, BACKGROUND_VESA_COLOR);
1096 * Like vesa_WriteChar, but draw the character in local memory rather than in
1097 * the VGA frame buffer.
1099 * vesa_redrawmap uses this to gather a row of cells in local memory and then
1100 * draw them in strict row-major order, minimizing the use of the VESA
1101 * windowing function.
1104 static void
1105 vesa_WriteCharInMemory(chr, col, buf, colour)
1106 int chr, col;
1107 char buf[TILE_Y][640*2];
1108 int colour;
1110 int i, j;
1111 int pixx;
1113 unsigned char __far *fp = font;
1114 unsigned char fnt;
1116 pixx = min(col, (CO - 1)) * 8; /* min() protects from callers */
1118 for (i = 0; i < MAX_ROWS_PER_CELL; ++i) {
1119 fnt = READ_ABSOLUTE((fp + chr * 16 + i));
1120 for (j = 0; j < 8; ++j) {
1121 if (fnt & (0x80 >> j)) {
1122 buf[i][pixx + j] = colour + FIRST_TEXT_COLOR;
1123 } else {
1124 buf[i][pixx + j] = BACKGROUND_VESA_COLOR;
1131 * This is the routine that displays a high-res "cell" pointed to by 'gp'
1132 * at the desired location (col,row).
1134 * Note: (col,row) in this case refer to the coordinate location in
1135 * aNetHack character grid terms, (ie. the 40 x 25 character grid),
1136 * not the x,y pixel location.
1139 static void
1140 vesa_DisplayCell(tile, col, row)
1141 const struct TileImage *tile;
1142 int col, row;
1144 int i, j, pixx, pixy;
1146 pixx = col * TILE_X;
1147 pixy = row * TILE_Y;
1148 if (iflags.over_view) {
1149 pixx /= 2;
1150 pixx += vesa_x_center;
1151 pixy += vesa_y_center;
1152 if (vesa_pixel_size != 8) {
1153 for (i = 0; i < TILE_Y; ++i) {
1154 for (j = 0; j < TILE_X; j += 2) {
1155 unsigned index = i * tile->width + j;
1156 unsigned long c1 = vesa_palette[tile->indexes[index + 0]];
1157 unsigned long c2 = vesa_palette[tile->indexes[index + 1]];
1158 unsigned char r1, r2, g1, g2, b1, b2;
1160 vesa_GetRGB(c1, &r1, &g1, &b1);
1161 vesa_GetRGB(c2, &r2, &g2, &b2);
1162 r1 = (r1 + r2) / 2;
1163 g1 = (g1 + g2) / 2;
1164 b1 = (b1 + b2) / 2;
1165 vesa_WritePixel32(pixx + j / 2, pixy + i,
1166 vesa_MakeColor(r1, g1, b1));
1169 } else {
1170 for (i = 0; i < TILE_Y; ++i) {
1171 for (j = 0; j < TILE_X; j += 2) {
1172 unsigned index = i * tile->width + j;
1173 vesa_WritePixel(pixx + j / 2, pixy + i, tile->indexes[index]);
1177 } else {
1178 pixx += vesa_x_center;
1179 pixy += vesa_y_center;
1180 for (i = 0; i < TILE_Y; ++i) {
1181 for (j = 0; j < TILE_X; ++j) {
1182 unsigned index = i * tile->width + j;
1183 vesa_WritePixel(pixx + j, pixy + i, tile->indexes[index]);
1190 * Like vesa_DisplayCell, but draw the tile in local memory rather than in
1191 * the VGA frame buffer.
1193 * vesa_redrawmap uses this to gather a row of cells in local memory and then
1194 * draw them in strict row-major order, minimizing the use of the VESA
1195 * windowing function.
1198 static void
1199 vesa_DisplayCellInMemory(tile, col, buf)
1200 const struct TileImage *tile;
1201 int col;
1202 char buf[TILE_Y][640*2];
1204 int i, j, pixx;
1206 pixx = col * TILE_X;
1207 if (iflags.over_view && vesa_pixel_size == 8) {
1208 pixx /= 2;
1209 for (i = 0; i < TILE_Y; ++i) {
1210 for (j = 0; j < TILE_X; j += 2) {
1211 unsigned index = i * tile->width + j;
1212 buf[i][pixx + j / 2] = tile->indexes[index];
1215 } else {
1216 for (i = 0; i < TILE_Y; ++i) {
1217 for (j = 0; j < TILE_X; ++j) {
1218 unsigned index = i * tile->width + j;
1219 buf[i][pixx + j] = tile->indexes[index];
1226 * Write the character string pointed to by 's', whose maximum length
1227 * is 'len' at location (x,y) using the 'colour' colour.
1230 static void
1231 vesa_WriteStr(s, len, col, row, colour)
1232 const char *s;
1233 int len, col, row, colour;
1235 const unsigned char *us;
1236 int i = 0;
1238 /* protection from callers */
1239 if (row > (LI - 1))
1240 return;
1242 i = 0;
1243 us = (const unsigned char *) s;
1244 while ((*us != 0) && (i < len) && (col < (CO - 1))) {
1245 vesa_WriteChar(*us, col, row, colour, FALSE);
1246 ++us;
1247 ++i;
1248 ++col;
1253 * Initialize the VGA palette with the desired colours. This
1254 * must be a series of 720 bytes for use with a card in 256
1255 * colour mode at 640 x 480. The first 240 palette entries are
1256 * used by the tile set; the last 16 are reserved for text.
1259 static boolean
1260 vesa_SetPalette(palette)
1261 const struct Pixel *palette;
1263 if (vesa_pixel_size == 8) {
1264 vesa_SetHardPalette(palette);
1265 } else {
1266 vesa_SetSoftPalette(palette);
1270 static boolean
1271 vesa_SetHardPalette(palette)
1272 const struct Pixel *palette;
1274 const struct Pixel *p = palette;
1275 int palette_sel = -1; /* custodial */
1276 int palette_seg;
1277 unsigned long palette_ptr;
1278 unsigned i, shift;
1279 unsigned char r, g, b;
1280 unsigned long color;
1281 __dpmi_regs regs;
1283 palette_seg = __dpmi_allocate_dos_memory( 1024 / 16, &palette_sel);
1284 if (palette_seg < 0) goto error;
1286 /* Use 8 bit DACs if we have them */
1287 memset(&regs, 0, sizeof(regs));
1288 regs.x.ax = 0x4F08;
1289 regs.h.bl = 0;
1290 regs.h.bh = 8;
1291 (void) __dpmi_int(VIDEO_BIOS, &regs);
1292 if (regs.x.ax != 0x004F) {
1293 shift = 2;
1294 } else if (regs.h.bh > 8) {
1295 shift = 0;
1296 } else {
1297 shift = 8 - regs.h.bh;
1300 /* Set the tile set and text colors */
1301 palette_ptr = palette_seg * 16L;
1302 #ifdef USE_TILES
1303 for (i = 0; i < FIRST_TEXT_COLOR; ++i) {
1304 r = p->r >> shift;
1305 g = p->g >> shift;
1306 b = p->b >> shift;
1307 color = ((unsigned long) r << 16)
1308 | ((unsigned long) g << 8)
1309 | ((unsigned long) b << 0);
1310 _farpokel(_dos_ds, palette_ptr, color);
1311 palette_ptr += 4;
1312 ++p;
1314 #else
1315 palette_ptr += FIRST_TEXT_COLOR * 4;
1316 #endif
1317 p = defpalette;
1318 for (i = FIRST_TEXT_COLOR; i < 256; ++i) {
1319 r = p->r >> shift;
1320 g = p->g >> shift;
1321 b = p->b >> shift;
1322 color = ((unsigned long) r << 16)
1323 | ((unsigned long) g << 8)
1324 | ((unsigned long) b << 0);
1325 _farpokel(_dos_ds, palette_ptr, color);
1326 palette_ptr += 4;
1327 ++p;
1330 memset(&regs, 0, sizeof(regs));
1331 regs.x.ax = 0x4F09;
1332 regs.h.bl = 0;
1333 regs.x.cx = 256;
1334 regs.x.dx = 0;
1335 regs.x.di = 0;
1336 regs.x.es = palette_seg;
1337 (void) __dpmi_int(VIDEO_BIOS, &regs);
1339 __dpmi_free_dos_memory(palette_sel);
1340 return TRUE;
1342 error:
1343 if (palette_sel != -1) __dpmi_free_dos_memory(palette_sel);
1344 return FALSE;
1347 static boolean
1348 vesa_SetSoftPalette(palette)
1349 const struct Pixel *palette;
1351 const struct Pixel *p;
1352 unsigned i;
1353 unsigned char r, g, b;
1355 /* Set the tile set and text colors */
1356 #ifdef USE_TILES
1357 p = palette;
1358 for (i = 0; i < FIRST_TEXT_COLOR; ++i) {
1359 r = p->r;
1360 g = p->g;
1361 b = p->b;
1362 vesa_palette[i] = vesa_MakeColor(r, g, b);
1363 ++p;
1365 #endif
1366 p = defpalette;
1367 for (i = FIRST_TEXT_COLOR; i < 256; ++i) {
1368 r = p->r;
1369 g = p->g;
1370 b = p->b;
1371 vesa_palette[i] = vesa_MakeColor(r, g, b);
1372 ++p;
1376 #ifdef POSITIONBAR
1378 #define PBAR_ROW (LI - 4)
1379 #define PBAR_COLOR_ON 16 /* slate grey background colour of tiles */
1380 #define PBAR_COLOR_OFF 0 /* bluish grey, used in old style only */
1381 #define PBAR_COLOR_STAIRS CLR_BROWN /* brown */
1382 #define PBAR_COLOR_HERO CLR_WHITE /* creamy white */
1384 static unsigned char pbar[COLNO];
1386 void
1387 vesa_update_positionbar(posbar)
1388 char *posbar;
1390 char *p = pbar;
1391 if (posbar)
1392 while (*posbar)
1393 *p++ = *posbar++;
1394 *p = 0;
1397 static void
1398 positionbar()
1400 char *posbar = pbar;
1401 int feature, ucol;
1402 int k, x, y, colour, row;
1404 int startk, stopk;
1405 boolean nowhere = FALSE;
1406 int pixy = (PBAR_ROW * MAX_ROWS_PER_CELL);
1407 int tmp;
1409 if (!iflags.grmode || !iflags.tile_view)
1410 return;
1411 if ((clipx < 0) || (clipxmax <= 0) || (clipx >= clipxmax))
1412 nowhere = TRUE;
1413 if (nowhere) {
1414 #ifdef DEBUG
1415 pline("Would have put bar using %d - %d.", clipx, clipxmax);
1416 #endif
1417 return;
1419 #ifdef OLD_STYLE
1420 for (y = pixy; y < (pixy + MAX_ROWS_PER_CELL); ++y) {
1421 for (x = 0; x < 640; ++x) {
1422 k = x / 8;
1423 if ((k < clipx) || (k > clipxmax)) {
1424 colour = PBAR_COLOR_OFF;
1425 } else
1426 colour = PBAR_COLOR_ON;
1427 vesa_WritePixel(x + vesa_x_center, y + vesa_y_center, colour);
1430 #else
1431 for (y = pixy, row = 0; y < (pixy + MAX_ROWS_PER_CELL); ++y, ++row) {
1432 if ((!row) || (row == (ROWS_PER_CELL - 1))) {
1433 startk = 0;
1434 stopk = SCREENBYTES;
1435 } else {
1436 startk = clipx;
1437 stopk = clipxmax;
1439 for (x = 0; x < 640; ++x) {
1440 k = x / 8;
1441 if ((k < startk) || (k > stopk))
1442 colour = BACKGROUND_VGA_COLOR;
1443 else
1444 colour = PBAR_COLOR_ON;
1445 vesa_WritePixel(x + vesa_x_center, y + vesa_y_center, colour);
1448 #endif
1449 ucol = 0;
1450 if (posbar) {
1451 while (*posbar != 0) {
1452 feature = *posbar++;
1453 switch (feature) {
1454 case '>':
1455 vesa_WriteChar(feature, (int) *posbar++, PBAR_ROW, PBAR_COLOR_STAIRS, TRUE);
1456 break;
1457 case '<':
1458 vesa_WriteChar(feature, (int) *posbar++, PBAR_ROW, PBAR_COLOR_STAIRS, TRUE);
1459 break;
1460 case '@':
1461 ucol = (int) *posbar++;
1462 vesa_WriteChar(feature, ucol, PBAR_ROW, PBAR_COLOR_HERO, TRUE);
1463 break;
1464 default: /* unanticipated symbols */
1465 vesa_WriteChar(feature, (int) *posbar++, PBAR_ROW, PBAR_COLOR_STAIRS, TRUE);
1466 break;
1470 #ifdef SIMULATE_CURSOR
1471 if (inmap) {
1472 tmp = curcol + 1;
1473 if ((tmp != ucol) && (curcol >= 0))
1474 vesa_WriteChar('_', tmp, PBAR_ROW, PBAR_COLOR_HERO, TRUE);
1476 #endif
1479 #endif /*POSITIONBAR*/
1481 #ifdef SIMULATE_CURSOR
1483 static unsigned long undercursor[TILE_Y][TILE_X];
1485 void
1486 vesa_DrawCursor()
1488 unsigned x, y, left, top, right, bottom, width;
1489 boolean isrogue = Is_rogue_level(&u.uz);
1490 boolean halfwidth =
1491 (isrogue || iflags.over_view || iflags.traditional_view || !inmap);
1492 int curtyp;
1494 if (!cursor_type && inmap)
1495 return; /* CURSOR_INVIS - nothing to do */
1497 x = min(curcol, (CO - 1)); /* protection from callers */
1498 y = min(currow, (LI - 1)); /* protection from callers */
1499 if (!halfwidth && ((x < clipx) || (x > clipxmax)))
1500 return;
1501 if (inmap)
1502 x -= clipx;
1503 left = x * TILE_X; /* convert to pixels */
1504 top = y * TILE_Y;
1505 if (halfwidth) {
1506 left /= 2;
1507 width = TILE_X / 2;
1508 } else {
1509 width = TILE_X;
1511 left += vesa_x_center;
1512 top += vesa_y_center;
1513 right = left + width - 1;
1514 bottom = top + TILE_Y - 1;
1516 for (y = 0; y < ROWS_PER_CELL; ++y) {
1517 for (x = 0; x < width; ++x) {
1518 undercursor[y][x] = vesa_ReadPixel32(left + x, top + y);
1523 * Now we have a snapshot of the current cell.
1524 * Write the cursor on top of the display.
1527 if (inmap)
1528 curtyp = cursor_type;
1529 else
1530 curtyp = CURSOR_UNDERLINE;
1532 switch (curtyp) {
1533 case CURSOR_CORNER:
1534 vesa_WritePixel(left , top , FIRST_TEXT_COLOR + 15);
1535 vesa_WritePixel(left + 1, top , FIRST_TEXT_COLOR + 15);
1536 vesa_WritePixel(right - 1, top , FIRST_TEXT_COLOR + 15);
1537 vesa_WritePixel(right , top , FIRST_TEXT_COLOR + 15);
1538 vesa_WritePixel(left , top + 1, FIRST_TEXT_COLOR + 15);
1539 vesa_WritePixel(right , top + 1, FIRST_TEXT_COLOR + 15);
1540 vesa_WritePixel(left , bottom - 1, FIRST_TEXT_COLOR + 15);
1541 vesa_WritePixel(right , bottom - 1, FIRST_TEXT_COLOR + 15);
1542 vesa_WritePixel(left , bottom , FIRST_TEXT_COLOR + 15);
1543 vesa_WritePixel(left + 1, bottom , FIRST_TEXT_COLOR + 15);
1544 vesa_WritePixel(right - 1, bottom , FIRST_TEXT_COLOR + 15);
1545 vesa_WritePixel(right , bottom , FIRST_TEXT_COLOR + 15);
1546 break;
1548 case CURSOR_UNDERLINE:
1549 for (x = left; x <= right; ++x) {
1550 vesa_WritePixel(x, bottom, FIRST_TEXT_COLOR + 15);
1552 break;
1554 case CURSOR_FRAME:
1556 /* fall through */
1558 default:
1559 for (x = left; x <= right; ++x) {
1560 vesa_WritePixel(x, top, FIRST_TEXT_COLOR + 15);
1562 for (y = top + 1; y <= bottom - 1; ++y) {
1563 vesa_WritePixel(left , y, FIRST_TEXT_COLOR + 15);
1564 vesa_WritePixel(right, y, FIRST_TEXT_COLOR + 15);
1566 for (x = left; x <= right; ++x) {
1567 vesa_WritePixel(x, bottom, FIRST_TEXT_COLOR + 15);
1569 break;
1571 #ifdef POSITIONBAR
1572 if (inmap)
1573 positionbar();
1574 #endif
1577 void
1578 vesa_HideCursor()
1580 unsigned x, y, left, top, width;
1581 boolean isrogue = Is_rogue_level(&u.uz);
1582 boolean halfwidth =
1583 (isrogue || iflags.over_view || iflags.traditional_view || !inmap);
1584 int curtyp;
1586 if (!cursor_type && inmap)
1587 return; /* CURSOR_INVIS - nothing to do */
1589 x = min(curcol, (CO - 1)); /* protection from callers */
1590 y = min(currow, (LI - 1)); /* protection from callers */
1591 if (!halfwidth && ((x < clipx) || (x > clipxmax)))
1592 return;
1593 if (inmap)
1594 x -= clipx;
1595 left = x * TILE_X; /* convert to pixels */
1596 top = y * TILE_Y;
1597 if (halfwidth) {
1598 left /= 2;
1599 width = TILE_X / 2;
1600 } else {
1601 width = TILE_X;
1603 left += vesa_x_center;
1604 top += vesa_y_center;
1606 for (y = 0; y < ROWS_PER_CELL; ++y) {
1607 for (x = 0; x < width; ++x) {
1608 vesa_WritePixel32(left + x, top + y, undercursor[y][x]);
1612 #endif /* SIMULATE_CURSOR */
1613 #endif /* SCREEN_VESA */