From 53c766d87062030099296b499cc4e67d0328c1c1 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Tue, 18 Feb 2020 21:25:11 -0500 Subject: [PATCH 01/26] First functional version of PDCurses on DOSVGA --- dosvga/Makefile | 85 ++++++++ dosvga/Makefile.bcc | 76 +++++++ dosvga/Makefile.wcc | 35 ++++ dosvga/README.md | 47 +++++ dosvga/pdcclip.c | 132 ++++++++++++ dosvga/pdcdisp.c | 232 +++++++++++++++++++++ dosvga/pdcdos.h | 206 +++++++++++++++++++ dosvga/pdcgetsc.c | 47 +++++ dosvga/pdckbd.c | 478 ++++++++++++++++++++++++++++++++++++++++++++ dosvga/pdcscrn.c | 264 ++++++++++++++++++++++++ dosvga/pdcsetsc.c | 88 ++++++++ dosvga/pdcutil.c | 103 ++++++++++ 12 files changed, 1793 insertions(+) create mode 100644 dosvga/Makefile create mode 100644 dosvga/Makefile.bcc create mode 100644 dosvga/Makefile.wcc create mode 100644 dosvga/README.md create mode 100644 dosvga/pdcclip.c create mode 100644 dosvga/pdcdisp.c create mode 100644 dosvga/pdcdos.h create mode 100644 dosvga/pdcgetsc.c create mode 100644 dosvga/pdckbd.c create mode 100644 dosvga/pdcscrn.c create mode 100644 dosvga/pdcsetsc.c create mode 100644 dosvga/pdcutil.c diff --git a/dosvga/Makefile b/dosvga/Makefile new file mode 100644 index 000000000..b3a34dda5 --- /dev/null +++ b/dosvga/Makefile @@ -0,0 +1,85 @@ +# GNU Makefile for PDCurses - DOS +# +# Usage: make [-f path\Makefile] [DEBUG=Y] [target] +# +# where target can be any of: +# [all|libs|demos|pdcurses.a|testcurs.exe...] + +O = o +E = .exe +RM = del + +ifndef PDCURSES_SRCDIR + PDCURSES_SRCDIR = .. +endif + +include $(PDCURSES_SRCDIR)/common/libobjs.mif + +osdir = $(PDCURSES_SRCDIR)/dosvga + +PDCURSES_DOS_H = $(osdir)/pdcdos.h + +CC = gcc + +ifeq ($(DEBUG),Y) + CFLAGS = -g -Wall -DPDCDEBUG + LDFLAGS = -g +else + CFLAGS = -O2 -Wall + LDFLAGS = +endif + +CFLAGS += -I$(PDCURSES_SRCDIR) + +LINK = gcc + +LIBEXE = ar +LIBFLAGS = rcv + +LIBCURSES = pdcurses.a + +.PHONY: all libs clean demos dist + +all: libs + +libs: $(LIBCURSES) + +clean: + -$(RM) *.o + -$(RM) *.a + -$(RM) *.exe + +demos: $(DEMOS) +ifneq ($(DEBUG),Y) + strip *.exe +endif + +$(LIBCURSES) : $(LIBOBJS) $(PDCOBJS) + $(LIBEXE) $(LIBFLAGS)S $@ addch.o addchstr.o addstr.o attr.o beep.o bkgd.o border.o clear.o color.o debug.o delch.o deleteln.o + $(LIBEXE) $(LIBFLAGS)S $@ getch.o getstr.o getyx.o inch.o inchstr.o initscr.o inopts.o insch.o insstr.o instr.o kernel.o keyname.o + $(LIBEXE) $(LIBFLAGS)S $@ mouse.o move.o outopts.o overlay.o pad.o panel.o pdcclip.o pdcdisp.o pdcgetsc.o pdckbd.o pdcscrn.o pdcsetsc.o + $(LIBEXE) $(LIBFLAGS) $@ pdcutil.o printw.o refresh.o scanw.o scr_dump.o scroll.o slk.o termattr.o touch.o util.o window.o + +$(LIBOBJS) $(PDCOBJS) : $(PDCURSES_HEADERS) +$(PDCOBJS) : $(PDCURSES_DOS_H) +$(DEMOS) : $(PDCURSES_CURSES_H) $(LIBCURSES) +panel.o : $(PANEL_HEADER) + +$(LIBOBJS) : %.o: $(srcdir)/%.c + $(CC) -c $(CFLAGS) $< + +$(PDCOBJS) : %.o: $(osdir)/%.c + $(CC) -c $(CFLAGS) $< + +firework.exe ozdemo.exe rain.exe testcurs.exe worm.exe xmas.exe \ +ptest.exe: %.exe: $(demodir)/%.c + $(CC) $(CFLAGS) -o$@ $< $(LIBCURSES) + +tuidemo.exe: tuidemo.o tui.o + $(LINK) $(LDFLAGS) -o$@ tuidemo.o tui.o $(LIBCURSES) + +tui.o: $(demodir)/tui.c $(demodir)/tui.h $(PDCURSES_CURSES_H) + $(CC) -c $(CFLAGS) -I$(demodir) -o$@ $< + +tuidemo.o: $(demodir)/tuidemo.c $(PDCURSES_CURSES_H) + $(CC) -c $(CFLAGS) -I$(demodir) -o$@ $< diff --git a/dosvga/Makefile.bcc b/dosvga/Makefile.bcc new file mode 100644 index 000000000..8c923b302 --- /dev/null +++ b/dosvga/Makefile.bcc @@ -0,0 +1,76 @@ +# Borland Makefile for PDCurses - DOS +# +# Usage: make -f [path\]Makefile.bcc [DEBUG=] [MODEL=c|h|l|m|s] [target] +# +# where target can be any of: +# [all|demos|pdcurses.lib|testcurs.exe...] + +!ifndef MODEL +MODEL = l +!endif + +O = obj +E = .exe +RM = del + +!ifndef PDCURSES_SRCDIR +PDCURSES_SRCDIR = .. +!endif + +!include $(PDCURSES_SRCDIR)\common\libobjs.mif + +osdir = $(PDCURSES_SRCDIR)\dosvga + +!ifdef DEBUG +CFLAGS = -N -v -y -DPDCDEBUG +!else +CFLAGS = -O +!endif + +CPPFLAGS = -I$(PDCURSES_SRCDIR) + +BUILD = $(CC) -1- -G -d -w-par -c -m$(MODEL) $(CFLAGS) $(CPPFLAGS) + +LIBEXE = tlib /C /E + +LIBCURSES = pdcurses.lib + +all: $(LIBCURSES) + +clean: + -$(RM) *.obj + -$(RM) *.lib + -$(RM) *.map + -$(RM) *.exe + +demos: $(LIBCURSES) $(DEMOS) + +$(LIBCURSES) : $(LIBOBJS) $(PDCOBJS) + -$(RM) $@ + $(LIBEXE) $@ @$(PDCURSES_SRCDIR)\common\borland.lrf + +.autodepend + +{$(srcdir)\}.c.obj: + $(BUILD) $< + +{$(osdir)\}.c.obj: + $(BUILD) $< + +{$(demodir)\}.c.obj: + $(BUILD) $< + +.c.obj: + $(BUILD) $< + +.obj.exe: + $(CC) -m$(MODEL) -e$@ $** $(LIBCURSES) + +tuidemo.exe: tuidemo.obj tui.obj $(LIBCURSES) + $(CC) -m$(MODEL) -e$@ $** + +tui.obj: $(demodir)\tui.c $(demodir)\tui.h $(PDCURSES_CURSES_H) + $(BUILD) -I$(demodir) $(demodir)\tui.c + +tuidemo.obj: $(demodir)\tuidemo.c $(PDCURSES_CURSES_H) + $(BUILD) -I$(demodir) $(demodir)\tuidemo.c diff --git a/dosvga/Makefile.wcc b/dosvga/Makefile.wcc new file mode 100644 index 000000000..ac00efee1 --- /dev/null +++ b/dosvga/Makefile.wcc @@ -0,0 +1,35 @@ +# Watcom Makefile for PDCurses - DOS +# +# Usage: wmake -f [path\]Makefile.wcc [DEBUG=Y] [MODEL=c|h|l|m|s|f] [target] +# +# where target can be any of: +# [all|demos|pdcurses.lib|testcurs.exe...] + +!ifndef MODEL +MODEL = l +!endif + +!ifdef %PDCURSES_SRCDIR +PDCURSES_SRCDIR = $(%PDCURSES_SRCDIR) +!else +PDCURSES_SRCDIR = .. +!endif + +osdir = $(PDCURSES_SRCDIR)/dosvga + +!ifeq MODEL f +CC = wcc386 +TARGET = dos4g +!else +CC = wcc +TARGET = dos +!endif + +CFLAGS = -bt=$(TARGET) -m$(MODEL) + +!include $(PDCURSES_SRCDIR)/common/watcom.mif + +$(LIBCURSES) : $(LIBOBJS) $(PDCOBJS) + %write wccdos.lrf $(LIBOBJS) $(PDCOBJS) + $(LIBEXE) $@ @wccdos.lrf + -$(RM) wccdos.lrf diff --git a/dosvga/README.md b/dosvga/README.md new file mode 100644 index 000000000..ad05ce691 --- /dev/null +++ b/dosvga/README.md @@ -0,0 +1,47 @@ +PDCurses for DOS +================ + +This directory contains PDCurses source code files specific to DOS. + + +Building +-------- + +- Choose the appropriate makefile for your compiler: + + Makefile - DJGPP + Makefile.bcc - Borland C++ + Makefile.wcc - Watcom + +- For 16-bit compilers, you can change the memory MODEL as a command- + line option. (Large model is the default, and recommended.) With + Watcom, specifying "MODEL=f" (flat) will automatically switch to a + 32-bit build. + +- Optionally, you can build in a different directory than the platform + directory by setting PDCURSES_SRCDIR to point to the directory where + you unpacked PDCurses, and changing to your target directory: + + set PDCURSES_SRCDIR=c:\pdcurses + +- Build it: + + make -f makefile + + (For Watcom, use "wmake" instead of "make".) You'll get the library + (pdcurses.lib or .a, depending on your compiler) and a lot of object + files. Add the target "demos" to build the sample programs. + + +Distribution Status +------------------- + +The files in this directory are released to the public domain. + + +Acknowledgements +---------------- + +Watcom C port was provided by Pieter Kunst + +DJGPP port was provided by David Nugent diff --git a/dosvga/pdcclip.c b/dosvga/pdcclip.c new file mode 100644 index 000000000..260669510 --- /dev/null +++ b/dosvga/pdcclip.c @@ -0,0 +1,132 @@ +/* PDCurses */ + +#include "pdcdos.h" + +#include + +/*man-start************************************************************** + +clipboard +--------- + +### Synopsis + + int PDC_getclipboard(char **contents, long *length); + int PDC_setclipboard(const char *contents, long length); + int PDC_freeclipboard(char *contents); + int PDC_clearclipboard(void); + +### Description + + PDC_getclipboard() gets the textual contents of the system's + clipboard. This function returns the contents of the clipboard in the + contents argument. It is the responsibility of the caller to free the + memory returned, via PDC_freeclipboard(). The length of the clipboard + contents is returned in the length argument. + + PDC_setclipboard copies the supplied text into the system's + clipboard, emptying the clipboard prior to the copy. + + PDC_clearclipboard() clears the internal clipboard. + +### Return Values + + indicator of success/failure of call. + PDC_CLIP_SUCCESS the call was successful + PDC_CLIP_MEMORY_ERROR unable to allocate sufficient memory for + the clipboard contents + PDC_CLIP_EMPTY the clipboard contains no text + PDC_CLIP_ACCESS_ERROR no clipboard support + +### Portability + X/Open ncurses NetBSD + PDC_getclipboard - - - + PDC_setclipboard - - - + PDC_freeclipboard - - - + PDC_clearclipboard - - - + +**man-end****************************************************************/ + +/* global clipboard contents, should be NULL if none set */ + +static char *pdc_DOS_clipboard = NULL; + +int PDC_getclipboard(char **contents, long *length) +{ + int len; + + PDC_LOG(("PDC_getclipboard() - called\n")); + + if (!pdc_DOS_clipboard) + return PDC_CLIP_EMPTY; + + len = strlen(pdc_DOS_clipboard); + *contents = malloc(len + 1); + if (!*contents) + return PDC_CLIP_MEMORY_ERROR; + + strcpy(*contents, pdc_DOS_clipboard); + *length = len; + + return PDC_CLIP_SUCCESS; +} + +int PDC_setclipboard(const char *contents, long length) +{ + PDC_LOG(("PDC_setclipboard() - called\n")); + + if (pdc_DOS_clipboard) + { + free(pdc_DOS_clipboard); + pdc_DOS_clipboard = NULL; + } + + if (contents) + { + pdc_DOS_clipboard = malloc(length + 1); + if (!pdc_DOS_clipboard) + return PDC_CLIP_MEMORY_ERROR; + + strcpy(pdc_DOS_clipboard, contents); + } + + return PDC_CLIP_SUCCESS; +} + +int PDC_freeclipboard(char *contents) +{ + PDC_LOG(("PDC_freeclipboard() - called\n")); + + /* should we also free empty the system clipboard? probably not */ + + if (contents) + { + /* NOTE: We free the memory, but we can not set caller's pointer + to NULL, so if caller calls again then will try to access + free'd memory. We 1st overwrite memory with a string so if + caller tries to use free memory they won't get what they + expect & hopefully notice. */ + + /* memset(contents, 0xFD, strlen(contents)); */ + + if (strlen(contents) >= strlen("PDCURSES")) + strcpy(contents, "PDCURSES"); + + free(contents); + } + + return PDC_CLIP_SUCCESS; +} + +int PDC_clearclipboard(void) +{ + PDC_LOG(("PDC_clearclipboard() - called\n")); + + if (pdc_DOS_clipboard) + { + free(pdc_DOS_clipboard); + pdc_DOS_clipboard = NULL; + } + + return PDC_CLIP_SUCCESS; +} diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c new file mode 100644 index 000000000..fd027be16 --- /dev/null +++ b/dosvga/pdcdisp.c @@ -0,0 +1,232 @@ +/* PDCurses */ + +#include "pdcdos.h" +#include "../common/acs437.h" + +/* Support cursor on graphics mode */ +static unsigned char bytes_behind[4][16]; +static unsigned char cursor_color = 15; +static void draw_glyph(int row, int col, chtype glyph); +static unsigned long address(int row, int col); +static void video_write_byte(unsigned long addr, unsigned char byte); +static unsigned char video_read_byte(unsigned long addr); + +/* position hardware cursor at (y, x) */ + +void PDC_gotoyx(int row, int col) +{ + if (PDC_state.cursor_visible) + PDC_private_cursor_off(); + PDC_private_cursor_on(row, col); +} + +/* update the given physical line to look like the corresponding line in + curscr */ + +void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) +{ + int i; + + PDC_LOG(("PDC_transform_line() - called: lineno=%d\n", lineno)); + + for (i = 0; i < len; i++) + { + draw_glyph(lineno, x + i, srcp[i]); + if (lineno == PDC_state.cursor_row && x + i == PDC_state.cursor_col) + PDC_private_cursor_on(PDC_state.cursor_row, PDC_state.cursor_col); + } + outportb(0x3c4, 2); + outportb(0x3c5, 0xF); +} + +void PDC_doupdate(void) +{ +} + +static void draw_glyph(int row, int col, chtype glyph) +{ + unsigned long addr = address(row, col); + unsigned long font_addr; + attr_t attr; + unsigned long cp; + unsigned char ch; + short fore, back; + unsigned char vplane; + int line; + int underline; + unsigned char fnt; + + /* Get the foreground and background colors */ + attr = glyph & (A_ATTRIBUTES ^ A_ALTCHARSET); + pair_content(PAIR_NUMBER(attr), &fore, &back); + + if (attr & A_BOLD) + fore |= 8; + if (attr & A_BLINK) + back |= 8; + + fore = PDC_state.pdc_curstoreal[fore]; + back = PDC_state.pdc_curstoreal[back]; + + if (attr & A_REVERSE) + { + short swap = fore; + fore = back; + back = swap; + } + + /* Set underline if requested */ + underline = (attr & A_UNDERLINE) ? 13 /*_FONT16*/ : -1; + + /* Get the index into the font */ + ch = glyph & 0xFF; + if (glyph & A_ALTCHARSET && !(glyph & 0xff80)) + ch = acs_map[ch & 0x7f] & 0xff; + + /* Get the address of the glyph in memory */ + font_addr = PDC_state.font_addr + ch * _FONT16; + + /* Planes where fore has 0 and back has 0 */ + vplane = ~fore & ~back & 0xF; + if (vplane != 0) { + outportb(0x3c4, 2); + outportb(0x3c5, vplane); + cp = addr; + for (line = 0; line < _FONT16; ++line) { + fnt = 0x00; + video_write_byte(cp, fnt); + cp += PDC_state.bytes_per_line; + } + } + /* Planes where fore has 1 and back has 0 */ + vplane = fore & ~back & 0xF; + if (vplane != 0) { + outportb(0x3c4, 2); + outportb(0x3c5, vplane); + cp = addr; + for (line = 0; line < _FONT16; ++line) { + if (line == underline) + fnt = 0xFF; + else + fnt = getdosmembyte(font_addr + line); + video_write_byte(cp, fnt); + cp += PDC_state.bytes_per_line; + } + } + /* Planes where fore has 0 and back has 1 */ + vplane = ~fore & back & 0xF; + if (vplane != 0) { + outportb(0x3c4, 2); + outportb(0x3c5, vplane); + cp = addr; + for (line = 0; line < _FONT16; ++line) { + if (line == underline) + fnt = 0x00; + else + fnt = ~getdosmembyte(font_addr + line); + video_write_byte(cp, fnt); + cp += PDC_state.bytes_per_line; + } + } + /* Planes where fore has 1 and back has 1 */ + vplane = fore & back & 0xF; + if (vplane != 0) { + outportb(0x3c4, 2); + outportb(0x3c5, vplane); + cp = addr; + for (line = 0; line < _FONT16; ++line) { + fnt = 0xFF; + video_write_byte(cp, fnt); + cp += PDC_state.bytes_per_line; + } + } +} + +void PDC_private_cursor_off(void) +{ + if (PDC_state.cursor_visible && PDC_state.cursor_row < (unsigned)LINES + && PDC_state.cursor_col < (unsigned)COLS) { + unsigned long addr = address(PDC_state.cursor_row, PDC_state.cursor_col); + unsigned plane; + unsigned line; + + for (plane = 0; plane < 4; ++plane) + { + unsigned long p = addr; + outportb(0x03C4, 2); + outportb(0x03C5, 1 << plane); + for (line = 0; line < _FONT16; ++line) + { + video_write_byte(p, bytes_behind[plane][line]); + p += PDC_state.bytes_per_line; + } + } + } + PDC_state.cursor_visible = FALSE; +} + +void PDC_private_cursor_on(int row, int col) +{ + unsigned long addr = address(row, col); + unsigned long p; + unsigned plane; + unsigned line; + + for (plane = 0; plane < 4; ++plane) + { + p = addr; + outportb(0x03CE, 4); + outportb(0x03CF, plane); + for (line = 0; line < _FONT16; ++line) + { + bytes_behind[plane][line] = video_read_byte(p); + p += PDC_state.bytes_per_line; + } + } + outportb(0x03C5, 2); + outportb(0x03C5, cursor_color); + p = address(row, col); + p += PDC_state.cursor_start * PDC_state.bytes_per_line; + for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) + { + video_write_byte(p, 0xFF); + p += PDC_state.bytes_per_line; + } + outportb(0x03C5, 2); + outportb(0x03C5, ~cursor_color); + p = address(row, col); + p += PDC_state.cursor_start * PDC_state.bytes_per_line; + for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) + { + video_write_byte(p, 0x00); + p += PDC_state.bytes_per_line; + } + outportb(0x03C5, 2); + outportb(0x03C5, 0xF); + PDC_state.cursor_visible = TRUE; + PDC_state.cursor_row = row; + PDC_state.cursor_col = col; +} + +static unsigned long address(int row, int col) +{ + return row * PDC_state.bytes_per_line * _FONT16 + col; +} + +static void video_write_byte(unsigned long addr, unsigned char byte) +{ + /* TODO: support VESA modes */ + if (addr < 0x10000) + setdosmembyte(0xA0000 + addr, byte); +} + +static unsigned char video_read_byte(unsigned long addr) +{ + /* TODO: support VESA modes */ + unsigned char byte; + if (addr < 0x10000) + byte = getdosmembyte(0xA0000 + addr); + else + byte = 0; + return byte; +} diff --git a/dosvga/pdcdos.h b/dosvga/pdcdos.h new file mode 100644 index 000000000..6c89e2f2a --- /dev/null +++ b/dosvga/pdcdos.h @@ -0,0 +1,206 @@ +/* PDCurses */ + +#include +#include + +/*---------------------------------------------------------------------- + * MEMORY MODEL SUPPORT: + * + * MODELS + * TINY cs,ds,ss all in 1 segment (not enough memory!) + * SMALL cs:1 segment, ds:1 segment + * MEDIUM cs:many segments, ds:1 segment + * COMPACT cs:1 segment, ds:many segments + * LARGE cs:many segments, ds:many segments + * HUGE cs:many segments, ds:segments > 64K + */ + +#ifdef __TINY__ +# define SMALL 1 +#endif +#ifdef __SMALL__ +# define SMALL 1 +#endif +#ifdef __MEDIUM__ +# define MEDIUM 1 +#endif +#ifdef __COMPACT__ +# define COMPACT 1 +#endif +#ifdef __LARGE__ +# define LARGE 1 +#endif +#ifdef __HUGE__ +# define HUGE 1 +#endif + +#include + +/* Information about the current video state */ +struct PDC_video_state +{ + /* Information about the current video mode: */ + unsigned short scrn_mode; + bool linear_buffer; + unsigned short video_width; /* Width of graphics mode in pixels */ + unsigned short video_height; /* Height of graphics mode in pixels */ + unsigned short bytes_per_line; /* Bytes per raster line */ + /* Location of the frame buffer in memory */ + unsigned window[2]; + unsigned offset[2]; + unsigned long window_size; + /* Window used to read and write */ + unsigned char read_win; + unsigned char write_win; + + unsigned long font_addr; /* Address of font in ROM */ + + /* Cursor state */ + bool cursor_visible; + int cursor_row; + int cursor_col; + unsigned char cursor_start; + unsigned char cursor_end; + + short pdc_curstoreal[16]; + +#if 0 + int pdc_adapter; /* screen type */ + int pdc_scrnmode; /* default screen mode */ + int pdc_font; /* default font size */ + bool pdc_direct_video; /* allow direct screen memory writes */ + bool pdc_bogus_adapter; /* TRUE if adapter has insane values */ + unsigned pdc_video_seg; /* video base segment */ + unsigned pdc_video_ofs; /* video base offset */ + + bool graphics_mode; /* TRUE if operating in a graphics mode */ + unsigned video_width; /* Width of graphics mode in pixels */ + unsigned video_height; /* Height of graphics mode in pixels */ +#endif +}; +extern struct PDC_video_state PDC_state; + +extern void PDC_private_cursor_off(void); +extern void PDC_private_cursor_on(int row, int col); + +#ifdef __DJGPP__ /* Note: works only in plain DOS... */ +# if DJGPP == 2 +# define _FAR_POINTER(s,o) ((((int)(s)) << 4) + ((int)(o))) +# else +# define _FAR_POINTER(s,o) (0xe0000000 + (((int)(s)) << 4) + ((int)(o))) +# endif +# define _FP_SEGMENT(p) (unsigned short)((((long)p) >> 4) & 0xffff) +#else +# ifdef __TURBOC__ +# define _FAR_POINTER(s,o) MK_FP(s,o) +# else +# if defined(__WATCOMC__) && defined(__FLAT__) +# define _FAR_POINTER(s,o) ((((int)(s)) << 4) + ((int)(o))) +# else +# define _FAR_POINTER(s,o) (((long)s << 16) | (long)o) +# endif +# endif +# define _FP_SEGMENT(p) (unsigned short)(((long)p) >> 4) +#endif +#define _FP_OFFSET(p) ((unsigned short)p & 0x000f) + +#ifdef __DJGPP__ +# include +unsigned char getdosmembyte(int offs); +unsigned short getdosmemword(int offs); +unsigned long getdosmemdword(int offs); +void setdosmembyte(int offs, unsigned char b); +void setdosmemword(int offs, unsigned short w); +#else +# if SMALL || MEDIUM +# define PDC_FAR far +# else +# define PDC_FAR +# endif +# define getdosmembyte(offs) \ + (*((unsigned char PDC_FAR *) _FAR_POINTER(0,offs))) +# define getdosmemword(offs) \ + (*((unsigned short PDC_FAR *) _FAR_POINTER(0,offs))) +# define getdosmemdword(offs) \ + (*((unsigned long PDC_FAR *) _FAR_POINTER(0,offs))) +# define setdosmembyte(offs,x) \ + (*((unsigned char PDC_FAR *) _FAR_POINTER(0,offs)) = (x)) +# define setdosmemword(offs,x) \ + (*((unsigned short PDC_FAR *) _FAR_POINTER(0,offs)) = (x)) +#endif + +#if defined(__WATCOMC__) && defined(__386__) + +typedef union +{ + struct + { + unsigned long edi, esi, ebp, res, ebx, edx, ecx, eax; + } d; + + struct + { + unsigned short di, di_hi, si, si_hi, bp, bp_hi, res, res_hi, + bx, bx_hi, dx, dx_hi, cx, cx_hi, ax, ax_hi, + flags, es, ds, fs, gs, ip, cs, sp, ss; + } w; + + struct + { + unsigned char edi[4], esi[4], ebp[4], res[4], + bl, bh, ebx_b2, ebx_b3, dl, dh, edx_b2, edx_b3, + cl, ch, ecx_b2, ecx_b3, al, ah, eax_b2, eax_b3; + } h; +} pdc_dpmi_regs; + +void PDC_dpmi_int(int, pdc_dpmi_regs *); + +#endif + +#ifdef __DJGPP__ +# include +# define PDCREGS __dpmi_regs +# define PDCINT(vector, regs) __dpmi_int(vector, ®s) +#else +# ifdef __WATCOMC__ +# ifdef __386__ +# define PDCREGS pdc_dpmi_regs +# define PDCINT(vector, regs) PDC_dpmi_int(vector, ®s) +# else +# define PDCREGS union REGPACK +# define PDCINT(vector, regs) intr(vector, ®s) +# endif +# else +# define PDCREGS union REGS +# define PDCINT(vector, regs) int86(vector, ®s, ®s) +# endif +#endif + +/* Wide registers in REGS: w or x? */ + +#ifdef __WATCOMC__ +# define W w +#else +# define W x +#endif + +/* Monitor (terminal) type information */ + +enum +{ + _NONE, _MDA, _CGA, + _EGACOLOR = 0x04, _EGAMONO, + _VGACOLOR = 0x07, _VGAMONO, + _MCGACOLOR = 0x0a, _MCGAMONO, + _MDS_GENIUS = 0x30 +}; + +/* Text-mode font size information */ + +enum +{ + _FONT8 = 8, + _FONT14 = 14, + _FONT15, /* GENIUS */ + _FONT16 +}; diff --git a/dosvga/pdcgetsc.c b/dosvga/pdcgetsc.c new file mode 100644 index 000000000..1d6efa3ba --- /dev/null +++ b/dosvga/pdcgetsc.c @@ -0,0 +1,47 @@ +/* PDCurses */ + +#include "pdcdos.h" + +#include + +/* return width of screen/viewport */ + +int PDC_get_columns(void) +{ + int cols; + + PDC_LOG(("PDC_get_columns() - called\n")); + + cols = PDC_state.video_width / 8; + + PDC_LOG(("PDC_get_columns() - returned: cols %d\n", cols)); + + return cols; +} + +/* get the cursor size/shape */ + +int PDC_get_cursor_mode(void) +{ + PDC_LOG(("PDC_get_cursor_mode() - called\n")); + + int start = _FONT16*3/4; + int end = _FONT16-1; + + return (start << 4) | end; +} + +/* return number of screen rows */ + +int PDC_get_rows(void) +{ + int rows; + + PDC_LOG(("PDC_get_rows() - called\n")); + + rows = PDC_state.video_height / _FONT16; + + PDC_LOG(("PDC_get_rows() - returned: rows %d\n", rows)); + + return rows; +} diff --git a/dosvga/pdckbd.c b/dosvga/pdckbd.c new file mode 100644 index 000000000..32ab22458 --- /dev/null +++ b/dosvga/pdckbd.c @@ -0,0 +1,478 @@ +/* PDCurses */ + +#include "pdcdos.h" + +#ifdef __DJGPP__ +# include +# include +# include +#endif + +/************************************************************************ + * Table for key code translation of function keys in keypad mode * + * These values are for strict IBM keyboard compatibles only * + ************************************************************************/ + +static short key_table[] = +{ + -1, ALT_ESC, -1, 0, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, ALT_BKSP, KEY_BTAB, + ALT_Q, ALT_W, ALT_E, ALT_R, + ALT_T, ALT_Y, ALT_U, ALT_I, + ALT_O, ALT_P, ALT_LBRACKET, ALT_RBRACKET, + ALT_ENTER, -1, ALT_A, ALT_S, + ALT_D, ALT_F, ALT_G, ALT_H, + ALT_J, ALT_K, ALT_L, ALT_SEMICOLON, + ALT_FQUOTE, ALT_BQUOTE, -1, ALT_BSLASH, + ALT_Z, ALT_X, ALT_C, ALT_V, + ALT_B, ALT_N, ALT_M, ALT_COMMA, + ALT_STOP, ALT_FSLASH, -1, ALT_PADSTAR, + -1, -1, -1, KEY_F(1), + KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), + KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), + KEY_F(10), -1, -1, KEY_HOME, + KEY_UP, KEY_PPAGE, ALT_PADMINUS, KEY_LEFT, + KEY_B2, KEY_RIGHT, ALT_PADPLUS, KEY_END, + KEY_DOWN, KEY_NPAGE, KEY_IC, KEY_DC, + KEY_F(13), KEY_F(14), KEY_F(15), KEY_F(16), + KEY_F(17), KEY_F(18), KEY_F(19), KEY_F(20), + KEY_F(21), KEY_F(22), KEY_F(25), KEY_F(26), + KEY_F(27), KEY_F(28), KEY_F(29), KEY_F(30), + KEY_F(31), KEY_F(32), KEY_F(33), KEY_F(34), + KEY_F(37), KEY_F(38), KEY_F(39), KEY_F(40), + KEY_F(41), KEY_F(42), KEY_F(43), KEY_F(44), + KEY_F(45), KEY_F(46), -1, CTL_LEFT, + CTL_RIGHT, CTL_END, CTL_PGDN, CTL_HOME, + ALT_1, ALT_2, ALT_3, ALT_4, + ALT_5, ALT_6, ALT_7, ALT_8, + ALT_9, ALT_0, ALT_MINUS, ALT_EQUAL, + CTL_PGUP, KEY_F(11), KEY_F(12), KEY_F(23), + KEY_F(24), KEY_F(35), KEY_F(36), KEY_F(47), + KEY_F(48), CTL_UP, CTL_PADMINUS, CTL_PADCENTER, + CTL_PADPLUS, CTL_DOWN, CTL_INS, CTL_DEL, + CTL_TAB, CTL_PADSLASH, CTL_PADSTAR, ALT_HOME, + ALT_UP, ALT_PGUP, -1, ALT_LEFT, + -1, ALT_RIGHT, -1, ALT_END, + ALT_DOWN, ALT_PGDN, ALT_INS, ALT_DEL, + ALT_PADSLASH, ALT_TAB, ALT_PADENTER, -1 +}; + +static struct {unsigned short pressed, released;} button[3]; + +static bool mouse_avail = FALSE, mouse_vis = FALSE, mouse_moved = FALSE, + mouse_button = FALSE, key_pressed = FALSE; + +static unsigned char mouse_scroll = 0; +static PDCREGS ms_regs, old_ms; +static unsigned short shift_status, old_shift = 0; +static unsigned char keyboard_function = 0xff, shift_function = 0xff, + check_function = 0xff; + +static const unsigned short button_map[3] = {0, 2, 1}; + +void PDC_set_keyboard_binary(bool on) +{ + PDC_LOG(("PDC_set_keyboard_binary() - called\n")); + +#ifdef __DJGPP__ + setmode(fileno(stdin), on ? O_BINARY : O_TEXT); + signal(SIGINT, on ? SIG_IGN : SIG_DFL); +#endif +} + +/* check if a key or mouse event is waiting */ + +bool PDC_check_key(void) +{ + PDCREGS regs; + + if (shift_function == 0xff) + { + int scan; + + /* get shift status for all keyboards */ + + regs.h.ah = 0x02; + PDCINT(0x16, regs); + scan = regs.h.al; + + /* get shift status for enhanced keyboards */ + + regs.h.ah = 0x12; + PDCINT(0x16, regs); + + if (scan == regs.h.al && getdosmembyte(0x496) == 0x10) + { + keyboard_function = 0x10; + check_function = 0x11; + shift_function = 0x12; + } + else + { + keyboard_function = 0; + check_function = 1; + shift_function = 2; + } + } + + regs.h.ah = shift_function; + PDCINT(0x16, regs); + + shift_status = regs.W.ax; + + if (mouse_vis) + { + unsigned short i; + + ms_regs.W.ax = 3; + PDCINT(0x33, ms_regs); + + mouse_button = FALSE; + + for (i = 0; i < 3; i++) + { + regs.W.ax = 6; + regs.W.bx = button_map[i]; + PDCINT(0x33, regs); + button[i].released = regs.W.bx; + if (regs.W.bx) + { + ms_regs.W.cx = regs.W.cx; + ms_regs.W.dx = regs.W.dx; + mouse_button = TRUE; + } + + regs.W.ax = 5; + regs.W.bx = button_map[i]; + PDCINT(0x33, regs); + button[i].pressed = regs.W.bx; + if (regs.W.bx) + { + ms_regs.W.cx = regs.W.cx; + ms_regs.W.dx = regs.W.dx; + mouse_button = TRUE; + } + } + + mouse_scroll = ms_regs.h.bh; + + mouse_moved = !mouse_button && ms_regs.h.bl && + ms_regs.h.bl == old_ms.h.bl && + (((ms_regs.W.cx ^ old_ms.W.cx) >> 3) || + ((ms_regs.W.dx / _FONT16) ^ (old_ms.W.dx / _FONT16))); + + if (mouse_scroll || mouse_button || mouse_moved) + return TRUE; + } + + if (old_shift && !shift_status) /* modifier released */ + { + if (!key_pressed && SP->return_key_modifiers) + return TRUE; + } + else if (!old_shift && shift_status) /* modifier pressed */ + key_pressed = FALSE; + + old_shift = shift_status; + + regs.h.ah = check_function; + PDCINT(0x16, regs); + + return !(regs.W.flags & 64); +} + +static int _process_mouse_events(void) +{ + int i; + short shift_flags = 0; + + memset(&SP->mouse_status, 0, sizeof(SP->mouse_status)); + + key_pressed = TRUE; + old_shift = shift_status; + SP->key_code = TRUE; + + /* Set shift modifiers */ + + if (shift_status & 3) + shift_flags |= BUTTON_SHIFT; + + if (shift_status & 4) + shift_flags |= BUTTON_CONTROL; + + if (shift_status & 8) + shift_flags |= BUTTON_ALT; + + /* Scroll wheel support for CuteMouse */ + + if (mouse_scroll) + { + SP->mouse_status.changes = mouse_scroll & 0x80 ? + PDC_MOUSE_WHEEL_UP : PDC_MOUSE_WHEEL_DOWN; + + SP->mouse_status.x = -1; + SP->mouse_status.y = -1; + + return KEY_MOUSE; + } + + if (mouse_moved) + { + SP->mouse_status.changes = PDC_MOUSE_MOVED; + + for (i = 0; i < 3; i++) + { + if (ms_regs.h.bl & (1 << button_map[i])) + { + SP->mouse_status.button[i] = BUTTON_MOVED | shift_flags; + SP->mouse_status.changes |= (1 << i); + } + } + } + else /* button event */ + { + for (i = 0; i < 3; i++) + { + if (button[i].pressed) + { + /* Check for a click -- a PRESS followed + immediately by a release */ + + if (!button[i].released) + { + if (SP->mouse_wait) + { + PDCREGS regs; + + napms(SP->mouse_wait); + + regs.W.ax = 6; + regs.W.bx = button_map[i]; + PDCINT(0x33, regs); + + SP->mouse_status.button[i] = regs.W.bx ? + BUTTON_CLICKED : BUTTON_PRESSED; + } + else + SP->mouse_status.button[i] = BUTTON_PRESSED; + } + else + SP->mouse_status.button[i] = BUTTON_CLICKED; + } + + if (button[i].pressed || button[i].released) + { + SP->mouse_status.button[i] |= shift_flags; + SP->mouse_status.changes |= (1 << i); + } + } + } + + SP->mouse_status.x = ms_regs.W.cx >> 3; + SP->mouse_status.y = ms_regs.W.dx / _FONT16; + + old_ms = ms_regs; + + return KEY_MOUSE; +} + +/* return the next available key or mouse event */ + +int PDC_get_key(void) +{ + PDCREGS regs; + int key, scan; + + SP->key_modifiers = 0; + + if (mouse_vis && (mouse_scroll || mouse_button || mouse_moved)) + return _process_mouse_events(); + + /* Return modifiers as keys? */ + + if (old_shift && !shift_status) + { + key = -1; + + if (old_shift & 1) + key = KEY_SHIFT_R; + + if (old_shift & 2) + key = KEY_SHIFT_L; + + if (shift_function == 0x12) + { + if (old_shift & 0x400) + key = KEY_CONTROL_R; + + if (old_shift & 0x100) + key = KEY_CONTROL_L; + + if (old_shift & 0x800) + key = KEY_ALT_R; + + if (old_shift & 0x200) + key = KEY_ALT_L; + } + else + { + if (old_shift & 4) + key = KEY_CONTROL_R; + + if (old_shift & 8) + key = KEY_ALT_R; + } + + key_pressed = FALSE; + old_shift = shift_status; + + SP->key_code = TRUE; + return key; + } + + regs.h.ah = keyboard_function; + PDCINT(0x16, regs); + key = regs.h.al; + scan = regs.h.ah; + + if (shift_status & 3) + SP->key_modifiers |= PDC_KEY_MODIFIER_SHIFT; + + if (shift_status & 4) + SP->key_modifiers |= PDC_KEY_MODIFIER_CONTROL; + + if (shift_status & 8) + SP->key_modifiers |= PDC_KEY_MODIFIER_ALT; + + if (shift_status & 0x20) + SP->key_modifiers |= PDC_KEY_MODIFIER_NUMLOCK; + + if (scan == 0x1c && key == 0x0a) /* ^Enter */ + key = CTL_ENTER; + else if (scan == 0xe0 && key == 0x0d) /* PadEnter */ + key = PADENTER; + else if (scan == 0xe0 && key == 0x0a) /* ^PadEnter */ + key = CTL_PADENTER; + else if (scan == 0x37 && key == 0x2a) /* Star */ + key = PADSTAR; + else if (scan == 0x4a && key == 0x2d) /* Minus */ + key = PADMINUS; + else if (scan == 0x4e && key == 0x2b) /* Plus */ + key = PADPLUS; + else if (scan == 0xe0 && key == 0x2f) /* Slash */ + key = PADSLASH; + else if (key == 0x00 || (key == 0xe0 && scan > 53 && scan != 86)) + key = (scan > 0xa7) ? -1 : key_table[scan]; + + if (shift_status & 3) + { + switch (key) + { + case KEY_HOME: /* Shift Home */ + key = KEY_SHOME; + break; + case KEY_UP: /* Shift Up */ + key = KEY_SUP; + break; + case KEY_PPAGE: /* Shift PgUp */ + key = KEY_SPREVIOUS; + break; + case KEY_LEFT: /* Shift Left */ + key = KEY_SLEFT; + break; + case KEY_RIGHT: /* Shift Right */ + key = KEY_SRIGHT; + break; + case KEY_END: /* Shift End */ + key = KEY_SEND; + break; + case KEY_DOWN: /* Shift Down */ + key = KEY_SDOWN; + break; + case KEY_NPAGE: /* Shift PgDn */ + key = KEY_SNEXT; + break; + case KEY_IC: /* Shift Ins */ + key = KEY_SIC; + break; + case KEY_DC: /* Shift Del */ + key = KEY_SDC; + } + } + + key_pressed = TRUE; + SP->key_code = ((unsigned)key >= 256); + + return key; +} + +/* discard any pending keyboard or mouse input -- this is the core + routine for flushinp() */ + +void PDC_flushinp(void) +{ + PDC_LOG(("PDC_flushinp() - called\n")); + + /* Force the BIOS keyboard buffer head and tail pointers to be + the same... Real nasty trick... */ + + setdosmemword(0x41a, getdosmemword(0x41c)); +} + +bool PDC_has_mouse(void) +{ + PDCREGS regs; + + if (!mouse_avail) + { + regs.W.ax = 0; + PDCINT(0x33, regs); + + mouse_avail = !!(regs.W.ax); + } + + return mouse_avail; +} + +int PDC_mouse_set(void) +{ + PDCREGS regs; + unsigned long mbe = SP->_trap_mbe; + + if (mbe && !mouse_avail) + mouse_avail = PDC_has_mouse(); + + if (mbe) + { + if (mouse_avail && !mouse_vis) + { + memset(&old_ms, 0, sizeof(old_ms)); + + regs.W.ax = 1; + PDCINT(0x33, regs); + + mouse_vis = TRUE; + } + } + else + { + if (mouse_avail && mouse_vis) + { + regs.W.ax = 2; + PDCINT(0x33, regs); + + mouse_vis = FALSE; + } + } + + return (mouse_avail || !mbe) ? OK : ERR; +} + +int PDC_modifiers_set(void) +{ + key_pressed = FALSE; + + return OK; +} diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c new file mode 100644 index 000000000..763f53d92 --- /dev/null +++ b/dosvga/pdcscrn.c @@ -0,0 +1,264 @@ +/* PDCurses */ + +#include "pdcdos.h" + +#include +#include + +/* TODO: support 8 bit palette registers if available */ +/* TODO: support modes with more than 4 bits per pixel */ + +struct PDC_video_state PDC_state; + +static short realtocurs[16] = +{ + COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, COLOR_RED, + COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE, COLOR_BLACK + 8, + COLOR_BLUE + 8, COLOR_GREEN + 8, COLOR_CYAN + 8, COLOR_RED + 8, + COLOR_MAGENTA + 8, COLOR_YELLOW + 8, COLOR_WHITE + 8 +}; + +static int saved_scrnmode[3]; + +/* _get_font_address() -- return the address of the font in ROM */ +static unsigned long _get_font_address(void) +{ + /* TODO: support compilers other than DJGPP */ + unsigned ofs = getdosmemword(0x43 * 4 + 0); + unsigned seg = getdosmemword(0x43 * 4 + 2); + return ((unsigned long)seg << 4) + ofs; +} + +/* _get_scrn_mode() - Return the current BIOS video mode */ + +static int _get_scrn_mode(void) +{ + PDCREGS regs; + + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x4F03; + PDCINT(0x10, regs); + if (regs.h.ah == 0) { + return (int)regs.W.bx; + } + + regs.h.ah = 0x0f; + PDCINT(0x10, regs); + + return (int)regs.h.al; +} + +/* _set_scrn_mode() - Sets the BIOS Video Mode Number */ + +static void _set_scrn_mode(int new_mode) +{ + PDCREGS regs; + + memset(®s, 0, sizeof(regs)); + if (new_mode >= 0x100) { + regs.W.ax = 0x4F02; + regs.W.bx = new_mode; + } else { + regs.h.ah = 0; + regs.h.al = (unsigned char) new_mode; + } + PDCINT(0x10, regs); + PDC_state.scrn_mode = new_mode & 0x3FFF; + + if (PDC_state.scrn_mode < 0x100) + { + PDC_state.linear_buffer = FALSE; + PDC_state.video_width = 640; + PDC_state.video_height = 400; + PDC_state.bytes_per_line = 80; + switch (PDC_state.scrn_mode) + { + case 0x0D: + case 0x0E: + PDC_state.video_height = 200; + break; + + case 0x0F: + case 0x10: + PDC_state.video_height = 350; + break; + + case 0x11: + case 0x12: + PDC_state.video_height = 480; + break; + } + } + else + { + /* TODO: support VESA modes */ + } + + PDC_state.font_addr = _get_font_address(); + LINES = PDC_get_rows(); + COLS = PDC_get_columns(); + PDC_curs_set(1); +} + +/* close the physical screen -- may restore the screen to its state + before PDC_scr_open(); miscellaneous cleanup */ + +void PDC_scr_close(void) +{ + PDCREGS regs; + + _set_scrn_mode(0x03); + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x1114; + regs.h.bl = 0x00; + PDCINT(0x10, regs); +} + +void PDC_scr_free(void) +{ +} + +/* open the physical screen -- miscellaneous initialization, may save + the existing screen for later restoration */ + +int PDC_scr_open(void) +{ +#if SMALL || MEDIUM + struct SREGS segregs; + int ds; +#endif + int i; + + PDC_LOG(("PDC_scr_open() - called\n")); + + SP = calloc(1, sizeof(SCREEN)); + + if (!SP) + return ERR; + + PDC_resize_screen(80, 25); + for (i = 0; i < 16; i++) + PDC_state.pdc_curstoreal[realtocurs[i]] = i; + + SP->orig_attr = FALSE; + + SP->mouse_wait = PDC_CLICK_PERIOD; + SP->audible = TRUE; + + SP->mono = FALSE; + SP->termattrs = A_COLOR | A_REVERSE | A_UNDERLINE; + + SP->_preserve = FALSE; + + return OK; +} + +/* the core of resize_term() */ + +int PDC_resize_screen(int nlines, int ncols) +{ + PDC_LOG(("PDC_resize_screen() - called. Lines: %d Cols: %d\n", + nlines, ncols)); + + /* Trash the stored value of orig_cursor -- it's only good if the + video mode doesn't change */ + + SP->orig_cursor = 0x0607; + + _set_scrn_mode(0x12); + + return OK; +} + +void PDC_reset_prog_mode(void) +{ + PDC_LOG(("PDC_reset_prog_mode() - called.\n")); +} + +void PDC_reset_shell_mode(void) +{ + PDC_LOG(("PDC_reset_shell_mode() - called.\n")); +} + +void PDC_restore_screen_mode(int i) +{ + if (i >= 0 && i <= 2) + { + _set_scrn_mode(saved_scrnmode[i]); + } +} + +void PDC_save_screen_mode(int i) +{ + if (i >= 0 && i <= 2) + { + saved_scrnmode[i] = _get_scrn_mode(); + } +} + +/* _egapal() - Find the EGA palette value (0-63) for the color (0-15). + On VGA, this is an index into the DAC. */ + +static short _egapal(short color) +{ + /* TODO: is this why I don't see output? */ + PDCREGS regs; + + regs.W.ax = 0x1007; + regs.h.bl = PDC_state.pdc_curstoreal[color]; + + PDCINT(0x10, regs); + + return regs.h.bh; +} + +bool PDC_can_change_color(void) +{ + return TRUE; +} + +/* These are only valid when PDC_state.pdc_adapter == _VGACOLOR */ + +int PDC_color_content(short color, short *red, short *green, short *blue) +{ + PDCREGS regs; + + /* Read single DAC register */ + /* TODO: support VESA modes */ + /* TODO: is this why I don't see output? */ + + regs.W.ax = 0x1015; + regs.h.bl = _egapal(color); + + PDCINT(0x10, regs); + + /* Scale and store */ + + *red = DIVROUND((unsigned)(regs.h.dh) * 1000, 63); + *green = DIVROUND((unsigned)(regs.h.ch) * 1000, 63); + *blue = DIVROUND((unsigned)(regs.h.cl) * 1000, 63); + + return OK; +} + +int PDC_init_color(short color, short red, short green, short blue) +{ + PDCREGS regs; + + /* Scale */ + + regs.h.dh = DIVROUND((unsigned)red * 63, 1000); + regs.h.ch = DIVROUND((unsigned)green * 63, 1000); + regs.h.cl = DIVROUND((unsigned)blue * 63, 1000); + + /* Set single DAC register */ + /* TODO: support VESA modes */ + /* TODO: is this why I don't see output? */ + + regs.W.ax = 0x1010; + regs.W.bx = _egapal(color); + + PDCINT(0x10, regs); + + return OK; +} diff --git a/dosvga/pdcsetsc.c b/dosvga/pdcsetsc.c new file mode 100644 index 000000000..84a5cc8fd --- /dev/null +++ b/dosvga/pdcsetsc.c @@ -0,0 +1,88 @@ +/* PDCurses */ + +#include "pdcdos.h" + +/*man-start************************************************************** + +pdcsetsc +-------- + +### Synopsis + + int PDC_set_blink(bool blinkon); + int PDC_set_bold(bool boldon); + void PDC_set_title(const char *title); + +### Description + + PDC_set_blink() toggles whether the A_BLINK attribute sets an actual + blink mode (TRUE), or sets the background color to high intensity + (FALSE). The default is platform-dependent (FALSE in most cases). It + returns OK if it could set the state to match the given parameter, + ERR otherwise. On DOS, this function also adjusts the value of COLORS + -- 16 for FALSE, and 8 for TRUE. + + PDC_set_bold() toggles whether the A_BOLD attribute selects an actual + bold font (TRUE), or sets the foreground color to high intensity + (FALSE). It returns OK if it could set the state to match the given + parameter, ERR otherwise. + + PDC_set_title() sets the title of the window in which the curses + program is running. This function may not do anything on some + platforms. + +### Portability + X/Open ncurses NetBSD + PDC_set_blink - - - + PDC_set_title - - - + +**man-end****************************************************************/ + +int PDC_curs_set(int visibility) +{ + int ret_vis, start, end; + + PDC_LOG(("PDC_curs_set() - called: visibility=%d\n", visibility)); + + ret_vis = SP->visibility; + SP->visibility = visibility; + + switch (visibility) + { + case 0: /* invisible */ + start = 1; + end = 0; + break; + case 2: /* highly visible */ + start = 0; /* full-height block */ + end = _FONT16 - 1; + break; + default: /* normal visibility */ + start = SP->orig_cursor >> 4; + end = SP->orig_cursor & 0xF; + } + + PDC_private_cursor_off(); + PDC_state.cursor_start = start; + PDC_state.cursor_end = end; + PDC_private_cursor_on(PDC_state.cursor_row, PDC_state.cursor_col); + + return ret_vis; +} + +void PDC_set_title(const char *title) +{ + PDC_LOG(("PDC_set_title() - called: <%s>\n", title)); +} + +int PDC_set_blink(bool blinkon) +{ + COLORS = 16; + return blinkon ? ERR : OK; +} + +int PDC_set_bold(bool boldon) +{ + /* TODO: support this */ + return boldon ? ERR : OK; +} diff --git a/dosvga/pdcutil.c b/dosvga/pdcutil.c new file mode 100644 index 000000000..c871762ff --- /dev/null +++ b/dosvga/pdcutil.c @@ -0,0 +1,103 @@ +/* PDCurses */ + +#include "pdcdos.h" + +void PDC_beep(void) +{ + PDCREGS regs; + + PDC_LOG(("PDC_beep() - called\n")); + + regs.W.ax = 0x0e07; /* Write ^G in TTY fashion */ + regs.W.bx = 0; + PDCINT(0x10, regs); +} + +void PDC_napms(int ms) +{ + PDCREGS regs; + long goal, start, current; + + PDC_LOG(("PDC_napms() - called: ms=%d\n", ms)); + + goal = DIVROUND((long)ms, 50); + if (!goal) + goal++; + + start = getdosmemdword(0x46c); + + goal += start; + + while (goal > (current = getdosmemdword(0x46c))) + { + if (current < start) /* in case of midnight reset */ + return; + + regs.W.ax = 0x1680; + PDCINT(0x2f, regs); + PDCINT(0x28, regs); + } +} + +const char *PDC_sysname(void) +{ + return "DOSVGA"; +} + +#ifdef __DJGPP__ + +unsigned char getdosmembyte(int offset) +{ + unsigned char b; + + dosmemget(offset, sizeof(unsigned char), &b); + return b; +} + +unsigned short getdosmemword(int offset) +{ + unsigned short w; + + dosmemget(offset, sizeof(unsigned short), &w); + return w; +} + +unsigned long getdosmemdword(int offset) +{ + unsigned long dw; + + dosmemget(offset, sizeof(unsigned long), &dw); + return dw; +} + +void setdosmembyte(int offset, unsigned char b) +{ + dosmemput(&b, sizeof(unsigned char), offset); +} + +void setdosmemword(int offset, unsigned short w) +{ + dosmemput(&w, sizeof(unsigned short), offset); +} + +#endif + +#if defined(__WATCOMC__) && defined(__386__) + +void PDC_dpmi_int(int vector, pdc_dpmi_regs *rmregs) +{ + union REGPACK regs = {0}; + + rmregs->w.ss = 0; + rmregs->w.sp = 0; + rmregs->w.flags = 0; + + regs.w.ax = 0x300; + regs.h.bl = vector; + regs.x.edi = FP_OFF(rmregs); + regs.x.es = FP_SEG(rmregs); + + intr(0x31, ®s); +} + +#endif From 2c23a5a8a69a9944d500298a76e315591c32ec2a Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Tue, 18 Feb 2020 22:37:19 -0500 Subject: [PATCH 02/26] Write like-colored characters in one pass Reduces the use of the plane register, which speeds up the write when running under emulation. --- dosvga/pdcdisp.c | 180 ++++++++++++++++++++++++++--------------------- 1 file changed, 100 insertions(+), 80 deletions(-) diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index fd027be16..9e0dd9ea2 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -6,7 +6,7 @@ /* Support cursor on graphics mode */ static unsigned char bytes_behind[4][16]; static unsigned char cursor_color = 15; -static void draw_glyph(int row, int col, chtype glyph); +static unsigned _get_colors(chtype glyph); static unsigned long address(int row, int col); static void video_write_byte(unsigned long addr, unsigned char byte); static unsigned char video_read_byte(unsigned long addr); @@ -20,21 +20,112 @@ void PDC_gotoyx(int row, int col) PDC_private_cursor_on(row, col); } +static void _new_packet(unsigned colors, int lineno, int x, int len, const chtype *srcp) +{ + unsigned fore, back; + int underline; + unsigned long addr = address(lineno, x); + unsigned pass; + + fore = colors & 0xF; + back = colors >> 4; + + /* Underline will go here if requested */ + underline = 13 /*_FONT16*/; + + /* Draw the text in four passes, to optimize for the memory architecture + of the VGA in four bit pixel modes */ + for (pass = 0; pass < 4; pass++) + { + unsigned char vplane; + unsigned long cp; + int line; + int col; + + /* Set memory planes to write */ + if (pass & 2) + vplane = fore; + else + vplane = ~fore; + if (pass & 1) + vplane &= back; + else + vplane &= ~back; + vplane &= 0xF; + if (vplane == 0) + continue; + outportb(0x3c4, 2); + outportb(0x3c5, vplane); + + /* Loop by raster line */ + cp = addr; + for (line = 0; line < _FONT16; line++) + { + /* Loop by column */ + for (col = 0; col < len; col++) + { + chtype glyph = srcp[col]; + int ch; + unsigned char byte; + + /* Get the index into the font */ + ch = glyph & 0xFF; + if ((glyph & A_ALTCHARSET) != 0 && (glyph & 0xff80) == 0) + ch = acs_map[ch & 0x7f] & 0xff; + + /* Get one byte of the glyph to be drawn */ + if (pass == 0 || pass == 3) + byte = 0x00; + else if (line == underline && (glyph & A_UNDERLINE) != 0) + byte = 0xFF; + else + byte = getdosmembyte(PDC_state.font_addr + ch*_FONT16 + line); + if (pass & 1) + byte = ~byte; + + /* Place the byte in the frame buffer */ + video_write_byte(cp + col, byte); + } + cp += PDC_state.bytes_per_line; + } + } +} + /* update the given physical line to look like the corresponding line in curscr */ void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) { - int i; + unsigned old_colors, colors; + int i, j; PDC_LOG(("PDC_transform_line() - called: lineno=%d\n", lineno)); - for (i = 0; i < len; i++) + /* Draw runs of characters that have the same colors */ + old_colors = _get_colors(srcp[0]); + + for (i = 1, j = 1; j < len; i++, j++) { - draw_glyph(lineno, x + i, srcp[i]); - if (lineno == PDC_state.cursor_row && x + i == PDC_state.cursor_col) - PDC_private_cursor_on(PDC_state.cursor_row, PDC_state.cursor_col); + colors = _get_colors(srcp[i]); + + if (colors != old_colors) + { + _new_packet(old_colors, lineno, x, i, srcp); + old_colors = colors; + srcp += i; + x += i; + i = 0; + } } + + _new_packet(old_colors, lineno, x, i, srcp); + + /* Redraw the cursor if it has been erased */ + if (lineno == PDC_state.cursor_row + && x <= PDC_state.cursor_col && PDC_state.cursor_col < x + len) + PDC_private_cursor_on(PDC_state.cursor_row, PDC_state.cursor_col); + + /* Reset the VGA plane register to its normal state */ outportb(0x3c4, 2); outportb(0x3c5, 0xF); } @@ -43,18 +134,10 @@ void PDC_doupdate(void) { } -static void draw_glyph(int row, int col, chtype glyph) +static unsigned _get_colors(chtype glyph) { - unsigned long addr = address(row, col); - unsigned long font_addr; attr_t attr; - unsigned long cp; - unsigned char ch; short fore, back; - unsigned char vplane; - int line; - int underline; - unsigned char fnt; /* Get the foreground and background colors */ attr = glyph & (A_ATTRIBUTES ^ A_ALTCHARSET); @@ -75,71 +158,8 @@ static void draw_glyph(int row, int col, chtype glyph) back = swap; } - /* Set underline if requested */ - underline = (attr & A_UNDERLINE) ? 13 /*_FONT16*/ : -1; - - /* Get the index into the font */ - ch = glyph & 0xFF; - if (glyph & A_ALTCHARSET && !(glyph & 0xff80)) - ch = acs_map[ch & 0x7f] & 0xff; - - /* Get the address of the glyph in memory */ - font_addr = PDC_state.font_addr + ch * _FONT16; - - /* Planes where fore has 0 and back has 0 */ - vplane = ~fore & ~back & 0xF; - if (vplane != 0) { - outportb(0x3c4, 2); - outportb(0x3c5, vplane); - cp = addr; - for (line = 0; line < _FONT16; ++line) { - fnt = 0x00; - video_write_byte(cp, fnt); - cp += PDC_state.bytes_per_line; - } - } - /* Planes where fore has 1 and back has 0 */ - vplane = fore & ~back & 0xF; - if (vplane != 0) { - outportb(0x3c4, 2); - outportb(0x3c5, vplane); - cp = addr; - for (line = 0; line < _FONT16; ++line) { - if (line == underline) - fnt = 0xFF; - else - fnt = getdosmembyte(font_addr + line); - video_write_byte(cp, fnt); - cp += PDC_state.bytes_per_line; - } - } - /* Planes where fore has 0 and back has 1 */ - vplane = ~fore & back & 0xF; - if (vplane != 0) { - outportb(0x3c4, 2); - outportb(0x3c5, vplane); - cp = addr; - for (line = 0; line < _FONT16; ++line) { - if (line == underline) - fnt = 0x00; - else - fnt = ~getdosmembyte(font_addr + line); - video_write_byte(cp, fnt); - cp += PDC_state.bytes_per_line; - } - } - /* Planes where fore has 1 and back has 1 */ - vplane = fore & back & 0xF; - if (vplane != 0) { - outportb(0x3c4, 2); - outportb(0x3c5, vplane); - cp = addr; - for (line = 0; line < _FONT16; ++line) { - fnt = 0xFF; - video_write_byte(cp, fnt); - cp += PDC_state.bytes_per_line; - } - } + /* Return them as a pair */ + return (back << 4) | fore; } void PDC_private_cursor_off(void) From 482d065af03dd33ced01f817b5b80e3e6cd2bfd0 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Tue, 18 Feb 2020 22:50:38 -0500 Subject: [PATCH 03/26] Remove some stray comments --- dosvga/pdcscrn.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index 763f53d92..c17f47e2e 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -201,7 +201,6 @@ void PDC_save_screen_mode(int i) static short _egapal(short color) { - /* TODO: is this why I don't see output? */ PDCREGS regs; regs.W.ax = 0x1007; @@ -225,7 +224,6 @@ int PDC_color_content(short color, short *red, short *green, short *blue) /* Read single DAC register */ /* TODO: support VESA modes */ - /* TODO: is this why I don't see output? */ regs.W.ax = 0x1015; regs.h.bl = _egapal(color); @@ -253,7 +251,6 @@ int PDC_init_color(short color, short red, short green, short blue) /* Set single DAC register */ /* TODO: support VESA modes */ - /* TODO: is this why I don't see output? */ regs.W.ax = 0x1010; regs.W.bx = _egapal(color); From fc2cec8c67e571b6a5e64ee8481f1a4b979aaaa7 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Wed, 19 Feb 2020 02:26:56 -0500 Subject: [PATCH 04/26] Support 4 bit VESA graphics modes --- dosvga/pdcdisp.c | 69 +++++---- dosvga/pdcdos.h | 19 +-- dosvga/pdcscrn.c | 356 ++++++++++++++++++++++++++++++++++++++++++----- dosvga/pdcvesa.h | 88 ++++++++++++ 4 files changed, 460 insertions(+), 72 deletions(-) create mode 100644 dosvga/pdcvesa.h diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index 9e0dd9ea2..6533ed3d2 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -7,9 +7,10 @@ static unsigned char bytes_behind[4][16]; static unsigned char cursor_color = 15; static unsigned _get_colors(chtype glyph); -static unsigned long address(int row, int col); -static void video_write_byte(unsigned long addr, unsigned char byte); -static unsigned char video_read_byte(unsigned long addr); +static unsigned long _address(int row, int col); +static void _video_write_byte(unsigned long addr, unsigned char byte); +static unsigned char _video_read_byte(unsigned long addr); +static unsigned _set_window(unsigned window, unsigned long addr); /* position hardware cursor at (y, x) */ @@ -24,7 +25,7 @@ static void _new_packet(unsigned colors, int lineno, int x, int len, const chtyp { unsigned fore, back; int underline; - unsigned long addr = address(lineno, x); + unsigned long addr = _address(lineno, x); unsigned pass; fore = colors & 0xF; @@ -84,7 +85,7 @@ static void _new_packet(unsigned colors, int lineno, int x, int len, const chtyp byte = ~byte; /* Place the byte in the frame buffer */ - video_write_byte(cp + col, byte); + _video_write_byte(cp + col, byte); } cp += PDC_state.bytes_per_line; } @@ -166,7 +167,7 @@ void PDC_private_cursor_off(void) { if (PDC_state.cursor_visible && PDC_state.cursor_row < (unsigned)LINES && PDC_state.cursor_col < (unsigned)COLS) { - unsigned long addr = address(PDC_state.cursor_row, PDC_state.cursor_col); + unsigned long addr = _address(PDC_state.cursor_row, PDC_state.cursor_col); unsigned plane; unsigned line; @@ -177,7 +178,7 @@ void PDC_private_cursor_off(void) outportb(0x03C5, 1 << plane); for (line = 0; line < _FONT16; ++line) { - video_write_byte(p, bytes_behind[plane][line]); + _video_write_byte(p, bytes_behind[plane][line]); p += PDC_state.bytes_per_line; } } @@ -187,7 +188,7 @@ void PDC_private_cursor_off(void) void PDC_private_cursor_on(int row, int col) { - unsigned long addr = address(row, col); + unsigned long addr = _address(row, col); unsigned long p; unsigned plane; unsigned line; @@ -199,26 +200,26 @@ void PDC_private_cursor_on(int row, int col) outportb(0x03CF, plane); for (line = 0; line < _FONT16; ++line) { - bytes_behind[plane][line] = video_read_byte(p); + bytes_behind[plane][line] = _video_read_byte(p); p += PDC_state.bytes_per_line; } } outportb(0x03C5, 2); outportb(0x03C5, cursor_color); - p = address(row, col); + p = _address(row, col); p += PDC_state.cursor_start * PDC_state.bytes_per_line; for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) { - video_write_byte(p, 0xFF); + _video_write_byte(p, 0xFF); p += PDC_state.bytes_per_line; } outportb(0x03C5, 2); outportb(0x03C5, ~cursor_color); - p = address(row, col); + p = _address(row, col); p += PDC_state.cursor_start * PDC_state.bytes_per_line; for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) { - video_write_byte(p, 0x00); + _video_write_byte(p, 0x00); p += PDC_state.bytes_per_line; } outportb(0x03C5, 2); @@ -228,25 +229,43 @@ void PDC_private_cursor_on(int row, int col) PDC_state.cursor_col = col; } -static unsigned long address(int row, int col) +static unsigned long _address(int row, int col) { return row * PDC_state.bytes_per_line * _FONT16 + col; } -static void video_write_byte(unsigned long addr, unsigned char byte) +static void _video_write_byte(unsigned long addr, unsigned char byte) { - /* TODO: support VESA modes */ - if (addr < 0x10000) - setdosmembyte(0xA0000 + addr, byte); + unsigned offset = _set_window(PDC_state.write_win, addr); + unsigned long addr2 = PDC_state.window[PDC_state.write_win]*16L + offset; + setdosmembyte(addr2, byte); } -static unsigned char video_read_byte(unsigned long addr) +static unsigned char _video_read_byte(unsigned long addr) { - /* TODO: support VESA modes */ - unsigned char byte; - if (addr < 0x10000) - byte = getdosmembyte(0xA0000 + addr); - else - byte = 0; + unsigned offset = _set_window(PDC_state.read_win, addr); + unsigned long addr2 = PDC_state.window[PDC_state.read_win]*16L + offset; + unsigned char byte = getdosmembyte(addr2); return byte; } + +static unsigned _set_window(unsigned window, unsigned long addr) +{ + unsigned long offset = PDC_state.offset[window]; + if (addr < offset || offset + PDC_state.window_size <= addr) + { + /* Need to move the window */ + __dpmi_regs regs; + unsigned long gran = PDC_state.window_gran * 1024L; + + memset(®s, 0, sizeof(regs)); + regs.x.ax = 0x4F05; + regs.x.bx = window; + regs.x.dx = addr / gran; + offset = regs.x.dx * gran; + __dpmi_int(0x10, ®s); + PDC_state.offset[window] = offset; + } + + return addr - offset; +} diff --git a/dosvga/pdcdos.h b/dosvga/pdcdos.h index 6c89e2f2a..b8386a876 100644 --- a/dosvga/pdcdos.h +++ b/dosvga/pdcdos.h @@ -46,9 +46,10 @@ struct PDC_video_state unsigned short video_height; /* Height of graphics mode in pixels */ unsigned short bytes_per_line; /* Bytes per raster line */ /* Location of the frame buffer in memory */ - unsigned window[2]; - unsigned offset[2]; + unsigned short window[2]; + unsigned long offset[2]; unsigned long window_size; + unsigned window_gran; /* Window used to read and write */ unsigned char read_win; unsigned char write_win; @@ -63,20 +64,6 @@ struct PDC_video_state unsigned char cursor_end; short pdc_curstoreal[16]; - -#if 0 - int pdc_adapter; /* screen type */ - int pdc_scrnmode; /* default screen mode */ - int pdc_font; /* default font size */ - bool pdc_direct_video; /* allow direct screen memory writes */ - bool pdc_bogus_adapter; /* TRUE if adapter has insane values */ - unsigned pdc_video_seg; /* video base segment */ - unsigned pdc_video_ofs; /* video base offset */ - - bool graphics_mode; /* TRUE if operating in a graphics mode */ - unsigned video_width; /* Width of graphics mode in pixels */ - unsigned video_height; /* Height of graphics mode in pixels */ -#endif }; extern struct PDC_video_state PDC_state; diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index c17f47e2e..22f974a4e 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -1,6 +1,7 @@ /* PDCurses */ #include "pdcdos.h" +#include "pdcvesa.h" #include #include @@ -20,6 +21,13 @@ static short realtocurs[16] = static int saved_scrnmode[3]; +static int _get_mode_info(unsigned mode, struct ModeInfoBlock *mode_info); +static unsigned _find_video_mode(int rows, int cols); +static unsigned _find_mode( + struct ModeInfoBlock *mode_info, + unsigned long mode_addr, + int rows, int cols); + /* _get_font_address() -- return the address of the font in ROM */ static unsigned long _get_font_address(void) { @@ -65,35 +73,6 @@ static void _set_scrn_mode(int new_mode) PDCINT(0x10, regs); PDC_state.scrn_mode = new_mode & 0x3FFF; - if (PDC_state.scrn_mode < 0x100) - { - PDC_state.linear_buffer = FALSE; - PDC_state.video_width = 640; - PDC_state.video_height = 400; - PDC_state.bytes_per_line = 80; - switch (PDC_state.scrn_mode) - { - case 0x0D: - case 0x0E: - PDC_state.video_height = 200; - break; - - case 0x0F: - case 0x10: - PDC_state.video_height = 350; - break; - - case 0x11: - case 0x12: - PDC_state.video_height = 480; - break; - } - } - else - { - /* TODO: support VESA modes */ - } - PDC_state.font_addr = _get_font_address(); LINES = PDC_get_rows(); COLS = PDC_get_columns(); @@ -136,7 +115,7 @@ int PDC_scr_open(void) if (!SP) return ERR; - PDC_resize_screen(80, 25); + PDC_resize_screen(25, 80); for (i = 0; i < 16; i++) PDC_state.pdc_curstoreal[realtocurs[i]] = i; @@ -165,7 +144,7 @@ int PDC_resize_screen(int nlines, int ncols) SP->orig_cursor = 0x0607; - _set_scrn_mode(0x12); + _set_scrn_mode(_find_video_mode(nlines, ncols)); return OK; } @@ -259,3 +238,318 @@ int PDC_init_color(short color, short red, short green, short blue) return OK; } + +static unsigned _find_video_mode(int rows, int cols) +{ + 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; + unsigned vesa_mode; + + /* Request VESA BIOS information */ + vbe_info_seg = __dpmi_allocate_dos_memory( + (sizeof(vbe_info) + 15) / 16, + &vbe_info_sel); + if (vbe_info_seg < 0) + goto error; + + memset(&vbe_info, 0, sizeof(vbe_info)); + memcpy(vbe_info.VbeSignature, "VBE2", 4); + dosmemput(&vbe_info, sizeof(vbe_info), vbe_info_seg * 16L); + + memset(®s, 0, sizeof(regs)); + regs.x.ax = 0x4F00; + regs.x.di = 0; + regs.x.es = vbe_info_seg; + __dpmi_int(0x10, ®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); + + /* Look for the best-fitting mode available */ + vesa_mode = _find_mode(&mode_info, mode_addr, rows, cols); + if (vesa_mode == 0xFFFF) + vesa_mode = _find_mode(&mode_info, mode_addr, 0, 0); + if (vesa_mode == 0xFFFF) + goto error; + + /* Set up frame buffer window */ + if ((mode_info.WinAAttributes & 0x2) != 0) + PDC_state.read_win = 0; /* Read through Window A */ + else if ((mode_info.WinBAttributes & 0x2) != 0) + PDC_state.read_win = 1; /* Read through Window B */ + else + goto error; /* shouldn't happen */ + if ((mode_info.WinAAttributes & 0x1) != 0) + PDC_state.write_win = 0; /* Write through Window A */ + else if ((mode_info.WinBAttributes & 0x1) != 0) + PDC_state.write_win = 1; /* Write through Window B */ + else + goto error; /* shouldn't happen */ + PDC_state.window[0] = mode_info.WinASegment; + PDC_state.window[1] = mode_info.WinBSegment; + if (vesa_mode == 0x12) + { + PDC_state.offset[0] = 0; + PDC_state.offset[1] = 0; + } + else + { + PDC_state.offset[0] = 0xFFFFFFFF; /* offset is unknown */ + PDC_state.offset[1] = 0xFFFFFFFF; + } + PDC_state.window_size = mode_info.WinSize * 1024L; + PDC_state.window_gran = mode_info.WinGranularity; + PDC_state.bytes_per_line = mode_info.BytesPerScanLine; + PDC_state.video_width = mode_info.XResolution; + PDC_state.video_height = mode_info.YResolution; + + __dpmi_free_dos_memory(vbe_info_sel); + return vesa_mode; + +error: + /* If we can't access the VESA BIOS Extensions for any reason, return the + 640x480 VGA mode */ + if (vbe_info_sel != -1) + __dpmi_free_dos_memory(vbe_info_sel); + + PDC_state.linear_buffer = FALSE; + PDC_state.video_width = 640; + PDC_state.video_height = 480; + PDC_state.bytes_per_line = 80; + PDC_state.read_win = 0; + PDC_state.write_win = 0; + PDC_state.window[0] = 0xA000; + PDC_state.window[1] = 0xA000; + PDC_state.offset[0] = 0; + PDC_state.offset[1] = 0; + PDC_state.window_size = (640/8) * 480; + PDC_state.window_gran = 1; + + return 0x12; +} + +static unsigned _find_mode( + struct ModeInfoBlock *mode_info, + unsigned long mode_addr, + int rows, int cols) +{ + unsigned selected_mode; + unsigned long selected_size; + + selected_mode = 0xFFFF; + selected_size = (rows == 0 && cols == 0) ? 0 : 0xFFFFFFFF; + + if (rows <= 30 && cols <= 80) + { + /* Set up a ModeInfoBlock for mode 0x0012 */ + selected_mode = 0x0012; + selected_size = 80 * 30; + memset(mode_info, 0, sizeof(*mode_info)); + mode_info->ModeAttributes = 0x1F; + mode_info->WinAAttributes = 0x07; + mode_info->WinBAttributes = 0x00; + mode_info->WinGranularity = 1; + mode_info->WinSize = 38; + mode_info->WinASegment = 0xA000; + mode_info->WinBSegment = 0; + mode_info->WinFuncPtr = 0; + mode_info->BytesPerScanLine = 80; + mode_info->XResolution = 640; + mode_info->YResolution = 480; + mode_info->NumberOfPlanes = 4; + mode_info->BitsPerPixel = 4; + mode_info->NumberOfBanks = 1; + mode_info->MemoryModel = 3; + } + + while (1) + { + unsigned mode; + struct ModeInfoBlock mode_info0; + unsigned new_rows, new_cols; + unsigned long new_size; + + mode = getdosmemword(mode_addr); + if (mode == 0xFFFF) + break; + mode_addr += 2; + + /* Query the mode info; skip if not supported */ + if (_get_mode_info(mode, &mode_info0) < 0) + continue; + + /* Check that the mode is acceptable: */ + /* Supported, graphics mode, color, VGA compatible */ + if ((mode_info0.ModeAttributes & 0x79) != 0x19) + continue; + /* Bits per pixel and memory model are acceptable */ + switch (mode_info0.BitsPerPixel) + { + case 4: + if (mode_info0.MemoryModel != 3) /* Planar */ + continue; + if (mode_info0.NumberOfPlanes != 4) + continue; + break; + /* TODO: 8, 15, 16, 24 and 32 bits */ + + default: + continue; + } + + /* At least as many rows and columns as requested */ + new_cols = mode_info0.XResolution / 8; + new_rows = mode_info0.YResolution / _FONT16; + if (new_cols < cols || new_rows < rows) + continue; + + /* If rows == 0 and cols == 0, select the largest available size; + otherwise, select the smallest that can hold that many rows and + columns */ + new_size = (unsigned long)new_rows * new_cols; + if (rows == 0 && cols == 0) + { + if (new_size <= selected_size) + continue; + } + else + { + if (new_size >= selected_size) + continue; + } + + /* Select this mode, pending discovery of a better one */ + selected_mode = mode; + selected_size = new_size; + *mode_info = mode_info0; + } + + return selected_mode; +} + +static int _get_mode_info(unsigned mode, struct ModeInfoBlock *mode_info) +{ + 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 */ + }; + static const struct OldModeInfo old_mode_table[] = + { + { 0x0100, 640, 480, 4 }, + { 0x0101, 640, 480, 8 }, + { 0x0102, 800, 600, 4 }, + { 0x0103, 800, 600, 8 }, + { 0x0104, 1024, 768, 4 }, + { 0x0105, 1024, 768, 8 }, + { 0x0106, 1280, 1024, 4 }, + { 0x0107, 1280, 1024, 8 }, + { 0x010D, 320, 200, 15 }, + { 0x010E, 320, 200, 16 }, + { 0x010F, 320, 200, 24 }, + { 0x0110, 640, 480, 15 }, + { 0x0111, 640, 480, 16 }, + { 0x0112, 640, 480, 24 }, + { 0x0113, 800, 600, 15 }, + { 0x0114, 800, 600, 16 }, + { 0x0115, 800, 600, 24 }, + { 0x0116, 1024, 768, 15 }, + { 0x0117, 1024, 768, 16 }, + { 0x0118, 1024, 768, 24 }, + { 0x0119, 1280, 1024, 15 }, + { 0x011A, 1280, 1024, 16 }, + { 0x011B, 1280, 1024, 24 }, + /* sentinel */ + { 0, 0, 0, 0 } + }; + + int mode_info_sel = -1; /* custodial */ + int mode_info_seg; + __dpmi_regs regs; + + mode_info_seg = __dpmi_allocate_dos_memory( + (sizeof(*mode_info) + 15) / 16, + &mode_info_sel); + if (mode_info_seg < 0) + goto error; + + memset(mode_info, 0, sizeof(*mode_info)); + dosmemput(mode_info, sizeof(*mode_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(0x10, ®s); + + if (regs.x.ax != 0x004F) + goto error; + dosmemget(mode_info_seg * 16L, sizeof(*mode_info), mode_info); + if (!(mode_info->ModeAttributes & 0x0001)) + goto error; + + if (!(mode_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; old_mode_table[i].mode != 0; ++i) + { + if (mode == old_mode_table[i].mode) + break; + } + if (old_mode_table[i].mode == 0) + goto error; + + mode_info->XResolution = old_mode_table[i].XResolution; + mode_info->YResolution = old_mode_table[i].YResolution; + mode_info->BitsPerPixel = old_mode_table[i].BitsPerPixel; + mode_info->NumberOfBanks = 1; + switch (mode_info->BitsPerPixel) + { + case 4: + mode_info->NumberOfPlanes = 4; + mode_info->MemoryModel = 3; + break; + + case 8: + mode_info->NumberOfPlanes = 1; + mode_info->MemoryModel = 4; + break; + + default: + mode_info->NumberOfPlanes = 1; + mode_info->MemoryModel = 6; + break; + } + } + + __dpmi_free_dos_memory(mode_info_sel); + return TRUE; + +error: + if (mode_info_sel != -1) __dpmi_free_dos_memory(mode_info_sel); + return FALSE; +} diff --git a/dosvga/pdcvesa.h b/dosvga/pdcvesa.h new file mode 100644 index 000000000..b30b43c41 --- /dev/null +++ b/dosvga/pdcvesa.h @@ -0,0 +1,88 @@ +/* VESA structures from the VESA BIOS Specification, retrieved 15 Jan 2016 + * from http://flint.cs.yale.edu/cs422/readings/hardware/vbe3.pdf */ + +#ifndef PDCVESA_H +#define PDCVESA_H + +#ifdef __GNUC__ +#pragma pack(push, 1) +#endif +#ifdef __WATCOMC__ +#pragma pack(__push, 1) +#endif +struct VbeInfoBlock { + unsigned char VbeSignature[4]; /* VBE Signature */ + unsigned short VbeVersion; /* VBE Version */ + unsigned long OemStringPtr; /* VbeFarPtr to OEM String */ + unsigned long Capabilities; /* Capabilities of graphics controller */ + unsigned long VideoModePtr; /* VbeFarPtr to VideoModeList */ + unsigned short TotalMemory; /* Number of 64kb memory blocks */ + /* Added for VBE 2.0+ */ + unsigned short OemSoftwareRev; /* VBE implementation Software revision */ + unsigned long OemVendorNamePtr; /* VbeFarPtr to Vendor Name String */ + unsigned long OemProductNamePtr; /* VbeFarPtr to Product Name String */ + unsigned long OemProductRevPtr; /* VbeFarPtr to Product Revision String */ + unsigned char Reserved[222]; /* Reserved for VBE implementation scratch area */ + unsigned char OemData[256]; /* Data Area for OEM Strings */ +}; + +struct ModeInfoBlock { + /* Mandatory information for all VBE revisions */ + unsigned short ModeAttributes; /* mode attributes */ + unsigned char WinAAttributes; /* window A attributes */ + unsigned char WinBAttributes; /* window B attributes */ + unsigned short WinGranularity; /* window granularity */ + unsigned short WinSize; /* window size */ + unsigned short WinASegment; /* window A start segment */ + unsigned short WinBSegment; /* window B start segment */ + unsigned long WinFuncPtr; /* real mode pointer to window function */ + unsigned short BytesPerScanLine; /* bytes per scan line */ + /* Mandatory information for VBE 1.2 and above */ + unsigned short XResolution; /* horizontal resolution in pixels or characters */ + unsigned short YResolution; /* vertical resolution in pixels or characters */ + unsigned char XCharSize; /* character cell width in pixels */ + unsigned char YCharSize; /* character cell height in pixels */ + unsigned char NumberOfPlanes; /* number of memory planes */ + unsigned char BitsPerPixel; /* bits per pixel */ + unsigned char NumberOfBanks; /* number of banks */ + unsigned char MemoryModel; /* memory model type */ + unsigned char BankSize; /* bank size in KB */ + unsigned char NumberOfImagePages; /* number of images */ + unsigned char Reserved1; /* reserved for page function */ + /* Direct Color fields (required for direct/6 and YUV/7 memory models) */ + unsigned char RedMaskSize; /* size of direct color red mask in bits */ + unsigned char RedFieldPosition; /* bit position of lsb of red mask */ + unsigned char GreenMaskSize; /* size of direct color green mask in bits */ + unsigned char GreenFieldPosition; /* bit position of lsb of green mask */ + unsigned char BlueMaskSize; /* size of direct color blue mask in bits */ + unsigned char BlueFieldPosition; /* bit position of lsb of blue mask */ + unsigned char RsvdMaskSize; /* size of direct color reserved mask in bits */ + unsigned char RsvdFieldPosition; /* bit position of lsb of reserved mask */ + unsigned char DirectColorModeInfo; /* direct color mode attributes */ + /* Mandatory information for VBE 2.0 and above */ + unsigned long PhysBasePtr; /* physical address for flat memory frame buffer */ + unsigned long Reserved2; /* Reserved - always set to 0 */ + unsigned short Reserved3; /* Reserved - always set to 0 */ + /* Mandatory information for VBE 3.0 and above */ + unsigned short LinBytesPerScanLine; /* bytes per scan line for linear modes */ + unsigned char BnkNumberOfImagePages; /* number of images for banked modes */ + unsigned char LinNumberOfImagePages; /* number of images for linear modes */ + unsigned char LinRedMaskSize; /* size of direct color red mask (linear modes) */ + unsigned char LinRedFieldPosition; /* bit position of lsb of red mask (linear modes) */ + unsigned char LinGreenMaskSize; /* size of direct color green mask (linear modes) */ + unsigned char LinGreenFieldPosition; /* bit position of lsb of green mask (linear modes) */ + unsigned char LinBlueMaskSize; /* size of direct color blue mask (linear modes) */ + unsigned char LinBlueFieldPosition; /* bit position of lsb of blue mask (linear modes) */ + unsigned char LinRsvdMaskSize; /* size of direct color reserved mask (linear modes) */ + unsigned char LinRsvdFieldPosition; /* bit position of lsb of reserved mask (linear modes) */ + unsigned long MaxPixelClock; /* maximum pixel clock (in Hz) for graphics mode */ + unsigned char Reserved4[189]; /* remainder of ModeInfoBlock */ +}; +#ifdef __GNUC__ +#pragma pack(pop) +#endif +#ifdef __WATCOMC__ +#pragma pack(__pop) +#endif + +#endif From d1796bc38852894502d9c16a5a1aa50e341bb64d Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Wed, 19 Feb 2020 02:28:40 -0500 Subject: [PATCH 05/26] Fix problems with drawing the cursor --- dosvga/pdcdisp.c | 11 +++++++++-- dosvga/pdcgetsc.c | 2 +- dosvga/pdcscrn.c | 8 ++------ dosvga/pdcsetsc.c | 7 ++++--- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index 6533ed3d2..62932d9b0 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -97,11 +97,19 @@ static void _new_packet(unsigned colors, int lineno, int x, int len, const chtyp void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) { + bool redraw_cursor; unsigned old_colors, colors; int i, j; PDC_LOG(("PDC_transform_line() - called: lineno=%d\n", lineno)); + redraw_cursor = PDC_state.cursor_visible + && lineno == PDC_state.cursor_row + && x <= PDC_state.cursor_col + && PDC_state.cursor_col < x + len; + if (redraw_cursor) + PDC_private_cursor_off(); + /* Draw runs of characters that have the same colors */ old_colors = _get_colors(srcp[0]); @@ -122,8 +130,7 @@ void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) _new_packet(old_colors, lineno, x, i, srcp); /* Redraw the cursor if it has been erased */ - if (lineno == PDC_state.cursor_row - && x <= PDC_state.cursor_col && PDC_state.cursor_col < x + len) + if (redraw_cursor) PDC_private_cursor_on(PDC_state.cursor_row, PDC_state.cursor_col); /* Reset the VGA plane register to its normal state */ diff --git a/dosvga/pdcgetsc.c b/dosvga/pdcgetsc.c index 1d6efa3ba..d75b39d70 100644 --- a/dosvga/pdcgetsc.c +++ b/dosvga/pdcgetsc.c @@ -28,7 +28,7 @@ int PDC_get_cursor_mode(void) int start = _FONT16*3/4; int end = _FONT16-1; - return (start << 4) | end; + return (start << 8) | end; } /* return number of screen rows */ diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index 22f974a4e..3e81b146c 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -76,7 +76,6 @@ static void _set_scrn_mode(int new_mode) PDC_state.font_addr = _get_font_address(); LINES = PDC_get_rows(); COLS = PDC_get_columns(); - PDC_curs_set(1); } /* close the physical screen -- may restore the screen to its state @@ -139,12 +138,9 @@ int PDC_resize_screen(int nlines, int ncols) PDC_LOG(("PDC_resize_screen() - called. Lines: %d Cols: %d\n", nlines, ncols)); - /* Trash the stored value of orig_cursor -- it's only good if the - video mode doesn't change */ - - SP->orig_cursor = 0x0607; - _set_scrn_mode(_find_video_mode(nlines, ncols)); + SP->orig_cursor = PDC_get_cursor_mode(); + PDC_curs_set(SP->visibility); return OK; } diff --git a/dosvga/pdcsetsc.c b/dosvga/pdcsetsc.c index 84a5cc8fd..1006d8b7b 100644 --- a/dosvga/pdcsetsc.c +++ b/dosvga/pdcsetsc.c @@ -58,14 +58,15 @@ int PDC_curs_set(int visibility) end = _FONT16 - 1; break; default: /* normal visibility */ - start = SP->orig_cursor >> 4; - end = SP->orig_cursor & 0xF; + start = SP->orig_cursor >> 8; + end = SP->orig_cursor & 0xFF; } PDC_private_cursor_off(); PDC_state.cursor_start = start; PDC_state.cursor_end = end; - PDC_private_cursor_on(PDC_state.cursor_row, PDC_state.cursor_col); + if (visibility != 0) + PDC_private_cursor_on(PDC_state.cursor_row, PDC_state.cursor_col); return ret_vis; } From a6026d11551890b8c2aa938e27c8603afd234ac5 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Fri, 21 Feb 2020 01:37:20 -0500 Subject: [PATCH 06/26] Add support for 8 bit color modes --- dosvga/pdcdisp.c | 253 ++++++++++++++++++++++++++++++++++++---------- dosvga/pdcdos.h | 8 +- dosvga/pdcscrn.c | 212 +++++++++++++++++++++++++++----------- dosvga/pdcsetsc.c | 1 - 4 files changed, 361 insertions(+), 113 deletions(-) diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index 62932d9b0..642daa0a2 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -4,10 +4,11 @@ #include "../common/acs437.h" /* Support cursor on graphics mode */ -static unsigned char bytes_behind[4][16]; +static unsigned long bytes_behind[8][16]; static unsigned char cursor_color = 15; -static unsigned _get_colors(chtype glyph); -static unsigned long _address(int row, int col); +static unsigned long _get_colors(chtype glyph); +static unsigned long _address_4(int row, int col); +static unsigned long _address_8(int row, int col); static void _video_write_byte(unsigned long addr, unsigned char byte); static unsigned char _video_read_byte(unsigned long addr); static unsigned _set_window(unsigned window, unsigned long addr); @@ -21,15 +22,18 @@ void PDC_gotoyx(int row, int col) PDC_private_cursor_on(row, col); } -static void _new_packet(unsigned colors, int lineno, int x, int len, const chtype *srcp) +/* Draw a run of characters with the same colors */ +/* Used with 4 bit pixels only */ + +static void _new_packet(unsigned long colors, int lineno, int x, int len, const chtype *srcp) { unsigned fore, back; int underline; - unsigned long addr = _address(lineno, x); + unsigned long addr = _address_4(lineno, x); unsigned pass; fore = colors & 0xF; - back = colors >> 4; + back = (colors >> 16) & 0xF; /* Underline will go here if requested */ underline = 13 /*_FONT16*/; @@ -92,24 +96,13 @@ static void _new_packet(unsigned colors, int lineno, int x, int len, const chtyp } } -/* update the given physical line to look like the corresponding line in - curscr */ - -void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) +/* PDC_transform_line for 4 bit pixels */ + +static void _transform_line_4(int lineno, int x, int len, const chtype *srcp) { - bool redraw_cursor; - unsigned old_colors, colors; + unsigned long old_colors, colors; int i, j; - PDC_LOG(("PDC_transform_line() - called: lineno=%d\n", lineno)); - - redraw_cursor = PDC_state.cursor_visible - && lineno == PDC_state.cursor_row - && x <= PDC_state.cursor_col - && PDC_state.cursor_col < x + len; - if (redraw_cursor) - PDC_private_cursor_off(); - /* Draw runs of characters that have the same colors */ old_colors = _get_colors(srcp[0]); @@ -129,20 +122,104 @@ void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) _new_packet(old_colors, lineno, x, i, srcp); + /* Reset the VGA plane register to its normal state */ + outportb(0x3c4, 2); + outportb(0x3c5, 0xF); +} + +/* PDC_transform_line for 8 bit pixels */ + +static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) +{ + unsigned long addr = _address_8(lineno, x); + unsigned underline; + unsigned line; + + /* Underline will go here if requested */ + underline = 13 /*_FONT16*/; + + /* Draw the entire line in pixel order, to minimize the use of the VESA + window function */ + + /* Loop by raster line */ + for (line = 0; line < _FONT16; line++) + { + int col; + unsigned addr2 = addr; + + /* Loop by column */ + for (col = 0; col < len; col++) + { + chtype glyph = srcp[col]; + int ch; + unsigned char byte, bit; + unsigned long colors; + unsigned fore, back; + + /* Get the index into the font */ + ch = glyph & 0xFF; + if ((glyph & A_ALTCHARSET) != 0 && (glyph & 0xff80) == 0) + ch = acs_map[ch & 0x7f] & 0xff; + + /* Get one byte from the font */ + if ((glyph & A_UNDERLINE) != 0 && line == underline) + byte = 0xFF; + else + byte = getdosmembyte(PDC_state.font_addr + ch*_FONT16 + line); + + /* Get the colors */ + colors = _get_colors(glyph); + fore = colors & 0xFF; + back = (colors >> 16) & 0xFF; + + /* Loop by pixel */ + for (bit = 0x80; bit != 0; bit >>= 1) + { + _video_write_byte(addr2++, (byte & bit) ? fore : back); + } + } + addr += PDC_state.bytes_per_line; + } +} + +/* update the given physical line to look like the corresponding line in + curscr */ + +void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) +{ + bool redraw_cursor; + + PDC_LOG(("PDC_transform_line() - called: lineno=%d\n", lineno)); + + redraw_cursor = PDC_state.cursor_visible + && lineno == PDC_state.cursor_row + && x <= PDC_state.cursor_col + && PDC_state.cursor_col < x + len; + if (redraw_cursor) + PDC_private_cursor_off(); + + switch (PDC_state.bits_per_pixel) + { + case 4: + _transform_line_4(lineno, x, len, srcp); + break; + + case 8: + _transform_line_8(lineno, x, len, srcp); + break; + } + /* Redraw the cursor if it has been erased */ if (redraw_cursor) PDC_private_cursor_on(PDC_state.cursor_row, PDC_state.cursor_col); - /* Reset the VGA plane register to its normal state */ - outportb(0x3c4, 2); - outportb(0x3c5, 0xF); } void PDC_doupdate(void) { } -static unsigned _get_colors(chtype glyph) +static unsigned long _get_colors(chtype glyph) { attr_t attr; short fore, back; @@ -151,14 +228,11 @@ static unsigned _get_colors(chtype glyph) attr = glyph & (A_ATTRIBUTES ^ A_ALTCHARSET); pair_content(PAIR_NUMBER(attr), &fore, &back); - if (attr & A_BOLD) + if ((attr & A_BOLD) != 0 && fore < 16) fore |= 8; - if (attr & A_BLINK) + if ((attr & A_BLINK) != 0 && back < 16) back |= 8; - fore = PDC_state.pdc_curstoreal[fore]; - back = PDC_state.pdc_curstoreal[back]; - if (attr & A_REVERSE) { short swap = fore; @@ -167,35 +241,66 @@ static unsigned _get_colors(chtype glyph) } /* Return them as a pair */ - return (back << 4) | fore; + return (back << 16) | fore; +} + +static void _cursor_off_4(void) +{ + unsigned long addr = _address_4(PDC_state.cursor_row, PDC_state.cursor_col); + unsigned plane; + unsigned line; + + for (plane = 0; plane < 4; plane++) + { + unsigned long p = addr; + outportb(0x03C4, 2); + outportb(0x03C5, 1 << plane); + for (line = 0; line < _FONT16; line++) + { + _video_write_byte(p, bytes_behind[plane][line]); + p += PDC_state.bytes_per_line; + } + } +} + +static void _cursor_off_8(void) +{ + unsigned long addr = _address_8(PDC_state.cursor_row, PDC_state.cursor_col); + unsigned long p; + unsigned line; + unsigned i; + + p = addr; + for (line = 0; line < _FONT16; line++) + { + for (i = 0; i < 8; i++) + _video_write_byte(p + i, bytes_behind[i][line]); + p += PDC_state.bytes_per_line; + } } void PDC_private_cursor_off(void) { if (PDC_state.cursor_visible && PDC_state.cursor_row < (unsigned)LINES - && PDC_state.cursor_col < (unsigned)COLS) { - unsigned long addr = _address(PDC_state.cursor_row, PDC_state.cursor_col); - unsigned plane; - unsigned line; - - for (plane = 0; plane < 4; ++plane) + && PDC_state.cursor_col < (unsigned)COLS) + { + switch (PDC_state.bits_per_pixel) { - unsigned long p = addr; - outportb(0x03C4, 2); - outportb(0x03C5, 1 << plane); - for (line = 0; line < _FONT16; ++line) - { - _video_write_byte(p, bytes_behind[plane][line]); - p += PDC_state.bytes_per_line; - } + case 4: + _cursor_off_4(); + break; + + case 8: + _cursor_off_8(); + break; } } PDC_state.cursor_visible = FALSE; } -void PDC_private_cursor_on(int row, int col) +void _cursor_on_4(int row, int col) { - unsigned long addr = _address(row, col); + unsigned long addr = _address_4(row, col); unsigned long p; unsigned plane; unsigned line; @@ -213,8 +318,7 @@ void PDC_private_cursor_on(int row, int col) } outportb(0x03C5, 2); outportb(0x03C5, cursor_color); - p = _address(row, col); - p += PDC_state.cursor_start * PDC_state.bytes_per_line; + p = addr + PDC_state.cursor_start * PDC_state.bytes_per_line; for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) { _video_write_byte(p, 0xFF); @@ -222,8 +326,7 @@ void PDC_private_cursor_on(int row, int col) } outportb(0x03C5, 2); outportb(0x03C5, ~cursor_color); - p = _address(row, col); - p += PDC_state.cursor_start * PDC_state.bytes_per_line; + p = addr + PDC_state.cursor_start * PDC_state.bytes_per_line; for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) { _video_write_byte(p, 0x00); @@ -231,16 +334,62 @@ void PDC_private_cursor_on(int row, int col) } outportb(0x03C5, 2); outportb(0x03C5, 0xF); +} + +void _cursor_on_8(int row, int col) +{ + unsigned long addr = _address_8(row, col); + unsigned long p; + unsigned line; + unsigned i; + + /* Save the bytes currently in the character cell */ + p = addr; + for (line = 0; line < _FONT16; line++) + { + for (i = 0; i < 8; i++) + bytes_behind[i][line] = _video_read_byte(p + i); + p += PDC_state.bytes_per_line; + } + + /* Write the cursor */ + p = addr + PDC_state.cursor_start * PDC_state.bytes_per_line; + for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) + { + for (i = 0; i < 8; i++) + _video_write_byte(p + i, cursor_color); + p += PDC_state.bytes_per_line; + } +} + +void PDC_private_cursor_on(int row, int col) +{ + switch (PDC_state.bits_per_pixel) + { + case 4: + _cursor_on_4(row, col); + break; + + case 8: + _cursor_on_8(row, col); + break; + } PDC_state.cursor_visible = TRUE; PDC_state.cursor_row = row; PDC_state.cursor_col = col; } -static unsigned long _address(int row, int col) +static unsigned long _address_4(int row, int col) { return row * PDC_state.bytes_per_line * _FONT16 + col; } +static unsigned long _address_8(int row, int col) +{ + return row * PDC_state.bytes_per_line * _FONT16 + + col * 8 * ((PDC_state.bits_per_pixel + 7)/8); +} + static void _video_write_byte(unsigned long addr, unsigned char byte) { unsigned offset = _set_window(PDC_state.write_win, addr); diff --git a/dosvga/pdcdos.h b/dosvga/pdcdos.h index b8386a876..7909dc0e5 100644 --- a/dosvga/pdcdos.h +++ b/dosvga/pdcdos.h @@ -37,11 +37,17 @@ #include /* Information about the current video state */ +struct PDC_color +{ + short r, g, b; +}; + struct PDC_video_state { /* Information about the current video mode: */ unsigned short scrn_mode; bool linear_buffer; + unsigned char bits_per_pixel; unsigned short video_width; /* Width of graphics mode in pixels */ unsigned short video_height; /* Height of graphics mode in pixels */ unsigned short bytes_per_line; /* Bytes per raster line */ @@ -63,7 +69,7 @@ struct PDC_video_state unsigned char cursor_start; unsigned char cursor_end; - short pdc_curstoreal[16]; + struct PDC_color colors[PDC_MAXCOL]; }; extern struct PDC_video_state PDC_state; diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index 3e81b146c..16851b6b4 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -11,16 +11,10 @@ struct PDC_video_state PDC_state; -static short realtocurs[16] = -{ - COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, COLOR_RED, - COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE, COLOR_BLACK + 8, - COLOR_BLUE + 8, COLOR_GREEN + 8, COLOR_CYAN + 8, COLOR_RED + 8, - COLOR_MAGENTA + 8, COLOR_YELLOW + 8, COLOR_WHITE + 8 -}; - static int saved_scrnmode[3]; +static void _init_palette(void); +static void _load_palette(void); static int _get_mode_info(unsigned mode, struct ModeInfoBlock *mode_info); static unsigned _find_video_mode(int rows, int cols); static unsigned _find_mode( @@ -105,7 +99,6 @@ int PDC_scr_open(void) struct SREGS segregs; int ds; #endif - int i; PDC_LOG(("PDC_scr_open() - called\n")); @@ -114,9 +107,8 @@ int PDC_scr_open(void) if (!SP) return ERR; + _init_palette(); PDC_resize_screen(25, 80); - for (i = 0; i < 16; i++) - PDC_state.pdc_curstoreal[realtocurs[i]] = i; SP->orig_attr = FALSE; @@ -139,15 +131,21 @@ int PDC_resize_screen(int nlines, int ncols) nlines, ncols)); _set_scrn_mode(_find_video_mode(nlines, ncols)); + _load_palette(); SP->orig_cursor = PDC_get_cursor_mode(); PDC_curs_set(SP->visibility); + if (PDC_state.bits_per_pixel <= 8) + COLORS = 1 << PDC_state.bits_per_pixel; + else + COLORS = PDC_MAXCOL; return OK; } void PDC_reset_prog_mode(void) { - PDC_LOG(("PDC_reset_prog_mode() - called.\n")); + PDC_LOG(("PDC_reset_prog_mode() - called.\n")); + _load_palette(); } void PDC_reset_shell_mode(void) @@ -171,19 +169,72 @@ void PDC_save_screen_mode(int i) } } -/* _egapal() - Find the EGA palette value (0-63) for the color (0-15). - On VGA, this is an index into the DAC. */ +/* _init_palette -- set up the initial palette */ -static short _egapal(short color) +static void _init_palette(void) { - PDCREGS regs; + unsigned i, r, g, b; - regs.W.ax = 0x1007; - regs.h.bl = PDC_state.pdc_curstoreal[color]; + /* The basic eight colors and their bold forms */ + for (i = 0; i < 8; i++) + { + PDC_state.colors[i+0].r = (i & COLOR_RED) ? 750 : 0; + PDC_state.colors[i+0].g = (i & COLOR_GREEN) ? 750 : 0; + PDC_state.colors[i+0].b = (i & COLOR_BLUE) ? 750 : 0; + PDC_state.colors[i+8].r = (i & COLOR_RED) ? 1000 : 250; + PDC_state.colors[i+8].g = (i & COLOR_GREEN) ? 1000 : 250; + PDC_state.colors[i+8].b = (i & COLOR_BLUE) ? 1000 : 250; + } - PDCINT(0x10, regs); + /* 6x6x6 color cube */ + i = 16; + for (r = 0; r < 6; r++) + { + for (g = 0; g < 6; g++) + { + for (b = 0; b < 6; b++) + { + PDC_state.colors[i].r = (r ? r * 157 + 215 : 0); + PDC_state.colors[i].g = (g ? g * 157 + 215 : 0); + PDC_state.colors[i].b = (b ? b * 157 + 215 : 0); + i++; + } + } + } + + /* 24 shades of gray */ + for (i = 232; i < 256; i++) + { + r = (i - 232) * 40 + 30; + PDC_state.colors[i].r = r; + PDC_state.colors[i].g = r; + PDC_state.colors[i].b = r; + } +} + +/* _load_palette -- load the current palette into the DAC */ + +static void _load_palette(void) +{ + if (PDC_state.bits_per_pixel <= 8) + { + PDCREGS regs; + unsigned i; - return regs.h.bh; + /* Load EGA palette registers as an identity map */ + for (i = 0; i < 16; i++) + { + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x1000; + regs.W.bx = i * 0x0101; + PDCINT(0x10, regs); + } + + /* Load the DAC registers from the current palette */ + for (i = 0; i < 1 << PDC_state.bits_per_pixel; i++) + PDC_init_color(i, PDC_state.colors[i].r, PDC_state.colors[i].g, + PDC_state.colors[i].b); + } } bool PDC_can_change_color(void) @@ -191,46 +242,67 @@ bool PDC_can_change_color(void) return TRUE; } -/* These are only valid when PDC_state.pdc_adapter == _VGACOLOR */ - int PDC_color_content(short color, short *red, short *green, short *blue) { - PDCREGS regs; - - /* Read single DAC register */ - /* TODO: support VESA modes */ - - regs.W.ax = 0x1015; - regs.h.bl = _egapal(color); - - PDCINT(0x10, regs); - - /* Scale and store */ - - *red = DIVROUND((unsigned)(regs.h.dh) * 1000, 63); - *green = DIVROUND((unsigned)(regs.h.ch) * 1000, 63); - *blue = DIVROUND((unsigned)(regs.h.cl) * 1000, 63); + *red = PDC_state.colors[color].r; + *green = PDC_state.colors[color].g; + *blue = PDC_state.colors[color].b; return OK; } int PDC_init_color(short color, short red, short green, short blue) { - PDCREGS regs; + PDC_state.colors[color].r = red; + PDC_state.colors[color].g = green; + PDC_state.colors[color].b = blue; - /* Scale */ + if (PDC_state.bits_per_pixel <= 8) + { + PDCREGS regs; + + if (PDC_state.scrn_mode >= 0x100) + { + /* VESA mode in use; first try the VESA function */ + int seg, sel; + unsigned char table[4]; + __dpmi_regs d_regs; + + seg = __dpmi_allocate_dos_memory(1, &sel); + if (seg < 0) + return ERR; + table[0] = DIVROUND((unsigned)red * 63, 1000); + table[1] = DIVROUND((unsigned)green * 63, 1000); + table[2] = DIVROUND((unsigned)blue * 63, 1000); + table[3] = 0; + dosmemput(table, sizeof(table), seg * 16L); + memset(&d_regs, 0, sizeof(d_regs)); + d_regs.x.ax = 0x4F09; + d_regs.h.bl = 0; + d_regs.x.cx = 1; + d_regs.x.dx = color; + d_regs.x.di = 0; + d_regs.x.es = seg; + __dpmi_int(0x10, &d_regs); + __dpmi_free_dos_memory(sel); + if (d_regs.x.ax == 0x004F) + return OK; + } - regs.h.dh = DIVROUND((unsigned)red * 63, 1000); - regs.h.ch = DIVROUND((unsigned)green * 63, 1000); - regs.h.cl = DIVROUND((unsigned)blue * 63, 1000); + /* Scale */ - /* Set single DAC register */ - /* TODO: support VESA modes */ + regs.h.dh = DIVROUND((unsigned)red * 63, 1000); + regs.h.ch = DIVROUND((unsigned)green * 63, 1000); + regs.h.cl = DIVROUND((unsigned)blue * 63, 1000); - regs.W.ax = 0x1010; - regs.W.bx = _egapal(color); + /* Set single DAC register */ + /* TODO: support VESA modes */ - PDCINT(0x10, regs); + regs.W.ax = 0x1010; + regs.W.bx = color; + + PDCINT(0x10, regs); + } return OK; } @@ -313,6 +385,8 @@ static unsigned _find_video_mode(int rows, int cols) PDC_state.bytes_per_line = mode_info.BytesPerScanLine; PDC_state.video_width = mode_info.XResolution; PDC_state.video_height = mode_info.YResolution; + PDC_state.linear_buffer = FALSE; + PDC_state.bits_per_pixel = mode_info.BitsPerPixel; __dpmi_free_dos_memory(vbe_info_sel); return vesa_mode; @@ -324,6 +398,7 @@ static unsigned _find_video_mode(int rows, int cols) __dpmi_free_dos_memory(vbe_info_sel); PDC_state.linear_buffer = FALSE; + PDC_state.bits_per_pixel = 4; PDC_state.video_width = 640; PDC_state.video_height = 480; PDC_state.bytes_per_line = 80; @@ -346,15 +421,18 @@ static unsigned _find_mode( { unsigned selected_mode; unsigned long selected_size; + unsigned selected_bits; selected_mode = 0xFFFF; selected_size = (rows == 0 && cols == 0) ? 0 : 0xFFFFFFFF; + selected_bits = 0; if (rows <= 30 && cols <= 80) { /* Set up a ModeInfoBlock for mode 0x0012 */ selected_mode = 0x0012; selected_size = 80 * 30; + selected_bits = 4; memset(mode_info, 0, sizeof(*mode_info)); mode_info->ModeAttributes = 0x1F; mode_info->WinAAttributes = 0x07; @@ -402,7 +480,15 @@ static unsigned _find_mode( if (mode_info0.NumberOfPlanes != 4) continue; break; - /* TODO: 8, 15, 16, 24 and 32 bits */ + + case 8: + if (mode_info0.MemoryModel != 4) /* Packed pixel */ + continue; + if (mode_info0.NumberOfPlanes != 1) + continue; + break; + + /* TODO: 15, 16, 24 and 32 bits */ default: continue; @@ -414,24 +500,32 @@ static unsigned _find_mode( if (new_cols < cols || new_rows < rows) continue; - /* If rows == 0 and cols == 0, select the largest available size; + /* Among modes that are large enough for rows and cols, choose one + with the most bits per pixel. Among modes with the same pixel depth, + if rows == 0 and cols == 0, select the largest available size; otherwise, select the smallest that can hold that many rows and - columns */ - new_size = (unsigned long)new_rows * new_cols; - if (rows == 0 && cols == 0) - { - if (new_size <= selected_size) - continue; - } - else + columns. */ + if (mode_info0.BitsPerPixel < selected_bits) + continue; + if (mode_info0.BitsPerPixel == selected_bits) { - if (new_size >= selected_size) - continue; + new_size = (unsigned long)new_rows * new_cols; + if (rows == 0 && cols == 0) + { + if (new_size <= selected_size) + continue; + } + else + { + if (new_size >= selected_size) + continue; + } } /* Select this mode, pending discovery of a better one */ selected_mode = mode; selected_size = new_size; + selected_bits = mode_info0.BitsPerPixel; *mode_info = mode_info0; } diff --git a/dosvga/pdcsetsc.c b/dosvga/pdcsetsc.c index 1006d8b7b..50d4253de 100644 --- a/dosvga/pdcsetsc.c +++ b/dosvga/pdcsetsc.c @@ -78,7 +78,6 @@ void PDC_set_title(const char *title) int PDC_set_blink(bool blinkon) { - COLORS = 16; return blinkon ? ERR : OK; } From 26dd4ee4aa424382b6abb09bb512002fd28b8053 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Fri, 21 Feb 2020 02:28:02 -0500 Subject: [PATCH 07/26] Fix the color selection --- dosvga/pdcscrn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index 16851b6b4..f32e665c8 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -271,9 +271,9 @@ int PDC_init_color(short color, short red, short green, short blue) seg = __dpmi_allocate_dos_memory(1, &sel); if (seg < 0) return ERR; - table[0] = DIVROUND((unsigned)red * 63, 1000); + table[0] = DIVROUND((unsigned)blue * 63, 1000); table[1] = DIVROUND((unsigned)green * 63, 1000); - table[2] = DIVROUND((unsigned)blue * 63, 1000); + table[2] = DIVROUND((unsigned)red * 63, 1000); table[3] = 0; dosmemput(table, sizeof(table), seg * 16L); memset(&d_regs, 0, sizeof(d_regs)); From df1ec7155149cf03fbed429d95e132f7c9d0c58c Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Fri, 21 Feb 2020 23:16:32 -0500 Subject: [PATCH 08/26] Fix mode selection problems new_mode might be used uninitialized selected_size initialized wrong for rows=0 and cols=0 --- dosvga/pdcscrn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index f32e665c8..33ac77560 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -427,7 +427,7 @@ static unsigned _find_mode( selected_size = (rows == 0 && cols == 0) ? 0 : 0xFFFFFFFF; selected_bits = 0; - if (rows <= 30 && cols <= 80) + if ((rows <= 30 && cols <= 80) && !(rows == 0 && cols == 0)) { /* Set up a ModeInfoBlock for mode 0x0012 */ selected_mode = 0x0012; @@ -507,9 +507,9 @@ static unsigned _find_mode( columns. */ if (mode_info0.BitsPerPixel < selected_bits) continue; + new_size = (unsigned long)new_rows * new_cols; if (mode_info0.BitsPerPixel == selected_bits) { - new_size = (unsigned long)new_rows * new_cols; if (rows == 0 && cols == 0) { if (new_size <= selected_size) From 66369464d6fb6fc1f72b9b2aad99f0b832fa54ea Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sat, 22 Feb 2020 00:36:11 -0500 Subject: [PATCH 09/26] Support direct color modes --- dosvga/pdcdisp.c | 280 +++++++++++++++++++++++++++++++++++++++++++++-- dosvga/pdcdos.h | 11 ++ dosvga/pdcscrn.c | 96 ++++++++++++++-- dosvga/pdcutil.c | 5 + 4 files changed, 371 insertions(+), 21 deletions(-) diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index 642daa0a2..c9d2a8f95 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -10,7 +10,13 @@ static unsigned long _get_colors(chtype glyph); static unsigned long _address_4(int row, int col); static unsigned long _address_8(int row, int col); static void _video_write_byte(unsigned long addr, unsigned char byte); +static void _video_write_word(unsigned long addr, unsigned short word); +static void _video_write_3byte(unsigned long addr, unsigned long byte3); +static void _video_write_dword(unsigned long addr, unsigned long dword); static unsigned char _video_read_byte(unsigned long addr); +static unsigned short _video_read_word(unsigned long addr); +static unsigned long _video_read_3byte(unsigned long addr); +static unsigned long _video_read_dword(unsigned long addr); static unsigned _set_window(unsigned window, unsigned long addr); /* position hardware cursor at (y, x) */ @@ -127,7 +133,7 @@ static void _transform_line_4(int lineno, int x, int len, const chtype *srcp) outportb(0x3c5, 0xF); } -/* PDC_transform_line for 8 bit pixels */ +/* PDC_transform_line for 8, 15, 16, 24 and 32 bit pixels */ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) { @@ -154,7 +160,7 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) int ch; unsigned char byte, bit; unsigned long colors; - unsigned fore, back; + unsigned long fore, back; /* Get the index into the font */ ch = glyph & 0xFF; @@ -169,13 +175,46 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) /* Get the colors */ colors = _get_colors(glyph); - fore = colors & 0xFF; - back = (colors >> 16) & 0xFF; + fore = colors & 0xFFFF; + back = (colors >> 16) & 0xFFFF; + if (PDC_state.bits_per_pixel > 8) + { + fore = PDC_state.colors[fore].mapped; + back = PDC_state.colors[back].mapped; + } /* Loop by pixel */ - for (bit = 0x80; bit != 0; bit >>= 1) + switch (PDC_state.bits_per_pixel) { - _video_write_byte(addr2++, (byte & bit) ? fore : back); + case 8: + for (bit = 0x80; bit != 0; bit >>= 1) + _video_write_byte(addr2++, (byte & bit) ? fore : back); + break; + + case 15: + case 16: + for (bit = 0x80; bit != 0; bit >>= 1) + { + _video_write_word(addr2, (byte & bit) ? fore : back); + addr2 += 2; + } + break; + + case 24: + for (bit = 0x80; bit != 0; bit >>= 1) + { + _video_write_3byte(addr2, (byte & bit) ? fore : back); + addr2 += 3; + } + break; + + case 32: + for (bit = 0x80; bit != 0; bit >>= 1) + { + _video_write_dword(addr2, (byte & bit) ? fore : back); + addr2 += 4; + } + break; } } addr += PDC_state.bytes_per_line; @@ -198,15 +237,13 @@ void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) if (redraw_cursor) PDC_private_cursor_off(); - switch (PDC_state.bits_per_pixel) + if (PDC_state.bits_per_pixel == 4) { - case 4: _transform_line_4(lineno, x, len, srcp); - break; - - case 8: + } + else + { _transform_line_8(lineno, x, len, srcp); - break; } /* Redraw the cursor if it has been erased */ @@ -279,6 +316,54 @@ static void _cursor_off_8(void) } } +static void _cursor_off_16(void) +{ + unsigned long addr = _address_8(PDC_state.cursor_row, PDC_state.cursor_col); + unsigned long p; + unsigned line; + unsigned i; + + p = addr; + for (line = 0; line < _FONT16; line++) + { + for (i = 0; i < 8; i++) + _video_write_word(p + i*2, bytes_behind[i][line]); + p += PDC_state.bytes_per_line; + } +} + +static void _cursor_off_24(void) +{ + unsigned long addr = _address_8(PDC_state.cursor_row, PDC_state.cursor_col); + unsigned long p; + unsigned line; + unsigned i; + + p = addr; + for (line = 0; line < _FONT16; line++) + { + for (i = 0; i < 8; i++) + _video_write_3byte(p + i*3, bytes_behind[i][line]); + p += PDC_state.bytes_per_line; + } +} + +static void _cursor_off_32(void) +{ + unsigned long addr = _address_8(PDC_state.cursor_row, PDC_state.cursor_col); + unsigned long p; + unsigned line; + unsigned i; + + p = addr; + for (line = 0; line < _FONT16; line++) + { + for (i = 0; i < 8; i++) + _video_write_dword(p + i*4, bytes_behind[i][line]); + p += PDC_state.bytes_per_line; + } +} + void PDC_private_cursor_off(void) { if (PDC_state.cursor_visible && PDC_state.cursor_row < (unsigned)LINES @@ -293,6 +378,19 @@ void PDC_private_cursor_off(void) case 8: _cursor_off_8(); break; + + case 15: + case 16: + _cursor_off_16(); + break; + + case 24: + _cursor_off_24(); + break; + + case 32: + _cursor_off_32(); + break; } } PDC_state.cursor_visible = FALSE; @@ -362,6 +460,87 @@ void _cursor_on_8(int row, int col) } } +void _cursor_on_16(int row, int col) +{ + unsigned long addr = _address_8(row, col); + unsigned long p; + unsigned line; + unsigned i; + unsigned short color = PDC_state.colors[cursor_color].mapped; + + /* Save the bytes currently in the character cell */ + p = addr; + for (line = 0; line < _FONT16; line++) + { + for (i = 0; i < 8; i++) + bytes_behind[i][line] = _video_read_word(p + i*2); + p += PDC_state.bytes_per_line; + } + + /* Write the cursor */ + p = addr + PDC_state.cursor_start * PDC_state.bytes_per_line; + for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) + { + for (i = 0; i < 8; i++) + _video_write_word(p + i*2, color); + p += PDC_state.bytes_per_line; + } +} + +void _cursor_on_24(int row, int col) +{ + unsigned long addr = _address_8(row, col); + unsigned long p; + unsigned line; + unsigned i; + unsigned long color = PDC_state.colors[cursor_color].mapped; + + /* Save the bytes currently in the character cell */ + p = addr; + for (line = 0; line < _FONT16; line++) + { + for (i = 0; i < 8; i++) + bytes_behind[i][line] = _video_read_3byte(p + i*3); + p += PDC_state.bytes_per_line; + } + + /* Write the cursor */ + p = addr + PDC_state.cursor_start * PDC_state.bytes_per_line; + for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) + { + for (i = 0; i < 8; i++) + _video_write_3byte(p + i*3, color); + p += PDC_state.bytes_per_line; + } +} + +void _cursor_on_32(int row, int col) +{ + unsigned long addr = _address_8(row, col); + unsigned long p; + unsigned line; + unsigned i; + unsigned long color = PDC_state.colors[cursor_color].mapped; + + /* Save the bytes currently in the character cell */ + p = addr; + for (line = 0; line < _FONT16; line++) + { + for (i = 0; i < 8; i++) + bytes_behind[i][line] = _video_read_dword(p + i*4); + p += PDC_state.bytes_per_line; + } + + /* Write the cursor */ + p = addr + PDC_state.cursor_start * PDC_state.bytes_per_line; + for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) + { + for (i = 0; i < 8; i++) + _video_write_dword(p + i*4, color); + p += PDC_state.bytes_per_line; + } +} + void PDC_private_cursor_on(int row, int col) { switch (PDC_state.bits_per_pixel) @@ -373,6 +552,19 @@ void PDC_private_cursor_on(int row, int col) case 8: _cursor_on_8(row, col); break; + + case 15: + case 16: + _cursor_on_16(row, col); + break; + + case 24: + _cursor_on_24(row, col); + break; + + case 32: + _cursor_on_32(row, col); + break; } PDC_state.cursor_visible = TRUE; PDC_state.cursor_row = row; @@ -397,6 +589,36 @@ static void _video_write_byte(unsigned long addr, unsigned char byte) setdosmembyte(addr2, byte); } +static void _video_write_word(unsigned long addr, unsigned short word) +{ + unsigned offset = _set_window(PDC_state.write_win, addr); + unsigned long addr2 = PDC_state.window[PDC_state.write_win]*16L + offset; + setdosmemword(addr2, word); +} + +static void _video_write_3byte(unsigned long addr, unsigned long byte3) +{ + /* Write a byte and a word. Split the write so that the word lies at an + * even address, so it does not cross a window boundary */ + if (addr & 1) + { + _video_write_byte(addr + 0, byte3 & 0xFF); + _video_write_word(addr + 1, byte3 >> 8); + } + else + { + _video_write_word(addr + 0, byte3 & 0xFFFF); + _video_write_byte(addr + 2, byte3 >> 8); + } +} + +static void _video_write_dword(unsigned long addr, unsigned long dword) +{ + unsigned offset = _set_window(PDC_state.write_win, addr); + unsigned long addr2 = PDC_state.window[PDC_state.write_win]*16L + offset; + setdosmemdword(addr2, dword); +} + static unsigned char _video_read_byte(unsigned long addr) { unsigned offset = _set_window(PDC_state.read_win, addr); @@ -405,6 +627,40 @@ static unsigned char _video_read_byte(unsigned long addr) return byte; } +static unsigned short _video_read_word(unsigned long addr) +{ + unsigned offset = _set_window(PDC_state.read_win, addr); + unsigned long addr2 = PDC_state.window[PDC_state.read_win]*16L + offset; + unsigned short word = getdosmembyte(addr2); + return word; +} + +static unsigned long _video_read_3byte(unsigned long addr) +{ + /* Read a byte and a word. Split the read so that the word lies at an + * even address, so it does not cross a window boundary */ + unsigned long byte3; + if (addr & 1) + { + byte3 = _video_read_byte(addr + 0); + byte3 += (unsigned long)_video_read_word(addr + 1) << 8; + } + else + { + byte3 = _video_read_word(addr + 0); + byte3 += (unsigned long)_video_read_byte(addr + 2) << 16; + } + return byte3; +} + +static unsigned long _video_read_dword(unsigned long addr) +{ + unsigned offset = _set_window(PDC_state.read_win, addr); + unsigned long addr2 = PDC_state.window[PDC_state.read_win]*16L + offset; + unsigned long dword = getdosmemdword(addr2); + return dword; +} + static unsigned _set_window(unsigned window, unsigned long addr) { unsigned long offset = PDC_state.offset[window]; diff --git a/dosvga/pdcdos.h b/dosvga/pdcdos.h index 7909dc0e5..db15caaa8 100644 --- a/dosvga/pdcdos.h +++ b/dosvga/pdcdos.h @@ -40,6 +40,7 @@ struct PDC_color { short r, g, b; + unsigned long mapped; }; struct PDC_video_state @@ -59,6 +60,13 @@ struct PDC_video_state /* Window used to read and write */ unsigned char read_win; unsigned char write_win; + /* Color mappings */ + unsigned char red_max; + unsigned char red_pos; + unsigned char green_max; + unsigned char green_pos; + unsigned char blue_max; + unsigned char blue_pos; unsigned long font_addr; /* Address of font in ROM */ @@ -104,6 +112,7 @@ unsigned short getdosmemword(int offs); unsigned long getdosmemdword(int offs); void setdosmembyte(int offs, unsigned char b); void setdosmemword(int offs, unsigned short w); +void setdosmemdword(int offs, unsigned long d); #else # if SMALL || MEDIUM # define PDC_FAR far @@ -120,6 +129,8 @@ void setdosmemword(int offs, unsigned short w); (*((unsigned char PDC_FAR *) _FAR_POINTER(0,offs)) = (x)) # define setdosmemword(offs,x) \ (*((unsigned short PDC_FAR *) _FAR_POINTER(0,offs)) = (x)) +# define setdosmemdword(offs,x) \ + (*((unsigned long PDC_FAR *) _FAR_POINTER(0,offs)) = (x)) #endif #if defined(__WATCOMC__) && defined(__386__) diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index 33ac77560..af0b08162 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -7,7 +7,6 @@ #include /* TODO: support 8 bit palette registers if available */ -/* TODO: support modes with more than 4 bits per pixel */ struct PDC_video_state PDC_state; @@ -235,6 +234,15 @@ static void _load_palette(void) PDC_init_color(i, PDC_state.colors[i].r, PDC_state.colors[i].g, PDC_state.colors[i].b); } + else + { + unsigned i; + + /* Set up mappings from color index to RGB */ + for (i = 0; i < PDC_MAXCOL; i++) + PDC_init_color(i, PDC_state.colors[i].r, PDC_state.colors[i].g, + PDC_state.colors[i].b); + } } bool PDC_can_change_color(void) @@ -271,9 +279,9 @@ int PDC_init_color(short color, short red, short green, short blue) seg = __dpmi_allocate_dos_memory(1, &sel); if (seg < 0) return ERR; - table[0] = DIVROUND((unsigned)blue * 63, 1000); - table[1] = DIVROUND((unsigned)green * 63, 1000); - table[2] = DIVROUND((unsigned)red * 63, 1000); + table[0] = DIVROUND((unsigned)blue * PDC_state.blue_max, 1000); + table[1] = DIVROUND((unsigned)green * PDC_state.green_max, 1000); + table[2] = DIVROUND((unsigned)red * PDC_state.red_max, 1000); table[3] = 0; dosmemput(table, sizeof(table), seg * 16L); memset(&d_regs, 0, sizeof(d_regs)); @@ -291,18 +299,28 @@ int PDC_init_color(short color, short red, short green, short blue) /* Scale */ - regs.h.dh = DIVROUND((unsigned)red * 63, 1000); - regs.h.ch = DIVROUND((unsigned)green * 63, 1000); - regs.h.cl = DIVROUND((unsigned)blue * 63, 1000); + regs.h.dh = DIVROUND((unsigned)red * PDC_state.red_max, 1000); + regs.h.ch = DIVROUND((unsigned)green * PDC_state.green_max, 1000); + regs.h.cl = DIVROUND((unsigned)blue * PDC_state.blue_max, 1000); /* Set single DAC register */ - /* TODO: support VESA modes */ regs.W.ax = 0x1010; regs.W.bx = color; PDCINT(0x10, regs); } + else + { + unsigned r = DIVROUND((unsigned)red * PDC_state.red_max, 1000); + unsigned g = DIVROUND((unsigned)green * PDC_state.green_max, 1000); + unsigned b = DIVROUND((unsigned)blue * PDC_state.blue_max, 1000); + + PDC_state.colors[color].mapped = + ((unsigned long)r << PDC_state.red_pos) + | ((unsigned long)g << PDC_state.green_pos) + | ((unsigned long)b << PDC_state.blue_pos); + } return OK; } @@ -388,6 +406,58 @@ static unsigned _find_video_mode(int rows, int cols) PDC_state.linear_buffer = FALSE; PDC_state.bits_per_pixel = mode_info.BitsPerPixel; + if (PDC_state.bits_per_pixel <= 8) + { + PDC_state.red_max = 63; + PDC_state.green_max = 63; + PDC_state.blue_max = 63; + } + else + { + if (mode_info.ModeAttributes & 0x2) + { + PDC_state.red_max = (1 << mode_info.RedMaskSize) - 1; + PDC_state.red_pos = mode_info.RedFieldPosition; + PDC_state.green_max = (1 << mode_info.GreenMaskSize) - 1; + PDC_state.green_pos = mode_info.GreenFieldPosition; + PDC_state.blue_max = (1 << mode_info.BlueMaskSize) - 1; + PDC_state.blue_pos = mode_info.BlueFieldPosition; + } + else + { + switch (PDC_state.bits_per_pixel) + { + case 15: + PDC_state.red_max = 31; + PDC_state.red_pos = 10; + PDC_state.green_max = 31; + PDC_state.green_pos = 5; + PDC_state.blue_max = 31; + PDC_state.blue_pos = 0; + break; + + case 16: + PDC_state.red_max = 31; + PDC_state.red_pos = 11; + PDC_state.green_max = 63; + PDC_state.green_pos = 5; + PDC_state.blue_max = 31; + PDC_state.blue_pos = 0; + break; + + case 24: + case 32: + PDC_state.red_max = 255; + PDC_state.red_pos = 16; + PDC_state.green_max = 255; + PDC_state.green_pos = 8; + PDC_state.blue_max = 255; + PDC_state.blue_pos = 0; + break; + } + } + } + __dpmi_free_dos_memory(vbe_info_sel); return vesa_mode; @@ -488,7 +558,15 @@ static unsigned _find_mode( continue; break; - /* TODO: 15, 16, 24 and 32 bits */ + case 15: + case 16: + case 24: + case 32: + if (mode_info0.MemoryModel != 6) /* Direct color */ + continue; + if (mode_info0.NumberOfPlanes != 1) + continue; + break; default: continue; diff --git a/dosvga/pdcutil.c b/dosvga/pdcutil.c index c871762ff..67b12833d 100644 --- a/dosvga/pdcutil.c +++ b/dosvga/pdcutil.c @@ -80,6 +80,11 @@ void setdosmemword(int offset, unsigned short w) dosmemput(&w, sizeof(unsigned short), offset); } +void setdosmemdword(int offset, unsigned long d) +{ + dosmemput(&d, sizeof(unsigned long), offset); +} + #endif #if defined(__WATCOMC__) && defined(__386__) From 8a21ab22bc308eade2cdffa66f942ff94d2c126a Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sat, 22 Feb 2020 02:20:51 -0500 Subject: [PATCH 10/26] Support 32 bit compile on Watcom --- dosvga/pdcdisp.c | 19 +++++-- dosvga/pdcgetsc.c | 4 +- dosvga/pdcscrn.c | 139 +++++++++++++++++++++++++++++++++------------- 3 files changed, 114 insertions(+), 48 deletions(-) diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index c9d2a8f95..02af78ff9 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -3,6 +3,13 @@ #include "pdcdos.h" #include "../common/acs437.h" +#ifdef __WATCOMC__ +/* For Watcom, we need conio.h, but the Curses macro for getch fouls it up */ +#undef getch +#include +#define outportb(a, b) outp((a), (b)) +#endif + /* Support cursor on graphics mode */ static unsigned long bytes_behind[8][16]; static unsigned char cursor_color = 15; @@ -667,15 +674,15 @@ static unsigned _set_window(unsigned window, unsigned long addr) if (addr < offset || offset + PDC_state.window_size <= addr) { /* Need to move the window */ - __dpmi_regs regs; + PDCREGS regs; unsigned long gran = PDC_state.window_gran * 1024L; memset(®s, 0, sizeof(regs)); - regs.x.ax = 0x4F05; - regs.x.bx = window; - regs.x.dx = addr / gran; - offset = regs.x.dx * gran; - __dpmi_int(0x10, ®s); + regs.W.ax = 0x4F05; + regs.W.bx = window; + regs.W.dx = addr / gran; + offset = regs.W.dx * gran; + PDCINT(0x10, regs); PDC_state.offset[window] = offset; } diff --git a/dosvga/pdcgetsc.c b/dosvga/pdcgetsc.c index d75b39d70..86b7cab24 100644 --- a/dosvga/pdcgetsc.c +++ b/dosvga/pdcgetsc.c @@ -23,11 +23,11 @@ int PDC_get_columns(void) int PDC_get_cursor_mode(void) { - PDC_LOG(("PDC_get_cursor_mode() - called\n")); - int start = _FONT16*3/4; int end = _FONT16-1; + PDC_LOG(("PDC_get_cursor_mode() - called\n")); + return (start << 8) | end; } diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index af0b08162..276d0e942 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -20,6 +20,12 @@ static unsigned _find_mode( struct ModeInfoBlock *mode_info, unsigned long mode_addr, int rows, int cols); +#if defined(__WATCOMC__) && defined(__386__) +static int __dpmi_allocate_dos_memory(int paras, int *sel_or_max); +static int __dpmi_free_dos_memory(int sel); +static void dosmemget(unsigned long addr, size_t size, void *buf); +static void dosmemput(const void *buf, size_t size, unsigned long addr); +#endif /* _get_font_address() -- return the address of the font in ROM */ static unsigned long _get_font_address(void) @@ -261,6 +267,11 @@ int PDC_color_content(short color, short *red, short *green, short *blue) int PDC_init_color(short color, short red, short green, short blue) { + /* Scale */ + unsigned r = DIVROUND((unsigned)red * PDC_state.red_max, 1000); + unsigned g = DIVROUND((unsigned)green * PDC_state.green_max, 1000); + unsigned b = DIVROUND((unsigned)blue * PDC_state.blue_max, 1000); + PDC_state.colors[color].r = red; PDC_state.colors[color].g = green; PDC_state.colors[color].b = blue; @@ -273,35 +284,31 @@ int PDC_init_color(short color, short red, short green, short blue) { /* VESA mode in use; first try the VESA function */ int seg, sel; - unsigned char table[4]; - __dpmi_regs d_regs; + unsigned long table; seg = __dpmi_allocate_dos_memory(1, &sel); if (seg < 0) return ERR; - table[0] = DIVROUND((unsigned)blue * PDC_state.blue_max, 1000); - table[1] = DIVROUND((unsigned)green * PDC_state.green_max, 1000); - table[2] = DIVROUND((unsigned)red * PDC_state.red_max, 1000); - table[3] = 0; - dosmemput(table, sizeof(table), seg * 16L); - memset(&d_regs, 0, sizeof(d_regs)); - d_regs.x.ax = 0x4F09; - d_regs.h.bl = 0; - d_regs.x.cx = 1; - d_regs.x.dx = color; - d_regs.x.di = 0; - d_regs.x.es = seg; - __dpmi_int(0x10, &d_regs); + table = ((unsigned long)b << 0) + | ((unsigned long)g << 8) + | ((unsigned long)r << 16); + setdosmemdword(seg * 16L, table); + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x4F09; + regs.h.bl = 0; + regs.W.cx = 1; + regs.W.dx = color; + regs.W.di = 0; + regs.W.es = seg; + PDCINT(0x10, regs); __dpmi_free_dos_memory(sel); - if (d_regs.x.ax == 0x004F) + if (regs.W.ax == 0x004F) return OK; } - /* Scale */ - - regs.h.dh = DIVROUND((unsigned)red * PDC_state.red_max, 1000); - regs.h.ch = DIVROUND((unsigned)green * PDC_state.green_max, 1000); - regs.h.cl = DIVROUND((unsigned)blue * PDC_state.blue_max, 1000); + regs.h.dh = r; + regs.h.ch = g; + regs.h.cl = b; /* Set single DAC register */ @@ -312,10 +319,6 @@ int PDC_init_color(short color, short red, short green, short blue) } else { - unsigned r = DIVROUND((unsigned)red * PDC_state.red_max, 1000); - unsigned g = DIVROUND((unsigned)green * PDC_state.green_max, 1000); - unsigned b = DIVROUND((unsigned)blue * PDC_state.blue_max, 1000); - PDC_state.colors[color].mapped = ((unsigned long)r << PDC_state.red_pos) | ((unsigned long)g << PDC_state.green_pos) @@ -330,7 +333,7 @@ static unsigned _find_video_mode(int rows, int cols) int vbe_info_sel = -1; /* custodial */ int vbe_info_seg; struct VbeInfoBlock vbe_info; - __dpmi_regs regs; + PDCREGS regs; unsigned long mode_addr; struct ModeInfoBlock mode_info; unsigned vesa_mode; @@ -346,14 +349,14 @@ static unsigned _find_video_mode(int rows, int cols) memcpy(vbe_info.VbeSignature, "VBE2", 4); dosmemput(&vbe_info, sizeof(vbe_info), vbe_info_seg * 16L); - memset(®s, 0, sizeof(regs)); - regs.x.ax = 0x4F00; - regs.x.di = 0; - regs.x.es = vbe_info_seg; - __dpmi_int(0x10, ®s); + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x4F00; + regs.W.di = 0; + regs.W.es = vbe_info_seg; + PDCINT(0x10, regs); /* Check for successful completion of function: is VESA BIOS present? */ - if (regs.x.ax != 0x004F) + if (regs.W.ax != 0x004F) goto error; dosmemget(vbe_info_seg * 16L, sizeof(vbe_info), &vbe_info); if (memcmp(vbe_info.VbeSignature, "VESA", 4) != 0) @@ -651,7 +654,7 @@ static int _get_mode_info(unsigned mode, struct ModeInfoBlock *mode_info) int mode_info_sel = -1; /* custodial */ int mode_info_seg; - __dpmi_regs regs; + PDCREGS regs; mode_info_seg = __dpmi_allocate_dos_memory( (sizeof(*mode_info) + 15) / 16, @@ -663,13 +666,13 @@ static int _get_mode_info(unsigned mode, struct ModeInfoBlock *mode_info) dosmemput(mode_info, sizeof(*mode_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(0x10, ®s); + regs.W.ax = 0x4F01; + regs.W.cx = mode; + regs.W.di = 0; + regs.W.es = mode_info_seg; + PDCINT(0x10, regs); - if (regs.x.ax != 0x004F) + if (regs.W.ax != 0x004F) goto error; dosmemget(mode_info_seg * 16L, sizeof(*mode_info), mode_info); if (!(mode_info->ModeAttributes & 0x0001)) @@ -718,6 +721,62 @@ static int _get_mode_info(unsigned mode, struct ModeInfoBlock *mode_info) return TRUE; error: - if (mode_info_sel != -1) __dpmi_free_dos_memory(mode_info_sel); + if (mode_info_sel != -1) + __dpmi_free_dos_memory(mode_info_sel); return FALSE; } + +/* DOS memory allocation routines as defined by DJGPP, for use by Watcom */ +#if defined(__WATCOMC__) && defined(__386__) +static int __dpmi_allocate_dos_memory(int paras, int *sel_or_max) +{ + int flags = 0, r_ax = 0, r_bx = 0, r_dx = 0; + + _asm { + mov ebx, paras; + mov eax, 0x0100; + int 0x31; + pushfd; + pop flags; + mov r_ax, eax; + mov r_bx, ebx; + mov r_dx, edx; + } + if (flags & 0x01) + { + /* carry set */ + *sel_or_max = r_bx; + return -1; + } + else + { + /* carry clear */ + *sel_or_max = r_dx; + return r_ax; + } +} + +static int __dpmi_free_dos_memory(int sel) +{ + int flags = 0; + + _asm { + mov edx, sel; + mov eax, 0x0101; + int 0x31; + pushfd; + pop flags; + } + return (flags & 0x01) ? -1 : 0; +} + +static void dosmemget(unsigned long addr, size_t size, void *buf) +{ + memcpy(buf, (const void *)addr, size); +} + +static void dosmemput(const void *buf, size_t size, unsigned long addr) +{ + memcpy((void *)addr, buf, size); +} +#endif From eba26e2a7908a2e7914e3c7ab553efcda1e9cdc7 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sat, 22 Feb 2020 07:54:31 -0500 Subject: [PATCH 11/26] Support Watcom in 16 bit mode Possibly enough for Borland also, but this is not yet tested. --- dosvga/pdcdisp.c | 20 +++++++------- dosvga/pdcdos.h | 2 ++ dosvga/pdcscrn.c | 69 +++++++++++++++++++++++++++++++++++++----------- dosvga/pdcvesa.h | 2 +- 4 files changed, 67 insertions(+), 26 deletions(-) diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index 02af78ff9..e52507800 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -158,7 +158,7 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) for (line = 0; line < _FONT16; line++) { int col; - unsigned addr2 = addr; + unsigned long addr2 = addr; /* Loop by column */ for (col = 0; col < len; col++) @@ -285,7 +285,7 @@ static unsigned long _get_colors(chtype glyph) } /* Return them as a pair */ - return (back << 16) | fore; + return ((unsigned long)back << 16) | fore; } static void _cursor_off_4(void) @@ -580,26 +580,26 @@ void PDC_private_cursor_on(int row, int col) static unsigned long _address_4(int row, int col) { - return row * PDC_state.bytes_per_line * _FONT16 + col; + return (unsigned long)row * PDC_state.bytes_per_line * _FONT16 + col; } static unsigned long _address_8(int row, int col) { - return row * PDC_state.bytes_per_line * _FONT16 + return (unsigned long)row * PDC_state.bytes_per_line * _FONT16 + col * 8 * ((PDC_state.bits_per_pixel + 7)/8); } static void _video_write_byte(unsigned long addr, unsigned char byte) { unsigned offset = _set_window(PDC_state.write_win, addr); - unsigned long addr2 = PDC_state.window[PDC_state.write_win]*16L + offset; + unsigned long addr2 = _FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); setdosmembyte(addr2, byte); } static void _video_write_word(unsigned long addr, unsigned short word) { unsigned offset = _set_window(PDC_state.write_win, addr); - unsigned long addr2 = PDC_state.window[PDC_state.write_win]*16L + offset; + unsigned long addr2 = _FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); setdosmemword(addr2, word); } @@ -622,14 +622,14 @@ static void _video_write_3byte(unsigned long addr, unsigned long byte3) static void _video_write_dword(unsigned long addr, unsigned long dword) { unsigned offset = _set_window(PDC_state.write_win, addr); - unsigned long addr2 = PDC_state.window[PDC_state.write_win]*16L + offset; + unsigned long addr2 = _FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); setdosmemdword(addr2, dword); } static unsigned char _video_read_byte(unsigned long addr) { unsigned offset = _set_window(PDC_state.read_win, addr); - unsigned long addr2 = PDC_state.window[PDC_state.read_win]*16L + offset; + unsigned long addr2 = _FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); unsigned char byte = getdosmembyte(addr2); return byte; } @@ -637,7 +637,7 @@ static unsigned char _video_read_byte(unsigned long addr) static unsigned short _video_read_word(unsigned long addr) { unsigned offset = _set_window(PDC_state.read_win, addr); - unsigned long addr2 = PDC_state.window[PDC_state.read_win]*16L + offset; + unsigned long addr2 = _FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); unsigned short word = getdosmembyte(addr2); return word; } @@ -663,7 +663,7 @@ static unsigned long _video_read_3byte(unsigned long addr) static unsigned long _video_read_dword(unsigned long addr) { unsigned offset = _set_window(PDC_state.read_win, addr); - unsigned long addr2 = PDC_state.window[PDC_state.read_win]*16L + offset; + unsigned long addr2 = _FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); unsigned long dword = getdosmemdword(addr2); return dword; } diff --git a/dosvga/pdcdos.h b/dosvga/pdcdos.h index db15caaa8..9101974f7 100644 --- a/dosvga/pdcdos.h +++ b/dosvga/pdcdos.h @@ -85,6 +85,7 @@ extern void PDC_private_cursor_off(void); extern void PDC_private_cursor_on(int row, int col); #ifdef __DJGPP__ /* Note: works only in plain DOS... */ +# define PDC_FLAT 1 # if DJGPP == 2 # define _FAR_POINTER(s,o) ((((int)(s)) << 4) + ((int)(o))) # else @@ -96,6 +97,7 @@ extern void PDC_private_cursor_on(int row, int col); # define _FAR_POINTER(s,o) MK_FP(s,o) # else # if defined(__WATCOMC__) && defined(__FLAT__) +# define PDC_FLAT 1 # define _FAR_POINTER(s,o) ((((int)(s)) << 4) + ((int)(o))) # else # define _FAR_POINTER(s,o) (((long)s << 16) | (long)o) diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index 276d0e942..d3df17956 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -30,10 +30,9 @@ static void dosmemput(const void *buf, size_t size, unsigned long addr); /* _get_font_address() -- return the address of the font in ROM */ static unsigned long _get_font_address(void) { - /* TODO: support compilers other than DJGPP */ unsigned ofs = getdosmemword(0x43 * 4 + 0); unsigned seg = getdosmemword(0x43 * 4 + 2); - return ((unsigned long)seg << 4) + ofs; + return _FAR_POINTER(seg, ofs); } /* _get_scrn_mode() - Return the current BIOS video mode */ @@ -268,9 +267,9 @@ int PDC_color_content(short color, short *red, short *green, short *blue) int PDC_init_color(short color, short red, short green, short blue) { /* Scale */ - unsigned r = DIVROUND((unsigned)red * PDC_state.red_max, 1000); - unsigned g = DIVROUND((unsigned)green * PDC_state.green_max, 1000); - unsigned b = DIVROUND((unsigned)blue * PDC_state.blue_max, 1000); + unsigned r = DIVROUND((unsigned long)red * PDC_state.red_max, 1000); + unsigned g = DIVROUND((unsigned long)green * PDC_state.green_max, 1000); + unsigned b = DIVROUND((unsigned long)blue * PDC_state.blue_max, 1000); PDC_state.colors[color].r = red; PDC_state.colors[color].g = green; @@ -283,25 +282,36 @@ int PDC_init_color(short color, short red, short green, short blue) if (PDC_state.scrn_mode >= 0x100) { /* VESA mode in use; first try the VESA function */ +#ifdef PDC_FLAT int seg, sel; +#endif unsigned long table; - seg = __dpmi_allocate_dos_memory(1, &sel); - if (seg < 0) - return ERR; table = ((unsigned long)b << 0) | ((unsigned long)g << 8) | ((unsigned long)r << 16); +#ifdef PDC_FLAT + seg = __dpmi_allocate_dos_memory(1, &sel); + if (seg < 0) + return ERR; setdosmemdword(seg * 16L, table); +#endif memset(®s, 0, sizeof(regs)); regs.W.ax = 0x4F09; regs.h.bl = 0; regs.W.cx = 1; regs.W.dx = color; +#ifdef PDC_FLAT regs.W.di = 0; regs.W.es = seg; +#else + regs.W.di = FP_OFF(&table); + regs.W.es = FP_SEG(&table); +#endif PDCINT(0x10, regs); +#ifdef PDC_FLAT __dpmi_free_dos_memory(sel); +#endif if (regs.W.ax == 0x004F) return OK; } @@ -330,8 +340,10 @@ int PDC_init_color(short color, short red, short green, short blue) static unsigned _find_video_mode(int rows, int cols) { +#ifdef PDC_FLAT int vbe_info_sel = -1; /* custodial */ int vbe_info_seg; +#endif struct VbeInfoBlock vbe_info; PDCREGS regs; unsigned long mode_addr; @@ -339,26 +351,35 @@ static unsigned _find_video_mode(int rows, int cols) unsigned vesa_mode; /* Request VESA BIOS information */ + memset(&vbe_info, 0, sizeof(vbe_info)); + memcpy(vbe_info.VbeSignature, "VBE2", 4); + +#ifdef PDC_FLAT vbe_info_seg = __dpmi_allocate_dos_memory( (sizeof(vbe_info) + 15) / 16, &vbe_info_sel); if (vbe_info_seg < 0) goto error; - - memset(&vbe_info, 0, sizeof(vbe_info)); - memcpy(vbe_info.VbeSignature, "VBE2", 4); dosmemput(&vbe_info, sizeof(vbe_info), vbe_info_seg * 16L); +#endif memset(®s, 0, sizeof(regs)); regs.W.ax = 0x4F00; +#ifdef PDC_FLAT regs.W.di = 0; regs.W.es = vbe_info_seg; +#else + regs.W.di = FP_OFF(&vbe_info); + regs.W.es = FP_SEG(&vbe_info); +#endif PDCINT(0x10, regs); /* Check for successful completion of function: is VESA BIOS present? */ if (regs.W.ax != 0x004F) goto error; +#ifdef PDC_FLAT dosmemget(vbe_info_seg * 16L, sizeof(vbe_info), &vbe_info); +#endif if (memcmp(vbe_info.VbeSignature, "VESA", 4) != 0) goto error; @@ -366,8 +387,8 @@ static unsigned _find_video_mode(int rows, int cols) /* 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); + mode_addr = _FAR_POINTER(vbe_info.VideoModePtr >> 16, + vbe_info.VideoModePtr & 0xFFFF); /* Look for the best-fitting mode available */ vesa_mode = _find_mode(&mode_info, mode_addr, rows, cols); @@ -461,14 +482,18 @@ static unsigned _find_video_mode(int rows, int cols) } } +#ifdef PDC_FLAT __dpmi_free_dos_memory(vbe_info_sel); +#endif return vesa_mode; error: /* If we can't access the VESA BIOS Extensions for any reason, return the 640x480 VGA mode */ +#ifdef PDC_FLAT if (vbe_info_sel != -1) __dpmi_free_dos_memory(vbe_info_sel); +#endif PDC_state.linear_buffer = FALSE; PDC_state.bits_per_pixel = 4; @@ -652,29 +677,39 @@ static int _get_mode_info(unsigned mode, struct ModeInfoBlock *mode_info) { 0, 0, 0, 0 } }; +#ifdef PDC_FLAT int mode_info_sel = -1; /* custodial */ int mode_info_seg; +#endif PDCREGS regs; + memset(mode_info, 0, sizeof(*mode_info)); +#ifdef PDC_FLAT mode_info_seg = __dpmi_allocate_dos_memory( (sizeof(*mode_info) + 15) / 16, &mode_info_sel); if (mode_info_seg < 0) goto error; - - memset(mode_info, 0, sizeof(*mode_info)); dosmemput(mode_info, sizeof(*mode_info), mode_info_seg * 16L); +#endif memset(®s, 0, sizeof(regs)); regs.W.ax = 0x4F01; regs.W.cx = mode; +#ifdef PDC_FLAT regs.W.di = 0; regs.W.es = mode_info_seg; +#else + regs.W.di = FP_OFF(mode_info); + regs.W.es = FP_SEG(mode_info); +#endif PDCINT(0x10, regs); if (regs.W.ax != 0x004F) goto error; +#ifdef PDC_FLAT dosmemget(mode_info_seg * 16L, sizeof(*mode_info), mode_info); +#endif if (!(mode_info->ModeAttributes & 0x0001)) goto error; @@ -717,12 +752,16 @@ static int _get_mode_info(unsigned mode, struct ModeInfoBlock *mode_info) } } +#ifdef PDC_FLAT __dpmi_free_dos_memory(mode_info_sel); +#endif return TRUE; error: +#ifdef PDC_FLAT if (mode_info_sel != -1) __dpmi_free_dos_memory(mode_info_sel); +#endif return FALSE; } diff --git a/dosvga/pdcvesa.h b/dosvga/pdcvesa.h index b30b43c41..0bfc1fd0e 100644 --- a/dosvga/pdcvesa.h +++ b/dosvga/pdcvesa.h @@ -76,7 +76,7 @@ struct ModeInfoBlock { unsigned char LinRsvdMaskSize; /* size of direct color reserved mask (linear modes) */ unsigned char LinRsvdFieldPosition; /* bit position of lsb of reserved mask (linear modes) */ unsigned long MaxPixelClock; /* maximum pixel clock (in Hz) for graphics mode */ - unsigned char Reserved4[189]; /* remainder of ModeInfoBlock */ + unsigned char Reserved4[190]; /* remainder of ModeInfoBlock */ }; #ifdef __GNUC__ #pragma pack(pop) From 10a68b4270a45cf9d57f2f6b6d2817b19f8147ed Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sat, 22 Feb 2020 07:55:05 -0500 Subject: [PATCH 12/26] Fix integer overflow in 16 bit compile Only dosvga can compile as 16 bit and also show full color, and so this bug has gone unnoticed. --- demos/testcurs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/testcurs.c b/demos/testcurs.c index d41feb049..b216cfad1 100644 --- a/demos/testcurs.c +++ b/demos/testcurs.c @@ -1209,7 +1209,7 @@ void gradient(int tmarg) move(tmarg + 3 + i, (COLS - 69) / 2); for (j = 0; j < len; j++) { - const int oval = j * 1000 / len; + const int oval = (int)(j * 1000L / len); const int reverse = 1000 - oval; if (!i) From 1e922870bd29e3b869aad9b8010d7356c127408c Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sat, 22 Feb 2020 10:27:21 -0500 Subject: [PATCH 13/26] Add support for the Borland compiler --- dosvga/pdcdisp.c | 12 +++++------ dosvga/pdcdos.h | 12 +++++------ dosvga/pdcscrn.c | 52 ++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index e52507800..ab10309f3 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -592,14 +592,14 @@ static unsigned long _address_8(int row, int col) static void _video_write_byte(unsigned long addr, unsigned char byte) { unsigned offset = _set_window(PDC_state.write_win, addr); - unsigned long addr2 = _FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); + unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); setdosmembyte(addr2, byte); } static void _video_write_word(unsigned long addr, unsigned short word) { unsigned offset = _set_window(PDC_state.write_win, addr); - unsigned long addr2 = _FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); + unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); setdosmemword(addr2, word); } @@ -622,14 +622,14 @@ static void _video_write_3byte(unsigned long addr, unsigned long byte3) static void _video_write_dword(unsigned long addr, unsigned long dword) { unsigned offset = _set_window(PDC_state.write_win, addr); - unsigned long addr2 = _FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); + unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); setdosmemdword(addr2, dword); } static unsigned char _video_read_byte(unsigned long addr) { unsigned offset = _set_window(PDC_state.read_win, addr); - unsigned long addr2 = _FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); + unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); unsigned char byte = getdosmembyte(addr2); return byte; } @@ -637,7 +637,7 @@ static unsigned char _video_read_byte(unsigned long addr) static unsigned short _video_read_word(unsigned long addr) { unsigned offset = _set_window(PDC_state.read_win, addr); - unsigned long addr2 = _FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); + unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); unsigned short word = getdosmembyte(addr2); return word; } @@ -663,7 +663,7 @@ static unsigned long _video_read_3byte(unsigned long addr) static unsigned long _video_read_dword(unsigned long addr) { unsigned offset = _set_window(PDC_state.read_win, addr); - unsigned long addr2 = _FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); + unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); unsigned long dword = getdosmemdword(addr2); return dword; } diff --git a/dosvga/pdcdos.h b/dosvga/pdcdos.h index 9101974f7..f14123c23 100644 --- a/dosvga/pdcdos.h +++ b/dosvga/pdcdos.h @@ -122,17 +122,17 @@ void setdosmemdword(int offs, unsigned long d); # define PDC_FAR # endif # define getdosmembyte(offs) \ - (*((unsigned char PDC_FAR *) _FAR_POINTER(0,offs))) + (*((unsigned char PDC_FAR *) (offs))) # define getdosmemword(offs) \ - (*((unsigned short PDC_FAR *) _FAR_POINTER(0,offs))) + (*((unsigned short PDC_FAR *) (offs))) # define getdosmemdword(offs) \ - (*((unsigned long PDC_FAR *) _FAR_POINTER(0,offs))) + (*((unsigned long PDC_FAR *) (offs))) # define setdosmembyte(offs,x) \ - (*((unsigned char PDC_FAR *) _FAR_POINTER(0,offs)) = (x)) + (*((unsigned char PDC_FAR *) (offs)) = (x)) # define setdosmemword(offs,x) \ - (*((unsigned short PDC_FAR *) _FAR_POINTER(0,offs)) = (x)) + (*((unsigned short PDC_FAR *) (offs)) = (x)) # define setdosmemdword(offs,x) \ - (*((unsigned long PDC_FAR *) _FAR_POINTER(0,offs)) = (x)) + (*((unsigned long PDC_FAR *) (offs)) = (x)) #endif #if defined(__WATCOMC__) && defined(__386__) diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index d3df17956..673a03a91 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -30,9 +30,13 @@ static void dosmemput(const void *buf, size_t size, unsigned long addr); /* _get_font_address() -- return the address of the font in ROM */ static unsigned long _get_font_address(void) { +#ifdef PDC_FLAT unsigned ofs = getdosmemword(0x43 * 4 + 0); unsigned seg = getdosmemword(0x43 * 4 + 2); return _FAR_POINTER(seg, ofs); +#else + return getdosmemdword(0x43 * 4); +#endif } /* _get_scrn_mode() - Return the current BIOS video mode */ @@ -99,11 +103,6 @@ void PDC_scr_free(void) int PDC_scr_open(void) { -#if SMALL || MEDIUM - struct SREGS segregs; - int ds; -#endif - PDC_LOG(("PDC_scr_open() - called\n")); SP = calloc(1, sizeof(SCREEN)); @@ -278,6 +277,9 @@ int PDC_init_color(short color, short red, short green, short blue) if (PDC_state.bits_per_pixel <= 8) { PDCREGS regs; +#if !defined(PDC_FLAT) && !defined(__WATCOMC__) + struct SREGS sregs; +#endif if (PDC_state.scrn_mode >= 0x100) { @@ -304,11 +306,17 @@ int PDC_init_color(short color, short red, short green, short blue) #ifdef PDC_FLAT regs.W.di = 0; regs.W.es = seg; -#else + PDCINT(0x10, regs); +#elif defined(__WATCOMC__) regs.W.di = FP_OFF(&table); regs.W.es = FP_SEG(&table); -#endif PDCINT(0x10, regs); +#else + regs.W.di = FP_OFF(&table); + segread(&sregs); + sregs.es = FP_SEG(&table); + int86x(0x10, ®s, ®s, &sregs); +#endif #ifdef PDC_FLAT __dpmi_free_dos_memory(sel); #endif @@ -346,6 +354,9 @@ static unsigned _find_video_mode(int rows, int cols) #endif struct VbeInfoBlock vbe_info; PDCREGS regs; +#if !defined(PDC_FLAT) && !defined(__WATCOMC__) + struct SREGS sregs; +#endif unsigned long mode_addr; struct ModeInfoBlock mode_info; unsigned vesa_mode; @@ -368,11 +379,17 @@ static unsigned _find_video_mode(int rows, int cols) #ifdef PDC_FLAT regs.W.di = 0; regs.W.es = vbe_info_seg; -#else + PDCINT(0x10, regs); +#elif defined(__WATCOMC__) regs.W.di = FP_OFF(&vbe_info); regs.W.es = FP_SEG(&vbe_info); -#endif PDCINT(0x10, regs); +#else + regs.W.di = FP_OFF(&vbe_info); + segread(&sregs); + sregs.es = FP_SEG(&vbe_info); + int86x(0x10, ®s, ®s, &sregs); +#endif /* Check for successful completion of function: is VESA BIOS present? */ if (regs.W.ax != 0x004F) @@ -387,8 +404,12 @@ static unsigned _find_video_mode(int rows, int cols) /* 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. */ +#ifdef PDC_FLAT mode_addr = _FAR_POINTER(vbe_info.VideoModePtr >> 16, vbe_info.VideoModePtr & 0xFFFF); +#else + mode_addr = vbe_info.VideoModePtr; +#endif /* Look for the best-fitting mode available */ vesa_mode = _find_mode(&mode_info, mode_addr, rows, cols); @@ -682,6 +703,9 @@ static int _get_mode_info(unsigned mode, struct ModeInfoBlock *mode_info) int mode_info_seg; #endif PDCREGS regs; +#if !defined(PDC_FLAT) && !defined(__WATCOMC__) + struct SREGS sregs; +#endif memset(mode_info, 0, sizeof(*mode_info)); #ifdef PDC_FLAT @@ -699,11 +723,17 @@ static int _get_mode_info(unsigned mode, struct ModeInfoBlock *mode_info) #ifdef PDC_FLAT regs.W.di = 0; regs.W.es = mode_info_seg; -#else + PDCINT(0x10, regs); +#elif defined(__WATCOMC__) regs.W.di = FP_OFF(mode_info); regs.W.es = FP_SEG(mode_info); -#endif PDCINT(0x10, regs); +#else + regs.W.di = FP_OFF(mode_info); + segread(&sregs); + sregs.es = FP_SEG(mode_info); + int86x(0x10, ®s, ®s, &sregs); +#endif if (regs.W.ax != 0x004F) goto error; From 081eb3c30a7a3dde922b03bf9b8c4074fef432e0 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sat, 22 Feb 2020 13:05:25 -0500 Subject: [PATCH 14/26] Support 8 bit DACs in 8 bit color mode This is disabled in 4 bit color mode, because it doesn't seem to work, and is not relevant in direct color modes. --- dosvga/pdcscrn.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index 673a03a91..e3f79e14c 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -6,8 +6,6 @@ #include #include -/* TODO: support 8 bit palette registers if available */ - struct PDC_video_state PDC_state; static int saved_scrnmode[3]; @@ -233,6 +231,22 @@ static void _load_palette(void) PDCINT(0x10, regs); } + /* Set 8 bit DACs if available */ + /* This doesn't seem to work with 4 bit color */ + if (PDC_state.bits_per_pixel == 8) + { + unsigned dacmax; + + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x4F08; + regs.W.bx = 0x0800; + PDCINT(0x10, regs); + dacmax = (regs.W.ax == 0x004F) ? (1 << regs.h.bh) - 1 : 63; + PDC_state.red_max = dacmax; + PDC_state.green_max = dacmax; + PDC_state.blue_max = dacmax; + } + /* Load the DAC registers from the current palette */ for (i = 0; i < 1 << PDC_state.bits_per_pixel; i++) PDC_init_color(i, PDC_state.colors[i].r, PDC_state.colors[i].g, From d98641d25ff025ecad10c285f695dc13bb552487 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sat, 22 Feb 2020 13:17:00 -0500 Subject: [PATCH 15/26] Add A_LEFT and A_RIGHT Also, fix incorrect saving of bytes under cursor in 15 and 16-bit modes. --- dosvga/pdcdisp.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index ab10309f3..1f21b1fd2 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -97,7 +97,13 @@ static void _new_packet(unsigned long colors, int lineno, int x, int len, const else if (line == underline && (glyph & A_UNDERLINE) != 0) byte = 0xFF; else + { byte = getdosmembyte(PDC_state.font_addr + ch*_FONT16 + line); + if (glyph & A_LEFT) + byte |= 0x80; + if (glyph & A_RIGHT) + byte |= 0x01; + } if (pass & 1) byte = ~byte; @@ -179,6 +185,11 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) byte = 0xFF; else byte = getdosmembyte(PDC_state.font_addr + ch*_FONT16 + line); + /* Bit mask for A_LEFT and A_RIGHT */ + if (glyph & A_LEFT) + byte |= 0x80; + if (glyph & A_RIGHT) + byte |= 0x01; /* Get the colors */ colors = _get_colors(glyph); @@ -638,7 +649,7 @@ static unsigned short _video_read_word(unsigned long addr) { unsigned offset = _set_window(PDC_state.read_win, addr); unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); - unsigned short word = getdosmembyte(addr2); + unsigned short word = getdosmemword(addr2); return word; } From 6ea186ecba21ec54062bb39d857fe6e073fd66e7 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sat, 22 Feb 2020 13:23:01 -0500 Subject: [PATCH 16/26] Include dosvga in the READMEs --- README.md | 2 ++ dosvga/README.md | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 35d3f63bb..73b36ad9c 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ platforms. Build instructions are in the README.md file for each platform: - [DOS] +- [DOS with full VGA support] - [OS/2] - [SDL 1.x] - [SDL 2.x] @@ -58,6 +59,7 @@ William McBrine [History]: docs/HISTORY.md [docs]: docs/README.md [DOS]: dos/README.md +[DOS with full VGA support]: dosvga/README.md [OS/2]: os2/README.md [SDL 1.x]: sdl1/README.md [SDL 2.x]: sdl2/README.md diff --git a/dosvga/README.md b/dosvga/README.md index ad05ce691..738efacb6 100644 --- a/dosvga/README.md +++ b/dosvga/README.md @@ -1,7 +1,8 @@ PDCurses for DOS ================ -This directory contains PDCurses source code files specific to DOS. +This directory contains PDCurses source code files specific to the +VGA-capable DOS port. Building From dcd159c9784837dd6a6b6e1c75a7644697bd28c7 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sat, 22 Feb 2020 15:01:02 -0500 Subject: [PATCH 17/26] Support linear frame buffer in 32 bit builds --- dosvga/pdcdisp.c | 141 ++++++++++++++++++++++++++++++----- dosvga/pdcdos.h | 3 +- dosvga/pdcscrn.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 311 insertions(+), 22 deletions(-) diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index 1f21b1fd2..4502b9f2e 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -3,6 +3,10 @@ #include "pdcdos.h" #include "../common/acs437.h" +#ifdef __DJGPP__ +#include +#endif + #ifdef __WATCOMC__ /* For Watcom, we need conio.h, but the Curses macro for getch fouls it up */ #undef getch @@ -25,6 +29,14 @@ static unsigned short _video_read_word(unsigned long addr); static unsigned long _video_read_3byte(unsigned long addr); static unsigned long _video_read_dword(unsigned long addr); static unsigned _set_window(unsigned window, unsigned long addr); +#if defined(__WATCOMC__) && defined(__386__) +static unsigned char _farpeekb(unsigned seg, unsigned long off); +static unsigned short _farpeekw(unsigned seg, unsigned long off); +static unsigned long _farpeekl(unsigned seg, unsigned long off); +static void _farpokeb(unsigned seg, unsigned long off, unsigned char byte); +static void _farpokew(unsigned seg, unsigned long off, unsigned short word); +static void _farpokel(unsigned seg, unsigned long off, unsigned long dword); +#endif /* position hardware cursor at (y, x) */ @@ -602,16 +614,34 @@ static unsigned long _address_8(int row, int col) static void _video_write_byte(unsigned long addr, unsigned char byte) { - unsigned offset = _set_window(PDC_state.write_win, addr); - unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); - setdosmembyte(addr2, byte); +#ifdef PDC_FLAT + if (PDC_state.linear_sel) + { + _farpokeb(PDC_state.linear_sel, addr, byte); + } + else +#endif + { + unsigned offset = _set_window(PDC_state.write_win, addr); + unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); + setdosmembyte(addr2, byte); + } } static void _video_write_word(unsigned long addr, unsigned short word) { - unsigned offset = _set_window(PDC_state.write_win, addr); - unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); - setdosmemword(addr2, word); +#ifdef PDC_FLAT + if (PDC_state.linear_sel) + { + _farpokew(PDC_state.linear_sel, addr, word); + } + else +#endif + { + unsigned offset = _set_window(PDC_state.write_win, addr); + unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); + setdosmemword(addr2, word); + } } static void _video_write_3byte(unsigned long addr, unsigned long byte3) @@ -632,24 +662,55 @@ static void _video_write_3byte(unsigned long addr, unsigned long byte3) static void _video_write_dword(unsigned long addr, unsigned long dword) { - unsigned offset = _set_window(PDC_state.write_win, addr); - unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); - setdosmemdword(addr2, dword); +#ifdef PDC_FLAT + if (PDC_state.linear_sel) + { + _farpokel(PDC_state.linear_sel, addr, dword); + } + else +#endif + { + unsigned offset = _set_window(PDC_state.write_win, addr); + unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); + setdosmemdword(addr2, dword); + } } static unsigned char _video_read_byte(unsigned long addr) { - unsigned offset = _set_window(PDC_state.read_win, addr); - unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); - unsigned char byte = getdosmembyte(addr2); + unsigned char byte; + +#ifdef PDC_FLAT + if (PDC_state.linear_sel) + { + byte = _farpeekb(PDC_state.linear_sel, addr); + } + else +#endif + { + unsigned offset = _set_window(PDC_state.read_win, addr); + unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); + byte = getdosmembyte(addr2); + } return byte; } static unsigned short _video_read_word(unsigned long addr) { - unsigned offset = _set_window(PDC_state.read_win, addr); - unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); - unsigned short word = getdosmemword(addr2); + unsigned short word; + +#ifdef PDC_FLAT + if (PDC_state.linear_sel) + { + word = _farpeekw(PDC_state.linear_sel, addr); + } + else +#endif + { + unsigned offset = _set_window(PDC_state.read_win, addr); + unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); + word = getdosmemword(addr2); + } return word; } @@ -673,9 +734,20 @@ static unsigned long _video_read_3byte(unsigned long addr) static unsigned long _video_read_dword(unsigned long addr) { - unsigned offset = _set_window(PDC_state.read_win, addr); - unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); - unsigned long dword = getdosmemdword(addr2); + unsigned long dword; + +#ifdef PDC_FLAT + if (PDC_state.linear_sel) + { + dword = _farpeekl(PDC_state.linear_sel, addr); + } + else +#endif + { + unsigned offset = _set_window(PDC_state.read_win, addr); + unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); + dword = getdosmemdword(addr2); + } return dword; } @@ -699,3 +771,36 @@ static unsigned _set_window(unsigned window, unsigned long addr) return addr - offset; } + +#if defined(__WATCOMC__) && defined(__386__) +/* Far peek and poke, as defined for DJGPP, made available for Watcom */ +static unsigned char _farpeekb(unsigned seg, unsigned long off) +{ + return *(unsigned char __far *)MK_FP(seg, off); +} + +static unsigned short _farpeekw(unsigned seg, unsigned long off) +{ + return *(unsigned short __far *)MK_FP(seg, off); +} + +static unsigned long _farpeekl(unsigned seg, unsigned long off) +{ + return *(unsigned long __far *)MK_FP(seg, off); +} + +static void _farpokeb(unsigned seg, unsigned long off, unsigned char byte) +{ + *(unsigned char __far *)MK_FP(seg, off) = byte; +} + +static void _farpokew(unsigned seg, unsigned long off, unsigned short word) +{ + *(unsigned short __far *)MK_FP(seg, off) = word; +} + +static void _farpokel(unsigned seg, unsigned long off, unsigned long dword) +{ + *(unsigned long __far *)MK_FP(seg, off) = dword; +} +#endif diff --git a/dosvga/pdcdos.h b/dosvga/pdcdos.h index f14123c23..ed7d3b9ba 100644 --- a/dosvga/pdcdos.h +++ b/dosvga/pdcdos.h @@ -47,7 +47,8 @@ struct PDC_video_state { /* Information about the current video mode: */ unsigned short scrn_mode; - bool linear_buffer; + int linear_sel; + unsigned long linear_addr; unsigned char bits_per_pixel; unsigned short video_width; /* Width of graphics mode in pixels */ unsigned short video_height; /* Height of graphics mode in pixels */ diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index e3f79e14c..b1c68ae2d 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -18,9 +18,18 @@ static unsigned _find_mode( struct ModeInfoBlock *mode_info, unsigned long mode_addr, int rows, int cols); +#ifdef PDC_FLAT +static unsigned long _map_frame_buffer(unsigned long phys_addr, + unsigned long size); +static void _unmap_frame_buffer(unsigned long phys_addr); +#endif #if defined(__WATCOMC__) && defined(__386__) static int __dpmi_allocate_dos_memory(int paras, int *sel_or_max); static int __dpmi_free_dos_memory(int sel); +static int __dpmi_allocate_ldt_descriptors(int count); +static int __dpmi_free_ldt_descriptor(int sel); +static int __dpmi_set_segment_base_address(int sel, unsigned long addr); +static int __dpmi_set_segment_limit(int sel, unsigned long limit); static void dosmemget(unsigned long addr, size_t size, void *buf); static void dosmemput(const void *buf, size_t size, unsigned long addr); #endif @@ -71,7 +80,7 @@ static void _set_scrn_mode(int new_mode) regs.h.al = (unsigned char) new_mode; } PDCINT(0x10, regs); - PDC_state.scrn_mode = new_mode & 0x3FFF; + PDC_state.scrn_mode = new_mode; PDC_state.font_addr = _get_font_address(); LINES = PDC_get_rows(); @@ -85,6 +94,11 @@ void PDC_scr_close(void) { PDCREGS regs; +#ifdef PDC_FLAT + _unmap_frame_buffer(PDC_state.linear_addr); + __dpmi_free_ldt_descriptor(PDC_state.linear_sel); +#endif + _set_scrn_mode(0x03); memset(®s, 0, sizeof(regs)); regs.W.ax = 0x1114; @@ -462,9 +476,35 @@ static unsigned _find_video_mode(int rows, int cols) PDC_state.bytes_per_line = mode_info.BytesPerScanLine; PDC_state.video_width = mode_info.XResolution; PDC_state.video_height = mode_info.YResolution; - PDC_state.linear_buffer = FALSE; PDC_state.bits_per_pixel = mode_info.BitsPerPixel; +#ifdef PDC_FLAT + /* Enable the linear frame buffer if available */ + if ((mode_info.ModeAttributes & 0x80) != 0) + { + do { /* while (FALSE) */ + unsigned win_size; + + PDC_state.linear_sel = __dpmi_allocate_ldt_descriptors(1); + if (PDC_state.linear_sel < 0) + break; + win_size = mode_info.BytesPerScanLine * mode_info.YResolution; + PDC_state.linear_addr = _map_frame_buffer(mode_info.PhysBasePtr, win_size); + if (PDC_state.linear_addr == 0) + { + __dpmi_free_ldt_descriptor(PDC_state.linear_sel); + PDC_state.linear_sel = 0; + break; + } + __dpmi_set_segment_base_address(PDC_state.linear_sel, PDC_state.linear_addr); + __dpmi_set_segment_limit(PDC_state.linear_sel, (win_size - 1) | 0xFFF); + vesa_mode |= 0x4000; + } while (FALSE); + } +#else + PDC_state.linear_sel = 0; +#endif + if (PDC_state.bits_per_pixel <= 8) { PDC_state.red_max = 63; @@ -473,6 +513,18 @@ static unsigned _find_video_mode(int rows, int cols) } else { +#ifdef PDC_FLAT + if (PDC_state.linear_sel && vbe_info.VbeVersion >= 0x300) + { + PDC_state.red_max = (1 << mode_info.LinRedMaskSize) - 1; + PDC_state.red_pos = mode_info.LinRedFieldPosition; + PDC_state.green_max = (1 << mode_info.LinGreenMaskSize) - 1; + PDC_state.green_pos = mode_info.LinGreenFieldPosition; + PDC_state.blue_max = (1 << mode_info.LinBlueMaskSize) - 1; + PDC_state.blue_pos = mode_info.LinBlueFieldPosition; + } + else +#endif if (mode_info.ModeAttributes & 0x2) { PDC_state.red_max = (1 << mode_info.RedMaskSize) - 1; @@ -530,7 +582,6 @@ static unsigned _find_video_mode(int rows, int cols) __dpmi_free_dos_memory(vbe_info_sel); #endif - PDC_state.linear_buffer = FALSE; PDC_state.bits_per_pixel = 4; PDC_state.video_width = 640; PDC_state.video_height = 480; @@ -809,6 +860,71 @@ static int _get_mode_info(unsigned mode, struct ModeInfoBlock *mode_info) return FALSE; } +/* Make a physical address mapping, to support the linear frame buffer */ +#ifdef __DJGPP__ +static unsigned long +_map_frame_buffer(unsigned long phys_addr, unsigned long size) +{ + __dpmi_meminfo info; + int rc; + + info.handle = 0; + info.address = phys_addr; + info.size = size; + rc = __dpmi_physical_address_mapping(&info); + + return rc == 0 ? info.address : 0; +} + +static void +_unmap_frame_buffer(unsigned long phys_addr) +{ + __dpmi_meminfo info; + + info.handle = 0; + info.address = phys_addr; + info.size = 0; + __dpmi_free_physical_address_mapping(&info); +} +#elif defined(__WATCOMC__) && defined(__386__) +static unsigned long +_map_frame_buffer(unsigned long phys_addr, unsigned long size) +{ + unsigned flags = 0; + unsigned long r_bxcx = 0; + + _asm { + mov ecx, phys_addr; + mov ebx, ecx; + shr ebx, 16; + mov edi, size; + mov esi, edi; + shr esi, 16; + mov eax, 0x0800; + int 0x31; + pushfd; + pop flags; + shl ebx, 16; + mov bx, cx; + mov r_bxcx, ebx; + } + + return (flags & 1) ? 0 : r_bxcx; +} + +static void +_unmap_frame_buffer(unsigned long phys_addr) +{ + _asm { + mov ecx, phys_addr; + mov ebx, ecx; + shr ebx, 16; + mov eax, 0x0801; + int 0x31; + } +} +#endif + /* DOS memory allocation routines as defined by DJGPP, for use by Watcom */ #if defined(__WATCOMC__) && defined(__386__) static int __dpmi_allocate_dos_memory(int paras, int *sel_or_max) @@ -853,6 +969,73 @@ static int __dpmi_free_dos_memory(int sel) return (flags & 0x01) ? -1 : 0; } +static int __dpmi_allocate_ldt_descriptors(int count) +{ + int flags = 0; + int r_eax = 0; + + _asm { + mov ecx, count; + mov eax, 0x0000; + int 0x31; + pushfd; + pop flags; + mov r_eax, eax; + } + + return (flags & 0x01) ? -1 : r_eax; +} + +static int __dpmi_free_ldt_descriptor(int sel) +{ + int flags = 0; + + _asm { + mov ebx, sel; + mov eax, 0x0001; + int 0x31; + pushfd; + pop flags; + } + return (flags & 0x01) ? -1 : 0; +} + +static int __dpmi_set_segment_base_address(int sel, unsigned long addr) +{ + int flags = 0; + + _asm { + mov ebx, sel; + mov edx, addr; + mov ecx, edx; + shr ecx, 16; + mov eax, 0x0007; + int 0x31; + pushfd; + pop flags; + } + + return (flags & 0x01) ? -1 : 0; +} + +static int __dpmi_set_segment_limit(int sel, unsigned long limit) +{ + int flags = 0; + + _asm { + mov ebx, sel; + mov edx, limit; + mov ecx, edx; + shr ecx, 16; + mov eax, 0x0008; + int 0x31; + pushfd; + pop flags; + } + + return (flags & 0x01) ? -1 : 0; +} + static void dosmemget(unsigned long addr, size_t size, void *buf) { memcpy(buf, (const void *)addr, size); From 1e35536b3cdd7b870cac95536fffa23f5d3b7180 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sat, 22 Feb 2020 15:28:57 -0500 Subject: [PATCH 18/26] Fail gracefully if no VGA installed --- dosvga/pdcscrn.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index b1c68ae2d..89a83fb5b 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -115,8 +115,17 @@ void PDC_scr_free(void) int PDC_scr_open(void) { + PDCREGS regs; + PDC_LOG(("PDC_scr_open() - called\n")); + /* Check for VGA and bail out if we don't find one */ + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x1A00; + PDCINT(0x10, regs); + if (regs.h.bl != 8) + return ERR; + SP = calloc(1, sizeof(SCREEN)); if (!SP) From 6e75f6d1b4ec5acfd7b9ca2356e9fca9cb1b64e4 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 23 Feb 2020 06:21:14 -0500 Subject: [PATCH 19/26] Fix a bug in 24 bit pixel handling --- dosvga/pdcdisp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index 4502b9f2e..06220821c 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -656,7 +656,7 @@ static void _video_write_3byte(unsigned long addr, unsigned long byte3) else { _video_write_word(addr + 0, byte3 & 0xFFFF); - _video_write_byte(addr + 2, byte3 >> 8); + _video_write_byte(addr + 2, byte3 >> 16); } } From 36e05ead4ef0ecee581475ba1d90ab1803f0172d Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 23 Feb 2020 15:33:18 -0500 Subject: [PATCH 20/26] Rewrite rendering functions for speed --- dosvga/pdcdisp.c | 351 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 243 insertions(+), 108 deletions(-) diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index 06220821c..4417c0068 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -4,6 +4,7 @@ #include "../common/acs437.h" #ifdef __DJGPP__ +#include #include #endif @@ -14,9 +15,17 @@ #define outportb(a, b) outp((a), (b)) #endif +/* Maximum run of characters per call to _transform_line_[48] */ +#ifdef PDC_FLAT +# define MAX_PACKET 512 /* optimize for speed */ +#else +# define MAX_PACKET 32 /* keep stack usage reasonable */ +#endif + /* Support cursor on graphics mode */ static unsigned long bytes_behind[8][16]; static unsigned char cursor_color = 15; + static unsigned long _get_colors(chtype glyph); static unsigned long _address_4(int row, int col); static unsigned long _address_8(int row, int col); @@ -24,6 +33,7 @@ static void _video_write_byte(unsigned long addr, unsigned char byte); static void _video_write_word(unsigned long addr, unsigned short word); static void _video_write_3byte(unsigned long addr, unsigned long byte3); static void _video_write_dword(unsigned long addr, unsigned long dword); +static void _video_write(unsigned long addr, const void *data, size_t size); static unsigned char _video_read_byte(unsigned long addr); static unsigned short _video_read_word(unsigned long addr); static unsigned long _video_read_3byte(unsigned long addr); @@ -52,10 +62,14 @@ void PDC_gotoyx(int row, int col) static void _new_packet(unsigned long colors, int lineno, int x, int len, const chtype *srcp) { + unsigned char bytes[16][MAX_PACKET]; unsigned fore, back; int underline; unsigned long addr = _address_4(lineno, x); - unsigned pass; + unsigned long cp; + int col; + unsigned line; + unsigned vplane; fore = colors & 0xF; back = (colors >> 16) & 0xF; @@ -63,72 +77,116 @@ static void _new_packet(unsigned long colors, int lineno, int x, int len, const /* Underline will go here if requested */ underline = 13 /*_FONT16*/; + /* Render to the bytes array and then copy to the frame buffer */ + /* Loop by column */ + for (col = 0; col < len; col++) + { + chtype glyph = srcp[col]; + int ch; + unsigned long font_addr; +#ifdef __DJGPP__ + unsigned char font_data[16]; +#else + unsigned char PDC_FAR *font_data; +#endif + unsigned char lr_mask; + + /* Get the index into the font */ + ch = glyph & 0xFF; + if ((glyph & A_ALTCHARSET) != 0 && (glyph & 0xff80) == 0) + ch = acs_map[ch & 0x7f] & 0xff; + font_addr = PDC_state.font_addr + ch*_FONT16; + + /* Get the font data */ +#ifdef __DJGPP__ + dosmemget(font_addr, _FONT16, font_data); +#else + font_data = (unsigned char PDC_FAR *)font_addr; +#endif + + /* Set pixels for A_LEFT and A_RIGHT */ + lr_mask = 0x00; + if (glyph & A_LEFT) + lr_mask |= 0x80; + if (glyph & A_RIGHT) + lr_mask |= 0x01; + + /* Copy font data into the bytes array */ + for (line = 0; line < _FONT16; line++) + { + unsigned char byte = font_data[line]; + bytes[line][col] = byte | lr_mask; + } + if (glyph & A_UNDERLINE) + bytes[underline][col] = 0xFF; + } + /* Draw the text in four passes, to optimize for the memory architecture of the VGA in four bit pixel modes */ - for (pass = 0; pass < 4; pass++) - { - unsigned char vplane; - unsigned long cp; - int line; - int col; - - /* Set memory planes to write */ - if (pass & 2) - vplane = fore; - else - vplane = ~fore; - if (pass & 1) - vplane &= back; - else - vplane &= ~back; - vplane &= 0xF; - if (vplane == 0) - continue; + + vplane = fore & ~back; + if (vplane != 0) + { + /* fore has 1, back has 0: copy bytes as rendered */ outportb(0x3c4, 2); outportb(0x3c5, vplane); + cp = addr; + for (line = 0; line < _FONT16; line++) + { + _video_write(cp, bytes[line], len); + cp += PDC_state.bytes_per_line; + } + } - /* Loop by raster line */ + vplane = ~fore & back; + if (vplane != 0) + { + /* fore has 0, back has 1: copy bytes inverted */ + outportb(0x3c4, 2); + outportb(0x3c5, vplane); cp = addr; for (line = 0; line < _FONT16; line++) { - /* Loop by column */ for (col = 0; col < len; col++) - { - chtype glyph = srcp[col]; - int ch; - unsigned char byte; - - /* Get the index into the font */ - ch = glyph & 0xFF; - if ((glyph & A_ALTCHARSET) != 0 && (glyph & 0xff80) == 0) - ch = acs_map[ch & 0x7f] & 0xff; - - /* Get one byte of the glyph to be drawn */ - if (pass == 0 || pass == 3) - byte = 0x00; - else if (line == underline && (glyph & A_UNDERLINE) != 0) - byte = 0xFF; - else - { - byte = getdosmembyte(PDC_state.font_addr + ch*_FONT16 + line); - if (glyph & A_LEFT) - byte |= 0x80; - if (glyph & A_RIGHT) - byte |= 0x01; - } - if (pass & 1) - byte = ~byte; + bytes[line][col] ^= 0xFF; + _video_write(cp, bytes[line], len); + cp += PDC_state.bytes_per_line; + } + } - /* Place the byte in the frame buffer */ - _video_write_byte(cp + col, byte); - } + vplane = ~fore & ~back; + if (vplane != 0) + { + /* fore has 0, back has 0: write 0x00 */ + outportb(0x3c4, 2); + outportb(0x3c5, vplane); + cp = addr; + memset(bytes[0], 0x00, len); + for (line = 0; line < _FONT16; line++) + { + _video_write(cp, bytes[0], len); + cp += PDC_state.bytes_per_line; + } + } + + vplane = fore & back; + if (vplane != 0) + { + /* fore has 1, back has 1: write 0xFF */ + outportb(0x3c4, 2); + outportb(0x3c5, vplane); + cp = addr; + memset(bytes[0], 0xFF, len); + for (line = 0; line < _FONT16; line++) + { + _video_write(cp, bytes[0], len); cp += PDC_state.bytes_per_line; } } } /* PDC_transform_line for 4 bit pixels */ - + static void _transform_line_4(int lineno, int x, int len, const chtype *srcp) { unsigned long old_colors, colors; @@ -141,7 +199,7 @@ static void _transform_line_4(int lineno, int x, int len, const chtype *srcp) { colors = _get_colors(srcp[i]); - if (colors != old_colors) + if (colors != old_colors || i >= MAX_PACKET) { _new_packet(old_colors, lineno, x, i, srcp); old_colors = colors; @@ -159,95 +217,125 @@ static void _transform_line_4(int lineno, int x, int len, const chtype *srcp) } /* PDC_transform_line for 8, 15, 16, 24 and 32 bit pixels */ - + static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) { + unsigned char bytes[MAX_PACKET*4*8]; unsigned long addr = _address_8(lineno, x); - unsigned underline; + unsigned bytes_per_pixel = (PDC_state.bits_per_pixel + 7) / 8; + unsigned long cp; + + struct + { + unsigned long font_addr; + unsigned char lr_mask; + unsigned char ul_mask; + unsigned long fore; + unsigned long back; + } glyphs[MAX_PACKET]; + + int col; unsigned line; + unsigned underline; /* Underline will go here if requested */ underline = 13 /*_FONT16*/; - /* Draw the entire line in pixel order, to minimize the use of the VESA - window function */ + /* Compute basic glyph data only once per character */ + for (col = 0; col < len; col++) + { + chtype glyph = srcp[col]; + unsigned ch; + unsigned long colors, fore, back; + + /* Get the index into the font */ + ch = glyph & 0xFF; + if ((glyph & A_ALTCHARSET) != 0 && (glyph & 0xff80) == 0) + ch = acs_map[ch & 0x7f] & 0xff; + + /* Get the address of the font data */ + glyphs[col].font_addr = PDC_state.font_addr + ch*_FONT16; + + /* Bit mask for underline */ + glyphs[col].ul_mask = (glyph & A_UNDERLINE) ? 0xFF : 0x00; + + /* Bit mask for A_LEFT and A_RIGHT */ + glyphs[col].lr_mask = 0x00; + if (glyph & A_LEFT) + glyphs[col].lr_mask |= 0x80; + if (glyph & A_RIGHT) + glyphs[col].lr_mask |= 0x01; + + /* Get the colors */ + colors = _get_colors(glyph); + fore = colors & 0xFFFF; + back = (colors >> 16) & 0xFFFF; + if (PDC_state.bits_per_pixel > 8) + { + fore = PDC_state.colors[fore].mapped; + back = PDC_state.colors[back].mapped; + } + glyphs[col].fore = fore; + glyphs[col].back = back; + } /* Loop by raster line */ + cp = addr; for (line = 0; line < _FONT16; line++) { - int col; - unsigned long addr2 = addr; + unsigned bindex; /* Loop by column */ + bindex = 0; for (col = 0; col < len; col++) { - chtype glyph = srcp[col]; - int ch; - unsigned char byte, bit; - unsigned long colors; - unsigned long fore, back; - - /* Get the index into the font */ - ch = glyph & 0xFF; - if ((glyph & A_ALTCHARSET) != 0 && (glyph & 0xff80) == 0) - ch = acs_map[ch & 0x7f] & 0xff; - - /* Get one byte from the font */ - if ((glyph & A_UNDERLINE) != 0 && line == underline) - byte = 0xFF; - else - byte = getdosmembyte(PDC_state.font_addr + ch*_FONT16 + line); - /* Bit mask for A_LEFT and A_RIGHT */ - if (glyph & A_LEFT) - byte |= 0x80; - if (glyph & A_RIGHT) - byte |= 0x01; - - /* Get the colors */ - colors = _get_colors(glyph); - fore = colors & 0xFFFF; - back = (colors >> 16) & 0xFFFF; - if (PDC_state.bits_per_pixel > 8) - { - fore = PDC_state.colors[fore].mapped; - back = PDC_state.colors[back].mapped; - } - - /* Loop by pixel */ - switch (PDC_state.bits_per_pixel) + /* Get glyph data */ + unsigned long font_addr = glyphs[col].font_addr; + unsigned long fore = glyphs[col].fore; + unsigned long back = glyphs[col].back; + unsigned byte, bit; + + /* Get one byte of the font data */ + byte = getdosmembyte(font_addr + line) | glyphs[col].lr_mask; + if (line == underline) + byte |= glyphs[col].ul_mask; + + /* Render one raster line of the glyph */ + switch (bytes_per_pixel) { - case 8: - for (bit = 0x80; bit != 0; bit >>= 1) - _video_write_byte(addr2++, (byte & bit) ? fore : back); - break; - - case 15: - case 16: + case 1: for (bit = 0x80; bit != 0; bit >>= 1) { - _video_write_word(addr2, (byte & bit) ? fore : back); - addr2 += 2; + unsigned long color = (byte & bit) ? fore : back; + bytes[bindex++] = (unsigned char)color; } break; - case 24: + case 2: for (bit = 0x80; bit != 0; bit >>= 1) { - _video_write_3byte(addr2, (byte & bit) ? fore : back); - addr2 += 3; + unsigned long color = (byte & bit) ? fore : back; + *(unsigned short *)(bytes+bindex) = (unsigned short)color; + bindex += 2; } break; - case 32: + default: + /* In 24 bit color mode, each pass writes one extra byte at + the end, which is overwritten by the next pixel and leaves + an extra unused byte. This will need to change if this + code is ever used on a big endian machine. */ for (bit = 0x80; bit != 0; bit >>= 1) { - _video_write_dword(addr2, (byte & bit) ? fore : back); - addr2 += 4; + unsigned long color = (byte & bit) ? fore : back; + *(unsigned long *)(bytes+bindex) = color; + bindex += bytes_per_pixel; } break; } } - addr += PDC_state.bytes_per_line; + _video_write(cp, bytes, bindex); + cp += PDC_state.bytes_per_line; } } @@ -273,6 +361,13 @@ void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) } else { + while (len > MAX_PACKET) + { + _transform_line_8(lineno, x, MAX_PACKET, srcp); + x += MAX_PACKET; + len -= MAX_PACKET; + srcp += MAX_PACKET; + } _transform_line_8(lineno, x, len, srcp); } @@ -676,6 +771,46 @@ static void _video_write_dword(unsigned long addr, unsigned long dword) } } +static void _video_write(unsigned long addr, const void *data, size_t size) +{ +#ifdef PDC_FLAT + if (PDC_state.linear_sel) + { +#ifdef __DJGPP__ + movedata(_go32_my_ds(), (unsigned)data, + PDC_state.linear_sel, addr, size); +#else /* Watcom */ + _fmemcpy(MK_FP(PDC_state.linear_sel, addr), data, size); +#endif + } + else +#endif + { + unsigned window = PDC_state.window[PDC_state.write_win]; + + while (size != 0) + { + unsigned offset = _set_window(PDC_state.write_win, addr); + unsigned long size2 = PDC_state.window_size - offset; + if (size2 > size) + size2 = size; +#ifdef __DJGPP__ + dosmemput(data, size2, window * 16L + offset); +#elif defined(__WATCOMC__) && defined(__386__) + _fmemcpy((void PDC_FAR *)(window * 16L + offset), data, size2); +#else + if (size2 >= 65532) + size2 = 65532; + + _fmemcpy(MK_FP(window, offset), data, size2); +#endif + addr += size2; + data = (const char *)data + size2; + size -= size2; + } + } +} + static unsigned char _video_read_byte(unsigned long addr) { unsigned char byte; From e6938780600f5b3ee878b0a3e9abba93ca648f70 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Thu, 27 Feb 2020 23:39:08 -0500 Subject: [PATCH 21/26] Use LinBytesPerScanLine for linear frame buffer --- dosvga/pdcscrn.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index 89a83fb5b..7704c68aa 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -493,11 +493,16 @@ static unsigned _find_video_mode(int rows, int cols) { do { /* while (FALSE) */ unsigned win_size; + unsigned width; + + width = (vbe_info.VbeVersion >= 0x300) + ? mode_info.LinBytesPerScanLine + : mode_info.BytesPerScanLine; PDC_state.linear_sel = __dpmi_allocate_ldt_descriptors(1); if (PDC_state.linear_sel < 0) break; - win_size = mode_info.BytesPerScanLine * mode_info.YResolution; + win_size = width * mode_info.YResolution; PDC_state.linear_addr = _map_frame_buffer(mode_info.PhysBasePtr, win_size); if (PDC_state.linear_addr == 0) { @@ -508,6 +513,7 @@ static unsigned _find_video_mode(int rows, int cols) __dpmi_set_segment_base_address(PDC_state.linear_sel, PDC_state.linear_addr); __dpmi_set_segment_limit(PDC_state.linear_sel, (win_size - 1) | 0xFFF); vesa_mode |= 0x4000; + PDC_state.bytes_per_line = width; } while (FALSE); } #else From 556ba5756c353c45992205348449cd979c389036 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Thu, 27 Feb 2020 23:40:07 -0500 Subject: [PATCH 22/26] Simplify cursor rendering Also, draw cursor in reverse video using the foreground color. --- dosvga/pdcdisp.c | 513 +++-------------------------------------------- 1 file changed, 32 insertions(+), 481 deletions(-) diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index 4417c0068..d06c25d41 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -22,31 +22,11 @@ # define MAX_PACKET 32 /* keep stack usage reasonable */ #endif -/* Support cursor on graphics mode */ -static unsigned long bytes_behind[8][16]; -static unsigned char cursor_color = 15; - static unsigned long _get_colors(chtype glyph); static unsigned long _address_4(int row, int col); static unsigned long _address_8(int row, int col); -static void _video_write_byte(unsigned long addr, unsigned char byte); -static void _video_write_word(unsigned long addr, unsigned short word); -static void _video_write_3byte(unsigned long addr, unsigned long byte3); -static void _video_write_dword(unsigned long addr, unsigned long dword); static void _video_write(unsigned long addr, const void *data, size_t size); -static unsigned char _video_read_byte(unsigned long addr); -static unsigned short _video_read_word(unsigned long addr); -static unsigned long _video_read_3byte(unsigned long addr); -static unsigned long _video_read_dword(unsigned long addr); static unsigned _set_window(unsigned window, unsigned long addr); -#if defined(__WATCOMC__) && defined(__386__) -static unsigned char _farpeekb(unsigned seg, unsigned long off); -static unsigned short _farpeekw(unsigned seg, unsigned long off); -static unsigned long _farpeekl(unsigned seg, unsigned long off); -static void _farpokeb(unsigned seg, unsigned long off, unsigned char byte); -static void _farpokew(unsigned seg, unsigned long off, unsigned short word); -static void _farpokel(unsigned seg, unsigned long off, unsigned long dword); -#endif /* position hardware cursor at (y, x) */ @@ -119,6 +99,13 @@ static void _new_packet(unsigned long colors, int lineno, int x, int len, const } if (glyph & A_UNDERLINE) bytes[underline][col] = 0xFF; + if (PDC_state.cursor_visible + && lineno == PDC_state.cursor_row + && col + x == PDC_state.cursor_col) + { + for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) + bytes[line][col] ^= 0xFF; + } } /* Draw the text in four passes, to optimize for the memory architecture @@ -299,6 +286,11 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) byte = getdosmembyte(font_addr + line) | glyphs[col].lr_mask; if (line == underline) byte |= glyphs[col].ul_mask; + if (PDC_state.cursor_visible + && lineno == PDC_state.cursor_row + && col + x == PDC_state.cursor_col + && PDC_state.cursor_start <= line && line <= PDC_state.cursor_end) + byte ^= 0xFF; /* Render one raster line of the glyph */ switch (bytes_per_pixel) @@ -344,17 +336,8 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) { - bool redraw_cursor; - PDC_LOG(("PDC_transform_line() - called: lineno=%d\n", lineno)); - redraw_cursor = PDC_state.cursor_visible - && lineno == PDC_state.cursor_row - && x <= PDC_state.cursor_col - && PDC_state.cursor_col < x + len; - if (redraw_cursor) - PDC_private_cursor_off(); - if (PDC_state.bits_per_pixel == 4) { _transform_line_4(lineno, x, len, srcp); @@ -370,11 +353,6 @@ void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) } _transform_line_8(lineno, x, len, srcp); } - - /* Redraw the cursor if it has been erased */ - if (redraw_cursor) - PDC_private_cursor_on(PDC_state.cursor_row, PDC_state.cursor_col); - } void PDC_doupdate(void) @@ -406,294 +384,39 @@ static unsigned long _get_colors(chtype glyph) return ((unsigned long)back << 16) | fore; } -static void _cursor_off_4(void) -{ - unsigned long addr = _address_4(PDC_state.cursor_row, PDC_state.cursor_col); - unsigned plane; - unsigned line; - - for (plane = 0; plane < 4; plane++) - { - unsigned long p = addr; - outportb(0x03C4, 2); - outportb(0x03C5, 1 << plane); - for (line = 0; line < _FONT16; line++) - { - _video_write_byte(p, bytes_behind[plane][line]); - p += PDC_state.bytes_per_line; - } - } -} - -static void _cursor_off_8(void) -{ - unsigned long addr = _address_8(PDC_state.cursor_row, PDC_state.cursor_col); - unsigned long p; - unsigned line; - unsigned i; - - p = addr; - for (line = 0; line < _FONT16; line++) - { - for (i = 0; i < 8; i++) - _video_write_byte(p + i, bytes_behind[i][line]); - p += PDC_state.bytes_per_line; - } -} - -static void _cursor_off_16(void) -{ - unsigned long addr = _address_8(PDC_state.cursor_row, PDC_state.cursor_col); - unsigned long p; - unsigned line; - unsigned i; - - p = addr; - for (line = 0; line < _FONT16; line++) - { - for (i = 0; i < 8; i++) - _video_write_word(p + i*2, bytes_behind[i][line]); - p += PDC_state.bytes_per_line; - } -} - -static void _cursor_off_24(void) -{ - unsigned long addr = _address_8(PDC_state.cursor_row, PDC_state.cursor_col); - unsigned long p; - unsigned line; - unsigned i; - - p = addr; - for (line = 0; line < _FONT16; line++) - { - for (i = 0; i < 8; i++) - _video_write_3byte(p + i*3, bytes_behind[i][line]); - p += PDC_state.bytes_per_line; - } -} - -static void _cursor_off_32(void) -{ - unsigned long addr = _address_8(PDC_state.cursor_row, PDC_state.cursor_col); - unsigned long p; - unsigned line; - unsigned i; - - p = addr; - for (line = 0; line < _FONT16; line++) - { - for (i = 0; i < 8; i++) - _video_write_dword(p + i*4, bytes_behind[i][line]); - p += PDC_state.bytes_per_line; - } -} - void PDC_private_cursor_off(void) { - if (PDC_state.cursor_visible && PDC_state.cursor_row < (unsigned)LINES - && PDC_state.cursor_col < (unsigned)COLS) - { - switch (PDC_state.bits_per_pixel) - { - case 4: - _cursor_off_4(); - break; - - case 8: - _cursor_off_8(); - break; - - case 15: - case 16: - _cursor_off_16(); - break; - - case 24: - _cursor_off_24(); - break; - - case 32: - _cursor_off_32(); - break; - } - } - PDC_state.cursor_visible = FALSE; -} - -void _cursor_on_4(int row, int col) -{ - unsigned long addr = _address_4(row, col); - unsigned long p; - unsigned plane; - unsigned line; - - for (plane = 0; plane < 4; ++plane) - { - p = addr; - outportb(0x03CE, 4); - outportb(0x03CF, plane); - for (line = 0; line < _FONT16; ++line) - { - bytes_behind[plane][line] = _video_read_byte(p); - p += PDC_state.bytes_per_line; - } - } - outportb(0x03C5, 2); - outportb(0x03C5, cursor_color); - p = addr + PDC_state.cursor_start * PDC_state.bytes_per_line; - for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) - { - _video_write_byte(p, 0xFF); - p += PDC_state.bytes_per_line; - } - outportb(0x03C5, 2); - outportb(0x03C5, ~cursor_color); - p = addr + PDC_state.cursor_start * PDC_state.bytes_per_line; - for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) - { - _video_write_byte(p, 0x00); - p += PDC_state.bytes_per_line; - } - outportb(0x03C5, 2); - outportb(0x03C5, 0xF); -} - -void _cursor_on_8(int row, int col) -{ - unsigned long addr = _address_8(row, col); - unsigned long p; - unsigned line; - unsigned i; - - /* Save the bytes currently in the character cell */ - p = addr; - for (line = 0; line < _FONT16; line++) - { - for (i = 0; i < 8; i++) - bytes_behind[i][line] = _video_read_byte(p + i); - p += PDC_state.bytes_per_line; - } + /* This gets called before atrtab is set up; avoid a null dereference */ + if (!SP || !SP->atrtab) + return; - /* Write the cursor */ - p = addr + PDC_state.cursor_start * PDC_state.bytes_per_line; - for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) - { - for (i = 0; i < 8; i++) - _video_write_byte(p + i, cursor_color); - p += PDC_state.bytes_per_line; - } -} - -void _cursor_on_16(int row, int col) -{ - unsigned long addr = _address_8(row, col); - unsigned long p; - unsigned line; - unsigned i; - unsigned short color = PDC_state.colors[cursor_color].mapped; - - /* Save the bytes currently in the character cell */ - p = addr; - for (line = 0; line < _FONT16; line++) - { - for (i = 0; i < 8; i++) - bytes_behind[i][line] = _video_read_word(p + i*2); - p += PDC_state.bytes_per_line; - } - - /* Write the cursor */ - p = addr + PDC_state.cursor_start * PDC_state.bytes_per_line; - for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) - { - for (i = 0; i < 8; i++) - _video_write_word(p + i*2, color); - p += PDC_state.bytes_per_line; - } -} - -void _cursor_on_24(int row, int col) -{ - unsigned long addr = _address_8(row, col); - unsigned long p; - unsigned line; - unsigned i; - unsigned long color = PDC_state.colors[cursor_color].mapped; - - /* Save the bytes currently in the character cell */ - p = addr; - for (line = 0; line < _FONT16; line++) - { - for (i = 0; i < 8; i++) - bytes_behind[i][line] = _video_read_3byte(p + i*3); - p += PDC_state.bytes_per_line; - } - - /* Write the cursor */ - p = addr + PDC_state.cursor_start * PDC_state.bytes_per_line; - for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) - { - for (i = 0; i < 8; i++) - _video_write_3byte(p + i*3, color); - p += PDC_state.bytes_per_line; - } -} - -void _cursor_on_32(int row, int col) -{ - unsigned long addr = _address_8(row, col); - unsigned long p; - unsigned line; - unsigned i; - unsigned long color = PDC_state.colors[cursor_color].mapped; - - /* Save the bytes currently in the character cell */ - p = addr; - for (line = 0; line < _FONT16; line++) + PDC_state.cursor_visible = FALSE; + if (PDC_state.cursor_row < (unsigned)LINES + && PDC_state.cursor_col < (unsigned)COLS) { - for (i = 0; i < 8; i++) - bytes_behind[i][line] = _video_read_dword(p + i*4); - p += PDC_state.bytes_per_line; - } + static const chtype space = ' '; - /* Write the cursor */ - p = addr + PDC_state.cursor_start * PDC_state.bytes_per_line; - for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) - { - for (i = 0; i < 8; i++) - _video_write_dword(p + i*4, color); - p += PDC_state.bytes_per_line; + PDC_transform_line(PDC_state.cursor_row, PDC_state.cursor_col, 1, + (curscr && curscr->_y) + ? &curscr->_y[PDC_state.cursor_row][PDC_state.cursor_col] + : &space); } } void PDC_private_cursor_on(int row, int col) { - switch (PDC_state.bits_per_pixel) - { - case 4: - _cursor_on_4(row, col); - break; - - case 8: - _cursor_on_8(row, col); - break; - - case 15: - case 16: - _cursor_on_16(row, col); - break; - - case 24: - _cursor_on_24(row, col); - break; - - case 32: - _cursor_on_32(row, col); - break; - } PDC_state.cursor_visible = TRUE; PDC_state.cursor_row = row; PDC_state.cursor_col = col; + if (row < (unsigned)LINES && col < (unsigned)COLS) + { + static const chtype space = ' '; + + PDC_transform_line(PDC_state.cursor_row, PDC_state.cursor_col, 1, + (curscr && curscr->_y) + ? &curscr->_y[PDC_state.cursor_row][PDC_state.cursor_col] + : &space); + } } static unsigned long _address_4(int row, int col) @@ -707,70 +430,6 @@ static unsigned long _address_8(int row, int col) + col * 8 * ((PDC_state.bits_per_pixel + 7)/8); } -static void _video_write_byte(unsigned long addr, unsigned char byte) -{ -#ifdef PDC_FLAT - if (PDC_state.linear_sel) - { - _farpokeb(PDC_state.linear_sel, addr, byte); - } - else -#endif - { - unsigned offset = _set_window(PDC_state.write_win, addr); - unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); - setdosmembyte(addr2, byte); - } -} - -static void _video_write_word(unsigned long addr, unsigned short word) -{ -#ifdef PDC_FLAT - if (PDC_state.linear_sel) - { - _farpokew(PDC_state.linear_sel, addr, word); - } - else -#endif - { - unsigned offset = _set_window(PDC_state.write_win, addr); - unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); - setdosmemword(addr2, word); - } -} - -static void _video_write_3byte(unsigned long addr, unsigned long byte3) -{ - /* Write a byte and a word. Split the write so that the word lies at an - * even address, so it does not cross a window boundary */ - if (addr & 1) - { - _video_write_byte(addr + 0, byte3 & 0xFF); - _video_write_word(addr + 1, byte3 >> 8); - } - else - { - _video_write_word(addr + 0, byte3 & 0xFFFF); - _video_write_byte(addr + 2, byte3 >> 16); - } -} - -static void _video_write_dword(unsigned long addr, unsigned long dword) -{ -#ifdef PDC_FLAT - if (PDC_state.linear_sel) - { - _farpokel(PDC_state.linear_sel, addr, dword); - } - else -#endif - { - unsigned offset = _set_window(PDC_state.write_win, addr); - unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.write_win], offset); - setdosmemdword(addr2, dword); - } -} - static void _video_write(unsigned long addr, const void *data, size_t size) { #ifdef PDC_FLAT @@ -811,81 +470,6 @@ static void _video_write(unsigned long addr, const void *data, size_t size) } } -static unsigned char _video_read_byte(unsigned long addr) -{ - unsigned char byte; - -#ifdef PDC_FLAT - if (PDC_state.linear_sel) - { - byte = _farpeekb(PDC_state.linear_sel, addr); - } - else -#endif - { - unsigned offset = _set_window(PDC_state.read_win, addr); - unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); - byte = getdosmembyte(addr2); - } - return byte; -} - -static unsigned short _video_read_word(unsigned long addr) -{ - unsigned short word; - -#ifdef PDC_FLAT - if (PDC_state.linear_sel) - { - word = _farpeekw(PDC_state.linear_sel, addr); - } - else -#endif - { - unsigned offset = _set_window(PDC_state.read_win, addr); - unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); - word = getdosmemword(addr2); - } - return word; -} - -static unsigned long _video_read_3byte(unsigned long addr) -{ - /* Read a byte and a word. Split the read so that the word lies at an - * even address, so it does not cross a window boundary */ - unsigned long byte3; - if (addr & 1) - { - byte3 = _video_read_byte(addr + 0); - byte3 += (unsigned long)_video_read_word(addr + 1) << 8; - } - else - { - byte3 = _video_read_word(addr + 0); - byte3 += (unsigned long)_video_read_byte(addr + 2) << 16; - } - return byte3; -} - -static unsigned long _video_read_dword(unsigned long addr) -{ - unsigned long dword; - -#ifdef PDC_FLAT - if (PDC_state.linear_sel) - { - dword = _farpeekl(PDC_state.linear_sel, addr); - } - else -#endif - { - unsigned offset = _set_window(PDC_state.read_win, addr); - unsigned long addr2 = (unsigned long)_FAR_POINTER(PDC_state.window[PDC_state.read_win], offset); - dword = getdosmemdword(addr2); - } - return dword; -} - static unsigned _set_window(unsigned window, unsigned long addr) { unsigned long offset = PDC_state.offset[window]; @@ -906,36 +490,3 @@ static unsigned _set_window(unsigned window, unsigned long addr) return addr - offset; } - -#if defined(__WATCOMC__) && defined(__386__) -/* Far peek and poke, as defined for DJGPP, made available for Watcom */ -static unsigned char _farpeekb(unsigned seg, unsigned long off) -{ - return *(unsigned char __far *)MK_FP(seg, off); -} - -static unsigned short _farpeekw(unsigned seg, unsigned long off) -{ - return *(unsigned short __far *)MK_FP(seg, off); -} - -static unsigned long _farpeekl(unsigned seg, unsigned long off) -{ - return *(unsigned long __far *)MK_FP(seg, off); -} - -static void _farpokeb(unsigned seg, unsigned long off, unsigned char byte) -{ - *(unsigned char __far *)MK_FP(seg, off) = byte; -} - -static void _farpokew(unsigned seg, unsigned long off, unsigned short word) -{ - *(unsigned short __far *)MK_FP(seg, off) = word; -} - -static void _farpokel(unsigned seg, unsigned long off, unsigned long dword) -{ - *(unsigned long __far *)MK_FP(seg, off) = dword; -} -#endif From e9f10e4a77a97aa444ef87ce29e2140e825d2e0c Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 1 Mar 2020 12:19:24 -0500 Subject: [PATCH 23/26] Add support for external PSF font --- dosvga/Makefile | 6 +- dosvga/Makefile.bcc | 10 +- dosvga/Makefile.wcc | 6 +- dosvga/README.md | 11 + dosvga/cp437.h | 184 ++++++++++++ dosvga/pdcdisp.c | 58 ++-- dosvga/pdcdos.h | 31 +- dosvga/pdcgetsc.c | 8 +- dosvga/pdckbd.c | 8 +- dosvga/pdcscrn.c | 693 ++++++++++++++++++++++++++++++++++++++++++-- dosvga/pdcsetsc.c | 2 +- 11 files changed, 935 insertions(+), 82 deletions(-) create mode 100644 dosvga/cp437.h diff --git a/dosvga/Makefile b/dosvga/Makefile index b3a34dda5..8f82cbcbc 100644 --- a/dosvga/Makefile +++ b/dosvga/Makefile @@ -1,6 +1,6 @@ # GNU Makefile for PDCurses - DOS # -# Usage: make [-f path\Makefile] [DEBUG=Y] [target] +# Usage: make [-f path\Makefile] [DEBUG=Y] [WIDE=Y] [target] # # where target can be any of: # [all|libs|demos|pdcurses.a|testcurs.exe...] @@ -31,6 +31,10 @@ endif CFLAGS += -I$(PDCURSES_SRCDIR) +ifeq ($(WIDE),Y) + CFLAGS += -DPDC_WIDE +endif + LINK = gcc LIBEXE = ar diff --git a/dosvga/Makefile.bcc b/dosvga/Makefile.bcc index 8c923b302..4cc3a8ce9 100644 --- a/dosvga/Makefile.bcc +++ b/dosvga/Makefile.bcc @@ -1,6 +1,6 @@ # Borland Makefile for PDCurses - DOS # -# Usage: make -f [path\]Makefile.bcc [DEBUG=] [MODEL=c|h|l|m|s] [target] +# Usage: make -f [path\]Makefile.bcc [DEBUG=] [WIDE=Y] [MODEL=c|h|l|m|s] [target] # # where target can be any of: # [all|demos|pdcurses.lib|testcurs.exe...] @@ -27,9 +27,15 @@ CFLAGS = -N -v -y -DPDCDEBUG CFLAGS = -O !endif +!ifdef WIDE +WIDEOPT = -DPDC_WIDE +!else +WIDEOPT = +!endif + CPPFLAGS = -I$(PDCURSES_SRCDIR) -BUILD = $(CC) -1- -G -d -w-par -c -m$(MODEL) $(CFLAGS) $(CPPFLAGS) +BUILD = $(CC) -1- -G -d -w-par -c -m$(MODEL) $(CFLAGS) $(CPPFLAGS) $(WIDEOPT) LIBEXE = tlib /C /E diff --git a/dosvga/Makefile.wcc b/dosvga/Makefile.wcc index ac00efee1..569d052e5 100644 --- a/dosvga/Makefile.wcc +++ b/dosvga/Makefile.wcc @@ -1,6 +1,6 @@ # Watcom Makefile for PDCurses - DOS # -# Usage: wmake -f [path\]Makefile.wcc [DEBUG=Y] [MODEL=c|h|l|m|s|f] [target] +# Usage: wmake -f [path\]Makefile.wcc [DEBUG=Y] [WIDE=Y] [MODEL=c|h|l|m|s|f] [target] # # where target can be any of: # [all|demos|pdcurses.lib|testcurs.exe...] @@ -27,6 +27,10 @@ TARGET = dos CFLAGS = -bt=$(TARGET) -m$(MODEL) +!ifeq WIDE Y +CFLAGS += -DPDC_WIDE +!endif + !include $(PDCURSES_SRCDIR)/common/watcom.mif $(LIBCURSES) : $(LIBOBJS) $(PDCOBJS) diff --git a/dosvga/README.md b/dosvga/README.md index 738efacb6..5ff3573ab 100644 --- a/dosvga/README.md +++ b/dosvga/README.md @@ -33,6 +33,17 @@ Building (pdcurses.lib or .a, depending on your compiler) and a lot of object files. Add the target "demos" to build the sample programs. + You can also give the optional parameter "WIDE=Y", to build the + library with wide-character (Unicode) support: + + wmake -f Makefile.wcc WIDE=Y + + (WIDE=Y is untested on the Borland compiler.) + +The font can be set via the environment variable PDC_FONT. The font must +be in the PSF format, version 2. At present, the width must be 8 and the +height cannot exceed 16; this restriction will eventually be lifted. + Distribution Status ------------------- diff --git a/dosvga/cp437.h b/dosvga/cp437.h new file mode 100644 index 000000000..9e3938c20 --- /dev/null +++ b/dosvga/cp437.h @@ -0,0 +1,184 @@ + +static const unsigned short cp437_to_unicode[256] = { + 0, + 0x263a, /* 1 smiling face */ + 0x263b, /* 2 smiling face inverted */ + 0x2665, /* 3 heart */ + 0x2666, /* 4 diamond */ + 0x2663, /* 5 club */ + 0x2660, /* 6 spade */ + 0x2024, /* 7 small bullet */ + 0x25d8, /* 8 inverted bullet */ + 0x25bc, /* 9 hollow bullet */ + 0x25d9, /* 10 inverted hollow bullet */ + 0x2642, /* 11 male/Mars symbol */ + 0x2640, /* 12 female/Venus symbol */ + 0x266a, /* 13 eighth note */ + 0x266c, /* 14 two sixteenth notes */ + 0x263c, /* 15 splat */ + 0x25b6, /* 16 right-pointing triangle */ + 0x25c0, /* 17 left-pointing triangle */ + 0x2195, /* 18 double up/down arrow */ + 0x203c, /* 19 double exclamation !! */ + 0x00b6, /* 20 pilcrow */ + 0xa7, /* 21 */ + 0x2582, /* 22 lower 1/3 block */ + 0x280d, /* 23 double up/down arrow */ + 0x2191, /* 24 up arrow */ + 0x2193, /* 25 down arrow */ + 0x2192, /* 26 right arrow */ + 0x2190, /* 27 left arrow */ + 0x2319, /* 28 */ + 0x280c, /* 29 left & right arrow */ + 0x25b2, /* 30 up triangle */ + 0x25bc, /* 31 down triangle */ + + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, + + 0x2302, /* 127 */ + 0x00c7, /* 128 */ + 0x00fc, /* 129 */ + 0x00e9, /* 130 */ + 0x00e2, /* 131 */ + 0x00e4, /* 132 */ + 0x00e0, /* 133 */ + 0x00e5, /* 134 */ + 0x00e7, /* 135 */ + 0x00ea, /* 136 */ + 0x00eb, /* 137 */ + 0x00e8, /* 138 */ + 0x00ef, /* 139 */ + 0x00ee, /* 140 */ + 0x00ec, /* 141 */ + 0x00c4, /* 142 */ + 0x00c5, /* 143 */ + + 0x00c9, /* 144 */ + 0x00e6, /* 145 */ + 0x00c6, /* 146 */ + 0x00f4, /* 147 */ + 0x00f5, /* 148 */ + 0x00f2, /* 149 */ + 0x00fb, /* 150 */ + 0x00f9, /* 151 */ + 0x00ff, /* 152 */ + 0x00d6, /* 153 */ + 0x00dc, /* 154 */ + 0x00a2, /* 155 */ + 0x00a3, /* 156 */ + 0x00a5, /* 157 */ + 0x20a7, /* 158 */ + 0x0192, /* 159 */ + + 0x00e1, /* 160 */ + 0x00ed, /* 161 */ + 0x00f3, /* 162 */ + 0x00fa, /* 163 */ + 0x00f1, /* 164 */ + 0x00d1, /* 165 */ + 0x00aa, /* 166 */ + 0x00ba, /* 167 */ + 0x00bf, /* 168 */ + 0x2310, /* 169 */ + 0x00ac, /* 170 */ + 0x00bd, /* 171 */ + 0x00bc, /* 172 */ + 0x00a1, /* 173 */ + 0x00ab, /* 174 */ + 0x00bb, /* 175 */ + + 0x2591, /* 176 */ + 0x2592, /* 177 */ + 0x2593, /* 178 */ + 0x2502, /* 179 */ + 0x2524, /* 180 */ + 0x2561, /* 181 */ + 0x2562, /* 182 */ + 0x2556, /* 183 */ + 0x2555, /* 184 */ + 0x2563, /* 185 */ + 0x2561, /* 186 */ + 0x2557, /* 187 */ + 0x255d, /* 188 */ + 0x255c, /* 189 */ + 0x255b, /* 190 */ + 0x2510, /* 191 */ + + 0x2514, /* 192 */ + 0x2534, /* 193 */ + 0x252c, /* 194 */ + 0x251c, /* 195 */ + 0x2500, /* 196 */ + 0x253c, /* 197 */ + 0x255e, /* 198 */ + 0x255f, /* 199 */ + 0x255a, /* 200 */ + 0x2554, /* 201 */ + 0x2569, /* 202 */ + 0x2568, /* 203 */ + 0x2560, /* 204 */ + 0x2550, /* 205 */ + 0x256c, /* 206 */ + 0x2567, /* 207 */ + + 0x2568, /* 208 */ + 0x2564, /* 209 */ + 0x2565, /* 210 */ + 0x2559, /* 211 */ + 0x2558, /* 212 */ + 0x2552, /* 213 */ + 0x2553, /* 214 */ + 0x256b, /* 215 */ + 0x256a, /* 216 */ + 0x2518, /* 217 */ + 0x250c, /* 218 */ + 0x2588, /* 219 */ + 0x2584, /* 220 */ + 0x258c, /* 221 */ + 0x2590, /* 222 */ + 0x2580, /* 223 */ + + 0x03b1, /* 224 */ + 0x00df, /* 225 */ + 0x0393, /* 226 */ + 0x03c0, /* 227 */ + 0x03a3, /* 228 */ + 0x03c3, /* 229 */ + 0x00b5, /* 230 */ + 0x03c4, /* 231 */ + 0x03a6, /* 232 */ + 0x0398, /* 233 */ + 0x03a9, /* 234 */ + 0x03b4, /* 235 */ + 0x221e, /* 236 */ + 0x036c, /* 237 */ + 0x03b5, /* 238 */ + 0x2229, /* 239 */ + + 0x2261, /* 240 */ + 0x00b1, /* 241 */ + 0x2265, /* 242 */ + 0x2264, /* 243 */ + 0x2320, /* 244 */ + 0x2321, /* 245 */ + 0x00f7, /* 246 */ + 0x2248, /* 247 */ + 0x00b0, /* 248 */ + 0x2219, /* 249 */ + 0x00b7, /* 250 */ + 0x221a, /* 251 */ + 0x207f, /* 252 */ + 0x00b2, /* 253 */ + 0x25a0, /* 254 */ + 0x00a0 }; /* 255 */ diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index d06c25d41..96a4dd82c 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -1,7 +1,11 @@ /* PDCurses */ #include "pdcdos.h" -#include "../common/acs437.h" +#ifdef PDC_WIDE +# include "../common/acsuni.h" +#else +# include "../common/acs437.h" +#endif #ifdef __DJGPP__ #include @@ -55,7 +59,7 @@ static void _new_packet(unsigned long colors, int lineno, int x, int len, const back = (colors >> 16) & 0xF; /* Underline will go here if requested */ - underline = 13 /*_FONT16*/; + underline = 13 /*PDC_state.font_height*/; /* Render to the bytes array and then copy to the frame buffer */ /* Loop by column */ @@ -63,26 +67,16 @@ static void _new_packet(unsigned long colors, int lineno, int x, int len, const { chtype glyph = srcp[col]; int ch; - unsigned long font_addr; -#ifdef __DJGPP__ - unsigned char font_data[16]; -#else - unsigned char PDC_FAR *font_data; -#endif + const unsigned char PDC_FAR *font_data; unsigned char lr_mask; /* Get the index into the font */ - ch = glyph & 0xFF; + ch = glyph & 0xFFFF; if ((glyph & A_ALTCHARSET) != 0 && (glyph & 0xff80) == 0) - ch = acs_map[ch & 0x7f] & 0xff; - font_addr = PDC_state.font_addr + ch*_FONT16; + ch = acs_map[ch & 0x7f]; /* Get the font data */ -#ifdef __DJGPP__ - dosmemget(font_addr, _FONT16, font_data); -#else - font_data = (unsigned char PDC_FAR *)font_addr; -#endif + font_data = PDC_state.font_glyph_data(FALSE, ch); /* Set pixels for A_LEFT and A_RIGHT */ lr_mask = 0x00; @@ -92,7 +86,7 @@ static void _new_packet(unsigned long colors, int lineno, int x, int len, const lr_mask |= 0x01; /* Copy font data into the bytes array */ - for (line = 0; line < _FONT16; line++) + for (line = 0; line < PDC_state.font_height; line++) { unsigned char byte = font_data[line]; bytes[line][col] = byte | lr_mask; @@ -118,7 +112,7 @@ static void _new_packet(unsigned long colors, int lineno, int x, int len, const outportb(0x3c4, 2); outportb(0x3c5, vplane); cp = addr; - for (line = 0; line < _FONT16; line++) + for (line = 0; line < PDC_state.font_height; line++) { _video_write(cp, bytes[line], len); cp += PDC_state.bytes_per_line; @@ -132,7 +126,7 @@ static void _new_packet(unsigned long colors, int lineno, int x, int len, const outportb(0x3c4, 2); outportb(0x3c5, vplane); cp = addr; - for (line = 0; line < _FONT16; line++) + for (line = 0; line < PDC_state.font_height; line++) { for (col = 0; col < len; col++) bytes[line][col] ^= 0xFF; @@ -149,7 +143,7 @@ static void _new_packet(unsigned long colors, int lineno, int x, int len, const outportb(0x3c5, vplane); cp = addr; memset(bytes[0], 0x00, len); - for (line = 0; line < _FONT16; line++) + for (line = 0; line < PDC_state.font_height; line++) { _video_write(cp, bytes[0], len); cp += PDC_state.bytes_per_line; @@ -164,7 +158,7 @@ static void _new_packet(unsigned long colors, int lineno, int x, int len, const outportb(0x3c5, vplane); cp = addr; memset(bytes[0], 0xFF, len); - for (line = 0; line < _FONT16; line++) + for (line = 0; line < PDC_state.font_height; line++) { _video_write(cp, bytes[0], len); cp += PDC_state.bytes_per_line; @@ -214,7 +208,7 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) struct { - unsigned long font_addr; + const unsigned char PDC_FAR *font_addr; unsigned char lr_mask; unsigned char ul_mask; unsigned long fore; @@ -226,7 +220,7 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) unsigned underline; /* Underline will go here if requested */ - underline = 13 /*_FONT16*/; + underline = 13 /*PDC_state.font_height*/; /* Compute basic glyph data only once per character */ for (col = 0; col < len; col++) @@ -236,12 +230,12 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) unsigned long colors, fore, back; /* Get the index into the font */ - ch = glyph & 0xFF; + ch = glyph & 0xFFFF; if ((glyph & A_ALTCHARSET) != 0 && (glyph & 0xff80) == 0) - ch = acs_map[ch & 0x7f] & 0xff; + ch = acs_map[ch & 0x7f]; /* Get the address of the font data */ - glyphs[col].font_addr = PDC_state.font_addr + ch*_FONT16; + glyphs[col].font_addr = PDC_state.font_glyph_data(FALSE, ch); /* Bit mask for underline */ glyphs[col].ul_mask = (glyph & A_UNDERLINE) ? 0xFF : 0x00; @@ -268,7 +262,7 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) /* Loop by raster line */ cp = addr; - for (line = 0; line < _FONT16; line++) + for (line = 0; line < PDC_state.font_height; line++) { unsigned bindex; @@ -277,13 +271,13 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) for (col = 0; col < len; col++) { /* Get glyph data */ - unsigned long font_addr = glyphs[col].font_addr; + const unsigned char PDC_FAR *font_addr = glyphs[col].font_addr; unsigned long fore = glyphs[col].fore; unsigned long back = glyphs[col].back; unsigned byte, bit; /* Get one byte of the font data */ - byte = getdosmembyte(font_addr + line) | glyphs[col].lr_mask; + byte = font_addr[line] | glyphs[col].lr_mask; if (line == underline) byte |= glyphs[col].ul_mask; if (PDC_state.cursor_visible @@ -421,13 +415,13 @@ void PDC_private_cursor_on(int row, int col) static unsigned long _address_4(int row, int col) { - return (unsigned long)row * PDC_state.bytes_per_line * _FONT16 + col; + return (unsigned long)row * PDC_state.bytes_per_line * PDC_state.font_height + col; } static unsigned long _address_8(int row, int col) { - return (unsigned long)row * PDC_state.bytes_per_line * _FONT16 - + col * 8 * ((PDC_state.bits_per_pixel + 7)/8); + return (unsigned long)row * PDC_state.bytes_per_line * PDC_state.font_height + + col * PDC_state.font_width * ((PDC_state.bits_per_pixel + 7)/8); } static void _video_write(unsigned long addr, const void *data, size_t size) diff --git a/dosvga/pdcdos.h b/dosvga/pdcdos.h index ed7d3b9ba..94cc2be90 100644 --- a/dosvga/pdcdos.h +++ b/dosvga/pdcdos.h @@ -36,6 +36,12 @@ #include +# if SMALL || MEDIUM +# define PDC_FAR far +# else +# define PDC_FAR +# endif + /* Information about the current video state */ struct PDC_color { @@ -69,7 +75,15 @@ struct PDC_video_state unsigned char blue_max; unsigned char blue_pos; - unsigned long font_addr; /* Address of font in ROM */ + /* Font support */ + void (*font_close)(bool bold); + unsigned (*font_char_width)(bool bold); + unsigned (*font_char_height)(bool bold); + const unsigned char PDC_FAR *(*font_glyph_data)(bool bold, unsigned long pos); + + bool have_bold_font; + unsigned font_width; /* Width of font in pixels */ + unsigned font_height; /* Height of font in pixels */ /* Cursor state */ bool cursor_visible; @@ -117,11 +131,6 @@ void setdosmembyte(int offs, unsigned char b); void setdosmemword(int offs, unsigned short w); void setdosmemdword(int offs, unsigned long d); #else -# if SMALL || MEDIUM -# define PDC_FAR far -# else -# define PDC_FAR -# endif # define getdosmembyte(offs) \ (*((unsigned char PDC_FAR *) (offs))) # define getdosmemword(offs) \ @@ -201,13 +210,3 @@ enum _MCGACOLOR = 0x0a, _MCGAMONO, _MDS_GENIUS = 0x30 }; - -/* Text-mode font size information */ - -enum -{ - _FONT8 = 8, - _FONT14 = 14, - _FONT15, /* GENIUS */ - _FONT16 -}; diff --git a/dosvga/pdcgetsc.c b/dosvga/pdcgetsc.c index 86b7cab24..ef6694857 100644 --- a/dosvga/pdcgetsc.c +++ b/dosvga/pdcgetsc.c @@ -12,7 +12,7 @@ int PDC_get_columns(void) PDC_LOG(("PDC_get_columns() - called\n")); - cols = PDC_state.video_width / 8; + cols = PDC_state.video_width / PDC_state.font_width; PDC_LOG(("PDC_get_columns() - returned: cols %d\n", cols)); @@ -23,8 +23,8 @@ int PDC_get_columns(void) int PDC_get_cursor_mode(void) { - int start = _FONT16*3/4; - int end = _FONT16-1; + int start = PDC_state.font_height * 3 / 4; + int end = PDC_state.font_height - 1; PDC_LOG(("PDC_get_cursor_mode() - called\n")); @@ -39,7 +39,7 @@ int PDC_get_rows(void) PDC_LOG(("PDC_get_rows() - called\n")); - rows = PDC_state.video_height / _FONT16; + rows = PDC_state.video_height / PDC_state.font_height; PDC_LOG(("PDC_get_rows() - returned: rows %d\n", rows)); diff --git a/dosvga/pdckbd.c b/dosvga/pdckbd.c index 32ab22458..40202bc37 100644 --- a/dosvga/pdckbd.c +++ b/dosvga/pdckbd.c @@ -160,8 +160,8 @@ bool PDC_check_key(void) mouse_moved = !mouse_button && ms_regs.h.bl && ms_regs.h.bl == old_ms.h.bl && - (((ms_regs.W.cx ^ old_ms.W.cx) >> 3) || - ((ms_regs.W.dx / _FONT16) ^ (old_ms.W.dx / _FONT16))); + (((ms_regs.W.cx / PDC_state.font_width) ^ (old_ms.W.cx / PDC_state.font_width)) || + ((ms_regs.W.dx / PDC_state.font_height) ^ (old_ms.W.dx / PDC_state.font_height))); if (mouse_scroll || mouse_button || mouse_moved) return TRUE; @@ -270,8 +270,8 @@ static int _process_mouse_events(void) } } - SP->mouse_status.x = ms_regs.W.cx >> 3; - SP->mouse_status.y = ms_regs.W.dx / _FONT16; + SP->mouse_status.x = ms_regs.W.cx / PDC_state.font_width; + SP->mouse_status.y = ms_regs.W.dx / PDC_state.font_height; old_ms = ms_regs; diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index 7704c68aa..8806a1244 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -33,18 +33,8 @@ static int __dpmi_set_segment_limit(int sel, unsigned long limit); static void dosmemget(unsigned long addr, size_t size, void *buf); static void dosmemput(const void *buf, size_t size, unsigned long addr); #endif - -/* _get_font_address() -- return the address of the font in ROM */ -static unsigned long _get_font_address(void) -{ -#ifdef PDC_FLAT - unsigned ofs = getdosmemword(0x43 * 4 + 0); - unsigned seg = getdosmemword(0x43 * 4 + 2); - return _FAR_POINTER(seg, ofs); -#else - return getdosmemdword(0x43 * 4); -#endif -} +static int _psf_font_open(const char *name, bool bold); +static int _vgafont_open(void); /* _get_scrn_mode() - Return the current BIOS video mode */ @@ -82,7 +72,6 @@ static void _set_scrn_mode(int new_mode) PDCINT(0x10, regs); PDC_state.scrn_mode = new_mode; - PDC_state.font_addr = _get_font_address(); LINES = PDC_get_rows(); COLS = PDC_get_columns(); } @@ -92,22 +81,21 @@ static void _set_scrn_mode(int new_mode) void PDC_scr_close(void) { - PDCREGS regs; - #ifdef PDC_FLAT _unmap_frame_buffer(PDC_state.linear_addr); __dpmi_free_ldt_descriptor(PDC_state.linear_sel); #endif _set_scrn_mode(0x03); - memset(®s, 0, sizeof(regs)); - regs.W.ax = 0x1114; - regs.h.bl = 0x00; - PDCINT(0x10, regs); } void PDC_scr_free(void) { + if (PDC_state.font_close != NULL) + { + PDC_state.font_close(FALSE); + PDC_state.font_close(TRUE); + } } /* open the physical screen -- miscellaneous initialization, may save @@ -115,6 +103,7 @@ void PDC_scr_free(void) int PDC_scr_open(void) { + const char *normal_font, *bold_font; PDCREGS regs; PDC_LOG(("PDC_scr_open() - called\n")); @@ -132,6 +121,35 @@ int PDC_scr_open(void) return ERR; _init_palette(); + + /* Set up fonts: + * * first try PDC_FONT and PDC_FONT_BOLD + * * Fall back to the ROM font if PDC_FONT is not specified + * * Width must be 8; height must be not greater than 16; the bold font, if + * specified, must have the same size as the normal font + */ + normal_font = getenv("PDC_FONT"); + bold_font = getenv("PDC_FONT_BOLD"); + if (normal_font != NULL && normal_font[0] != '\0') + { + if (_psf_font_open(normal_font, FALSE) == 0) + { + /* Opened the normal font; try the bold font */ + if (_psf_font_open(bold_font, TRUE) == 0 + && PDC_state.font_char_width(FALSE) == PDC_state.font_char_width(TRUE) + && PDC_state.font_char_height(FALSE) == PDC_state.font_char_height(TRUE)) + PDC_state.have_bold_font = TRUE; + } + } + if (PDC_state.font_glyph_data == NULL) + { + if (_vgafont_open() < 0) + return ERR; + PDC_state.have_bold_font = FALSE; + } + PDC_state.font_width = PDC_state.font_char_width(FALSE); + PDC_state.font_height = PDC_state.font_char_height(FALSE); + PDC_resize_screen(25, 80); SP->orig_attr = FALSE; @@ -702,8 +720,8 @@ static unsigned _find_mode( } /* At least as many rows and columns as requested */ - new_cols = mode_info0.XResolution / 8; - new_rows = mode_info0.YResolution / _FONT16; + new_cols = mode_info0.XResolution / PDC_state.font_width; + new_rows = mode_info0.YResolution / PDC_state.font_height; if (new_cols < cols || new_rows < rows) continue; @@ -1061,3 +1079,636 @@ static void dosmemput(const void *buf, size_t size, unsigned long addr) memcpy((void *)addr, buf, size); } #endif + +/***************************************************************************** +* Support for a built-in 16 line font * +*****************************************************************************/ + +static void _vgafont_close(bool bold); +static unsigned _vgafont_char_width(bool bold); +static unsigned _vgafont_char_height(bool bold); +static const unsigned char *_vgafont_glyph_data(bool bold, unsigned long pos); +#ifdef __DJGPP__ +static unsigned char font437[4096]; +#else +static unsigned char PDC_FAR *font437; +#endif + +#ifdef PDC_WIDE +/* This maps Unicode to CP437 */ + +static const struct +{ + unsigned short uni; + unsigned char pos; +} cp437_map[] = +{ + /* Regular mappings */ + { 0x0000, 0x00 }, + { 0x263A, 0x01 }, + { 0x263B, 0x02 }, + { 0x2665, 0x03 }, + { 0x2666, 0x04 }, + { 0x2663, 0x05 }, + { 0x2660, 0x06 }, + { 0x2022, 0x07 }, + { 0x25D8, 0x08 }, + { 0x25CB, 0x09 }, + { 0x25D9, 0x0A }, + { 0x2642, 0x0B }, + { 0x2640, 0x0C }, + { 0x266A, 0x0D }, + { 0x266B, 0x0E }, + { 0x263C, 0x0F }, + { 0x25BA, 0x10 }, + { 0x25C4, 0x11 }, + { 0x2195, 0x12 }, + { 0x203C, 0x13 }, + { 0x00B6, 0x14 }, + { 0x00A7, 0x15 }, + { 0x25AC, 0x16 }, + { 0x21A8, 0x17 }, + { 0x2191, 0x18 }, + { 0x2193, 0x19 }, + { 0x2192, 0x1A }, + { 0x2190, 0x1B }, + { 0x221F, 0x1C }, + { 0x2194, 0x1D }, + { 0x25B2, 0x1E }, + { 0x25BC, 0x1F }, + { 0x2302, 0x7F }, + { 0x00C7, 0x80 }, + { 0x00FC, 0x81 }, + { 0x00E9, 0x82 }, + { 0x00E2, 0x83 }, + { 0x00E4, 0x84 }, + { 0x00E0, 0x85 }, + { 0x00E5, 0x86 }, + { 0x00E7, 0x87 }, + { 0x00EA, 0x88 }, + { 0x00EB, 0x89 }, + { 0x00E8, 0x8A }, + { 0x00EF, 0x8B }, + { 0x00EE, 0x8C }, + { 0x00EC, 0x8D }, + { 0x00C4, 0x8E }, + { 0x00C5, 0x8F }, + { 0x00C9, 0x90 }, + { 0x00E6, 0x91 }, + { 0x00C6, 0x92 }, + { 0x00F4, 0x93 }, + { 0x00F6, 0x94 }, + { 0x00F2, 0x95 }, + { 0x00FB, 0x96 }, + { 0x00F9, 0x97 }, + { 0x00FF, 0x98 }, + { 0x00D6, 0x99 }, + { 0x00DC, 0x9A }, + { 0x00A2, 0x9B }, + { 0x00A3, 0x9C }, + { 0x00A5, 0x9D }, + { 0x20A7, 0x9E }, + { 0x0192, 0x9F }, + { 0x00E1, 0xA0 }, + { 0x00ED, 0xA1 }, + { 0x00F3, 0xA2 }, + { 0x00FA, 0xA3 }, + { 0x00F1, 0xA4 }, + { 0x00D1, 0xA5 }, + { 0x00AA, 0xA6 }, + { 0x00BA, 0xA7 }, + { 0x00BF, 0xA8 }, + { 0x2310, 0xA9 }, + { 0x00AC, 0xAA }, + { 0x00BD, 0xAB }, + { 0x00BC, 0xAC }, + { 0x00A1, 0xAD }, + { 0x00AB, 0xAE }, + { 0x00BB, 0xAF }, + { 0x2591, 0xB0 }, + { 0x2592, 0xB1 }, + { 0x2593, 0xB2 }, + { 0x2502, 0xB3 }, + { 0x2524, 0xB4 }, + { 0x2561, 0xB5 }, + { 0x2562, 0xB6 }, + { 0x2556, 0xB7 }, + { 0x2555, 0xB8 }, + { 0x2563, 0xB9 }, + { 0x2551, 0xBA }, + { 0x2557, 0xBB }, + { 0x255D, 0xBC }, + { 0x255C, 0xBD }, + { 0x255B, 0xBE }, + { 0x2510, 0xBF }, + { 0x2514, 0xC0 }, + { 0x2534, 0xC1 }, + { 0x252C, 0xC2 }, + { 0x251C, 0xC3 }, + { 0x2500, 0xC4 }, + { 0x253C, 0xC5 }, + { 0x255E, 0xC6 }, + { 0x255F, 0xC7 }, + { 0x255A, 0xC8 }, + { 0x2554, 0xC9 }, + { 0x2569, 0xCA }, + { 0x2566, 0xCB }, + { 0x2560, 0xCC }, + { 0x2550, 0xCD }, + { 0x256C, 0xCE }, + { 0x2567, 0xCF }, + { 0x2568, 0xD0 }, + { 0x2564, 0xD1 }, + { 0x2565, 0xD2 }, + { 0x2559, 0xD3 }, + { 0x2558, 0xD4 }, + { 0x2552, 0xD5 }, + { 0x2553, 0xD6 }, + { 0x256B, 0xD7 }, + { 0x256A, 0xD8 }, + { 0x2518, 0xD9 }, + { 0x250C, 0xDA }, + { 0x2588, 0xDB }, + { 0x2584, 0xDC }, + { 0x258C, 0xDD }, + { 0x2590, 0xDE }, + { 0x2580, 0xDF }, + { 0x03B1, 0xE0 }, + { 0x00DF, 0xE1 }, + { 0x0393, 0xE2 }, + { 0x03C0, 0xE3 }, + { 0x03A3, 0xE4 }, + { 0x03C3, 0xE5 }, + { 0x00B5, 0xE6 }, + { 0x03C4, 0xE7 }, + { 0x03A6, 0xE8 }, + { 0x0398, 0xE9 }, + { 0x03A9, 0xEA }, + { 0x03B4, 0xEB }, + { 0x221E, 0xEC }, + { 0x03C6, 0xED }, + { 0x03B5, 0xEE }, + { 0x2229, 0xEF }, + { 0x2261, 0xF0 }, + { 0x00B1, 0xF1 }, + { 0x2265, 0xF2 }, + { 0x2264, 0xF3 }, + { 0x2320, 0xF4 }, + { 0x2321, 0xF5 }, + { 0x00F7, 0xF6 }, + { 0x2248, 0xF7 }, + { 0x00B0, 0xF8 }, + { 0x2219, 0xF9 }, + { 0x00B7, 0xFA }, + { 0x221A, 0xFB }, + { 0x207F, 0xFC }, + { 0x00B2, 0xFD }, + { 0x25A0, 0xFE }, + { 0x00A0, 0xFF }, + /* Extra mappings so ACS_* will work */ + { 0x00A4, 0x0F }, + { 0x2260, 0xD8 }, + { 0x23BA, 0x2D }, + { 0x23BB, 0x2D }, + { 0x23BC, 0x2D }, + { 0x23BD, 0x5F } +}; + +#define NO_CHAR 0xFE +static unsigned char pages[10][256]; +static unsigned char *map[256]; + +static void _build_rom_map(void) +{ + unsigned page = 0; + unsigned i; + + memset(pages, NO_CHAR, sizeof(pages)); + for (i = 0; i < 256; ++i) + map[i] = NULL; + /* Map ASCII as identity */ + map[0] = pages[page++]; + for (i = 0x20; i <= 0x7E; ++i) + map[0][i] = i; + /* Map according to the list */ + for (i = 0; i < sizeof(cp437_map)/sizeof(cp437_map[0]); ++i) + { + unsigned cp = cp437_map[i].uni; + unsigned t1 = cp >> 8; + unsigned t2 = cp & 0xFF; + if (map[t1] == NULL) + { + if (page >= sizeof(pages)/sizeof(pages[0])) + { + fprintf(stderr, "Need to adjust size of pages array\n)"); + abort(); + } + map[t1] = pages[page++]; + } + map[t1][t2] = cp437_map[i].pos; + } +} + +static unsigned char _unicode_to_cp437(unsigned long cp) +{ + unsigned t1, t2; + + if (cp > 0xFFFF) + return NO_CHAR; + t1 = cp >> 8; + t2 = cp & 0xFF; + if (map[t1] == NULL) + return NO_CHAR; + return map[t1][t2]; +} +#endif + +static int _vgafont_open(void) +{ +#ifdef PDC_FLAT + unsigned ofs = getdosmemword(0x43 * 4 + 0); + unsigned seg = getdosmemword(0x43 * 4 + 2); + unsigned long addr = _FAR_POINTER(seg, ofs); +#else + unsigned long addr = getdosmemdword(0x43 * 4); +#endif +#ifdef __DJGPP__ + dosmemget(addr, sizeof(font437), font437); +#else + font437 = (void PDC_FAR *)addr; +#endif + +#ifdef PDC_WIDE + _build_rom_map(); +#endif + PDC_state.font_close = _vgafont_close; + PDC_state.font_char_width = _vgafont_char_width; + PDC_state.font_char_height = _vgafont_char_height; + PDC_state.font_glyph_data = _vgafont_glyph_data; + return 0; +} + +static void _vgafont_close(bool bold) +{ + /* no operation */ +} + +static unsigned _vgafont_char_width(bool bold) +{ + return 8; +} + +static unsigned _vgafont_char_height(bool bold) +{ + return 16; +} + +static const unsigned char PDC_FAR *_vgafont_glyph_data(bool bold, unsigned long pos) +{ + unsigned pos437; +#ifdef PDC_WIDE + pos437 = _unicode_to_cp437(pos); +#else + pos437 = pos & 0xFF; +#endif + return font437 + pos437*16; +} + +/***************************************************************************** +* Support for PSF fonts * +*****************************************************************************/ + +/* PSF specification from: + https://www.win.tue.nl/~aeb/linux/kbd/font-formats-1.html + Only PSF version 2 is supported. */ + +#define PSF2_MAGIC "\x72\xb5\x4A\x86" + +/* bits used in flags */ +#define PSF2_HAS_UNICODE_TABLE 0x01 + +/* max version recognized so far */ +#define PSF2_MAXVERSION 0 + +/* UTF8 separators */ +#define PSF2_SEPARATOR 0xFF +#define PSF2_STARTSEQ 0xFE + +struct psf2_header +{ + unsigned char magic[4]; + unsigned long version; + unsigned long headersize; /* offset of bitmaps in file */ + unsigned long flags; + unsigned long length; /* number of glyphs */ + unsigned long charsize; /* number of bytes for each character */ + unsigned long height, width; /* max dimensions of glyphs */ + /* charsize = height * ((width + 7) / 8) */ +}; + +/* Information about a single font */ +struct font_data +{ + struct psf2_header header; + unsigned char **glyphs; /* Bits from the font */ + size_t **map[17]; /* Map code points to font positions */ + unsigned char *blank; /* Default glyph */ +}; + +static struct font_data psf_fonts[2]; /* normal and bold */ + +static void _psf_font_close(bool bold); +static unsigned _psf_font_char_width(bool bold); +static unsigned _psf_font_char_height(bool bold); +static const unsigned char PDC_FAR *_psf_font_glyph_data( + bool bold, unsigned long codepoint); +static void _psf_font_do_close(struct font_data *fdata); +static long _psf_font_read_utf8(FILE *fp); +static int _psf_font_map_char(struct font_data *fdata, long codepoint, + size_t pos); +static const unsigned char *_psf_font_do_glyph_data( + struct font_data *fdata, long codepoint); + +/* Open the font with the given file name, as the normal or the bold font. + * Return 0 if OK, -1 on any error. */ +static int _psf_font_open(const char *name, bool bold) +{ + struct font_data *fdata = &psf_fonts[bold != 0]; + FILE *fp; + size_t size; + size_t pos; + + memset(fdata, 0, sizeof(*fdata)); + + fp = fopen(name, "rb"); + if (fp == NULL) + goto error; + + /* Read and check the header */ + size = fread(&fdata->header, sizeof(fdata->header), 1, fp); + if (size != 1) + goto error; + if (memcmp(fdata->header.magic, PSF2_MAGIC, 4) != 0) + goto error; + if (fdata->header.charsize < fdata->header.height * ((fdata->header.width + 7) / 8)) + goto error; + + /* Temporary until pdcdisp.c is upgraded: + * width must be 8, height cannot exceed 16 */ + if (fdata->header.width != 8 || fdata->header.height > 16) + goto error; + + /* Read the bitmap data */ + if (fdata->header.length != (size_t)fdata->header.length) + goto error; /* only possible if size_t has less than four bytes */ + fdata->glyphs = calloc(fdata->header.length, sizeof(fdata->glyphs[0])); + if (fdata->glyphs == NULL) + goto error; + for (pos = 0; pos < fdata->header.length; ++pos) + { + fdata->glyphs[pos] = malloc(fdata->header.charsize); + if (fdata->glyphs[pos] == NULL) + goto error; + size = fread(fdata->glyphs[pos], 1, fdata->header.charsize, fp); + if (size != fdata->header.charsize) + goto error; + } + + /* Read the Unicode mapping if one is indicated */ + if (fdata->header.flags & PSF2_HAS_UNICODE_TABLE) + { + pos = 0; + while (1) + { + long codepoint = _psf_font_read_utf8(fp); + if (codepoint == -PSF2_STARTSEQ) + { + /* Introduces a sequence of combining characters; these are + * not supported */ + do + { + codepoint = _psf_font_read_utf8(fp); + } while (codepoint != -1 && codepoint != -PSF2_SEPARATOR); + } + if (codepoint == -PSF2_SEPARATOR) + { + ++pos; /* next glyph position */ + } + else if (codepoint < 0) + { + break; /* end of file or error */ + } + else + { + /* single code point mapped to the current position */ + if (pos >= fdata->header.length) + goto error; + if (_psf_font_map_char(fdata, codepoint, pos) < 0) + goto error; + } + } + } + + /* Provide a blank glyph for nonexistent mappings */ + if (_psf_font_do_glyph_data(fdata, 0xFFFD) == NULL) + { + fdata->blank = calloc(1, fdata->header.charsize); + if (fdata->blank == NULL) + goto error; + } + else + { + fdata->blank = NULL; + } + + fclose(fp); + PDC_state.font_close = _psf_font_close; + PDC_state.font_char_width = _psf_font_char_width; + PDC_state.font_char_height = _psf_font_char_height; + PDC_state.font_glyph_data = _psf_font_glyph_data; + return 0; + +error: + if (fp != NULL) + fclose(fp); + _psf_font_do_close(fdata); + return -1; +} + +/* Close the normal or the bold font */ +static void _psf_font_close(bool bold) +{ + _psf_font_do_close(&psf_fonts[bold != 0]); +} + +/* Free memory associated with a font */ +static void _psf_font_do_close(struct font_data *fdata) +{ + size_t pos; + unsigned i, j; + + /* Free the glyph data */ + if (fdata->glyphs != NULL) + { + for (pos = 0; pos < fdata->header.length; ++pos) + free(fdata->glyphs[pos]); + free(fdata->glyphs); + fdata->glyphs = NULL; + } + free(fdata->blank); + fdata->blank = NULL; + + /* Free the Unicode mapping */ + for (i = 0; i < 17; ++i) + { + if (fdata->map[i] != NULL) + { + for (j = 0; j < 256; ++j) + free(fdata->map[i][j]); + free(fdata->map[i]); + fdata->map[i] = NULL; + } + } +} + +/* Local function to read a UTF-8 sequence or a separator from the font file */ +static long _psf_font_read_utf8(FILE *fp) +{ + int byte; + long codepoint; + long min; + unsigned count; + + /* Read first byte */ + byte = fgetc(fp); + if (byte == EOF) + return -1; + if (byte == PSF2_STARTSEQ || byte == PSF2_SEPARATOR) + return -byte; /* markers meaningful to the font format */ + if (byte < 0x80) + { + return byte; /* ASCII */ + } + else if (byte < 0xC2) + { + return -1; /* Not valid as first byte */ + } + else if (byte < 0xE0) + { + /* Two byte character */ + codepoint = byte & 0x1F; + min = 0x80; + count = 1; + } + else if (byte < 0xF0) + { + /* Three byte character */ + codepoint = byte & 0x0F; + min = 0x800; + count = 2; + } + else if (byte < 0xF5) + { + /* Four byte character */ + codepoint = byte & 0x07; + min = 0x10000; + count = 3; + } + else + { + return -1; /* Not valid as first byte */ + } + + /* Read continuation bytes */ + while (count != 0) + { + byte = fgetc(fp); + if (byte < 0x80 || 0xBF < byte) + return -1; + codepoint = (codepoint << 6) | (byte & 0x3F); + --count; + } + + /* Check for overlong, surrogate, out of range */ + if (codepoint < min || codepoint > 0x10FFFF + || (0xD800 <= codepoint && codepoint <= 0xDFFF)) + return -1; + + return codepoint; +} + +/* Local function to establish a mapping from a codepoint to a font position */ +static int _psf_font_map_char(struct font_data *fdata, long codepoint, size_t pos) +{ + unsigned t1 = codepoint >> 16; + unsigned t2 = (codepoint >> 8) & 0xFF; + unsigned t3 = codepoint & 0xFF; + unsigned i; + + if (fdata->map[t1] == NULL) + { + fdata->map[t1] = calloc(256, sizeof(fdata->map[0][0])); + if (fdata->map[t1] == NULL) + return -1; + } + if (fdata->map[t1][t2] == NULL) + { + fdata->map[t1][t2] = malloc(256 * sizeof(fdata->map[0][0][0])); + if (fdata->map[t1][t2] == NULL) + return -1; + for (i = 0; i < 256; ++i) + fdata->map[t1][t2][i] = (size_t)-1; + } + fdata->map[t1][t2][t3] = pos; + return 0; +} + +/* Return the character width in pixels */ +static unsigned _psf_font_char_width(bool bold) +{ + return psf_fonts[bold != 0].header.width; +} + +/* Return the character height in pixels */ +static unsigned _psf_font_char_height(bool bold) +{ + return psf_fonts[bold != 0].header.height; +} + +/* Return the glyph data as read from the file */ +/* Never returns NULL. If the codepoint is not mapped, returns the mapping + * for U+FFFD if that exists, or the blank glyph otherwise */ +static const unsigned char PDC_FAR *_psf_font_glyph_data( + bool bold, unsigned long codepoint) +{ + struct font_data *fdata = &psf_fonts[bold != 0]; + const unsigned char *bitmap; + + bitmap = _psf_font_do_glyph_data(fdata, codepoint); + if (bitmap == NULL) + bitmap = _psf_font_do_glyph_data(fdata, 0xFFFD); + if (bitmap == NULL) + bitmap = fdata->blank; + + return bitmap; +} + +/* Return the glyph data as read from the file */ +/* Local function used by PDC_psf_glyph_data; can return NULL */ +static const unsigned char *_psf_font_do_glyph_data( + struct font_data *fdata, long codepoint) +{ + unsigned t1 = codepoint >> 16; + unsigned t2 = (codepoint >> 8) & 0xFF; + unsigned t3 = codepoint & 0xFF; + const unsigned char *bitmap = NULL; + size_t pos; + + if (t1 <= 17 && fdata->map[t1] != NULL && fdata->map[t1][t2] != NULL) + { + pos = fdata->map[t1][t2][t3]; + if (pos != (size_t)-1) + bitmap = fdata->glyphs[pos]; + } + return bitmap; +} diff --git a/dosvga/pdcsetsc.c b/dosvga/pdcsetsc.c index 50d4253de..12b3811e5 100644 --- a/dosvga/pdcsetsc.c +++ b/dosvga/pdcsetsc.c @@ -55,7 +55,7 @@ int PDC_curs_set(int visibility) break; case 2: /* highly visible */ start = 0; /* full-height block */ - end = _FONT16 - 1; + end = PDC_state.font_height - 1; break; default: /* normal visibility */ start = SP->orig_cursor >> 8; From 0ae1cee005787cca08a9ecc86cc25ff1ac07ef5b Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 1 Mar 2020 12:19:59 -0500 Subject: [PATCH 24/26] Provide wcslen for the DJGPP build --- demos/testcurs.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/demos/testcurs.c b/demos/testcurs.c index b216cfad1..ddbb5d75c 100644 --- a/demos/testcurs.c +++ b/demos/testcurs.c @@ -25,6 +25,9 @@ #if HAVE_WIDE # include +# ifdef __DJGPP__ +static size_t wcslen(const wchar_t *); +# endif #endif #if defined(PDCURSES) && !defined(XCURSES) @@ -1380,3 +1383,13 @@ void display_menu(int old_option, int new_option) "Use Up and Down Arrows to select - Enter to run - Q to quit"); refresh(); } + +#if HAVE_WIDE && defined(__DJGPP__) +/* wide character function missing in DJGPP */ +static size_t wcslen(const wchar_t *str) +{ + size_t i; + for (i = 0; str[i] != L'\0'; ++i) {} + return i; +} +#endif From 7be7a7bf6fe292b43508682a5edd2428fd31a4be Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 1 Mar 2020 20:54:29 -0500 Subject: [PATCH 25/26] Support fonts of arbitrary size Also, bring in @Bill-Gray's font.h; the ROM font doesn't seem to work in some configurations --- dosvga/README.md | 3 +- dosvga/font.h | 454 +++++++++++++++++++++++++++++++++++++++++ dosvga/pdcdisp.c | 513 +++++++++++++++++++++++++++++++++-------------- dosvga/pdcdos.h | 3 +- dosvga/pdcscrn.c | 64 +++--- 5 files changed, 849 insertions(+), 188 deletions(-) create mode 100644 dosvga/font.h diff --git a/dosvga/README.md b/dosvga/README.md index 5ff3573ab..582cc62a8 100644 --- a/dosvga/README.md +++ b/dosvga/README.md @@ -41,8 +41,7 @@ Building (WIDE=Y is untested on the Borland compiler.) The font can be set via the environment variable PDC_FONT. The font must -be in the PSF format, version 2. At present, the width must be 8 and the -height cannot exceed 16; this restriction will eventually be lifted. +be in the PSF format, version 2. Distribution Status diff --git a/dosvga/font.h b/dosvga/font.h new file mode 100644 index 000000000..1a4c2d67b --- /dev/null +++ b/dosvga/font.h @@ -0,0 +1,454 @@ +/* Converted from thin-14 using mk_font.c (q.v.) */ +/* Fonts found in https://hack.org/mc/fonts/vgafonts.tar.gz */ +static const unsigned char font_bytes[3584] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x44, 0x82, 0xaa, 0x82, 0xaa, 0xba, 0x44, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x7c, + 0xfe, 0xd6, 0xfe, 0xba, 0xc6, 0x7c, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0xee, 0xee, 0xfe, + 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0xfe, 0x7c, + 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x38, 0x10, 0xfe, 0xee, 0x54, 0x10, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, + 0x7c, 0xfe, 0xfe, 0xee, 0x54, 0x10, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, + 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, + 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x24, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe7, + 0xdb, 0xbd, 0xbd, 0xbd, 0xdb, 0xe7, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x0e, 0x06, 0x0a, + 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x10, + 0x10, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x1c, 0x14, 0x14, 0x10, 0x10, 0x30, 0x70, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x38, + 0x2c, 0x66, 0xe2, 0xc2, 0x06, 0x0e, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x44, + 0xc6, 0x44, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0xf8, 0xfe, 0xf8, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x3e, 0xfe, 0x3e, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, + 0x7c, 0x10, 0x10, 0x7c, 0x38, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x8a, 0x8a, 0x8a, 0x7a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x44, 0x40, 0x30, 0x28, 0x18, 0x04, 0x44, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0x10, + 0x10, 0x7c, 0x38, 0x10, 0x00, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x7c, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x38, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x0c, 0xfe, 0x0c, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60, + 0xfe, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, + 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, + 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0xfe, 0x28, + 0x28, 0x28, 0xfe, 0x28, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x7c, 0x92, 0x90, 0x7c, 0x12, + 0x92, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0xa2, 0xa4, 0x48, 0x10, 0x24, 0x4a, 0x8a, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x48, + 0x48, 0x30, 0x50, 0x8a, 0x84, 0x84, 0x7a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x10, 0x7c, 0x10, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0xfe, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x08, + 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x84, 0x8c, 0x94, 0xa4, 0xc4, + 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x30, 0x50, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x84, + 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x84, 0x04, 0x04, + 0x38, 0x04, 0x04, 0x84, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x18, 0x28, 0x48, 0x88, 0x88, + 0xfe, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfc, 0x80, 0x80, 0x80, 0xf8, 0x04, 0x04, 0x84, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x84, + 0x80, 0x80, 0xf8, 0x84, 0x84, 0x84, 0x78, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x04, 0x04, 0x08, + 0x10, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x84, 0x84, 0x84, 0x78, 0x84, + 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x84, 0x84, 0x84, 0x7c, 0x04, 0x04, 0x84, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x18, 0x00, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, + 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x10, + 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, + 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x82, 0x82, 0x02, + 0x0c, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x42, 0x9a, 0xa6, 0xa6, 0x9a, + 0x80, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x28, 0x44, 0x82, 0x82, 0xfe, 0x82, 0x82, + 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x42, + 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x42, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0x44, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x44, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x80, 0x80, 0x80, 0xf8, 0x80, 0x80, 0x80, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, + 0x80, 0x80, 0xf8, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x80, 0x80, + 0x8e, 0x82, 0x82, 0x42, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x82, 0x82, 0x82, 0x82, 0xfe, 0x82, + 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x84, 0x84, 0x78, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x82, 0x84, 0x88, 0x90, + 0xe0, 0x90, 0x88, 0x84, 0x82, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0xc6, 0xaa, 0x92, 0x92, 0x82, 0x82, 0x82, + 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x82, + 0xc2, 0xa2, 0x92, 0x8a, 0x86, 0x82, 0x82, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x82, 0x82, 0x82, 0xfc, 0x80, + 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x44, 0x82, 0x82, 0x82, 0x92, 0x8a, 0x44, + 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x82, + 0x82, 0x82, 0xfc, 0x90, 0x88, 0x84, 0x82, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x82, 0x80, 0x80, + 0x7c, 0x02, 0x02, 0x82, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x44, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x82, + 0x82, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0x82, + 0x92, 0x92, 0x92, 0xaa, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x82, 0x82, 0x44, 0x28, 0x10, 0x28, + 0x44, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x82, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, + 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x44, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, + 0x00, 0x00, 0x08, 0x10, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x78, 0x04, 0x7c, 0x84, 0x84, + 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, + 0x80, 0xb8, 0xc4, 0x84, 0x84, 0xc4, 0xb8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, + 0x84, 0x80, 0x80, 0x84, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x04, 0x04, 0x74, 0x8c, 0x84, + 0x84, 0x8c, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x78, 0x84, 0xfc, 0x80, 0x84, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, + 0x20, 0xf8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, + 0x8c, 0x8c, 0x8c, 0x74, 0x04, 0x84, 0x78, 0x00, + 0x00, 0x00, 0x80, 0x80, 0x80, 0xb8, 0xc4, 0x84, + 0x84, 0x84, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x88, + 0x70, 0x00, 0x00, 0x00, 0x80, 0x80, 0x84, 0x88, + 0x90, 0xa0, 0xd0, 0x88, 0x84, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xec, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb8, 0xc4, 0x84, 0x84, 0x84, 0x84, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, + 0x84, 0x84, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xc4, 0x84, + 0xc4, 0xb8, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x74, 0x8c, 0x84, 0x8c, 0x74, + 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb8, 0xc4, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, + 0x84, 0x60, 0x18, 0x84, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0xf8, 0x20, 0x20, + 0x20, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x84, 0x84, 0x84, 0x84, 0x8c, + 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x82, 0x82, 0x44, 0x44, 0x28, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, + 0x82, 0x92, 0x92, 0xaa, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x48, 0x30, + 0x30, 0x48, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x84, 0x84, 0x84, 0x8c, 0x74, + 0x04, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x08, 0x10, 0x20, 0x40, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x10, 0x10, 0x10, + 0x20, 0x10, 0x10, 0x10, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x08, 0x08, 0x08, 0x04, 0x08, 0x08, 0x08, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x98, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x28, 0x44, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x42, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x42, 0x3c, 0x04, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x84, 0x84, 0x84, 0x84, 0x8c, + 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x10, + 0x00, 0x78, 0x84, 0xfc, 0x80, 0x80, 0x78, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x78, + 0x04, 0x7c, 0x84, 0x84, 0x7a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x78, 0x04, 0x7c, + 0x84, 0x84, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x08, 0x00, 0x78, 0x04, 0x7c, 0x84, 0x84, + 0x7a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x10, + 0x00, 0x78, 0x04, 0x7c, 0x84, 0x84, 0x7a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, + 0x84, 0x80, 0x80, 0x84, 0x78, 0x08, 0x70, 0x00, + 0x00, 0x30, 0x48, 0x84, 0x00, 0x78, 0x84, 0xfc, + 0x80, 0x80, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x78, 0x84, 0xfc, 0x80, 0x80, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, + 0x00, 0x78, 0x84, 0xfc, 0x80, 0x80, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x30, + 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x28, 0x44, 0x00, 0x30, 0x10, 0x10, + 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, + 0x10, 0x28, 0x44, 0x82, 0xfe, 0x82, 0x82, 0x00, + 0x00, 0x00, 0x10, 0x28, 0x10, 0x00, 0x10, 0x28, + 0x44, 0x82, 0xfe, 0x82, 0x82, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x20, 0x00, 0xfc, 0x80, 0x80, 0xf0, + 0x80, 0x80, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xec, 0x12, 0x7c, 0x90, 0x90, + 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, + 0x50, 0x90, 0x9e, 0xf0, 0x90, 0x90, 0x9e, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x48, 0x84, 0x00, 0x78, + 0x84, 0x84, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x78, 0x84, 0x84, + 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x10, 0x00, 0x78, 0x84, 0x84, 0x84, 0x84, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x30, 0x48, 0x84, + 0x00, 0x84, 0x84, 0x84, 0x84, 0x8c, 0x74, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x84, + 0x84, 0x84, 0x84, 0x8c, 0x74, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x84, 0x84, 0x84, + 0x8c, 0x74, 0x04, 0x84, 0x78, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x38, 0x44, 0x82, 0x82, 0x82, 0x44, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x44, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x78, 0x84, + 0x80, 0x80, 0x84, 0x78, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x84, 0x80, 0x40, 0xf8, 0x20, + 0x20, 0x62, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x44, 0x28, 0x10, 0x7c, 0x10, 0x7c, 0x10, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x88, + 0x88, 0xf0, 0x88, 0x9c, 0x88, 0x88, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0xc0, 0x00, + 0x00, 0x00, 0x18, 0x20, 0x00, 0x78, 0x04, 0x7c, + 0x84, 0x84, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x20, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x20, + 0x00, 0x78, 0x84, 0x84, 0x84, 0x84, 0x78, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x20, 0x00, 0x84, + 0x84, 0x84, 0x84, 0x8c, 0x74, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x64, 0x98, 0x00, 0xb8, 0xc4, 0x84, + 0x84, 0x84, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x4c, 0x82, 0xc2, 0xa2, 0x92, 0x8a, 0x86, + 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x08, + 0x38, 0x48, 0x34, 0x00, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, + 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x60, 0x80, + 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x80, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x02, 0x02, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x48, 0x50, + 0x20, 0x5c, 0x04, 0x08, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0xc0, 0x48, 0x50, 0x20, 0x54, + 0x14, 0x1e, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, + 0x24, 0x48, 0x90, 0x48, 0x24, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x48, 0x24, + 0x12, 0x24, 0x48, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, + 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0xaa, 0x54, + 0xaa, 0x54, 0xaa, 0x54, 0xaa, 0x54, 0xaa, 0x54, + 0xaa, 0x54, 0xaa, 0x54, 0x76, 0xdc, 0x76, 0xdc, + 0x76, 0xdc, 0x76, 0xdc, 0x76, 0xdc, 0x76, 0xdc, + 0x76, 0xdc, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0xf8, 0x08, 0xf8, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0xf4, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x08, 0xf8, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, + 0x14, 0x14, 0x14, 0xf4, 0x04, 0xf4, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0x04, 0xf4, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0xf4, 0x04, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0xfc, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, + 0x08, 0xf8, 0x08, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x17, 0x10, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0x10, 0x17, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xf7, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x17, 0x14, 0x17, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x14, + 0x14, 0xf7, 0x00, 0xf7, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0x08, 0x0f, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0xff, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0x08, 0xff, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x90, 0x90, + 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x44, 0x84, 0xb8, 0x88, 0x84, 0x84, 0xa4, + 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x82, + 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, + 0xa4, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x42, 0x20, 0x10, 0x08, 0x10, + 0x20, 0x42, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x88, 0x88, 0x88, 0x88, + 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x42, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0xa0, 0x20, 0x20, 0x28, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x10, 0x7c, 0x92, 0x92, 0x92, + 0x7c, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x82, 0xfe, 0x82, 0x44, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, + 0x82, 0x82, 0x82, 0x44, 0x28, 0xaa, 0xee, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x24, 0x10, 0x78, + 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x92, 0x92, + 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb8, 0x44, 0xa2, 0x92, 0x8a, 0x44, 0x3a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0x40, 0x80, 0xfe, 0x80, 0x40, 0x3e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0xfe, 0x00, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, 0x00, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, + 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, + 0x20, 0x10, 0x08, 0x00, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x12, 0x16, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xd0, 0x90, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0xfe, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x98, + 0x00, 0x64, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x48, 0x48, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x10, 0x10, 0x10, 0x10, + 0x90, 0x50, 0x30, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x58, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x24, 0x08, 0x10, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +int PDC_font_height = 14; +int PDC_font_width = 8; diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c index 96a4dd82c..bbfea83cb 100644 --- a/dosvga/pdcdisp.c +++ b/dosvga/pdcdisp.c @@ -29,6 +29,7 @@ static unsigned long _get_colors(chtype glyph); static unsigned long _address_4(int row, int col); static unsigned long _address_8(int row, int col); +static void _video_read(void *data, unsigned long addr, size_t size); static void _video_write(unsigned long addr, const void *data, size_t size); static unsigned _set_window(unsigned window, unsigned long addr); @@ -46,122 +47,285 @@ void PDC_gotoyx(int row, int col) static void _new_packet(unsigned long colors, int lineno, int x, int len, const chtype *srcp) { - unsigned char bytes[16][MAX_PACKET]; - unsigned fore, back; - int underline; - unsigned long addr = _address_4(lineno, x); - unsigned long cp; - int col; - unsigned line; - unsigned vplane; - - fore = colors & 0xF; - back = (colors >> 16) & 0xF; - - /* Underline will go here if requested */ - underline = 13 /*PDC_state.font_height*/; - - /* Render to the bytes array and then copy to the frame buffer */ - /* Loop by column */ - for (col = 0; col < len; col++) + struct { - chtype glyph = srcp[col]; - int ch; - const unsigned char PDC_FAR *font_data; - unsigned char lr_mask; + const unsigned char *font_addr; + } glyphs[MAX_PACKET]; + int i; - /* Get the index into the font */ - ch = glyph & 0xFFFF; - if ((glyph & A_ALTCHARSET) != 0 && (glyph & 0xff80) == 0) - ch = acs_map[ch & 0x7f]; + /* Colors */ + unsigned fore = colors & 0xF; + unsigned back = (colors >> 16) & 0xF; - /* Get the font data */ - font_data = PDC_state.font_glyph_data(FALSE, ch); + /* Width of a character in bytes */ + unsigned ch_width = (PDC_state.font_width + 7) / 8; - /* Set pixels for A_LEFT and A_RIGHT */ - lr_mask = 0x00; - if (glyph & A_LEFT) - lr_mask |= 0x80; - if (glyph & A_RIGHT) - lr_mask |= 0x01; + /* Bit to set for A_RIGHT */ + unsigned char r_mask = 0x80 >> ((PDC_state.font_width - 1) % 8); - /* Copy font data into the bytes array */ - for (line = 0; line < PDC_state.font_height; line++) - { - unsigned char byte = font_data[line]; - bytes[line][col] = byte | lr_mask; - } - if (glyph & A_UNDERLINE) - bytes[underline][col] = 0xFF; - if (PDC_state.cursor_visible - && lineno == PDC_state.cursor_row - && col + x == PDC_state.cursor_col) - { - for (line = PDC_state.cursor_start; line <= PDC_state.cursor_end; ++line) - bytes[line][col] ^= 0xFF; - } - } + /* Bytes to write in a single pass */ + unsigned char bytes[1024]; - /* Draw the text in four passes, to optimize for the memory architecture - of the VGA in four bit pixel modes */ + /* Which plane we're writing */ + unsigned plane; - vplane = fore & ~back; - if (vplane != 0) + /* Compute these just once */ + for (i = 0; i < len; ++i) { - /* fore has 1, back has 0: copy bytes as rendered */ - outportb(0x3c4, 2); - outportb(0x3c5, vplane); - cp = addr; - for (line = 0; line < PDC_state.font_height; line++) - { - _video_write(cp, bytes[line], len); - cp += PDC_state.bytes_per_line; - } + chtype glyph = srcp[i]; + unsigned ch = glyph & A_CHARTEXT; + if ((glyph & A_ALTCHARSET) != 0 && (ch & 0xff80) == 0) + ch = acs_map[ch]; + glyphs[i].font_addr = PDC_state.font_glyph_data(FALSE, ch); } - vplane = ~fore & back; - if (vplane != 0) + if (PDC_state.font_width % 8 == 0) { - /* fore has 0, back has 1: copy bytes inverted */ - outportb(0x3c4, 2); - outportb(0x3c5, vplane); - cp = addr; - for (line = 0; line < PDC_state.font_height; line++) + /* Faster algorithm for use when we're always writing whole bytes */ + + /* Write data twice: once direct, once inverted */ + for (plane = 0; plane < 2; ++plane) { - for (col = 0; col < len; col++) - bytes[line][col] ^= 0xFF; - _video_write(cp, bytes[line], len); - cp += PDC_state.bytes_per_line; + unsigned xpix = x * PDC_state.font_width; + unsigned long addr = _address_4(lineno, xpix / 8); + unsigned plane_bit; + unsigned char invert; + unsigned line; + + if (plane == 0) + { + plane_bit = fore & ~back & 0xF; + invert = 0x00; + } + else + { + plane_bit = ~fore & back & 0xF; + invert = 0xFF; + } + if (plane_bit == 0) + continue; + + /* Select the planes */ + outportb(0x3c4, 2); + outportb(0x3c5, plane_bit); + + /* Loop once per raster line */ + for (line = 0; line < PDC_state.font_height; ++line) + { + unsigned long cp; + unsigned num_bytes = 0; + int col; + + /* Loop once per column */ + cp = addr; + for (col = 0; col < len; ++col) + { + chtype glyph = srcp[col]; + const unsigned char *font_data; + unsigned ch_byte; + + font_data = glyphs[col].font_addr; + + /* Loop once per byte within the font */ + for (ch_byte = 0; ch_byte < ch_width; ++ch_byte) + { + unsigned index = line * ch_width + ch_byte; + unsigned char byte = font_data[index]; + if ((glyph & A_UNDERLINE) && line == PDC_state.underline) + byte |= 0xFF; + if ((glyph & A_LEFT) != 0 && ch_byte == 0) + byte |= 0x80; + if ((glyph & A_RIGHT) != 0 && ch_byte + 1 == ch_width) + byte |= r_mask; + bytes[num_bytes++] = byte ^ invert; + if (num_bytes >= sizeof(bytes)) + { + /* Flush the bytes array to the frame buffer */ + _video_write(cp, bytes, num_bytes); + cp += num_bytes; + num_bytes = 0; + } + } + } + /* Write any remaining bytes */ + _video_write(cp, bytes, num_bytes); + + addr += PDC_state.bytes_per_line; + } } - } - vplane = ~fore & ~back; - if (vplane != 0) - { - /* fore has 0, back has 0: write 0x00 */ - outportb(0x3c4, 2); - outportb(0x3c5, vplane); - cp = addr; - memset(bytes[0], 0x00, len); - for (line = 0; line < PDC_state.font_height; line++) + /* Write fill bytes: once all zeros, once all ones */ + for (plane = 0; plane < 2; ++plane) { - _video_write(cp, bytes[0], len); - cp += PDC_state.bytes_per_line; + unsigned xpix = x * PDC_state.font_width; + unsigned long addr = _address_4(lineno, xpix / 8); + unsigned plane_bit; + unsigned char fill; + unsigned width; + unsigned line; + + if (plane == 0) + { + plane_bit = ~fore & ~back & 0xF; + fill = 0x00; + } + else + { + plane_bit = fore & back & 0xF; + fill = 0xFF; + } + if (plane_bit == 0) + continue; + + /* Select the planes */ + outportb(0x3c4, 2); + outportb(0x3c5, plane_bit); + + /* Fill with bytes to be written */ + width = ch_width * len; + memset(bytes, fill, (width < sizeof(bytes)) ? width : sizeof(bytes)); + + /* Loop once per raster line */ + for (line = 0; line < PDC_state.font_height; ++line) + { + unsigned count = width; + unsigned long cp = addr; + /* Fill */ + while (count > sizeof(bytes)) + { + _video_write(cp, bytes, sizeof(bytes)); + cp += sizeof(bytes); + count -= sizeof(bytes); + } + _video_write(cp, bytes, count); + addr += PDC_state.bytes_per_line; + } } } - - vplane = fore & back; - if (vplane != 0) + else { - /* fore has 1, back has 1: write 0xFF */ - outportb(0x3c4, 2); - outportb(0x3c5, vplane); - cp = addr; - memset(bytes[0], 0xFF, len); - for (line = 0; line < PDC_state.font_height; line++) + /* Loop once per plane */ + for (plane = 0; plane < 4; ++plane) { - _video_write(cp, bytes[0], len); - cp += PDC_state.bytes_per_line; + unsigned xpix = x * PDC_state.font_width; + unsigned long addr = _address_4(lineno, xpix / 8); + unsigned plane_bit = 1 << plane; + unsigned cbits; + unsigned line; + + /* Select the plane */ + outportb(0x3c4, 2); + outportb(0x3c5, plane_bit); + outportb(0x3ce, 4); + outportb(0x3cf, plane); + + /* Select the mask for the current plane */ + cbits = ((fore & plane_bit) ? 1 : 0) + | ((back & plane_bit) ? 2 : 0); + + /* Loop once per raster line */ + for (line = 0; line < PDC_state.font_height; ++line) + { + unsigned shift = xpix % 8; + unsigned long cp; + unsigned num_bytes = 0; + int col; + unsigned ch_byte; + + if (shift != 0) + { + /* We need the existing data from the frame buffer */ + _video_read(bytes, addr, 1); + bytes[0] &= 0xFF00 >> shift; + } + else + { + bytes[0] = 0; + } + + col = 0; + ch_byte = 0; + cp = addr; + while (col < len) + { + /* Render one byte from the current character */ + chtype glyph = srcp[col]; + const unsigned char *font_data = glyphs[col].font_addr; + unsigned char byte; + unsigned num_bits; + + /* Get one byte of pixel data for the current plane */ + if (cbits == 1 || cbits == 2) + { + unsigned index = line * ch_width + ch_byte; + byte = font_data[index]; + if ((glyph & A_UNDERLINE) && line == PDC_state.underline) + byte |= 0xFF; + if ((glyph & A_LEFT) != 0 && ch_byte == 0) + byte |= 0x80; + if ((glyph & A_RIGHT) != 0 && ch_byte + 1 == ch_width) + byte |= r_mask; + } + else + { + byte = 0x00; + } + if (cbits & 2) + byte ^= 0xFF; + + /* Get the number of bits to render in this pass */ + if (ch_byte + 1 < ch_width) + num_bits = 8; + else + { + num_bits = PDC_state.font_width - ch_byte * 8; + byte &= 0xFF00 >> num_bits; + } + + /* Add the bits to the bytes array */ + bytes[num_bytes] |= byte >> shift; + byte <<= 8 - shift; + shift += num_bits; + if (shift >= 8) + { + ++num_bytes; + shift -= 8; + if (num_bytes >= sizeof(bytes)) + { + /* Flush the bytes array to the frame buffer */ + _video_write(cp, bytes, num_bytes); + cp += num_bytes; + num_bytes = 0; + } + bytes[num_bytes] = byte; + } + + /* Advance to the next byte of the character */ + ++ch_byte; + if (ch_byte >= ch_width) + { + ch_byte = 0; + ++col; + } + } + if (num_bytes != 0) + { + /* There are bytes remaining in the bytes array */ + _video_write(cp, bytes, num_bytes); + cp += num_bytes; + bytes[0] = bytes[num_bytes]; + } + if (shift != 0) + { + /* There are bits remaining in the bytes array */ + unsigned char b; + _video_read(&b, cp, 1); + bytes[0] |= b & (0xFF >> shift); + _video_write(cp, bytes, 1); + } + + addr += PDC_state.bytes_per_line; + } } } } @@ -201,26 +365,26 @@ static void _transform_line_4(int lineno, int x, int len, const chtype *srcp) static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) { - unsigned char bytes[MAX_PACKET*4*8]; + unsigned char bytes[1024]; unsigned long addr = _address_8(lineno, x); unsigned bytes_per_pixel = (PDC_state.bits_per_pixel + 7) / 8; - unsigned long cp; struct { - const unsigned char PDC_FAR *font_addr; - unsigned char lr_mask; + const unsigned char *font_addr; unsigned char ul_mask; unsigned long fore; unsigned long back; } glyphs[MAX_PACKET]; + /* Width of a character in bytes */ + unsigned ch_width = (PDC_state.font_width + 7) / 8; + + /* Bit to set for A_RIGHT */ + unsigned char r_mask = 0x80 >> ((PDC_state.font_width - 1) % 8); + int col; unsigned line; - unsigned underline; - - /* Underline will go here if requested */ - underline = 13 /*PDC_state.font_height*/; /* Compute basic glyph data only once per character */ for (col = 0; col < len; col++) @@ -240,13 +404,6 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) /* Bit mask for underline */ glyphs[col].ul_mask = (glyph & A_UNDERLINE) ? 0xFF : 0x00; - /* Bit mask for A_LEFT and A_RIGHT */ - glyphs[col].lr_mask = 0x00; - if (glyph & A_LEFT) - glyphs[col].lr_mask |= 0x80; - if (glyph & A_RIGHT) - glyphs[col].lr_mask |= 0x01; - /* Get the colors */ colors = _get_colors(glyph); fore = colors & 0xFFFF; @@ -256,14 +413,20 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) fore = PDC_state.colors[fore].mapped; back = PDC_state.colors[back].mapped; } + /* + * If this is ever run on big endian hardware, we'll need to shift + * fore and back left as follows: + * fore <<= 32 - (bytes_per_pixel * 8); + * back <<= 32 - (bytes_per_pixel * 8); + */ glyphs[col].fore = fore; glyphs[col].back = back; } /* Loop by raster line */ - cp = addr; for (line = 0; line < PDC_state.font_height; line++) { + unsigned long cp = addr; unsigned bindex; /* Loop by column */ @@ -271,57 +434,57 @@ static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) for (col = 0; col < len; col++) { /* Get glyph data */ - const unsigned char PDC_FAR *font_addr = glyphs[col].font_addr; + chtype glyph = srcp[col]; + const unsigned char *font_addr = glyphs[col].font_addr; + unsigned index = line * ch_width; unsigned long fore = glyphs[col].fore; unsigned long back = glyphs[col].back; - unsigned byte, bit; - - /* Get one byte of the font data */ - byte = font_addr[line] | glyphs[col].lr_mask; - if (line == underline) - byte |= glyphs[col].ul_mask; - if (PDC_state.cursor_visible - && lineno == PDC_state.cursor_row - && col + x == PDC_state.cursor_col - && PDC_state.cursor_start <= line && line <= PDC_state.cursor_end) - byte ^= 0xFF; - - /* Render one raster line of the glyph */ - switch (bytes_per_pixel) - { - case 1: - for (bit = 0x80; bit != 0; bit >>= 1) - { - unsigned long color = (byte & bit) ? fore : back; - bytes[bindex++] = (unsigned char)color; - } - break; + unsigned ch_byte; + unsigned byte; - case 2: - for (bit = 0x80; bit != 0; bit >>= 1) - { - unsigned long color = (byte & bit) ? fore : back; - *(unsigned short *)(bytes+bindex) = (unsigned short)color; - bindex += 2; - } - break; - - default: - /* In 24 bit color mode, each pass writes one extra byte at - the end, which is overwritten by the next pixel and leaves - an extra unused byte. This will need to change if this - code is ever used on a big endian machine. */ - for (bit = 0x80; bit != 0; bit >>= 1) + /* Loop by byte within the font */ + for (ch_byte = 0; ch_byte < ch_width; ++ch_byte) + { + unsigned bit, num_bits; + + /* Get one byte of the font data */ + byte = font_addr[index + ch_byte]; + if ((glyph & A_LEFT) != 0 && ch_byte == 0) + byte |= 0x80; + if ((glyph & A_RIGHT) != 0 && ch_byte + 1 == ch_width) + byte |= r_mask; + if (line == PDC_state.underline) + byte |= glyphs[col].ul_mask; + if (PDC_state.cursor_visible + && lineno == PDC_state.cursor_row + && col + x == PDC_state.cursor_col + && PDC_state.cursor_start <= line && line <= PDC_state.cursor_end) + byte ^= 0xFF; + + /* Number of pixels to render on this pass */ + if (ch_byte + 1 == ch_width) + num_bits = PDC_state.font_width - ch_byte * 8; + else + num_bits = 8; + + /* Render one byte's worth of pixels of the glyph */ + for (bit = 0; bit < num_bits; ++bit) { - unsigned long color = (byte & bit) ? fore : back; - *(unsigned long *)(bytes+bindex) = color; + unsigned long color = (byte & (0x80 >> bit)) ? fore : back; + *(unsigned long *)(bytes + bindex) = color; bindex += bytes_per_pixel; + if (bindex + sizeof(unsigned long) > sizeof(bytes)) + { + /* Flush bytes to the frame buffer */ + _video_write(cp, bytes, bindex); + cp += bindex; + bindex = 0; + } } - break; } } _video_write(cp, bytes, bindex); - cp += PDC_state.bytes_per_line; + addr += PDC_state.bytes_per_line; } } @@ -424,6 +587,46 @@ static unsigned long _address_8(int row, int col) + col * PDC_state.font_width * ((PDC_state.bits_per_pixel + 7)/8); } +static void _video_read(void *data, unsigned long addr, size_t size) +{ +#ifdef PDC_FLAT + if (PDC_state.linear_sel) + { +#ifdef __DJGPP__ + movedata(PDC_state.linear_sel, addr, + _go32_my_ds(), (unsigned)data, size); +#else /* Watcom */ + _fmemcpy(data, MK_FP(PDC_state.linear_sel, addr), size); +#endif + } + else +#endif + { + unsigned window = PDC_state.window[PDC_state.read_win]; + + while (size != 0) + { + unsigned offset = _set_window(PDC_state.read_win, addr); + unsigned long size2 = PDC_state.window_size - offset; + if (size2 > size) + size2 = size; +#ifdef __DJGPP__ + dosmemget(window * 16L + offset, size2, data); +#elif defined(__WATCOMC__) && defined(__386__) + _fmemcpy(data, (void PDC_FAR *)(window * 16L + offset), size2); +#else + if (size2 >= 65532) + size2 = 65532; + + _fmemcpy(data, MK_FP(window, offset), size2); +#endif + addr += size2; + data = (char *)data + size2; + size -= size2; + } + } +} + static void _video_write(unsigned long addr, const void *data, size_t size) { #ifdef PDC_FLAT diff --git a/dosvga/pdcdos.h b/dosvga/pdcdos.h index 94cc2be90..1cf46c9cb 100644 --- a/dosvga/pdcdos.h +++ b/dosvga/pdcdos.h @@ -79,11 +79,12 @@ struct PDC_video_state void (*font_close)(bool bold); unsigned (*font_char_width)(bool bold); unsigned (*font_char_height)(bool bold); - const unsigned char PDC_FAR *(*font_glyph_data)(bool bold, unsigned long pos); + const unsigned char *(*font_glyph_data)(bool bold, unsigned long pos); bool have_bold_font; unsigned font_width; /* Width of font in pixels */ unsigned font_height; /* Height of font in pixels */ + unsigned underline; /* Where to draw the underline */ /* Cursor state */ bool cursor_visible; diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index 8806a1244..6d78d962a 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -2,6 +2,7 @@ #include "pdcdos.h" #include "pdcvesa.h" +#include "font.h" #include #include @@ -98,6 +99,29 @@ void PDC_scr_free(void) } } +/* Set the location of the underline */ +static void _set_underline(void) +{ + unsigned width = (PDC_state.font_width + 7) / 8; + unsigned height = PDC_state.font_height; + unsigned size = width * height; + unsigned i; + const unsigned char *underscore = PDC_state.font_glyph_data(FALSE, 0x5F); + + /* Set underscore at first line of U+005F that is not blank */ + for (i = 0; i < size; ++i) + { + if (underscore[i] != 0) + { + PDC_state.underline = i / width; + return; + } + } + + /* How peculiar; U+005F is blank. Make a guess. */ + PDC_state.underline = PDC_state.font_height * 3 / 4; +} + /* open the physical screen -- miscellaneous initialization, may save the existing screen for later restoration */ @@ -149,6 +173,7 @@ int PDC_scr_open(void) } PDC_state.font_width = PDC_state.font_char_width(FALSE); PDC_state.font_height = PDC_state.font_char_height(FALSE); + _set_underline(); PDC_resize_screen(25, 80); @@ -644,11 +669,13 @@ static unsigned _find_mode( selected_size = (rows == 0 && cols == 0) ? 0 : 0xFFFFFFFF; selected_bits = 0; - if ((rows <= 30 && cols <= 80) && !(rows == 0 && cols == 0)) + if (rows * PDC_state.font_height <= 480 && cols * PDC_state.font_width <= 640) { /* Set up a ModeInfoBlock for mode 0x0012 */ + unsigned new_rows = 480 / PDC_state.font_height; + unsigned new_cols = 640 / PDC_state.font_width; selected_mode = 0x0012; - selected_size = 80 * 30; + selected_size = new_rows * new_cols; selected_bits = 4; memset(mode_info, 0, sizeof(*mode_info)); mode_info->ModeAttributes = 0x1F; @@ -1088,11 +1115,6 @@ static void _vgafont_close(bool bold); static unsigned _vgafont_char_width(bool bold); static unsigned _vgafont_char_height(bool bold); static const unsigned char *_vgafont_glyph_data(bool bold, unsigned long pos); -#ifdef __DJGPP__ -static unsigned char font437[4096]; -#else -static unsigned char PDC_FAR *font437; -#endif #ifdef PDC_WIDE /* This maps Unicode to CP437 */ @@ -1325,19 +1347,6 @@ static unsigned char _unicode_to_cp437(unsigned long cp) static int _vgafont_open(void) { -#ifdef PDC_FLAT - unsigned ofs = getdosmemword(0x43 * 4 + 0); - unsigned seg = getdosmemword(0x43 * 4 + 2); - unsigned long addr = _FAR_POINTER(seg, ofs); -#else - unsigned long addr = getdosmemdword(0x43 * 4); -#endif -#ifdef __DJGPP__ - dosmemget(addr, sizeof(font437), font437); -#else - font437 = (void PDC_FAR *)addr; -#endif - #ifdef PDC_WIDE _build_rom_map(); #endif @@ -1360,10 +1369,10 @@ static unsigned _vgafont_char_width(bool bold) static unsigned _vgafont_char_height(bool bold) { - return 16; + return 14; } -static const unsigned char PDC_FAR *_vgafont_glyph_data(bool bold, unsigned long pos) +static const unsigned char *_vgafont_glyph_data(bool bold, unsigned long pos) { unsigned pos437; #ifdef PDC_WIDE @@ -1371,7 +1380,7 @@ static const unsigned char PDC_FAR *_vgafont_glyph_data(bool bold, unsigned long #else pos437 = pos & 0xFF; #endif - return font437 + pos437*16; + return font_bytes + pos437*14; } /***************************************************************************** @@ -1420,7 +1429,7 @@ static struct font_data psf_fonts[2]; /* normal and bold */ static void _psf_font_close(bool bold); static unsigned _psf_font_char_width(bool bold); static unsigned _psf_font_char_height(bool bold); -static const unsigned char PDC_FAR *_psf_font_glyph_data( +static const unsigned char *_psf_font_glyph_data( bool bold, unsigned long codepoint); static void _psf_font_do_close(struct font_data *fdata); static long _psf_font_read_utf8(FILE *fp); @@ -1453,11 +1462,6 @@ static int _psf_font_open(const char *name, bool bold) if (fdata->header.charsize < fdata->header.height * ((fdata->header.width + 7) / 8)) goto error; - /* Temporary until pdcdisp.c is upgraded: - * width must be 8, height cannot exceed 16 */ - if (fdata->header.width != 8 || fdata->header.height > 16) - goto error; - /* Read the bitmap data */ if (fdata->header.length != (size_t)fdata->header.length) goto error; /* only possible if size_t has less than four bytes */ @@ -1678,7 +1682,7 @@ static unsigned _psf_font_char_height(bool bold) /* Return the glyph data as read from the file */ /* Never returns NULL. If the codepoint is not mapped, returns the mapping * for U+FFFD if that exists, or the blank glyph otherwise */ -static const unsigned char PDC_FAR *_psf_font_glyph_data( +static const unsigned char *_psf_font_glyph_data( bool bold, unsigned long codepoint) { struct font_data *fdata = &psf_fonts[bold != 0]; From b812ef57cdaee5f3b31d89077e840f2c04dc914c Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 1 Mar 2020 22:12:12 -0500 Subject: [PATCH 26/26] Fix the default VGA mode --- dosvga/pdcscrn.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c index 6d78d962a..e4de24d6e 100644 --- a/dosvga/pdcscrn.c +++ b/dosvga/pdcscrn.c @@ -652,6 +652,9 @@ static unsigned _find_video_mode(int rows, int cols) PDC_state.offset[1] = 0; PDC_state.window_size = (640/8) * 480; PDC_state.window_gran = 1; + PDC_state.red_max = 63; + PDC_state.green_max = 63; + PDC_state.blue_max = 63; return 0x12; }