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.