[Back to EGAVGA SWAG index] [Back to Main SWAG index] [Original]

    Unit LF;

    {$IFDEF Windows}
    !! - Bite me!  This will not work with Windows!
    {$ENDIF}

    { Text-mode font routines                                                    }
    { (c)1994 Chris Lautenbach                                                   }
    {                                                                            }
    { Date         Revision     Description                                      }
    { ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ }
    { Sep 07 94         1.0     Wrote real mode routines                         }
    { Sep 09 94         1.1     Added protected mode versions                    }
    { Sep 11 94         1.2     Added Set2FontMode() and SetNormalFontMode()     }

    { Notes:                                                                     }

    { It is important to note, that under protected mode, the normal VGA BIOS    }
    { extensions could not access the memory procured by GetMem().  This is why  }
    { the SimulateRealModeInt() and XGlobalDosAlloc() routines were needed.      }
    { XGlobalDosAlloc() allocates memory under the 1mb mark that the VGA BIOS is }
    { capable of accessing, and thereby allows font loads in p-mode.             }

    { Any size/line font may be used.  This is because I used subfunction $11    }
    { instead of $10.  $11 will calculate the scanlines/etc required for the     }
    { font you are loading by dividing the number of characters by the fonts     }
    { total size (as does LoadFont(), so that we may properly allocate memory).  }
    { I've tested 25, 33, 50, and 66 line mode fonts with it and they all work   }
    { fine.  Make sure the font you are loading is _pure_ binary, and does not   }
    { contain header information for some sort of font editing/loading program.  }

    { The calls to LoadFont() are identical in p-mode to real mode, so you won't }
    { need to do any code changes should you decide to switch between the modes  }
    { later on.  Nor is any special setup necessary.  Just USE it, and load      }
    { fonts, that's it! :)                                                       }

    { Using the VGA's 2 font mode:                                               }

    { The variable LoadBank has been provided so you can use LoadFont() to load  }
    { a font into a different font bank (VGA has up to 8 slots, 0-7).  The new   }
    { Set2FontMode() procedure allows you to switch to this mode.                }
    { SetNormalFontMode should be called to return you to normal mode.  To use   }
    { this mode, you must use two identical line mode fonts (eg. 25 line and 25  }
    { line, 50 and 50, etc).  One must be loaded into bank 0, and the other must }
    { be loaded into bank 6 (don't ask me why.. :).  Any characters that are     }
    { displayed in low intensity will be displayed in the font in bank 6, and    }
    { high intensity characters will be displayed in bank 0's font (the normal   }
    { font if you haven't changed it.                                            }

    { Restrictions:                                                              }

    { It is _ASSUMED_ that the machine has a VGA adapter.  If it does not, god   }
    { only knows what will happen.  It is up to you to make sure a VGA is        }
    { present before calling these routines.                                     }

    { Don't you dare use this code for profit without proclaiming my name in a   }
    { prominent place in your program!  :) (Oh, and it don't work under Windoze  }
    { but I'm sure you knew that...)                                             }

    { Oh, and I'm not an artist.  If you want to pay me for these routines,      }
    { leave me e-mail to viper@ttcbbs.com.                                       }

    INTERFACE

    {$IFDEF DPMI}
    Uses WinApi;
    {$ENDIF}

    function LoadFont(FileName : string) : boolean;
    { Loads a 255-character font from FileName to font 0 and sets it on }

    procedure NormalFont;
    { Returns the system to the normal system 8x16 character font }

    procedure Set2FontMode;
    { Sets the VGA to allow 2 fonts simulataneously displayed }

    procedure SetNormalFontMode;
    { Returns the VGA to normal single font mode }

    var LoadBank : byte;                      { Default bank # to load font into }

    IMPLEMENTATION

    {$IFDEF DPMI}
    Type LongRec = record
           Selector, Segment : word;
         end;

         DoubleWord = record
           Lo, Hi : word;
         end;

         QuadrupleByte = record
           Lo, Hi, sLo, sHi : byte;
         end;

         TDPMIRegisters = record
           EDI, ESI, EBP, Reserved, EBX, EDX, ECX, EAX : longint;
           Flags, ES, DS, FS, GS, IP, CS, SP, SS : word;
         end;

      function XGlobalDosAlloc(Size : longint; var P : Pointer) : word;
      { Allocates memory in an area that DOS can access properly }
      var Long : longint;
      begin
        Long := GlobalDosAlloc(Size);
        P := Ptr(LongRec(Long).Selector, 0);
        XGlobalDosAlloc := LongRec(Long).Segment;
      end;

      function SimulateRealModeInt(IntNo : word;
                                   var Regs : TDPMIRegisters) : word; assembler;
      { Simulates a real mode interrupt }
      asm
        PUSH BP                                          { Save BP, just in case }
        MOV BX,IntNo                         { Move the Interrupt number into BX }
        XOR CX,CX                                                     { Clear CX }
        LES DI,Regs                              { Load the registers into ES:DI }
        MOV AX,$300                                { Set function number to 300h }
        INT $31                             { Call Interrupt 31h - DPMI Services }
        JC @Exit                                         { Jump to exit on carry }
        XOR AX,AX                                                     { Clear AX }
        @Exit:                                                      { Exit label }
        POP BP                                                      { Restore BP }
      end;

      function LoadFont(FileName : string) : boolean;
      { Loads a 255-character font from FileName to font 0 and sets it on }
      var FontFile : file;
          Font, Tmp : pointer;
          S, O, FontSize, RMSeg, DPSel : word;
          BPC : byte;
          Regs : TDPMIRegisters;
      begin
        {$I-}
        Assign(FontFile, FileName);                              { Open the file }
        Reset(FontFile, 1);                                           { Reset it }
        {$I+}
        If (IOResult <> 0) then                  { File opening was unsuccessful }
        begin
          LoadFont := FALSE;                                      { Return FALSE }
          Exit;                                               { Return to caller }
        end;
        FontSize := FileSize(FontFile);                      { Get the font size }
        FillChar(Regs, SizeOf(Regs), #0);             { Clear the DPMI registers }
        Regs.ES := XGlobalDosAlloc(FontSize, Font);            { Allocate memory }
        BlockRead(FontFile, Font^, FontSize);                    { Load the font }
        BPC := FontSize DIV 256;                 { Calculate bytes per character }
        Close(FontFile);                                   { Close the font file }
        DoubleWord(Regs.EBP).Hi := Regs.ES;       { Load font address into ES:BP }
        QuadrupleByte(Regs.EAX).Hi := $11;                    { Set function $11 }
        QuadrupleByte(Regs.EAX).Lo := $10;                { Set sub-function $10 }
        QuadrupleByte(Regs.EBX).Hi := BPC;        { Set # of bytes per character }
        QuadrupleByte(Regs.EBX).Lo := LoadBank;           { Set font number to 0 }
        DoubleWord(Regs.ECX).Lo := $FF;               { # of chars to load = 256 }
        DoubleWord(Regs.EDX).Lo := $0;                     { Set start char to 0 }
        SimulateRealModeInt($10, Regs);                     { Call the interrupt }
        GlobalDosFree(LongRec(Font).Selector);              { Free up the memory }
        LoadFont := TRUE;                   { Return TRUE - function successful! }
      end;
    {$ENDIF}

    {$IFDEF MSDOS}
      function LoadFont(FileName : string) : boolean;
      { Loads a 255-character font from FileName to font 0 and sets it on }
      var FontFile : file;
          Font, Tmp : pointer;
          S, O, FontSize, RMSeg, DPSel : word;
          BPC : byte;
      begin
        {$I-}
        Assign(FontFile, FileName);                              { Open the file }
        Reset(FontFile, 1);                                           { Reset it }
        {$I+}
        If (IOResult <> 0) then                  { File opening was unsuccessful }
        begin
          LoadFont := FALSE;                                      { Return FALSE }
          Exit;                                               { Return to caller }
        end;
        FontSize := FileSize(FontFile);                      { Get the font size }
        GetMem(Font, FontSize);                       { Allocate memory for font }
        BlockRead(FontFile, Font^, FontSize);                    { Load the font }
        BPC := FontSize DIV 256;                 { Calculate bytes per character }
        Close(FontFile);                                   { Close the font file }
        S := Seg(Font^);                                   { Get segment of font }
        O := Ofs(Font^);                                    { Get offset of font }
        asm
          PUSH BP                                                      { Save BP }
          MOV AL,$10                                      { Set sub-function $10 }
          MOV AH,$11                                          { Set function $11 }
          MOV BH,BPC                              { Set # of bytes per character }
          MOV BL,LoadBank                                   { Set font # to load }
          MOV CX,$FF                                    { Set # of chars to load }
          MOV DX,$0                           { Set start of load to character 0 }
          MOV ES,S                                { Load segment of font to load }
          MOV BP,O                                 { Load offset of font to load }
          INT $10                                      { Call BIOS Interrupt 10h }
          POP BP                                                    { Restore BP }
        end;
        FreeMem(Font, FontSize);                      { Release allocated memory }
        LoadFont := TRUE;                   { Return TRUE - function successful! }
      end;
    {$ENDIF}

      procedure Set2FontMode; assembler;
      { Puts the VGA into double-font mode.  The first font should be contained
        in bank 0, and the second in bank 6. }
      asm
        MOV AL,$03                                  { Set register offset to 03h }
        MOV DX,$3C4                                    { Set output port to 3C4h }
        OUT DX,AL                                  { Send our command to the VGA }
        INC DX                           { Increment port to 3C5h, the data port }
        MOV AL,$12                                { Put our 'magic byte' into AL }
        OUT DX,AL                             { Send the 'magic byte' to the VGA }
      end;

      procedure SetNormalFontMode; assembler;
      { Puts the VGA back into normal single-font mode. }
      asm
        MOV AL,$03                                  { Set register offset to 03h }
        MOV DX,$3C4                                    { Set output port to 3C4h }
        OUT DX,AL                                  { Send the command to the VGA }
        INC DX                           { Increment port to 3C5h, the data port }
        MOV AL,$00                           { Put 00h into AL, all bets are off }
        OUT DX,AL                                  { Send our command to the VGA }
      end;

      procedure NormalFont; assembler;
      { Returns the system to the normal system 8x16 character font }
      asm
        MOV AL,$04                                        { Set sub-function 04h }
        MOV AH,$11                                            { Set function 11h }
        MOV BL,$00                           { Select font 0 as the one to reset }
        INT $10                                        { Call BIOS Interrupt 10h }
      end;

    begin
      LoadBank := $00;                              { Set default load bank to 0 }
    end.

[Back to EGAVGA SWAG index] [Back to Main SWAG index] [Original]