From 4aec98ce9ca8b5b2e09f5b653a910b48c51a7ed2 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 7 Mar 2016 08:36:24 -0500 Subject: [PATCH] missed a file MSDOS --- Files | 2 +- sys/msdos/vidvesa.c | 1613 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1614 insertions(+), 1 deletion(-) create mode 100644 sys/msdos/vidvesa.c diff --git a/Files b/Files index 959393d8e..322450292 100644 --- a/Files +++ b/Files @@ -120,7 +120,7 @@ Install.dos Makefile.BC Makefile.GCC Makefile.MSC moveinit.pat msdos.c msdoshlp.txt ovlinit.c pckeys.c pctiles.c pctiles.h pcvideo.h portio.h schema1.BC schema2.BC schema3.MSC SCHEMA35.MSC setup.bat sound.c tile2bin.c -video.c vidtxt.c vidvga.c +video.c vidtxt.c vidvesa.c vidvga.c (files for running MSDOS binary under Windows) nhico.uu nhpif.uu diff --git a/sys/msdos/vidvesa.c b/sys/msdos/vidvesa.c new file mode 100644 index 000000000..4f497ef9b --- /dev/null +++ b/sys/msdos/vidvesa.c @@ -0,0 +1,1613 @@ +/* Copyright (c) NetHack PC Development Team 1995 */ +/* VESA BIOS functions copyright (c) Ray Chason 2016 */ +/* NetHack may be freely redistributed. See license for details. */ +/* + * vidvesa.c - VGA Hardware video support with VESA BIOS Extensions + */ + +#include "hack.h" + +#ifdef SCREEN_VESA /* this file is for SCREEN_VESA only */ +#include + +#include "pcvideo.h" +#include "tile.h" +#include "pctiles.h" +#include "vesa.h" +#include "wintty.h" +#include "tileset.h" + +#define BACKGROUND_VESA_COLOR 1 +#define FIRST_TEXT_COLOR 240 + +static unsigned long FDECL(vesa_SetWindow, (int window, unsigned long offset)); +static unsigned long FDECL(vesa_ReadPixel32, (unsigned x, unsigned y)); +static void FDECL(vesa_WritePixel32, (unsigned x, unsigned y, + unsigned long color)); +static void FDECL(vesa_WritePixel, (unsigned x, unsigned y, unsigned color)); +static unsigned long FDECL(vesa_MakeColor, (unsigned r, unsigned g, unsigned b)); +static void FDECL(vesa_GetRGB, ( + unsigned long color, + unsigned char *rp, unsigned char *gp, unsigned char *bp)); +static void FDECL(vesa_FillRect, ( + unsigned left, unsigned top, + unsigned width, unsigned height, + unsigned color)); + +static void NDECL(vesa_redrawmap); +static void FDECL(vesa_cliparound, (int, int)); +static void FDECL(decal_packed, (const struct TileImage *tile, unsigned special)); +static void FDECL(vesa_SwitchMode, (unsigned mode)); +static boolean FDECL(vesa_SetPalette, (const struct Pixel *)); +static boolean FDECL(vesa_SetHardPalette, (const struct Pixel *)); +static boolean FDECL(vesa_SetSoftPalette, (const struct Pixel *)); +static void FDECL(vesa_DisplayCell, (const struct TileImage *tile, int, int)); +static void FDECL(vesa_DisplayCellInMemory, (const struct TileImage *tile, + int, char buf[TILE_Y][640*2])); +static unsigned FDECL(vesa_FindMode, (unsigned long mode_addr, unsigned bits)); +static void FDECL(vesa_WriteChar, (int, int, int, int, BOOLEAN_P)); +static void FDECL(vesa_WriteCharInMemory, (int, int, char buf[TILE_Y][640*2], + int)); +static void FDECL(vesa_WriteStr, (const char *, int, int, int, int)); +static char __far *NDECL(vesa_FontPtrs); + +#ifdef POSITIONBAR +static void NDECL(positionbar); +#endif + +extern int clipx, clipxmax; /* current clipping column from wintty.c */ +extern int curcol, currow; /* current column and row */ +extern int g_attribute; +extern int attrib_text_normal; /* text mode normal attribute */ +extern int attrib_gr_normal; /* graphics mode normal attribute */ +extern int attrib_gr_intense; /* graphics mode intense attribute */ +extern boolean inmap; /* in the map window */ +extern boolean restoring; + +/* + * Global Variables + */ + +static unsigned char __far *font; + +static struct map_struct { + int glyph; + int ch; + int attr; + unsigned special; +} map[ROWNO][COLNO]; /* track the glyphs */ + +#define vesa_clearmap() \ + { \ + int x, y; \ + for (y = 0; y < ROWNO; ++y) \ + for (x = 0; x < COLNO; ++x) { \ + map[y][x].glyph = cmap_to_glyph(S_stone); \ + map[y][x].ch = S_stone; \ + map[y][x].attr = 0; \ + map[y][x].special = 0; \ + } \ + } +#define TOP_MAP_ROW 1 + +static int viewport_size = 40; + +static const struct Pixel defpalette[] = { /* Colors for text and the position bar */ + { 0x18, 0x18, 0x18, 0xff }, /* CLR_BLACK */ + { 0xaa, 0x00, 0x00, 0xff }, /* CLR_RED */ + { 0x00, 0xaa, 0x00, 0xff }, /* CLR_GREEN */ + { 0x99, 0x40, 0x00, 0xff }, /* CLR_BROWN */ + { 0x00, 0x00, 0xaa, 0xff }, /* CLR_BLUE */ + { 0xaa, 0x00, 0xaa, 0xff }, /* CLR_MAGENTA */ + { 0x00, 0xaa, 0xaa, 0xff }, /* CLR_CYAN */ + { 0xaa, 0xaa, 0xaa, 0xff }, /* CLR_GRAY */ + { 0x55, 0x55, 0x55, 0xff }, /* NO_COLOR */ + { 0xff, 0x90, 0x00, 0xff }, /* CLR_ORANGE */ + { 0x00, 0xff, 0x00, 0xff }, /* CLR_BRIGHT_GREEN */ + { 0xff, 0xff, 0x00, 0xff }, /* CLR_YELLOW */ + { 0x00, 0x00, 0xff, 0xff }, /* CLR_BRIGHT_BLUE */ + { 0xff, 0x00, 0xff, 0xff }, /* CLR_BRIGHT_MAGENTA */ + { 0x00, 0xff, 0xff, 0xff }, /* CLR_BRIGHT_CYAN */ + { 0xff, 0xff, 0xff, 0xff } /* CLR_WHITE */ +}; + +/* Information about the selected VESA mode */ +static unsigned short vesa_mode = 0xFFFF; /* Mode number */ +static unsigned short vesa_x_res; /* X resolution */ +static unsigned short vesa_y_res; /* Y resolution */ +static unsigned short vesa_x_center; /* X centering offset */ +static unsigned short vesa_y_center; /* Y centering offset */ +static unsigned short vesa_scan_line; /* Bytes per scan line */ +static int vesa_read_win; /* Select the read window */ +static int vesa_write_win; /* Select the write window */ +static unsigned long vesa_win_pos[2]; /* Window position */ +static unsigned long vesa_win_addr[2]; /* Window physical address */ +static unsigned long vesa_win_size; /* Window size */ +static unsigned long vesa_win_gran; /* Window granularity */ +static unsigned char vesa_pixel_size; +static unsigned char vesa_pixel_bytes; +static unsigned char vesa_red_pos; +static unsigned char vesa_red_size; +static unsigned char vesa_green_pos; +static unsigned char vesa_green_size; +static unsigned char vesa_blue_pos; +static unsigned char vesa_blue_size; +static unsigned long vesa_palette[256]; + +struct OldModeInfo { + unsigned mode; + + unsigned short XResolution; /* horizontal resolution in pixels or characters */ + unsigned short YResolution; /* vertical resolution in pixels or characters */ + unsigned char BitsPerPixel; /* bits per pixel */ + unsigned char MemoryModel; /* memory model type */ +}; + +static const struct OldModeInfo old_mode_table[] = { + { 0x0101, 640, 480, 8, 4 }, + { 0x0103, 800, 600, 8, 4 }, + { 0x0105, 1024, 768, 8, 4 }, + { 0x0107, 1280, 1024, 8, 4 }, + { 0x0110, 640, 480, 15, 6 }, + { 0x0111, 640, 480, 16, 6 }, + { 0x0112, 640, 480, 24, 6 }, + { 0x0113, 800, 600, 15, 6 }, + { 0x0114, 800, 600, 16, 6 }, + { 0x0115, 800, 600, 24, 6 }, + { 0x0116, 1024, 768, 15, 6 }, + { 0x0117, 1024, 768, 16, 6 }, + { 0x0118, 1024, 768, 24, 6 }, + { 0x0119, 1280, 1024, 15, 6 }, + { 0x011A, 1280, 1024, 16, 6 }, + { 0x011B, 1280, 1024, 24, 6 }, +}; + +/* Retrieve the mode info block */ +static boolean +vesa_GetModeInfo(mode, info) +unsigned mode; +struct ModeInfoBlock *info; +{ + int mode_info_sel = -1; /* custodial */ + int mode_info_seg; + __dpmi_regs regs; + + mode_info_seg = __dpmi_allocate_dos_memory( + (sizeof(*info) + 15) / 16, + &mode_info_sel); + if (mode_info_seg < 0) goto error; + + memset(info, 0, sizeof(*info)); + dosmemput(info, sizeof(*info), mode_info_seg * 16L); + + memset(®s, 0, sizeof(regs)); + regs.x.ax = 0x4F01; + regs.x.cx = mode; + regs.x.di = 0; + regs.x.es = mode_info_seg; + (void) __dpmi_int(VIDEO_BIOS, ®s); + + if (regs.x.ax != 0x004F) goto error; + dosmemget(mode_info_seg * 16L, sizeof(*info), info); + if (!(info->ModeAttributes & 0x0001)) goto error; + + if (!(info->ModeAttributes & 0x0002)) { + /* Older VESA BIOS that did not return certain mode properties, but + that has fixed mode numbers; search the table to find the right + mode properties */ + + unsigned i; + + for (i = 0; i < SIZE(old_mode_table); ++i) { + if (mode == old_mode_table[i].mode) { + break; + } + } + if (i >= SIZE(old_mode_table)) goto error; + + info->XResolution = old_mode_table[i].XResolution; + info->YResolution = old_mode_table[i].YResolution; + info->NumberOfPlanes = 1; + info->BitsPerPixel = old_mode_table[i].BitsPerPixel; + info->NumberOfBanks = 1; + info->MemoryModel = old_mode_table[i].MemoryModel; + } + + __dpmi_free_dos_memory(mode_info_sel); + return TRUE; + +error: + if (mode_info_sel != -1) __dpmi_free_dos_memory(mode_info_sel); + return FALSE; +} + +/* Set the memory window and return the offset */ +static unsigned long +vesa_SetWindow(window, offset) +int window; +unsigned long offset; +{ + /* If the desired offset is already within the window, leave the window + as it is and return the address based on the current window position. + This minimizes the use of the window switch function. + + On the first call to the function, vesa_win_pos[window] == 0xFFFFFFFF, + the offset will always be less than this, and the BIOS will always be + called. */ + + unsigned long pos = vesa_win_pos[window]; + if (offset < pos || pos + vesa_win_size <= offset) { + __dpmi_regs regs; + + memset(®s, 0, sizeof(regs)); + regs.x.ax = 0x4F05; + regs.h.bh = 0x00; + regs.h.bl = window; + regs.x.dx = offset / vesa_win_gran; + pos = regs.x.dx * vesa_win_gran; + (void) __dpmi_int(VIDEO_BIOS, ®s); + vesa_win_pos[window] = pos; + } + + offset = offset - vesa_win_pos[window] + vesa_win_addr[window]; + /* Keep from crashing the system if some malfunction gives us a bad + offset */ + if (offset < 0xA0000 || offset > 0xBFFFF) { + vesa_SwitchMode(MODETEXT); + fprintf(stderr, "Abort: offset=%08lX\n", offset); + exit(1); + } + return offset; +} + +static unsigned long +vesa_ReadPixel32(x, y) +unsigned x, y; +{ + unsigned long offset = y * vesa_scan_line + x * vesa_pixel_bytes; + unsigned long addr, color; + unsigned i; + + switch (vesa_pixel_size) { + case 8: + addr = vesa_SetWindow(vesa_read_win, offset); + color = _farpeekb(_dos_ds, addr); + break; + + case 15: + case 16: + addr = vesa_SetWindow(vesa_read_win, offset); + color = _farpeekw(_dos_ds, addr); + break; + + case 24: + /* Pixel may cross a window boundary */ + color = 0; + for (i = 0; i < 3; ++i) { + addr = vesa_SetWindow(vesa_read_win, offset + i); + color |= (unsigned long) _farpeekb(_dos_ds, addr) << (i * 8); + } + break; + + case 32: + addr = vesa_SetWindow(vesa_read_win, offset); + color = _farpeekl(_dos_ds, addr); + break; + } + return color; +} + +static void +vesa_WritePixel32(x, y, color) +unsigned x, y; +unsigned long color; +{ + unsigned long offset = y * vesa_scan_line + x * vesa_pixel_bytes; + unsigned long addr; + unsigned i; + + switch (vesa_pixel_size) { + case 8: + addr = vesa_SetWindow(vesa_write_win, offset); + _farpokeb(_dos_ds, addr, color); + break; + + case 15: + case 16: + addr = vesa_SetWindow(vesa_write_win, offset); + _farpokew(_dos_ds, addr, color); + break; + + case 24: + /* Pixel may cross a window boundary */ + for (i = 0; i < 3; ++i) { + addr = vesa_SetWindow(vesa_read_win, offset + i); + _farpokeb(_dos_ds, addr, (unsigned char) (color >> (i * 8))); + } + break; + + case 32: + addr = vesa_SetWindow(vesa_write_win, offset); + _farpokel(_dos_ds, addr, color); + break; + } +} + +static void +vesa_WritePixel(x, y, color) +unsigned x, y; +unsigned color; +{ + if (vesa_pixel_size == 8) { + vesa_WritePixel32(x, y, color); + } else { + vesa_WritePixel32(x, y, vesa_palette[color & 0xFF]); + } +} + +static unsigned long +vesa_MakeColor(r, g, b) +unsigned r, g, b; +{ + r = (r & 0xFF) >> (8 - vesa_red_size); + g = (g & 0xFF) >> (8 - vesa_green_size); + b = (b & 0xFF) >> (8 - vesa_blue_size); + return ((unsigned long) r << vesa_red_pos) + | ((unsigned long) g << vesa_green_pos) + | ((unsigned long) b << vesa_blue_pos); +} + +static void +vesa_GetRGB(color, rp, gp, bp) +unsigned long color; +unsigned char *rp, *gp, *bp; +{ + unsigned r, g, b; + + r = color >> vesa_red_pos; + g = color >> vesa_green_pos; + b = color >> vesa_blue_pos; + r <<= 8 - vesa_red_size; + g <<= 8 - vesa_green_size; + b <<= 8 - vesa_blue_size; + *rp = (unsigned char) r; + *gp = (unsigned char) g; + *bp = (unsigned char) b; +} + +static void +vesa_FillRect(left, top, width, height, color) +unsigned left, top, width, height, color; +{ + unsigned x, y; + + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + vesa_WritePixel(left + x, top + y, color); + } + } +} + +void +vesa_get_scr_size() +{ + CO = 80; + LI = 29; +} + +void +vesa_backsp() +{ + int col, row; + + col = curcol; /* Character cell row and column */ + row = currow; + + if (col > 0) + col = col - 1; + vesa_gotoloc(col, row); +} + +void +vesa_clear_screen(colour) +int colour; +{ + vesa_FillRect(0, 0, vesa_x_res, vesa_y_res, colour); + if (iflags.tile_view) + vesa_clearmap(); + vesa_gotoloc(0, 0); /* is this needed? */ +} + +/* clear to end of line */ +void +vesa_cl_end(col, row) +int col, row; +{ + unsigned left = vesa_x_center + col * 8; + unsigned top = vesa_y_center + row * 16; + unsigned width = (CO - 1 - col) * 8; + unsigned height = 16; + + vesa_FillRect(left, top, width, height, BACKGROUND_VESA_COLOR); +} + +/* clear to end of screen */ +void +vesa_cl_eos(cy) +int cy; +{ + int count; + + cl_end(); + if (cy < LI - 1) { + unsigned left = vesa_x_center; + unsigned top = vesa_y_center + cy * 16; + unsigned width = 640; + unsigned height = (LI - 1 - cy) * 16; + + vesa_FillRect(left, top, width, height, BACKGROUND_VESA_COLOR); + } +} + +void +vesa_tty_end_screen() +{ + vesa_clear_screen(BACKGROUND_VESA_COLOR); + vesa_SwitchMode(MODETEXT); +} + +void +vesa_tty_startup(wid, hgt) +int *wid, *hgt; +{ + /* code to sense display adapter is required here - MJA */ + + vesa_get_scr_size(); + if (CO && LI) { + *wid = CO; + *hgt = LI; + } + + attrib_gr_normal = ATTRIB_VGA_NORMAL; + attrib_gr_intense = ATTRIB_VGA_INTENSE; + g_attribute = attrib_gr_normal; /* Give it a starting value */ +} + +/* + * Screen output routines (these are heavily used). + * + * These are the 3 routines used to place information on the screen + * in the VGA PC tty port of NetHack. These are the routines + * that get called by the general interface routines in video.c. + * + * vesa_xputs -Writes a c null terminated string at the current location. + * + * vesa_xputc -Writes a single character at the current location. Since + * various places in the code assume that control characters + * can be used to control, we are forced to interpret some of + * the more common ones, in order to keep things looking correct. + * + * vesa_xputg -This routine is used to display a graphical representation of a + * NetHack glyph (a tile) at the current location. For more + * information on NetHack glyphs refer to the comments in + * include/display.h. + * + */ + +void +vesa_xputs(s, col, row) +const char *s; +int col, row; +{ + if (s != NULL) { + vesa_WriteStr(s, strlen(s), col, row, g_attribute); + } +} + +/* write out character (and attribute) */ +void +vesa_xputc(ch, attr) +char ch; +int attr; +{ + int col, row; + + col = curcol; + row = currow; + + switch (ch) { + case '\n': + col = 0; + ++row; + break; + default: + vesa_WriteChar((unsigned char) ch, col, row, attr, FALSE); + if (col < (CO - 1)) + ++col; + break; + } /* end switch */ + vesa_gotoloc(col, row); +} + +#if defined(USE_TILES) +/* Place tile represent. a glyph at current location */ +void +vesa_xputg(glyphnum, ch, + special) +int glyphnum; +int ch; +unsigned special; /* special feature: corpse, invis, detected, pet, ridden - + hack.h */ +{ + int col, row; + int attr; + int ry; + const struct TileImage *packcell; + + row = currow; + col = curcol; + if ((col < 0 || col >= COLNO) + || (row < TOP_MAP_ROW || row >= (ROWNO + TOP_MAP_ROW))) + return; + ry = row - TOP_MAP_ROW; + map[ry][col].glyph = glyphnum; + map[ry][col].ch = ch; + map[ry][col].special = special; + attr = (g_attribute == 0) ? attrib_gr_normal : g_attribute; + map[ry][col].attr = attr; + if (iflags.traditional_view) { + vesa_WriteChar((unsigned char) ch, col, row, attr, FALSE); + } else { + if ((col >= clipx) && (col <= clipxmax)) { + packcell = get_tile(glyph2tile[glyphnum]); + if (!iflags.over_view && map[ry][col].special) + decal_packed(packcell, special); + vesa_DisplayCell(packcell, col - clipx, row); + } + } + if (col < (CO - 1)) + ++col; + vesa_gotoloc(col, row); +} +#endif /* USE_TILES */ + +/* + * Cursor location manipulation, and location information fetching + * routines. + * These include: + * + * vesa_gotoloc(x,y) - Moves the "cursor" on screen to the specified x + * and y character cell location. This routine + * determines the location where screen writes + * will occur next, it does not change the location + * of the player on the NetHack level. + */ + +void +vesa_gotoloc(col, row) +int col, row; +{ + curcol = min(col, CO - 1); /* protection from callers */ + currow = min(row, LI - 1); +} + +#if defined(USE_TILES) && defined(CLIPPING) +static void +vesa_cliparound(x, y) +int x, y; +{ + int oldx = clipx; + + if (!iflags.tile_view || iflags.over_view || iflags.traditional_view) + return; + + if (x < clipx + 5) { + clipx = max(0, x - (viewport_size / 2)); + clipxmax = clipx + (viewport_size - 1); + } else if (x > clipxmax - 5) { + clipxmax = min(COLNO - 1, x + (viewport_size / 2)); + clipx = clipxmax - (viewport_size - 1); + } + if (clipx != oldx) { + if (on_level(&u.uz0, &u.uz) && !restoring) + /* (void) doredraw(); */ + vesa_redrawmap(); + } +} + +static void +vesa_redrawmap() +{ + int x, y, t; + const struct TileImage *packcell; + + /* y here is in screen rows*/ + /* Build each row in local memory, then write, to minimize use of the + window switch function */ + for (y = 0; y < ROWNO; ++y) { + char buf[TILE_Y][640*2]; + + for (x = clipx; x <= clipxmax; ++x) { + if (iflags.traditional_view) { + vesa_WriteCharInMemory((unsigned char) map[y][x].ch, x, + buf, map[y][x].attr); + } else { + t = map[y][x].glyph; + packcell = get_tile(glyph2tile[t]); + if (!iflags.over_view && map[y][x].special) + decal_packed(packcell, map[y][x].special); + vesa_DisplayCellInMemory(packcell, x - clipx, buf); + } + } + if (iflags.over_view && vesa_pixel_size != 8) { + for (t = 0; t < TILE_Y; ++t) { + for (x = 0; x < 640; ++x) { + unsigned long c1 = vesa_palette[buf[t][x * 2 + 0]]; + unsigned long c2 = vesa_palette[buf[t][x * 2 + 1]]; + unsigned char r1, r2, g1, g2, b1, b2; + + vesa_GetRGB(c1, &r1, &g1, &b1); + vesa_GetRGB(c2, &r2, &g2, &b2); + r1 = (r1 + r2) / 2; + g1 = (g1 + g2) / 2; + b1 = (b1 + b2) / 2; + vesa_WritePixel32(x, (y + TOP_MAP_ROW) * TILE_Y + t, + vesa_MakeColor(r1, g1, b1)); + } + } + } else { + for (t = 0; t < TILE_Y; ++t) { + for (x = 0; x < 640; ++x) { + vesa_WritePixel(x, (y + TOP_MAP_ROW) * TILE_Y + t, buf[t][x]); + } + } + } + } +} +#endif /* USE_TILES && CLIPPING */ + +void +vesa_userpan(left) +boolean left; +{ + int x; + + /* pline("Into userpan"); */ + if (iflags.over_view || iflags.traditional_view) + return; + if (left) + x = min(COLNO - 1, clipxmax + 10); + else + x = max(0, clipx - 10); + vesa_cliparound(x, 10); /* y value is irrelevant on VGA clipping */ + positionbar(); + vesa_DrawCursor(); +} + +void +vesa_overview(on) +boolean on; +{ + /* vesa_HideCursor(); */ + if (on) { + iflags.over_view = TRUE; + clipx = 0; + clipxmax = CO - 1; + } else { + iflags.over_view = FALSE; + clipx = max(0, (curcol - viewport_size / 2)); + if (clipx > ((CO - 1) - viewport_size)) + clipx = (CO - 1) - viewport_size; + clipxmax = clipx + (viewport_size - 1); + } +} + +void +vesa_traditional(on) +boolean on; +{ + /* vesa_HideCursor(); */ + if (on) { + /* switch_symbols(FALSE); */ + iflags.traditional_view = TRUE; + clipx = 0; + clipxmax = CO - 1; + } else { + iflags.traditional_view = FALSE; + if (!iflags.over_view) { + clipx = max(0, (curcol - viewport_size / 2)); + if (clipx > ((CO - 1) - viewport_size)) + clipx = (CO - 1) - viewport_size; + clipxmax = clipx + (viewport_size - 1); + } + } +} + +void +vesa_refresh() +{ + positionbar(); + vesa_redrawmap(); + vesa_DrawCursor(); +} + +static void +decal_packed(gp, special) +const struct TileImage *gp; +unsigned special; +{ + /* FIXME: the tile array is fixed in memory and should not be changed; + if we ever implement this, we'll have to copy the pixels */ + if (special & MG_CORPSE) { + } else if (special & MG_INVIS) { + } else if (special & MG_DETECT) { + } else if (special & MG_PET) { + } else if (special & MG_RIDDEN) { + } +} + +/* + * Open tile files, + * initialize the SCREEN, switch it to graphics mode, + * initialize the pointers to the fonts, clear + * the screen. + * + */ +void +vesa_Init(void) +{ + const struct Pixel *paletteptr; +#ifdef USE_TILES + const char *tile_file; + int tilefailure = 0; + /* + * Attempt to open the required tile files. If we can't + * don't perform the video mode switch, use TTY code instead. + * + */ + tile_file = iflags.wc_tile_file; + if (tile_file == NULL || tile_file == '\0') { + tile_file = "nhtiles.bmp"; + } + if (!read_tiles(tile_file, FALSE)) + tilefailure |= 1; + if (get_palette() == NULL) + tilefailure |= 4; + + if (tilefailure) { + raw_printf("Reverting to TTY mode, tile initialization failure (%d).", + tilefailure); + wait_synch(); + iflags.usevga = 0; + iflags.tile_view = FALSE; + iflags.over_view = FALSE; + CO = 80; + LI = 25; + /* clear_screen() */ /* not vesa_clear_screen() */ + return; + } +#endif + + if (vesa_mode == 0xFFFF) { + vesa_detect(); + } + vesa_SwitchMode(vesa_mode); + windowprocs.win_cliparound = vesa_cliparound; +#ifdef USE_TILES + paletteptr = get_palette(); + iflags.tile_view = TRUE; + iflags.over_view = FALSE; +#else + paletteptr = defpalette; +#endif + vesa_SetPalette(paletteptr); + g_attribute = attrib_gr_normal; + font = vesa_FontPtrs(); + clear_screen(); + clipx = 0; + clipxmax = clipx + (viewport_size - 1); +} + +/* + * Switches modes of the video card. + * + * If mode == MODETEXT (0x03), then the card is placed into text + * mode. Otherwise, the card is placed in the mode selected by + * vesa_detect. Supported modes are those with packed 8 bit pixels. + * + */ +static void +vesa_SwitchMode(mode) +unsigned mode; +{ + __dpmi_regs regs; + + if (mode == MODETEXT) { + iflags.grmode = 0; + regs.x.ax = mode; + (void) __dpmi_int(VIDEO_BIOS, ®s); + } else if (mode >= 0x100) { + iflags.grmode = 1; + regs.x.ax = 0x4F02; + regs.x.bx = mode & 0x81FF; + (void) __dpmi_int(VIDEO_BIOS, ®s); + /* Record that the window position is unknown */ + vesa_win_pos[0] = 0xFFFFFFFF; + vesa_win_pos[1] = 0xFFFFFFFF; + } else { + iflags.grmode = 0; /* force text mode for error msg */ + regs.x.ax = MODETEXT; + (void) __dpmi_int(VIDEO_BIOS, ®s); + g_attribute = attrib_text_normal; + impossible("vesa_SwitchMode: Bad video mode requested 0x%X", mode); + } +} + +/* + * This allows grouping of several tasks to be done when + * switching back to text mode. This is a public (extern) function. + * + */ +void +vesa_Finish(void) +{ + free_tiles(); + vesa_SwitchMode(MODETEXT); + windowprocs.win_cliparound = tty_cliparound; + g_attribute = attrib_text_normal; + iflags.tile_view = FALSE; +} + +/* + * + * Returns a far pointer (or flat 32 bit pointer under djgpp) to the + * location of the appropriate ROM font for the _current_ video mode + * (so you must place the card into the desired video mode before + * calling this function). + * + * This function takes advantage of the video BIOS loading the + * address of the appropriate character definition table for + * the current graphics mode into interrupt vector 0x43 (0000:010C). + */ +static char __far * +vesa_FontPtrs(void) +{ + USHORT __far *tmp; + char __far *retval; + USHORT fseg, foff; + tmp = (USHORT __far *) MK_PTR(((USHORT) FONT_PTR_SEGMENT), + ((USHORT) FONT_PTR_OFFSET)); + foff = READ_ABSOLUTE_WORD(tmp); + ++tmp; + fseg = READ_ABSOLUTE_WORD(tmp); + retval = (char __far *) MK_PTR(fseg, foff); + return retval; +} + +/* + * This will verify the existance of a VGA adapter on the machine. + * Video function call 0x4F00 returns 0x004F in AX if successful, and + * returns a VbeInfoBlock describing the features of the VESA BIOS. + */ +int +vesa_detect() +{ + int vbe_info_sel = -1; /* custodial */ + int vbe_info_seg; + struct VbeInfoBlock vbe_info; + __dpmi_regs regs; + unsigned long mode_addr; + struct ModeInfoBlock mode_info; + + vbe_info_seg = __dpmi_allocate_dos_memory( + (sizeof(vbe_info) + 15) / 16, + &vbe_info_sel); + if (vbe_info_seg < 0) goto error; + + /* Request VBE 2.0 information if it is available */ + memset(&vbe_info, 0, sizeof(vbe_info)); + memcpy(vbe_info.VbeSignature, "VBE2", 4); + dosmemput(&vbe_info, sizeof(vbe_info), vbe_info_seg * 16L); + + /* Request VESA BIOS information */ + regs.x.ax = 0x4F00; + regs.x.di = 0; + regs.x.es = vbe_info_seg; + (void) __dpmi_int(VIDEO_BIOS, ®s); + + /* Check for successful completion of function: is VESA BIOS present? */ + if (regs.x.ax != 0x004F) goto error; + dosmemget(vbe_info_seg * 16L, sizeof(vbe_info), &vbe_info); + if (memcmp(vbe_info.VbeSignature, "VESA", 4) != 0) goto error; + + /* Get the address of the mode list */ + /* The mode list may be within the DOS memory area allocated above. + That area must remain allocated and must not be rewritten until + we're done here. */ + mode_addr = (vbe_info.VideoModePtr >> 16) * 16L + + (vbe_info.VideoModePtr & 0xFFFF); + + /* Scan the mode list for an acceptable mode */ + vesa_mode = vesa_FindMode(mode_addr, 32); + if (vesa_mode == 0xFFFF) + vesa_mode = vesa_FindMode(mode_addr, 24); + if (vesa_mode == 0xFFFF) + vesa_mode = vesa_FindMode(mode_addr, 16); + if (vesa_mode == 0xFFFF) + vesa_mode = vesa_FindMode(mode_addr, 15); + if (vesa_mode == 0xFFFF) + vesa_mode = vesa_FindMode(mode_addr, 8); + if (vesa_mode == 0xFFFF) + goto error; + + /* Set up the variables for the pixel functions */ + vesa_GetModeInfo(vesa_mode, &mode_info); + vesa_x_res = mode_info.XResolution; + vesa_y_res = mode_info.YResolution; + vesa_x_center = (vesa_x_res - 640) / 2; + vesa_y_center = (vesa_y_res - 480) / 2; + vesa_scan_line = mode_info.BytesPerScanLine; + vesa_win_size = mode_info.WinSize * 1024L; + vesa_win_gran = mode_info.WinGranularity * 1024L; + vesa_pixel_size = mode_info.BitsPerPixel; + vesa_pixel_bytes = (vesa_pixel_size + 7) / 8; + if (vbe_info.VbeVersion >= 0x0300) { + vesa_red_pos = mode_info.RedFieldPosition; + vesa_red_size = mode_info.RedMaskSize; + vesa_green_pos = mode_info.GreenFieldPosition; + vesa_green_size = mode_info.GreenMaskSize; + vesa_blue_pos = mode_info.BlueFieldPosition; + vesa_blue_size = mode_info.BlueMaskSize; + } else { + switch (vesa_pixel_size) { + case 15: + vesa_blue_pos = 0; + vesa_blue_size = 5; + vesa_green_pos = 5; + vesa_green_size = 5; + vesa_red_pos = 10; + vesa_red_size = 5; + break; + + case 16: + vesa_blue_pos = 0; + vesa_blue_size = 5; + vesa_green_pos = 5; + vesa_green_size = 6; + vesa_red_pos = 11; + vesa_red_size = 5; + break; + + case 24: + case 32: + vesa_blue_pos = 0; + vesa_blue_size = 8; + vesa_green_pos = 8; + vesa_green_size = 8; + vesa_red_pos = 16; + vesa_red_size = 8; + break; + } + } + vesa_win_addr[0] = mode_info.WinASegment * 16L; + vesa_win_addr[1] = mode_info.WinBSegment * 16L; + vesa_win_pos[0] = 0xFFFFFFFF; /* position unknown */ + vesa_win_pos[1] = 0xFFFFFFFF; + /* Read window */ + if (mode_info.WinAAttributes & 0x2) { + vesa_read_win = 0; + } else if (mode_info.WinBAttributes & 0x2) { + vesa_read_win = 1; + } else { + goto error; /* Shouldn't happen */ + } + /* Write window */ + if (mode_info.WinAAttributes & 0x4) { + vesa_write_win = 0; + } else if (mode_info.WinBAttributes & 0x4) { + vesa_write_win = 1; + } else { + goto error; /* Shouldn't happen */ + } + + __dpmi_free_dos_memory(vbe_info_sel); + return TRUE; + +error: + if (vbe_info_sel != -1) __dpmi_free_dos_memory(vbe_info_sel); + return FALSE; +} + +static unsigned +vesa_FindMode(mode_addr, bits) +unsigned long mode_addr; +unsigned bits; +{ + unsigned selected_mode; + struct ModeInfoBlock mode_info0, mode_info; + unsigned model = (bits == 8) ? 4 : 6; + + memset(&mode_info, 0, sizeof(mode_info)); + selected_mode = 0xFFFF; + while (1) { + unsigned mode = _farpeekw(_dos_ds, mode_addr); + if (mode == 0xFFFF) break; + mode_addr += 2; + + /* Query the mode info; skip to next if not in fact supported */ + if (!vesa_GetModeInfo(mode, &mode_info0)) continue; + + /* Check that the mode is acceptable */ + if (mode_info0.XResolution < 640) continue; + if (mode_info0.YResolution < 480) continue; + if (mode_info0.NumberOfPlanes != 1) continue; + if (mode_info0.BitsPerPixel != bits) continue; + if (mode_info0.NumberOfBanks != 1) continue; + if (mode_info0.MemoryModel != model) continue; + if (mode_info0.ModeAttributes & 0x40) continue; + + /* The mode is OK. Accept it if it is smaller than any previous mode + or if no previous mode is accepted. */ + if (selected_mode == 0xFFFF + || mode_info0.XResolution * mode_info0.YResolution + < mode_info.XResolution * mode_info.YResolution) { + selected_mode = mode; + mode_info = mode_info0; + } + } + + return selected_mode; +} + +/* + * Write character 'ch', at (x,y) and + * do it using the colour 'colour'. + * + */ +static void +vesa_WriteChar(chr, col, row, colour, transparent) +int chr, col, row, colour; +boolean transparent; +{ + int i, j; + int pixx, pixy; + + unsigned char __far *fp = font; + unsigned char fnt; + + pixx = min(col, (CO - 1)) * 8; /* min() protects from callers */ + pixy = min(row, (LI - 1)) * 16; /* assumes 8 x 16 char set */ + pixx += vesa_x_center; + pixy += vesa_y_center; + + for (i = 0; i < MAX_ROWS_PER_CELL; ++i) { + fnt = READ_ABSOLUTE((fp + chr * 16 + i)); + for (j = 0; j < 8; ++j) { + if (fnt & (0x80 >> j)) { + vesa_WritePixel(pixx + j, pixy + i, colour + FIRST_TEXT_COLOR); + } else if (!transparent) { + vesa_WritePixel(pixx + j, pixy + i, BACKGROUND_VESA_COLOR); + } + } + } +} + +/* + * Like vesa_WriteChar, but draw the character in local memory rather than in + * the VGA frame buffer. + * + * vesa_redrawmap uses this to gather a row of cells in local memory and then + * draw them in strict row-major order, minimizing the use of the VESA + * windowing function. + * + */ +static void +vesa_WriteCharInMemory(chr, col, buf, colour) +int chr, col; +char buf[TILE_Y][640*2]; +int colour; +{ + int i, j; + int pixx; + + unsigned char __far *fp = font; + unsigned char fnt; + + pixx = min(col, (CO - 1)) * 8; /* min() protects from callers */ + + for (i = 0; i < MAX_ROWS_PER_CELL; ++i) { + fnt = READ_ABSOLUTE((fp + chr * 16 + i)); + for (j = 0; j < 8; ++j) { + if (fnt & (0x80 >> j)) { + buf[i][pixx + j] = colour + FIRST_TEXT_COLOR; + } else { + buf[i][pixx + j] = BACKGROUND_VESA_COLOR; + } + } + } +} + +/* + * This is the routine that displays a high-res "cell" pointed to by 'gp' + * at the desired location (col,row). + * + * Note: (col,row) in this case refer to the coordinate location in + * NetHack character grid terms, (ie. the 40 x 25 character grid), + * not the x,y pixel location. + * + */ +static void +vesa_DisplayCell(tile, col, row) +const struct TileImage *tile; +int col, row; +{ + int i, j, pixx, pixy; + + pixx = col * TILE_X; + pixy = row * TILE_Y; + if (iflags.over_view) { + pixx /= 2; + pixx += vesa_x_center; + pixy += vesa_y_center; + if (vesa_pixel_size != 8) { + for (i = 0; i < TILE_Y; ++i) { + for (j = 0; j < TILE_X; j += 2) { + unsigned index = i * tile->width + j; + unsigned long c1 = vesa_palette[tile->indexes[index + 0]]; + unsigned long c2 = vesa_palette[tile->indexes[index + 1]]; + unsigned char r1, r2, g1, g2, b1, b2; + + vesa_GetRGB(c1, &r1, &g1, &b1); + vesa_GetRGB(c2, &r2, &g2, &b2); + r1 = (r1 + r2) / 2; + g1 = (g1 + g2) / 2; + b1 = (b1 + b2) / 2; + vesa_WritePixel32(pixx + j / 2, pixy + i, + vesa_MakeColor(r1, g1, b1)); + } + } + } else { + for (i = 0; i < TILE_Y; ++i) { + for (j = 0; j < TILE_X; j += 2) { + unsigned index = i * tile->width + j; + vesa_WritePixel(pixx + j / 2, pixy + i, tile->indexes[index]); + } + } + } + } else { + pixx += vesa_x_center; + pixy += vesa_y_center; + for (i = 0; i < TILE_Y; ++i) { + for (j = 0; j < TILE_X; ++j) { + unsigned index = i * tile->width + j; + vesa_WritePixel(pixx + j, pixy + i, tile->indexes[index]); + } + } + } +} + +/* + * Like vesa_DisplayCell, but draw the tile in local memory rather than in + * the VGA frame buffer. + * + * vesa_redrawmap uses this to gather a row of cells in local memory and then + * draw them in strict row-major order, minimizing the use of the VESA + * windowing function. + * + */ +static void +vesa_DisplayCellInMemory(tile, col, buf) +const struct TileImage *tile; +int col; +char buf[TILE_Y][640*2]; +{ + int i, j, pixx; + + pixx = col * TILE_X; + if (iflags.over_view && vesa_pixel_size == 8) { + pixx /= 2; + for (i = 0; i < TILE_Y; ++i) { + for (j = 0; j < TILE_X; j += 2) { + unsigned index = i * tile->width + j; + buf[i][pixx + j / 2] = tile->indexes[index]; + } + } + } else { + for (i = 0; i < TILE_Y; ++i) { + for (j = 0; j < TILE_X; ++j) { + unsigned index = i * tile->width + j; + buf[i][pixx + j] = tile->indexes[index]; + } + } + } +} + +/* + * Write the character string pointed to by 's', whose maximum length + * is 'len' at location (x,y) using the 'colour' colour. + * + */ +static void +vesa_WriteStr(s, len, col, row, colour) +const char *s; +int len, col, row, colour; +{ + const unsigned char *us; + int i = 0; + + /* protection from callers */ + if (row > (LI - 1)) + return; + + i = 0; + us = (const unsigned char *) s; + while ((*us != 0) && (i < len) && (col < (CO - 1))) { + vesa_WriteChar(*us, col, row, colour, FALSE); + ++us; + ++i; + ++col; + } +} + +/* + * Initialize the VGA palette with the desired colours. This + * must be a series of 720 bytes for use with a card in 256 + * colour mode at 640 x 480. The first 240 palette entries are + * used by the tile set; the last 16 are reserved for text. + * + */ +static boolean +vesa_SetPalette(palette) +const struct Pixel *palette; +{ + if (vesa_pixel_size == 8) { + vesa_SetHardPalette(palette); + } else { + vesa_SetSoftPalette(palette); + } +} + +static boolean +vesa_SetHardPalette(palette) +const struct Pixel *palette; +{ + const struct Pixel *p = palette; + int palette_sel = -1; /* custodial */ + int palette_seg; + unsigned long palette_ptr; + unsigned i, shift; + unsigned char r, g, b; + unsigned long color; + __dpmi_regs regs; + + palette_seg = __dpmi_allocate_dos_memory( 1024 / 16, &palette_sel); + if (palette_seg < 0) goto error; + + /* Use 8 bit DACs if we have them */ + memset(®s, 0, sizeof(regs)); + regs.x.ax = 0x4F08; + regs.h.bl = 0; + regs.h.bh = 8; + (void) __dpmi_int(VIDEO_BIOS, ®s); + if (regs.x.ax != 0x004F) { + shift = 2; + } else if (regs.h.bh > 8) { + shift = 0; + } else { + shift = 8 - regs.h.bh; + } + + /* Set the tile set and text colors */ + palette_ptr = palette_seg * 16L; +#ifdef USE_TILES + for (i = 0; i < FIRST_TEXT_COLOR; ++i) { + r = p->r >> shift; + g = p->g >> shift; + b = p->b >> shift; + color = ((unsigned long) r << 16) + | ((unsigned long) g << 8) + | ((unsigned long) b << 0); + _farpokel(_dos_ds, palette_ptr, color); + palette_ptr += 4; + ++p; + } +#else + palette_ptr += FIRST_TEXT_COLOR * 4; +#endif + p = defpalette; + for (i = FIRST_TEXT_COLOR; i < 256; ++i) { + r = p->r >> shift; + g = p->g >> shift; + b = p->b >> shift; + color = ((unsigned long) r << 16) + | ((unsigned long) g << 8) + | ((unsigned long) b << 0); + _farpokel(_dos_ds, palette_ptr, color); + palette_ptr += 4; + ++p; + } + + memset(®s, 0, sizeof(regs)); + regs.x.ax = 0x4F09; + regs.h.bl = 0; + regs.x.cx = 256; + regs.x.dx = 0; + regs.x.di = 0; + regs.x.es = palette_seg; + (void) __dpmi_int(VIDEO_BIOS, ®s); + + __dpmi_free_dos_memory(palette_sel); + return TRUE; + +error: + if (palette_sel != -1) __dpmi_free_dos_memory(palette_sel); + return FALSE; +} + +static boolean +vesa_SetSoftPalette(palette) +const struct Pixel *palette; +{ + const struct Pixel *p; + unsigned i; + unsigned char r, g, b; + + /* Set the tile set and text colors */ +#ifdef USE_TILES + p = palette; + for (i = 0; i < FIRST_TEXT_COLOR; ++i) { + r = p->r; + g = p->g; + b = p->b; + vesa_palette[i] = vesa_MakeColor(r, g, b); + ++p; + } +#endif + p = defpalette; + for (i = FIRST_TEXT_COLOR; i < 256; ++i) { + r = p->r; + g = p->g; + b = p->b; + vesa_palette[i] = vesa_MakeColor(r, g, b); + ++p; + } +} + +#ifdef POSITIONBAR + +#define PBAR_ROW (LI - 4) +#define PBAR_COLOR_ON 16 /* slate grey background colour of tiles */ +#define PBAR_COLOR_OFF 0 /* bluish grey, used in old style only */ +#define PBAR_COLOR_STAIRS CLR_BROWN /* brown */ +#define PBAR_COLOR_HERO CLR_WHITE /* creamy white */ + +static unsigned char pbar[COLNO]; + +void +vesa_update_positionbar(posbar) +char *posbar; +{ + char *p = pbar; + if (posbar) + while (*posbar) + *p++ = *posbar++; + *p = 0; +} + +static void +positionbar() +{ + char *posbar = pbar; + int feature, ucol; + int k, x, y, colour, row; + + int startk, stopk; + boolean nowhere = FALSE; + int pixy = (PBAR_ROW * MAX_ROWS_PER_CELL); + int tmp; + + if (!iflags.grmode || !iflags.tile_view) + return; + if ((clipx < 0) || (clipxmax <= 0) || (clipx >= clipxmax)) + nowhere = TRUE; + if (nowhere) { +#ifdef DEBUG + pline("Would have put bar using %d - %d.", clipx, clipxmax); +#endif + return; + } +#ifdef OLD_STYLE + for (y = pixy; y < (pixy + MAX_ROWS_PER_CELL); ++y) { + for (x = 0; x < 640; ++x) { + k = x / 8; + if ((k < clipx) || (k > clipxmax)) { + colour = PBAR_COLOR_OFF; + } else + colour = PBAR_COLOR_ON; + vesa_WritePixel(x + vesa_x_center, y + vesa_y_center, colour); + } + } +#else + for (y = pixy, row = 0; y < (pixy + MAX_ROWS_PER_CELL); ++y, ++row) { + if ((!row) || (row == (ROWS_PER_CELL - 1))) { + startk = 0; + stopk = SCREENBYTES; + } else { + startk = clipx; + stopk = clipxmax; + } + for (x = 0; x < 640; ++x) { + k = x / 8; + if ((k < startk) || (k > stopk)) + colour = BACKGROUND_VGA_COLOR; + else + colour = PBAR_COLOR_ON; + vesa_WritePixel(x + vesa_x_center, y + vesa_y_center, colour); + } + } +#endif + ucol = 0; + if (posbar) { + while (*posbar != 0) { + feature = *posbar++; + switch (feature) { + case '>': + vesa_WriteChar(feature, (int) *posbar++, PBAR_ROW, PBAR_COLOR_STAIRS, TRUE); + break; + case '<': + vesa_WriteChar(feature, (int) *posbar++, PBAR_ROW, PBAR_COLOR_STAIRS, TRUE); + break; + case '@': + ucol = (int) *posbar++; + vesa_WriteChar(feature, ucol, PBAR_ROW, PBAR_COLOR_HERO, TRUE); + break; + default: /* unanticipated symbols */ + vesa_WriteChar(feature, (int) *posbar++, PBAR_ROW, PBAR_COLOR_STAIRS, TRUE); + break; + } + } + } +#ifdef SIMULATE_CURSOR + if (inmap) { + tmp = curcol + 1; + if ((tmp != ucol) && (curcol >= 0)) + vesa_WriteChar('_', tmp, PBAR_ROW, PBAR_COLOR_HERO, TRUE); + } +#endif +} + +#endif /*POSITIONBAR*/ + +#ifdef SIMULATE_CURSOR + +static unsigned long undercursor[TILE_Y][TILE_X]; + +void +vesa_DrawCursor() +{ + unsigned x, y, left, top, right, bottom, width; + boolean isrogue = Is_rogue_level(&u.uz); + boolean halfwidth = + (isrogue || iflags.over_view || iflags.traditional_view || !inmap); + int curtyp; + + if (!cursor_type && inmap) + return; /* CURSOR_INVIS - nothing to do */ + + x = min(curcol, (CO - 1)); /* protection from callers */ + y = min(currow, (LI - 1)); /* protection from callers */ + if (!halfwidth && ((x < clipx) || (x > clipxmax))) + return; + if (inmap) + x -= clipx; + left = x * TILE_X; /* convert to pixels */ + top = y * TILE_Y; + if (halfwidth) { + left /= 2; + width = TILE_X / 2; + } else { + width = TILE_X; + } + left += vesa_x_center; + top += vesa_y_center; + right = left + width - 1; + bottom = top + TILE_Y - 1; + + for (y = 0; y < ROWS_PER_CELL; ++y) { + for (x = 0; x < width; ++x) { + undercursor[y][x] = vesa_ReadPixel32(left + x, top + y); + } + } + + /* + * Now we have a snapshot of the current cell. + * Write the cursor on top of the display. + */ + + if (inmap) + curtyp = cursor_type; + else + curtyp = CURSOR_UNDERLINE; + + switch (curtyp) { + case CURSOR_CORNER: + vesa_WritePixel(left , top , FIRST_TEXT_COLOR + 15); + vesa_WritePixel(left + 1, top , FIRST_TEXT_COLOR + 15); + vesa_WritePixel(right - 1, top , FIRST_TEXT_COLOR + 15); + vesa_WritePixel(right , top , FIRST_TEXT_COLOR + 15); + vesa_WritePixel(left , top + 1, FIRST_TEXT_COLOR + 15); + vesa_WritePixel(right , top + 1, FIRST_TEXT_COLOR + 15); + vesa_WritePixel(left , bottom - 1, FIRST_TEXT_COLOR + 15); + vesa_WritePixel(right , bottom - 1, FIRST_TEXT_COLOR + 15); + vesa_WritePixel(left , bottom , FIRST_TEXT_COLOR + 15); + vesa_WritePixel(left + 1, bottom , FIRST_TEXT_COLOR + 15); + vesa_WritePixel(right - 1, bottom , FIRST_TEXT_COLOR + 15); + vesa_WritePixel(right , bottom , FIRST_TEXT_COLOR + 15); + break; + + case CURSOR_UNDERLINE: + for (x = left; x <= right; ++x) { + vesa_WritePixel(x, bottom, FIRST_TEXT_COLOR + 15); + } + break; + + case CURSOR_FRAME: + + /* fall through */ + + default: + for (x = left; x <= right; ++x) { + vesa_WritePixel(x, top, FIRST_TEXT_COLOR + 15); + } + for (y = top + 1; y <= bottom - 1; ++y) { + vesa_WritePixel(left , y, FIRST_TEXT_COLOR + 15); + vesa_WritePixel(right, y, FIRST_TEXT_COLOR + 15); + } + for (x = left; x <= right; ++x) { + vesa_WritePixel(x, bottom, FIRST_TEXT_COLOR + 15); + } + break; + } +#ifdef POSITIONBAR + if (inmap) + positionbar(); +#endif +} + +void +vesa_HideCursor() +{ + unsigned x, y, left, top, width; + boolean isrogue = Is_rogue_level(&u.uz); + boolean halfwidth = + (isrogue || iflags.over_view || iflags.traditional_view || !inmap); + int curtyp; + + if (!cursor_type && inmap) + return; /* CURSOR_INVIS - nothing to do */ + + x = min(curcol, (CO - 1)); /* protection from callers */ + y = min(currow, (LI - 1)); /* protection from callers */ + if (!halfwidth && ((x < clipx) || (x > clipxmax))) + return; + if (inmap) + x -= clipx; + left = x * TILE_X; /* convert to pixels */ + top = y * TILE_Y; + if (halfwidth) { + left /= 2; + width = TILE_X / 2; + } else { + width = TILE_X; + } + left += vesa_x_center; + top += vesa_y_center; + + for (y = 0; y < ROWS_PER_CELL; ++y) { + for (x = 0; x < width; ++x) { + vesa_WritePixel32(left + x, top + y, undercursor[y][x]); + } + } +} +#endif /* SIMULATE_CURSOR */ +#endif /* SCREEN_VESA */ -- 2.50.1