--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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
#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);
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);
static struct map_struct {
int glyph;
- int ch;
+ uint32 ch;
int attr;
unsigned special;
short int tileidx;
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;
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)
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)) {
unsigned i;
unsigned num_pixels, num_oview_pixels;
const char *tile_file;
+ const char *font_name;
int tilefailure = 0;
if (inited) return;
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 *));
*
*/
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;
* 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)) {
/* 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) {
}
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;
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 (ch < 0 || 255 < ch) return FALSE;
- offset = ch * 16 + (y * 16 / vesa_char_height);
- fp = font;
- fnt = READ_ABSOLUTE((fp + offset));
+ if (vesa_font != NULL) {
+ const unsigned char *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;
- }
- while (width > 8) {
- fnt2 = vesa_DoublePixels(fnt2);
- width /= 2;
+ 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 (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));
}
- fnt2 <<= 32 - vesa_char_width;
- fnt = (unsigned char)(fnt2 >> (24 - 8 * x1));
}
-
return fnt;
}
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)
$(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
../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 \
$(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=