{
I managed to write a unit called Fonts that will allow you to customise your
EGA/VGA character sets and fonts like it is done in the Norton Utilities, save
and restore them easily. There are given some different sizes for fonts:

8x8        (VGA mode 80x50 or EGA mode 80x43)
8x14       (EGA mode 80x25)
8x16       (VGA mode 80x25)
and
9x16 (not currently supported)

Each character represents the matrix with length of 8, 14, or 16 bytes. Here is
the table for 8x8, 8x14 and 8x16 fonts, respectively:

8x8 font        8x14 font       8x16 font

00000000        00000000        00000000
00000000        00000000        00000000
00000000        00000000        00000000
00000000        00000000        00000000
00000000        00000000        00000000
00000000        00000000        00000000
00000000        00000000        00000000
00000000        00000000        00000000
                00000000        00000000
                00000000        00000000
                00000000        00000000
                00000000        00000000
                00000000        00000000
                00000000        00000000
                                00000000
                                00000000

So for 8x8 font there is array[0..255,1..8] of Byte, for 8x14 -
array[0..255,1..14] of Byte, and for 8x16 - array[0..255,1..16] of Byte.

How to reprogram a ASCII character so it will look 'as you would like it to
be'?

Single scan line of each character of any font type consists of 8 bits (1
byte) each. Each font (as said earlier) has 8, 14, or 16 scan lines and will
occupy whether 256*8=2048, 256*14=3584, or 256*16=4096 bytes (since there are
0..255=256 bytes in the ASCII table).

To define your own 'A' letter, for example, in font 8x8 you would need:

1. To define first your own 8x8 matrix for 'A' character like shown below:

00011111   hex 1F
00110011   hex 33
01100011   hex 63
11000011   hex C3
11000011   hex C3
11111111   hex FF
11000011   hex C3
11000011   hex C3

2. To replace active matrix of character 'A' with the new one using the Fonts
unit do the following:

Define a new 'A' character matrix for 8x8. NewA contains the buffer to load
matrix from

const
  NewA : array[1..8] of Byte = ($1F, $33, $63, $C3, $C3, $FF, $C3, $C3);

Begin
  LoadCharset(NewA, Ord('A'), 1, 8)
End.

}

Unit Fonts;
{ Copyright (c) 1994 by Andrew Eigus  Fidonet: 2:5100/33 }
{ Public Domain, ready for SWAG }

(*
  This unit provides EGA/VGA font management routines and enables you
  to save/restore characters or charsets and also makes it easy for you
  to set your own (custom) characters or charsets in EGA/VGA modes

  8x8 font:  for EGA 80x43 or VGA 80x50 modes,
  8x14 font: for EGA 80x25 mode,
  8x16 font: for VGA 80x25 mode
*)

interface

type
  { 8x8 font table type }
  P8x8Charset = ^T8x8Charset;
  T8x8Charset = array[0..255, 1..8] of Byte;

  { 8x14 font table type }
  P8x14Charset = ^T8x14Charset;
  T8x14Charset = array[0..255,1..14] of Byte;

  { 8x16 font table type }
  P8x16Charset = ^T8x16Charset;
  T8x16Charset = array[0..255, 1..16] of Byte;

