program mirror_text; {$G+,X+} { MIRROR2.PAS -- Demonstration of 512-character set application. Written by Scott F. Earnest -- Donated to Public Domain current e-mail address: sinykal@cyberspace.org Thanks to Osmo Ronkanen (ronkanen@cc.helsinki.fi) for pointing out why I couldn't get the 9x16 supplemental font set to work correctly. This is a demonstration of one application of the 512-character font. It loads a copy of the VGA 9x16 font into memory, modifies it and uses it to display a 512-character set on screen. Notes: - 512-character fonts are also possible in EGA, but this code is set to support VGA only. - Originally it was my understanding that when using 512 characters, blink or bright backgrounds were disabled. Now that I've played with this, I see this isn't true; character set is chosen with bit 3, not bit 7. Blinking is still possible. Though I haven't tested it, bright backrounds will very likely not work, since color plane 3 must be disabled. - This is written for TP7 and modified to compile under TP6. Earlier versions may need extensive modifications in order to get this to compile. - Corrected in this version: This now correctly loads the entire 9x16 character set, so the mirrored font is now identical to original font (except, of course, for the fact that it's been rotated around). - This is very simple and could use lots of improvements, but I've tested it and it DOES work on VGA. There's plenty of room for improvement, and I think I've commented it well enough. Please pass this around. It would also be a VERY useful addition to SWAG. Use this freely, but if you use this or modify it, please give me due credit, thanks! } {$IFNDEF VER60} {$IFNDEF VER70} STOP: This requires TP 6.0 or TP/BP 7.0x to compile! {$ENDIF} {$ENDIF} uses crt; {$IFDEF VER60} const SegB800 = $b800; {$ENDIF} const CHARSIZE = 4096; {Size of memory needed to store 9x16 font set} type {structures for storing/accessing a font in memory} Tcharmap = array[0..CHARSIZE-1] of byte; Pcharmap = ^Tcharmap; Pbyte = ^byte; procedure reverse_set (var m : Tcharmap); { This function takes a character set and rotates in 180 degrees. The result is a cool upside-down character set. } var ch : array [0..15] of byte; b, c : byte; function reverse_byte (b : byte) : byte; assembler; asm {setup:} mov cx,0008h {iterate shift 8 times} mov ah,[b] {number to be reversed} xor al,al {clear AL to receive shifted value} @1: rcr ah,1 {shift lowest bit of AH into CF} rcl al,1 {shift CF into lowest bit of AL} loop @1 end; procedure byteswap (var a, b : byte); var c : byte; begin c := a; a := b; b := c; end; begin for c := 0 to 255 do begin move (m[c*16],ch,16); {get character into temporary array} for b := 0 to 7 do begin {flip the character in array ch[]} byteswap (ch[b],ch[15-b]); ch[b] := reverse_byte (ch[b]); ch[15-b] := reverse_byte(ch[15-b]); end; move (ch,m[c*16],16); {write modified char map back to font map} end; end; function getcharsetptr (setnum : byte) : pointer; assembler; { This function uses the video BIOS to return the address of one of the character sets in memory. Those sets are: 0 -- int 1fh, user 8x8 upper 128 characters 1 -- int 43h, user 8x8 lower/8x14 2 -- ROM 8x14 3 -- ROM 8x8 lower 4 -- ROM 8x8 upper 5 -- ROM 9x14 supplement 6 -- ROM 8x16 7 -- ROM 9x16 supplement Other information is returned in CX and DL, however these are ingored by this function. } asm push bp mov bh,[setnum] mov ax,1130h int 10h mov dx,es mov ax,bp pop bp end; procedure Get9x16font (const base : PCharMap); { Loads supplemental font over allocated 8x16 font. My own implementation, but based on code written by Osmo Ronkanen (ronkanen@cc.helsinki.fi). This procedure was rewritten to eliminate some unneeded structures and reduce memory requirements. } var s, w : Pbyte; c : byte; begin s := getcharsetptr (7); while s^<>0 do begin w := Pbyte(base); inc (w,s^*16); inc (s); move (s^,w^,16); inc (s,16); end; end; procedure installVGAfont (p : Pcharmap; block : byte); assembler; { Install a user font. 'p' is the pointer to the character map in memory, and block is the font number to write. For VGA, valid values are 0-7. Note: This procedure is hard-coded to write a 16-scanline-per-pixel character set. } asm push bp mov ax,1110h mov bl,[block] mov bh,10h les bp,[p] mov cx,0100h mov dx,0000h int 10h pop bp end; procedure set512characters; assembler; { This sets video to use two chained character sets. In this case, sets 0 and 1 are set to be used. This can be rewritten to accept two values, which represent which 2 of the 8 sets to use. } asm {step 1: disable color plane 3 -- keeps set B from always being bright} mov ax,1000h mov bl,12h mov bh,07h int 10h {step 2: enable set A and B -- A=0 (the normal set) B=1 (modified set)} mov ax,1103h mov bl,00000100b int 10h end; procedure reset256characters; assembler; { This performs the opposite of above to return to a single 256 character set. } asm mov ax,1000h mov bl,12h mov bh,0fh int 10h mov ax,1103h mov bl,00h int 10h end; procedure waitkey; begin while keypressed do readkey; repeat until keypressed; while keypressed do readkey; end; procedure writechar (x, y : byte; ch : char; attr : byte); { This just writes a single character to video memory in a specific attribute. } var m : word; begin m := (pred(y)*80+pred(x))*2; mem[SegB800:m] := ord(ch); mem[SegB800:succ(m)] := attr; end; var mirrorfont : Pcharmap; fp : pointer; xp, yp : byte; begin {allocate memory for modified set} new (mirrorfont); {load font into memory} fp := getcharsetptr (6); move (fp^,mirrorfont^,CHARSIZE); Get9x16font (mirrorfont); {modify the character maps} reverse_set (mirrorfont^); {draw up a demonstration on the screen} textattr := $17; clrscr; textattr := $1f; gotoxy (26,4); writeln ('!ereht olleH -- tset a si sihT'); textattr := $17; gotoxy (26,5); writeln ('This is a test -- Hello there!'); for yp := 0 to 7 do for xp := 0 to 31 do begin writechar (6+xp,10+yp,chr(yp*32+xp),$17); writechar (75-xp,17-yp,chr(yp*32+xp),$1f); end; gotoxy (1,22); writeln ('This is before . . .'); {wait for a keypress} waitkey; {install the font} installVGAfont (mirrorfont,1); set512characters; {now update the banner message and wait once more} gotoxy (1,22); textattr := $1f; writeln ('!retfa si siht dna . . .'); waitkey; {reset fonts and wait once more} reset256characters; gotoxy (1,22); textattr := $17; writeln ('And now back to normal! '); waitkey; {clean up memory and reset the video system} dispose (mirrorfont); asm mov ax,0003h; int 10h; end; end. -- Scott F. Earnest | We now return you to our regularly scheduled | sinykal@cyberspace.org | chaos and mayhem. . . . |