From fb88488583c39a1fbbea10f655cc3c0e542bfb61 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sat, 8 Oct 2022 18:50:38 -0400 Subject: [PATCH 1/6] Support Unicode symbols in VESA modes --- sys/msdos/font.c | 276 ++++++++++++++++++++++++++ sys/msdos/font.h | 53 +++++ sys/msdos/vidvesa.c | 129 ++++++++---- sys/unix/hints/include/cross-post.370 | 3 +- sys/unix/hints/include/cross-pre.370 | 2 + 5 files changed, 419 insertions(+), 44 deletions(-) create mode 100755 sys/msdos/font.c create mode 100755 sys/msdos/font.h diff --git a/sys/msdos/font.c b/sys/msdos/font.c new file mode 100755 index 000000000..d7fd72046 --- /dev/null +++ b/sys/msdos/font.c @@ -0,0 +1,276 @@ +/* Maintain a data structure describing a monospaced bitmap font */ + +#include "hack.h" +#include "integer.h" +#include "font.h" + +static uint32 read_u32(const unsigned char *); +static void add_unicode_index( + struct BitmapFont *font, + uint32 ch, + unsigned index); +static uint32 *uni_8to32(const char *); + +struct BitmapFont * +load_font(const char *filename) +{ + FILE *fp; + struct BitmapFont *font = NULL; + unsigned char header[32]; + size_t size; + uint32 magic; + uint32 version; + uint32 headersize; + uint32 flags; + uint32 length; + uint32 charsize; + uint32 height; + uint32 width; + uint32 bwidth, memsize; + uint32 i; + + fp = fopen(filename, "rb"); + if (fp == NULL) goto error; + + /* Read the PSF header */ + size = fread(header, 1, sizeof(header), fp); + if (size != sizeof(header)) goto error; + + /* Convert from little endian order */ + magic = read_u32(header + 0); + if (magic != 0x864AB572) goto error; + version = read_u32(header + 4); + if (version != 0) goto error; + headersize = read_u32(header + 8); + if (headersize < sizeof(header)) goto error; + flags = read_u32(header + 12); + length = read_u32(header + 16); + charsize = read_u32(header + 20); + height = read_u32(header + 24); + width = read_u32(header + 28); + + /* Check that the declared character size can hold the declared width + and height */ + bwidth = (width + 7) / 8; + memsize = bwidth * height; + if (memsize > charsize) goto error; + + /* Allocate a font structure */ + font = (struct BitmapFont *) alloc(sizeof(struct BitmapFont)); + memset(font, 0, sizeof(struct BitmapFont)); + + /* Dimensions of the font */ + font->width = width; + font->height = height; + font->num_glyphs = length; + + /* The glyph array */ + font->glyphs = (unsigned char **) alloc(length * sizeof(unsigned char *)); + memset(font->glyphs, 0, length * sizeof(unsigned char *)); + + /* Read the glyphs */ + fseek(fp, headersize, SEEK_SET); + for (i = 0; i < length; ++i) { + font->glyphs[i] = (unsigned char *) alloc(memsize); + size = fread(font->glyphs[i], 1, memsize, fp); + if (size != memsize) goto error; + fseek(fp, charsize - memsize, SEEK_CUR); + } + + if (flags & 0x01) { + /* Read the Unicode table */ + char buf[128], buf2[128+1]; + unsigned bufsize, strsize; + char *p; + uint32 *codepoints; + + bufsize = 0; + i = 0; + while (i < length) { + unsigned j; + + size = fread(buf + bufsize, 1, sizeof(buf) - bufsize, fp); + if (ferror(fp)) goto error; + bufsize += size; + if (bufsize == 0) goto error; /* unexpected EOF */ + + p = memchr(buf, 0xFF, bufsize); + if (p != NULL) { /* end marker found */ + strsize = p - buf; + memcpy(buf2, buf, strsize); + buf2[strsize] = '\0'; + bufsize -= strsize + 1; + memmove(buf, buf + strsize + 1, bufsize); + } else { /* partial string */ + strsize = bufsize - 1; + /* Roll back to character boundary in case of partial character */ + while (strsize != 0 && (buf[strsize] & 0xC0) == 0x80) + --strsize; + if (strsize == 0) /* avoid infinite loop */ + strsize = (bufsize < 4) ? bufsize : 4; + memcpy(buf2, buf, strsize); + buf2[strsize] = '\0'; + bufsize -= strsize; + memmove(buf, buf + strsize, bufsize); + } + codepoints = uni_8to32(buf2); + for (j = 0; codepoints[j] != 0; ++j) { + add_unicode_index(font, codepoints[j], i); + } + free(codepoints); + if (p != NULL) + ++i; + } + } else { + /* Fake a Unicode table, assuming that ASCII glyphs are in the + expected places */ + for (i = 0x20; i <= 0x7E; ++i) { + add_unicode_index(font, i, i); + } + } + + fclose(fp); + return font; + +error: + if (fp != NULL) fclose(fp); + free_font(font); + return NULL; +} + +void +free_font(struct BitmapFont *font) +{ + unsigned i, j; + + if (font == NULL) return; + + if (font->glyphs != NULL) { + for (i = 0; i < font->num_glyphs; ++i) + free(font->glyphs[i]); + free(font->glyphs); + } + + for (i = 0; i < SIZE(font->unicode); ++i) { + if (font->unicode[i] == NULL) continue; + for (j = 0; j < 256; ++j) + free(font->unicode[i][j]); + free(font->unicode[i]); + } + + free(font); +} + +const unsigned char * +get_font_glyph(struct BitmapFont *font, uint32 ch, boolean unicode) +{ + unsigned index; + + if (unicode) { + index = 0; + if (ch <= 0x10FFFF && (ch & 0xFFFFD800) != 0xD800) { + unsigned i, j, k; + + i = (unsigned) (ch >> 16); + j = (unsigned) ((ch >> 8) & 0xFF); + k = (unsigned) (ch & 0xFF); + if (font->unicode[i] != NULL + && font->unicode[i][j] != NULL) { + index = font->unicode[i][j][k]; + } + } + } else { + index = ch; + } + + if (index >= font->num_glyphs) + index = 0; + + return font->glyphs[index]; +} + +static void +add_unicode_index(struct BitmapFont *font, uint32 ch, unsigned index) +{ + unsigned i, j, k; + + i = (unsigned) (ch >> 16); + j = (unsigned) ((ch >> 8) & 0xFF); + k = (unsigned) (ch & 0xFF); + + if (font->unicode[i] == NULL) { + /* Create the second level node */ + font->unicode[i] = (unsigned **) alloc(256 * sizeof(unsigned *)); + memset(font->unicode[i], 0, 256 * sizeof(unsigned *)); + } + if (font->unicode[i][j] == NULL) { + /* Create the third level node */ + font->unicode[i][j] = (unsigned *) alloc(256 * sizeof(unsigned)); + memset(font->unicode[i][j], 0, 256 * sizeof(unsigned)); + } + font->unicode[i][j][k] = index; +} + +static uint32 +read_u32(const unsigned char *buf) +{ + return ((uint32) buf[0] << 0) + | ((uint32) buf[1] << 8) + | ((uint32) buf[2] << 16) + | ((uint32) buf[3] << 24); +} + +static uint32 * +uni_8to32(const char *inp) +{ + size_t i, j; + uint32 *out; + + /* Output string */ + out = (uint32 *) alloc((strlen(inp) + 1) * sizeof(out[0])); + + i = 0; + j = 0; + while (inp[i] != 0) { + unsigned char byte = inp[i++]; + uint32 ch32; + uint32 min = 0; + unsigned count = 0; + + if (byte < 0x80) { + ch32 = byte; + } else if (byte < 0xC0) { + ch32 = 0xFFFD; + } else if (byte < 0xE0) { + ch32 = byte & 0x1F; + min = 0x80; + count = 1; + } else if (byte < 0xF0) { + ch32 = byte & 0x0F; + min = 0x800; + count = 2; + } else if (byte < 0xF5) { + ch32 = byte & 0x07; + min = 0x10000; + count = 3; + } else { + ch32 = 0xFFFD; + } + + for (; count != 0; --count) { + byte = inp[i]; + if ((byte & 0xC0) != 0x80) { + break; + } + ++i; + ch32 = (ch32 << 6) | (byte & 0x3F); + } + if (count != 0 || ch32 < min || ((ch32 & 0xFFFFF800) == 0xD800)) { + ch32 = 0xFFFD; + } + out[j++] = ch32; + } + + out[j] = 0; + return out; +} diff --git a/sys/msdos/font.h b/sys/msdos/font.h new file mode 100755 index 000000000..d5274fa6f --- /dev/null +++ b/sys/msdos/font.h @@ -0,0 +1,53 @@ +/* Maintain a data structure describing a monospaced bitmap font */ + +#ifndef FONT_H +#define FONT_H + +#include "integer.h" + +/* + * The file format is Linux PSF, version 2. Version 1 is not supported. + * Actual Linux fonts are restricted to 256 or 512 glyphs; for NetHack, the + * font can have any number of glyphs. The Unicode map is expected to be + * present, but combining sequences are not supported. + * The fonts supplied for use with this data structure have the first 256 + * glyphs arranged according to IBM code page 437, for simpler support of + * the IBM handling mode for the map. + */ + +/* For Unicode lookup, a three level tree provides constant-time access to + the glyphs without using an excessive amount of memory. + The root has seventeen entries, one for each plane of Unicode. Most fonts + will populate only plane 0, and Unicode defines only planes 0, 1, 2, 3, 15 + and 16. + The second level has 256 entries, each pointing to a third level node with + 256 entries. Each third level entry has type unsigned, and gives the index + of the glyph. + Given the Unicode code point, we can use bits 20 through 16 to index the + root, bits 15 through 8 for the second level and bits 7 through 0 for the + third level. */ + +struct BitmapFont { + /* Dimensions of a single glyph */ + unsigned width; + unsigned height; + + /* The glyphs, in the order that they appear in the font */ + /* IBM handling will index the glyphs this way */ + /* glyph points to an allocated array, each element of which points to + another allocated array */ + unsigned num_glyphs; + unsigned char **glyphs; + + /* The root node of the Unicode tree */ + unsigned **unicode[17]; +}; + +extern struct BitmapFont *load_font(const char *filename); +extern void free_font(struct BitmapFont *font); +extern const unsigned char *get_font_glyph( + struct BitmapFont *font, + uint32 ch, + boolean unicode); + +#endif diff --git a/sys/msdos/vidvesa.c b/sys/msdos/vidvesa.c index 10877b7a6..5fce6e866 100644 --- a/sys/msdos/vidvesa.c +++ b/sys/msdos/vidvesa.c @@ -16,13 +16,14 @@ #include "vesa.h" #include "wintty.h" #include "tileset.h" +#include "font.h" #define FIRST_TEXT_COLOR 240 extern int total_tiles_used, Tile_corr, Tile_unexplored; /* from tile.c */ struct VesaCharacter { int colour; - int chr; + uint32 chr; }; static unsigned long vesa_SetWindow(int window, unsigned long offset); @@ -47,13 +48,13 @@ static boolean vesa_SetHardPalette(const struct Pixel *); static boolean vesa_SetSoftPalette(const struct Pixel *); static void vesa_DisplayCell(int, int, int); static unsigned vesa_FindMode(unsigned long mode_addr, unsigned bits); -static void vesa_WriteChar(int, int, int, int); -static void vesa_WriteCharXY(int, int, int, int); +static void vesa_WriteChar(uint32, int, int, int); +static void vesa_WriteCharXY(uint32, int, int, int); static void vesa_WriteCharTransparent(int, int, int, int); static void vesa_WriteTextRow(int pixx, int pixy, struct VesaCharacter const *t_row, unsigned t_row_width); static boolean vesa_GetCharPixel(int, unsigned, unsigned); -static unsigned char vesa_GetCharPixelRow(int, unsigned, unsigned); +static unsigned char vesa_GetCharPixelRow(uint32, unsigned, unsigned); static unsigned long vesa_DoublePixels(unsigned long); static unsigned long vesa_TriplePixels(unsigned long); static void vesa_WriteStr(const char *, int, int, int, int); @@ -81,7 +82,7 @@ static unsigned char __far *font; static struct map_struct { int glyph; - int ch; + uint32 ch; int attr; unsigned special; short int tileidx; @@ -151,6 +152,7 @@ static unsigned vesa_char_width = 8, vesa_char_height = 16; static unsigned vesa_oview_width, vesa_oview_height; static unsigned char **vesa_tiles; static unsigned char **vesa_oview_tiles; +static struct BitmapFont *vesa_font; #ifdef SIMULATE_CURSOR static unsigned long *undercursor; @@ -670,12 +672,17 @@ vesa_xputc(char ch, int attr) void vesa_xputg(const glyph_info *glyphinfo) { - int glyphnum = glyphinfo->glyph, ch = glyphinfo->ttychar; + int glyphnum = glyphinfo->glyph; + uint32 ch = (uchar) glyphinfo->ttychar; unsigned special = glyphinfo->gm.glyphflags; int col, row; int attr; int ry; + if (SYMHANDLING(H_UTF8) && glyphinfo->gm.u && glyphinfo->gm.u->utf8str) { + ch = glyphinfo->gm.u->utf32ch; + } + row = currow; col = curcol; if ((col < 0 || col >= COLNO) @@ -689,7 +696,7 @@ vesa_xputg(const glyph_info *glyphinfo) 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); + vesa_WriteChar(ch, col, row, attr); } else { if ((col >= clipx) && (col <= clipxmax) && (ry >= clipy) && (ry <= clipymax)) { @@ -1011,6 +1018,7 @@ vesa_Init(void) unsigned i; unsigned num_pixels, num_oview_pixels; const char *tile_file; + const char *font_name; int tilefailure = 0; if (inited) return; @@ -1090,22 +1098,48 @@ vesa_Init(void) vesa_oview_height = (unsigned) iflags.wc_tile_height; } - /* Use the map font size to set the font size */ - /* Supported sizes are 8x16, 16x32, 24x48 and 32x64 */ - vesa_char_height = iflags.wc_fontsiz_map; - if (vesa_char_height <= 0 || vesa_char_height > vesa_y_res / 30) { - vesa_char_height = vesa_y_res / 30; - } - if (vesa_char_height < 32) { - vesa_char_height = 16; - } else if (vesa_char_height < 48) { - vesa_char_height = 32; - } else if (vesa_char_height < 64) { - vesa_char_height = 48; + /* Load a font of size appropriate to the screen size */ + if (vesa_x_res >= 1280 && vesa_y_res >= 960) + font_name = "ter-u32b.psf"; + else if (vesa_x_res >= 1120 && vesa_y_res >= 840) + font_name = "ter-u28b.psf"; + else if (vesa_x_res >= 960 && vesa_y_res >= 720) + font_name = "ter-u24b.psf"; + else if (vesa_x_res >= 880 && vesa_y_res >= 660) + font_name = "ter-u22b.psf"; + else if (vesa_x_res >= 800 && vesa_y_res >= 600) + font_name = "ter-u20b.psf"; + else if (vesa_x_res >= 720 && vesa_y_res >= 540) + font_name = "ter-u18b.psf"; + else + font_name = "ter-u16v.psf"; + if (iflags.wc_font_map != NULL && iflags.wc_font_map[0] != '\0') + font_name = iflags.wc_font_map; + free_font(vesa_font); + vesa_font = load_font(font_name); + /* if load_font fails, vesa_font is NULL and we'll fall back to the font + defined in ROM */ + if (vesa_font != NULL) { + vesa_char_width = vesa_font->width; + vesa_char_height = vesa_font->height; } else { - vesa_char_height = 64; + /* Use the map font size to set the font size */ + /* Supported sizes are 8x16, 16x32, 24x48 and 32x64 */ + vesa_char_height = iflags.wc_fontsiz_map; + if (vesa_char_height <= 0 || vesa_char_height > vesa_y_res / 30) { + vesa_char_height = vesa_y_res / 30; + } + if (vesa_char_height < 32) { + vesa_char_height = 16; + } else if (vesa_char_height < 48) { + vesa_char_height = 32; + } else if (vesa_char_height < 64) { + vesa_char_height = 48; + } else { + vesa_char_height = 64; + } + vesa_char_width = vesa_char_height / 2; } - vesa_char_width = vesa_char_height / 2; /* Process tiles for the current video mode */ vesa_tiles = (unsigned char **) alloc(total_tiles_used * sizeof(void *)); @@ -1508,7 +1542,7 @@ vesa_FindMode(unsigned long mode_addr, unsigned bits) * */ static void -vesa_WriteChar(int chr, int col, int row, int colour) +vesa_WriteChar(uint32 chr, int col, int row, int colour) { int pixx, pixy; @@ -1527,7 +1561,7 @@ vesa_WriteChar(int chr, int col, int row, int colour) * transparency */ static void -vesa_WriteCharXY(int chr, int pixx, int pixy, int colour) +vesa_WriteCharXY(uint32 chr, int pixx, int pixy, int colour) { /* Flush if cache is full or if not contiguous to the last character */ if (chr_cache_size >= SIZE(chr_cache)) { @@ -1604,7 +1638,7 @@ vesa_WriteTextRow(int pixx, int pixy, struct VesaCharacter const *t_row, /* Second loop: draw one raster line of one character */ x = 0; for (i = 0; i < t_row_width; ++i) { - int chr = t_row[i].chr; + uint32 chr = t_row[i].chr; int colour = t_row[i].colour + FIRST_TEXT_COLOR; /* Preprocess the foreground color */ if (vesa_pixel_bytes == 1) { @@ -1655,8 +1689,9 @@ vesa_GetCharPixel(int ch, unsigned x, unsigned y) } static unsigned char -vesa_GetCharPixelRow(int ch, unsigned x, unsigned y) +vesa_GetCharPixelRow(uint32 ch, unsigned x, unsigned y) { + unsigned fnt_width; unsigned x1; unsigned char fnt; size_t offset; @@ -1664,30 +1699,38 @@ vesa_GetCharPixelRow(int ch, unsigned x, unsigned y) if (x >= vesa_char_width) return 0; if (y >= vesa_char_height) return 0; + fnt_width = (vesa_char_width + 7) / 8; x1 = x / 8; - const unsigned char __far *fp; + if (vesa_font != NULL) { + const unsigned char *fp; - if (ch < 0 || 255 < ch) return FALSE; - offset = ch * 16 + (y * 16 / vesa_char_height); - fp = font; - fnt = READ_ABSOLUTE((fp + offset)); + offset = y * fnt_width + x1; + fp = get_font_glyph(vesa_font, ch, SYMHANDLING(H_UTF8)); + fnt = fp[offset]; + } else { + const unsigned char __far *fp; - if (vesa_char_width != 8) { - unsigned long fnt2 = fnt; - unsigned width = vesa_char_width; - if (width % 3 == 0) { - fnt2 = vesa_TriplePixels(fnt2); - width /= 3; + if (255 < ch) return 0; + offset = (ch * vesa_char_height + y) * fnt_width + x1; + fp = font; + fnt = READ_ABSOLUTE((fp + offset)); + + if (vesa_char_width != 8) { + unsigned long fnt2 = fnt; + unsigned width = vesa_char_width; + if (width % 3 == 0) { + fnt2 = vesa_TriplePixels(fnt2); + width /= 3; + } + while (width > 8) { + fnt2 = vesa_DoublePixels(fnt2); + width /= 2; + } + fnt2 <<= 32 - vesa_char_width; + fnt = (unsigned char)(fnt2 >> (24 - 8 * x1)); } - while (width > 8) { - fnt2 = vesa_DoublePixels(fnt2); - width /= 2; - } - fnt2 <<= 32 - vesa_char_width; - fnt = (unsigned char)(fnt2 >> (24 - 8 * x1)); } - return fnt; } diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index 4a056813f..c530bc070 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -6,6 +6,7 @@ ifdef CROSS_TO_MSDOS # $(TARGETPFX)msdos.o : ../sys/msdos/msdos.c $(HACK_H) +$(TARGETPFX)font.o : ../sys/msdos/font.c ../sys/msdos/font.h $(HACK_H) $(TARGETPFX)pckeys.o : ../sys/msdos/pckeys.c $(HACK_H) $(TARGETPFX)pctiles.o : ../sys/msdos/pctiles.c ../sys/msdos/portio.h $(HACK_H) $(TARGETPFX)video.o : ../sys/msdos/video.c ../sys/msdos/portio.h $(HACK_H) @@ -14,7 +15,7 @@ $(TARGETPFX)vidtxt.o : ../sys/msdos/vidtxt.c ../sys/msdos/portio.h \ $(TARGETPFX)vidvga.o : ../sys/msdos/vidvga.c ../sys/msdos/portio.h \ ../win/share/tile.h ../include/tileset.h $(HACK_H) $(TARGETPFX)vidvesa.o : ../sys/msdos/vidvesa.c ../sys/msdos/portio.h \ - ../win/share/tile.h ../include/tileset.h $(HACK_H) + ../win/share/tile.h ../include/tileset.h ../sys/msdos/font.h $(HACK_H) $(TARGETPFX)vidstub.o : ../sys/msdos/vidvesa.c ../sys/msdos/portio.h \ $(HACK_H) $(TARGETPFX)tile.o : tile.c diff --git a/sys/unix/hints/include/cross-pre.370 b/sys/unix/hints/include/cross-pre.370 index f3d11aa93..5acfdef11 100644 --- a/sys/unix/hints/include/cross-pre.370 +++ b/sys/unix/hints/include/cross-pre.370 @@ -185,6 +185,7 @@ override SYSSRC = ../sys/share/pcmain.c ../sys/msdos/msdos.c \ ../sys/share/pcunix.c ../sys/msdos/video.c \ ../sys/msdos/vidtxt.c ../sys/msdos/pckeys.c \ ../sys/msdos/vidvga.c ../sys/msdos/vidvesa.c \ + ../sys/msdos/font.c \ ../win/share/bmptiles.c ../win/share/giftiles.c \ ../win/share/tileset.c override SYSOBJ= $(TARGETPFX)pcmain.o $(TARGETPFX)msdos.o \ @@ -192,6 +193,7 @@ override SYSOBJ= $(TARGETPFX)pcmain.o $(TARGETPFX)msdos.o \ $(TARGETPFX)pcunix.o $(TARGETPFX)video.o \ $(TARGETPFX)vidtxt.o $(TARGETPFX)pckeys.o \ $(TARGETPFX)vidvga.o $(TARGETPFX)vidvesa.o \ + $(TARGETPFX)font.o \ $(TARGETPFX)bmptiles.o $(TARGETPFX)giftiles.o \ $(TARGETPFX)tileset.o $(TARGETPFX)tile.o override WINLIB= From 6400ce073aa2cfb88e4ee94a606853baf05b9cb0 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sat, 8 Oct 2022 19:41:22 -0400 Subject: [PATCH 2/6] Support Unicode symbols in 16 color mode --- sys/msdos/vidvga.c | 80 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/sys/msdos/vidvga.c b/sys/msdos/vidvga.c index 99c7f3cfc..062b6cff5 100644 --- a/sys/msdos/vidvga.c +++ b/sys/msdos/vidvga.c @@ -11,6 +11,7 @@ #include "pcvideo.h" #include "tile.h" #include "tileset.h" +#include "font.h" #include #include @@ -123,7 +124,8 @@ static void vga_DisplayCell_O(struct overview_planar_cell_struct *, int, int); static void vga_SwitchMode(unsigned int); static void vga_SetPalette(const struct Pixel *); -static void vga_WriteChar(int, int, int, int); +static void vga_WriteChar(uint32, int, int, int); +static void vga_GetBitmap(uint32, unsigned char *); static void vga_WriteStr(char *, int, int, int, int); static void read_planar_tile(unsigned, struct planar_cell_struct *); @@ -149,13 +151,14 @@ extern glyph_map glyphmap[MAX_GLYPH]; * Global Variables */ -static unsigned char __far *font; +static unsigned char __far *rom_font; +static struct BitmapFont *psf_font; static char *screentable[SCREENHEIGHT]; static const struct Pixel *paletteptr; static struct map_struct { int glyph; - int ch; + uint32 ch; int attr; unsigned special; short int tileidx; @@ -363,12 +366,18 @@ void vga_xputc(char ch, int attr) void vga_xputg(const glyph_info *glyphinfo) { - int glyphnum = glyphinfo->glyph, ch = glyphinfo->ttychar; + int glyphnum = glyphinfo->glyph; + uint32 ch = glyphinfo->ttychar; unsigned special = glyphinfo->gm.glyphflags; int col, row; int attr; int ry; + if (psf_font != NULL && SYMHANDLING(H_UTF8) && glyphinfo->gm.u + && glyphinfo->gm.u->utf8str) { + ch = glyphinfo->gm.u->utf32ch; + } + /* If statue glyph, map to the generic statue */ #if 0 if (GLYPH_STATUE_OFF <= glyphnum && glyphnum < GLYPH_STATUE_OFF + NUMMONS) { @@ -389,7 +398,7 @@ vga_xputg(const glyph_info *glyphinfo) map[ry][col].attr = attr; map[ry][col].tileidx = glyphinfo->gm.tileidx; if (iflags.traditional_view) { - vga_WriteChar((unsigned char) ch, col, row, attr); + vga_WriteChar(ch, col, row, attr); } else if (!iflags.over_view) { if ((col >= clipx) && (col <= clipxmax)) { read_planar_tile(glyphnum, &planecell); @@ -479,7 +488,7 @@ vga_redrawmap(boolean clearfirst) #endif if (iflags.traditional_view) { if (!(clearfirst && map[y][x].ch == S_stone)) - vga_WriteChar((unsigned char) map[y][x].ch, x, + vga_WriteChar(map[y][x].ch, x, y + TOP_MAP_ROW, map[y][x].attr); } else { t = map[y][x].glyph; @@ -723,6 +732,7 @@ void vga_Init(void) { int i; + const char *font_name; #ifdef USE_TILES const char *tile_file; @@ -773,7 +783,21 @@ vga_Init(void) #endif vga_SetPalette(paletteptr); g_attribute = attrib_gr_normal; - font = (unsigned char __far *) vga_FontPtrs(); + rom_font = (unsigned char __far *) vga_FontPtrs(); + + /* Load an external font if requested */ + font_name = "ter-u16v.psf"; + if (iflags.wc_font_map != NULL && iflags.wc_font_map[0] != '\0') { + font_name = iflags.wc_font_map; + } + free_font(psf_font); + psf_font = load_font(font_name); + if (psf_font->width != 8 || psf_font->height != 16) { + raw_printf("VGA mode only supports 8x16 fonts"); + free_font(psf_font); + psf_font = NULL; + } + clear_screen(); clipx = 0; clipxmax = clipx + (viewport_size - 1); @@ -910,22 +934,23 @@ vga_detect(void) * */ static void -vga_WriteChar(int chr, int col, int row, int colour) +vga_WriteChar(uint32 chr, int col, int row, int colour) { int i; int x, pixy; char __far *cp; - unsigned char __far *fp = font; unsigned char fnt; int actual_colour = vgacmap[colour]; int vplane; + unsigned char bitmap[ROWS_PER_CELL]; + + /* if (chr < ' ') chr = ' '; */ /* assumes ASCII set */ + vga_GetBitmap(chr, bitmap); x = min(col, (CO - 1)); /* min() used protection from callers */ pixy = min(row, (LI - 1)) * 16; /* assumes 8 x 16 char set */ - /* if (chr < ' ') chr = ' '; */ /* assumes ASCII set */ - chr = chr << 4; vplane = ~actual_colour & ~BACKGROUND_VGA_COLOR & 0xF; if (vplane != 0) { egawriteplane(vplane); @@ -939,7 +964,7 @@ vga_WriteChar(int chr, int col, int row, int colour) egawriteplane(vplane); for (i = 0; i < MAX_ROWS_PER_CELL; ++i) { cp = screentable[pixy + i] + x; - fnt = READ_ABSOLUTE((fp + chr + i)); + fnt = bitmap[i]; WRITE_ABSOLUTE(cp, (char) fnt); } } @@ -948,7 +973,7 @@ vga_WriteChar(int chr, int col, int row, int colour) egawriteplane(vplane); for (i = 0; i < MAX_ROWS_PER_CELL; ++i) { cp = screentable[pixy + i] + x; - fnt = ~READ_ABSOLUTE((fp + chr + i)); + fnt = ~bitmap[i]; WRITE_ABSOLUTE(cp, (char) fnt); } } @@ -963,6 +988,28 @@ vga_WriteChar(int chr, int col, int row, int colour) egawriteplane(15); } +/* + * Given the character, return the bitmap that displays that character + */ +static void +vga_GetBitmap(uint32 chr, unsigned char *bitmap) +{ + unsigned i; + + if (psf_font) { + unsigned char const *fp = get_font_glyph(psf_font, chr, + SYMHANDLING(H_UTF8)); + for (i = 0; i < ROWS_PER_CELL; ++i) { + bitmap[i] = fp[i]; + } + } else { + unsigned char const __far *fp = rom_font + chr * ROWS_PER_CELL; + for (i = 0; i < ROWS_PER_CELL; ++i) { + bitmap[i] = READ_ABSOLUTE((fp + i)); + } + } +} + /* * This is the routine that displays a high-res "cell" pointed to by 'gp' * at the desired location (col,row). @@ -1045,7 +1092,7 @@ vga_WriteStr(char *s, int len, int col, int row, int colour) i = 0; us = (unsigned char *) s; while ((*us != 0) && (i < len) && (col < (CO - 1))) { - vga_WriteChar(*us, col, row, colour); + vga_WriteChar((uchar) *us, col, row, colour); ++us; ++i; ++col; @@ -1221,6 +1268,9 @@ vga_special(int chr, int col, int color) int vplane; char fnt; char bits[SCREENPLANES][ROWS_PER_CELL]; + unsigned char bitmap[ROWS_PER_CELL]; + + vga_GetBitmap(chr, bitmap); pixy = PBAR_ROW * MAX_ROWS_PER_CELL; for (vplane = 0; vplane < SCREENPLANES; ++vplane) { @@ -1229,7 +1279,7 @@ vga_special(int chr, int col, int color) for (i = 0; i < ROWS_PER_CELL; ++i) { tmp_d = screentable[y++] + col; bits[vplane][i] = READ_ABSOLUTE(tmp_d); - fnt = READ_ABSOLUTE((font + ((chr << 4) + i))); + fnt = READ_ABSOLUTE((rom_font + ((chr << 4) + i))); if (colorbits[vplane] & color) bits[vplane][i] |= fnt; else From e4f921f50874fe50c03807871dd6cef1049907eb Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 9 Oct 2022 02:53:13 -0400 Subject: [PATCH 3/6] Update the native compile --- sys/msdos/Makefile.GCC | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sys/msdos/Makefile.GCC b/sys/msdos/Makefile.GCC index 48e16813c..61bdc0e83 100644 --- a/sys/msdos/Makefile.GCC +++ b/sys/msdos/Makefile.GCC @@ -202,7 +202,7 @@ U = $(UTIL)/ # Utility Objects. #========================================== -VGAOBJ = $(O)vidvga.o $(O)vidvesa.o +VGAOBJ = $(O)vidvga.o $(O)vidvesa.o $(O)font.o MAKESRC = makedefs.c @@ -601,9 +601,7 @@ ifdef CWSDPMI else @$(subst /,\,echo Could not find a copy of CWSDPMI.EXE to put into $(GAMEDIR)) endif -ifdef WANT_DOSVGA @$(subst /,\,copy $(MSYS)/fonts/*.psf $(GAMEDIR)) -endif @$(subst /,\,echo install done > $@) #========================================== @@ -925,7 +923,6 @@ $(O)luac.o: $(LUASRC)/luac.c # Fonts for Unicode support #========================================== -ifdef WANT_DOSVGA $(O)fonts.tag: lua.exe $(MSYS)/fonts/makefont.lua lua $(MSYS)/fonts/makefont.lua $(FONTTOP)/ter-u16b.bdf $(MSYS)/fonts/ter-u16b.psf lua $(MSYS)/fonts/makefont.lua $(FONTTOP)/ter-u16v.bdf $(MSYS)/fonts/ter-u16v.psf @@ -936,10 +933,6 @@ $(O)fonts.tag: lua.exe $(MSYS)/fonts/makefont.lua lua $(MSYS)/fonts/makefont.lua $(FONTTOP)/ter-u28b.bdf $(MSYS)/fonts/ter-u28b.psf lua $(MSYS)/fonts/makefont.lua $(FONTTOP)/ter-u32b.bdf $(MSYS)/fonts/ter-u32b.psf @echo Fonts done >$(O)fonts.tag -else -$(O)fonts.tag: - @echo Fonts not needed >$(O)fonts.tag -endif #========================================== # Housekeeping. @@ -1052,6 +1045,9 @@ $(O)vidvesa.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/portio.h $(TILE_H) $(MSYS)/ $(O)vidtxt.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/portio.h $(TILE_H) $(MSYS)/vidtxt.c # $(CC) $(cflags) -o$@ -I$(MSYS) $(MSYS)/vidtxt.c +$(O)font.o : $(HACK_H) $(MSYS)/font.h $(MSYS)/font.c + $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/font.c + $(O)stubvid.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/video.c $(CC) $(cflags) -I$(MSYS) -DSTUBVIDEO -o$@ $(MSYS)/video.c From 98a145db955c96160dc70ef305f4f5cfb0e5ee05 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 9 Oct 2022 02:53:52 -0400 Subject: [PATCH 4/6] Always compile the Terminus fonts --- sys/unix/hints/include/cross-post.370 | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index c530bc070..693f7c9c4 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -43,11 +43,7 @@ $(FONTDIR)/ter-u32b.psf: $(FONTTOP)/ter-u32b.bdf $(FONTDIR)/makefont.lua $(LUABI $(LUABIN) $(FONTDIR)/makefont.lua $(FONTTOP)/ter-u32b.bdf $@ # .PHONY: dodata dospkg dosfonts -ifdef WANT_DOSVGA dosfonts: $(FONTTARGETS) -else -dosfonts: -endif dospkg: dodata dosfonts $(GAMEBIN) $(TARGETPFX)recover.exe ../dat/nhtiles.bmp $(TARGET_STUBEDIT) $(GAMEBIN) minstack=2048K mkdir -p $(TARGETPFX)pkg @@ -60,7 +56,6 @@ dospkg: dodata dosfonts $(GAMEBIN) $(TARGETPFX)recover.exe ../dat/nhtiles.bmp cp ../sys/share/NetHack.cnf $(TARGETPFX)pkg/NETHACK.CNF cp ../sys/msdos/sysconf $(TARGETPFX)pkg/SYSCONF cp ../doc/nethack.txt $(TARGETPFX)pkg/NETHACK.TXT -ifdef WANT_DOSVGA cp ../sys/msdos/fonts/ter-u16b.psf $(TARGETPFX)pkg/TER-U16B.PSF cp ../sys/msdos/fonts/ter-u16v.psf $(TARGETPFX)pkg/TER-U16V.PSF cp ../sys/msdos/fonts/ter-u18b.psf $(TARGETPFX)pkg/TER-U18B.PSF @@ -69,7 +64,6 @@ ifdef WANT_DOSVGA cp ../sys/msdos/fonts/ter-u24b.psf $(TARGETPFX)pkg/TER-U24B.PSF cp ../sys/msdos/fonts/ter-u28b.psf $(TARGETPFX)pkg/TER-U28B.PSF cp ../sys/msdos/fonts/ter-u32b.psf $(TARGETPFX)pkg/TER-U32B.PSF -endif cp ../lib/djgpp/cwsdpmi/bin/CWSDPMI.EXE $(TARGETPFX)pkg/CWSDPMI.EXE -touch $(TARGETPFX)pkg/RECORD cd $(TARGETPFX)pkg ; zip -9 ../NH370DOS.ZIP * ; cd ../../.. From 613828f5dddd32f3936c5559c24e5717f40078fc Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 9 Oct 2022 08:59:20 -0400 Subject: [PATCH 5/6] Support 24 bit color for Unicode symbols --- sys/msdos/video.c | 1 + sys/msdos/vidvesa.c | 40 ++++++++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/sys/msdos/video.c b/sys/msdos/video.c index 795c4611a..a2668d78c 100644 --- a/sys/msdos/video.c +++ b/sys/msdos/video.c @@ -476,6 +476,7 @@ tty_start_screen(void) void gr_init(void) { + windowprocs.wincap2 &= ~WC2_U_24BITCOLOR; #ifdef SCREEN_VGA if (iflags.usevga) { vga_Init(); diff --git a/sys/msdos/vidvesa.c b/sys/msdos/vidvesa.c index 5fce6e866..45504a890 100644 --- a/sys/msdos/vidvesa.c +++ b/sys/msdos/vidvesa.c @@ -22,7 +22,7 @@ extern int total_tiles_used, Tile_corr, Tile_unexplored; /* from tile.c */ struct VesaCharacter { - int colour; + uint32 colour; uint32 chr; }; @@ -48,8 +48,8 @@ static boolean vesa_SetHardPalette(const struct Pixel *); static boolean vesa_SetSoftPalette(const struct Pixel *); static void vesa_DisplayCell(int, int, int); static unsigned vesa_FindMode(unsigned long mode_addr, unsigned bits); -static void vesa_WriteChar(uint32, int, int, int); -static void vesa_WriteCharXY(uint32, int, int, int); +static void vesa_WriteChar(uint32, int, int, uint32); +static void vesa_WriteCharXY(uint32, int, int, uint32); static void vesa_WriteCharTransparent(int, int, int, int); static void vesa_WriteTextRow(int pixx, int pixy, struct VesaCharacter const *t_row, unsigned t_row_width); @@ -83,7 +83,7 @@ static unsigned char __far *font; static struct map_struct { int glyph; uint32 ch; - int attr; + uint32 attr; unsigned special; short int tileidx; } map[ROWNO][COLNO]; /* track the glyphs */ @@ -676,11 +676,16 @@ vesa_xputg(const glyph_info *glyphinfo) uint32 ch = (uchar) glyphinfo->ttychar; unsigned special = glyphinfo->gm.glyphflags; int col, row; - int attr; + uint32_t attr = (g_attribute == 0) ? attrib_gr_normal : g_attribute; int ry; if (SYMHANDLING(H_UTF8) && glyphinfo->gm.u && glyphinfo->gm.u->utf8str) { ch = glyphinfo->gm.u->utf32ch; + if (vesa_pixel_size > 8 && glyphinfo->gm.u->ucolor != 0) { + /* FIXME: won't display black (0,0,0) correctly, but the background + is usually black anyway */ + attr = glyphinfo->gm.u->ucolor | 0x80000000; + } } row = currow; @@ -693,7 +698,6 @@ vesa_xputg(const glyph_info *glyphinfo) map[ry][col].ch = ch; map[ry][col].special = special; map[ry][col].tileidx = glyphinfo->gm.tileidx; - attr = (g_attribute == 0) ? attrib_gr_normal : g_attribute; map[ry][col].attr = attr; if (iflags.traditional_view) { vesa_WriteChar(ch, col, row, attr); @@ -1071,6 +1075,9 @@ vesa_Init(void) vesa_SwitchMode(vesa_mode); vesa_SetViewPort(); windowprocs.win_cliparound = vesa_cliparound; + if (vesa_pixel_size > 8) { + windowprocs.wincap2 |= WC2_U_24BITCOLOR; + } #ifdef USE_TILES paletteptr = get_palette(); iflags.tile_view = TRUE; @@ -1367,8 +1374,12 @@ vesa_detect(void) } /* Scan the mode list for an acceptable mode */ + /* Choose the widest bit-width, even if the tile set can handle 8 bits, + so that Unicode symbols can display in their colors */ +#ifndef ENHANCED_SYMBOLS if (get_palette() != NULL && vesa_mode == 0xFFFF) vesa_mode = vesa_FindMode(mode_addr, 8); +#endif if (vesa_mode == 0xFFFF) vesa_mode = vesa_FindMode(mode_addr, 32); if (vesa_mode == 0xFFFF) @@ -1542,7 +1553,7 @@ vesa_FindMode(unsigned long mode_addr, unsigned bits) * */ static void -vesa_WriteChar(uint32 chr, int col, int row, int colour) +vesa_WriteChar(uint32 chr, int col, int row, uint32 colour) { int pixx, pixy; @@ -1561,7 +1572,7 @@ vesa_WriteChar(uint32 chr, int col, int row, int colour) * transparency */ static void -vesa_WriteCharXY(uint32 chr, int pixx, int pixy, int colour) +vesa_WriteCharXY(uint32 chr, int pixx, int pixy, uint32 colour) { /* Flush if cache is full or if not contiguous to the last character */ if (chr_cache_size >= SIZE(chr_cache)) { @@ -1639,12 +1650,17 @@ vesa_WriteTextRow(int pixx, int pixy, struct VesaCharacter const *t_row, x = 0; for (i = 0; i < t_row_width; ++i) { uint32 chr = t_row[i].chr; - int colour = t_row[i].colour + FIRST_TEXT_COLOR; + uint32 colour = t_row[i].colour; /* Preprocess the foreground color */ - if (vesa_pixel_bytes == 1) { - fg[0] = colour; + if (colour & 0x80000000) { + fg[0] = colour & 0xFF; + fg[1] = (colour >> 8) & 0xFF; + fg[2] = (colour >> 16) & 0xFF; + fg[3] = 0; + } else if (vesa_pixel_bytes == 1) { + fg[0] = colour + FIRST_TEXT_COLOR; } else { - unsigned long pix = vesa_palette[colour]; + unsigned long pix = vesa_palette[colour + FIRST_TEXT_COLOR]; fg[0] = pix & 0xFF; fg[1] = (pix >> 8) & 0xFF; fg[2] = (pix >> 16) & 0xFF; From ea3d322a112439cd6010fc25ac0e98d5d90990f8 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 9 Oct 2022 09:04:23 -0400 Subject: [PATCH 6/6] Fix compile when no ENHANCED_SYMBOLS --- sys/msdos/vidvesa.c | 4 ++++ sys/msdos/vidvga.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/sys/msdos/vidvesa.c b/sys/msdos/vidvesa.c index 45504a890..ac0f3fcc1 100644 --- a/sys/msdos/vidvesa.c +++ b/sys/msdos/vidvesa.c @@ -679,6 +679,7 @@ vesa_xputg(const glyph_info *glyphinfo) uint32_t attr = (g_attribute == 0) ? attrib_gr_normal : g_attribute; int ry; +#ifdef ENHANCED_SYMBOLS if (SYMHANDLING(H_UTF8) && glyphinfo->gm.u && glyphinfo->gm.u->utf8str) { ch = glyphinfo->gm.u->utf32ch; if (vesa_pixel_size > 8 && glyphinfo->gm.u->ucolor != 0) { @@ -687,6 +688,7 @@ vesa_xputg(const glyph_info *glyphinfo) attr = glyphinfo->gm.u->ucolor | 0x80000000; } } +#endif row = currow; col = curcol; @@ -1075,9 +1077,11 @@ vesa_Init(void) vesa_SwitchMode(vesa_mode); vesa_SetViewPort(); windowprocs.win_cliparound = vesa_cliparound; +#ifdef ENHANCED_SYMBOLS if (vesa_pixel_size > 8) { windowprocs.wincap2 |= WC2_U_24BITCOLOR; } +#endif #ifdef USE_TILES paletteptr = get_palette(); iflags.tile_view = TRUE; diff --git a/sys/msdos/vidvga.c b/sys/msdos/vidvga.c index 062b6cff5..178bba54d 100644 --- a/sys/msdos/vidvga.c +++ b/sys/msdos/vidvga.c @@ -373,10 +373,12 @@ vga_xputg(const glyph_info *glyphinfo) int attr; int ry; +#ifdef ENHANCED_SYMBOLS if (psf_font != NULL && SYMHANDLING(H_UTF8) && glyphinfo->gm.u && glyphinfo->gm.u->utf8str) { ch = glyphinfo->gm.u->utf32ch; } +#endif /* If statue glyph, map to the generic statue */ #if 0