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

{
    With all the tonnes of absolutely NO help that the Pascal conferences
    provided me <in one day> I've managed to hack my VGA Font loading code
    to work properly in p-mode.

    It's quite a trick getting the DPMI servers to allocate memory under
    the one meg mark, but it is possible if you write a couple of routines
    like the ones below (or golly-gee, use those! :) ..

    Oh yeah - one other tip.  Those of you who use OpCrt, TpCrt, or maybe
    even plain CRT.  The ScreenHeight function will not return the correct
    value after a font change (if the change is a new line mode) unless you
    call ReInitCRT.

    Here's the code:
}
Unit LF;

{$IFDEF Windows}
  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                    }

{ 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! :)                                                       }

{ Restrictions:                                                              }

{ 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...)                                             }

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 }
{ !! This routine works fine under p-mode without modifications since it }
{    does no memory allocation of any kind. }

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;

... Viper: The offline mail reader for the best of us.
___ Viper v2.0 [0004] * Multi-part message, 1 of 3 *
---
 þ RoseMail 2.55á: NANet - Toronto Twilight (416)663-1103 - 7 Nodes
                                       
{SWAG=???.SWG,CHRIS LAUTENBACH,VGA Fonts, they work[2/3]}

  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 := $00;                { 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,$00                                        { 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 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
end.

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