const
  { ROM table pointer request codes to use with #SaveROMFont#: }

  reqInt1F = 0; { return current Int 1Fh graphics font address }
  reqInt44 = 1; { return current Int 44h graphics font address }
  req8x14  = 2; { return ROM 8x14 font table address }
  req8x8   = 3; { return ROM 8x8 double dot font table address }
  req8x8t  = 4; { return ROM 8x8 double dot address (top) }
  req9x14  = 5; { return ROM 9x14 alternate table address }
  req8x16  = 6; { return ROM 8x16 font table address }


function EGAInstalled : boolean;
{ Determines whether EGA/VGA is installed or not. If EGA/VGA is installed,
  True is returned and you may freely use all of those routines in this
  unit.

  See also #GetScanLines# }

function GetScanLines : byte;
{ Performs auto detection of scan lines per one character in active video
  mode.

  for 80x43 EGA or 80x50 VGA mode - 8,
  for 80x25 EGA mode - 14,
  and
  for 80x25 VGA mode - 16 }

procedure SaveCharset(var Buffer; StartChar, Count, ScanLines : word);
{ Saves Count characters from video memory into Buffer starting with
  StartChar ASCII code and using the ScanLines number for each character
  matrix. To determine number of scan lines in active video font,
  use function #GetScanLines#. (see #SaveFont# procedure) }

procedure LoadCharset(var Buffer; StartChar, Count, ScanLines : word);
{ Loads Count characters from Buffer into video memory starting with
  StartChar ASCII code and using the ScanLines for each character matrix.
  To determine number of scan lines in active video font,
  use function #GetScanLines#. (see #LoadFont# procedure) }

procedure LoadROMCharset(var Buffer; StartChar, Count, ScanLines : word);
{ Loads Count characters from ROM charset into video memory starting with
  StartChar ASCII code and using the ScanLines for each character matrix.
  To determine number a number of scan lines in active video font,
  use function #GetScanLines#. }

procedure SaveROMFont(var Font; Code : byte);
{ Saves ROM font table into Buffer for the specified table pointer
  request code. See ROM table pointer request codes for more information. }

procedure SaveFont(var Font; ScanLines : byte);
{ Saves the whole active video font into Buffer and uses the value of
  ScanLines to calculate the font size. }

procedure LoadFont(var Font; ScanLines : byte);
{ Loads the whole into video memory and uses the value of
  ScanLines to calculate the font size. }


implementation

Procedure OpenRegs; near; assembler;
{ This is used internally and required by the unit }
Asm
  cli
  mov dx,03C4h
  mov ax,0402h
  out dx,ax
  mov ax,0704h
  out dx,ax
  mov dl,0CEh { port 03CEh }
  mov ax,0204h
  out dx,ax
  mov ax,0005h
  out dx,ax
  mov ax,0406h
  out dx,ax
End; { OpenRegs }

Procedure CloseRegs; near; assembler;
{ This is used internally and required by the unit. }
Asm
  mov dx,03C4h
  mov ax,0302h
  out dx,ax
  mov ax,0304h
  out dx,ax
  mov dl,0CEh { port 03CEh }
  mov ax,0004h
  out dx,ax
  mov ax,1005h
  out dx,ax
  mov es,Seg0040
  mov ax,0E06h
  cmp byte ptr es:[0049h],07h
  jne @color
  mov ax,0A06h
@color:
  out dx,ax
  sti
End; { CloseRegs }

Function EGAInstalled; assembler;
Asm
  mov ax,1200h
  mov bx,0010h
  xor cx,cx
  int 10h
  xor al,al { mov al,False }
  or  cx,0  { still cx the same? yes, there's no EGA }
  jz  @noega
  inc al { al gets True }
@noega:
End; { EGAInstalled }

Function GetScanLines; assembler;
Asm
  mov es,Seg0040
  mov al,byte ptr es:[0085h]
End; { GetScanLines }

Procedure SaveCharset; assembler;
Asm
  call OpenRegs
  push ds
  mov ax,SegA000
  mov ds,ax
  mov ax,StartChar
  mov bx,32
  mul bx
  mov si,ax
  les di,Buffer
  cld
  mov ax,Count
  mul bx
  mov dx,ScanLines
@@1:
  mov cx,dx
  rep movsb
  mov cx,bx
  sub cx,dx
  add si,cx
  sub ax,bx
  cmp ax,0
  jnz @@1
  pop ds
  call CloseRegs
End; { SaveCharset }

Procedure LoadCharset; assembler;
Asm
  call OpenRegs
  push ds
  mov es,SegA000
  mov ax,StartChar
  mov bx,32
  mul bx
  mov di,ax
  mov ax,Count
  mul bx
  mov dx,ScanLines
  lds si,Buffer
  cld
@@1:
  mov cx,dx
  rep movsb
  mov cx,bx
  sub cx,dx
  add di,cx
  sub ax,bx
  cmp ax,0
  jnz @@1
  pop ds
  call CloseRegs
End; { LoadCharset }

Procedure SaveROMFont; assembler;
Asm
  mov ax,1130h
  mov bh,Code
  les bp,Font
  int 10h
End; { SaveROMFont }

Procedure LoadROMCharset; assembler;
Asm
  mov ah,11h
  xor al,al
  mov cx,Count
  mov dx,StartChar
  xor bl,bl
  mov bh,byte ptr ScanLines
  les bp,Buffer
  int 10h
End; { LoadROMCharset }

Procedure SaveFont;
Begin
  SaveCharset(Font, 0, 256, ScanLines)
End; { SaveFont }

Procedure LoadFont;
Begin
  LoadCharset(Font, 0, 256, ScanLines)
End; { LoadFont }

End.
