[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]