{********************************************************************** * SoftScrp : Demonstrates soft scrolling on EGA and VGA cards. * **-------------------------------------------------------------------** * Author : Michael Tischer * * Developed on : 01/23/90 * * Last update : 02/20/92 * **********************************************************************} program SoftScrp; uses dos, { Add units } crt; const SLOW = 1; { Speed constant for ShowScrlText() } MEDIUM = 2; FAST = 3; const PCOLR = $5E; { Yellow from lilac palette } PCOLR1 = $5F; { White from lilac palette } CWIDTH = 8; { Character width in pixels } CHEIGHT = 14; { Character height in scan lines } COLUMNS = 216; { Columns per row in video RAM } BANDSIZE = 10800; { Band size } BANDNUM = 3; { Number of bands } MAXLEN = 61; { Maximum number of characters } STARTR = 6; { Starting character row on screen } CrtAttr = $3C0; { CRT attribute controller register } CrtStatus = $3da; { Status port } CrtAdr = $3d4; { Monitor address port } type VRAM = array[1..BANDNUM,1..25,1..COLUMNS] of word; { Video RAM } VPTR = ^VRAM; { Pointer to video RAM } var vp : vptr; { Pointer to video RAM } type CRDTYPE = ( EGA, VGA, NEITHERNOR ); { Video card type } procedure CLI; inline( $FA ); { Disable interrupts } procedure STI; inline( $FB ); { Enable interrupts } {********************************************************************** * SetOrigin : Specifies the visible part of video RAM for * * programming the video controller. * **-------------------------------------------------------------------** * Input : BAND = Number of band to be displayed (1-5) * * COLUMN, = Number of columns and rows displayed in the * * SCROW upper-left corner of the screen (origin=0/0) * * PIXX, = Pixel offsets * * PIXY * **********************************************************************} procedure SetOrigin( band, column, scrow, pixx, pixy : byte ); var offset : integer; { Offset of video RAM start } ch : char; begin offset := ( BANDSIZE div 2 ) * (band-1) + scrow * COLUMNS + column; {-- Execute vertical rescan and wait for end -----------------------} repeat until port[CrtStatus] and 8 = 8; repeat until port[CrtStatus] and 8 = 0; {-- Write offset for start of video RAM to registers 0CH and 0DH, } {-- after ensuring that next screen layout is valid } CLI; { Disable interrupts } portw[ CrtAdr ] := hi( offset ) shl 8 + $0c; portw[ CrtAdr ] := lo( offset ) shl 8 + $0d; STI; {-- While waiting for next rescan, write new -------------------} {-- pixel offset and set up new starting address -------------------} repeat until port[CrtStatus] and 8 = 8; {-- Write pixel offsets in register 08H or -----------------------} {-- register 13H of the attribute controller -----------------------} CLI; portw[ CrtAdr ] := pixy shl 8 + $08; port[ CrtAttr ] := $13 or $20; { Access attribute } port[ CrtAttr ] := pixx; { controller by bytes } STI; { Enable interrupts } { ch := readkey; } end; {********************************************************************** * PrintChar : Creates a character within the visible range of * * video RAM. * **-------------------------------------------------------------------** * Input : THECHAR = Character to be created * * BAND = Band number (0-4) * * COLUMN = Column in video RAM at which the column * * should begin * * Info : The character can be moved in the visible range of * * the screen by calling SmoothLeft. * * The character is created from a 14x8 matrix, based on * * the EGA/VGA ROM font. * **********************************************************************} procedure PrintChar( thechar : char; band, column : byte ); type FDEF = array[0..255,1..14] of byte; { Font array } TPTR = ^FDEF; { Pointer to font } var Regs : Registers; { Registers for interrupt call } ch : char; { Character pixels } i, k, { Loop counter } BMask : byte; { Bit mask for character design } const fptr : TPTR = NIL; { Pointer to ROM font } begin if fptr = NIL then { Pointer to font already set? } begin { No } Regs.AH := $11; { Call video BIOS function } Regs.AL := $30; { 11H, sub-function 30H } Regs.BH := 2; { Get pointer to 8x14 font } intr( $10, Regs ); fptr := ptr( Regs.ES, Regs.BP ); { Set pointers } end; {-- Generate character line by line --------------------------------} for i := 1 to CHEIGHT do begin BMask := fptr^[ord(thechar),i]; { Get bit pattern for one line } for k := 1 to CWIDTH do { Set individual bits } begin if BMask and 128 = 128 then ch := #219 { Set pixel } else ch := #32; { Unset pixel } vp^[band, STARTR+i, (column-1)*CWIDTH+k] := ord(ch) + PCOLR shl 8; BMask := BMask shl 1; { Process next bit } end; end; end; {********************************************************************** * IsEgaVga : Determines whether an EGA or a VGA card is installed. * **-------------------------------------------------------------------** * Input : None * * Output : EGA, VGA or NEITHERNOR * **********************************************************************} function IsEgaVga : CRDTYPE; var Regs : Registers; { Processor registers for interrupt call } begin Regs.AX := $1a00; { Function 1AH applies to VGA only } Intr( $10, Regs ); if ( Regs.AL = $1a ) then { Is the function available? } IsEgaVga := VGA else begin Regs.ah := $12; { Call function 12H, } Regs.bl := $10; { sub-function 10H } intr($10, Regs); { Call video BIOS } if ( Regs.bl <> $10 ) then IsEgaVga := EGA else IsEgaVga := NEITHERNOR; end; end; {********************************************************************** * ShowScrstext : Scrolls text on the screen. * **-------------------------------------------------------------------** * Input : STEXT = String of text for scrolling * * SPEED = Scroll speed (see SLOW, FAST constants) * * VC = Video card type (EGA or VGA) * **********************************************************************} procedure ShowScrlText( stext : string; speed : byte; vc : crdtype ); var band, { Current band } column, { Current column } index, { Index to string to be created } len, { Length of text to be displayed } i, k : integer; { Loop counter } step, { Increment } uplimit : byte; { Number of loop executions } Regs : Registers; { Processor registers for interrupt call } const steptable : array [EGA..VGA,1..3,1..10] of byte = ( ( { EGA step values } ( 0, 1, 2, 3, 4, 5, 6, 7, 255, 255 ), ( 0, 2, 4, 6, 255, 255, 255, 255, 255, 255 ), ( 0, 4, 255, 255, 255, 255, 255, 255, 255, 255 ) ), ( { VGA step values } ( 8, 0, 1, 2, 3, 4, 5, 6, 7, 255 ), ( 8, 2, 5, 255, 255, 255, 255, 255, 255, 255 ), ( 8, 3, 255, 255, 255, 255, 255, 255, 255, 255 ) ) ); begin vp := ptr( $B800, $0000 ); { Set pointer to video RAM } {-- Fill entire video RAM with blank spaces ------------------------} for index := 1 to BANDNUM do for i := 1 to 25 do for k := 1 to COLUMNS do vp^[ index, i, k ] := PCOLR shl 8 + 32; {-- Draw horizontal bands ------------------------------------------} for k := 1 to BANDNUM do for i := 1 to COLUMNS do begin vp^[ k, STARTR-2, i ] := ord('Í') + PCOLR1 shl 8; vp^[ k, STARTR + CHEIGHT + 2, i ] := ord('Í') + PCOLR1 shl 8; end; gotoxy( 1, 1 ); { Remove cursor when scrolling the screen } {-- Set screen border color ----------------------------------------} Regs.AH := $10; { Function number: Set screen border color } Regs.AL := $01; { Sub-function number } Regs.BH := PCOLR shr 4; { border color } intr( $10, Regs ); {-- Place number of columns per row in video RAM from COLUMNS ------} portw[ CrtAdr ] := ( COLUMNS div 2 ) shl 8 + $13; {-- Place scrolling text in video RAM ------------------------------} if length( stext ) > MAXLEN then len := MAXLEN else len := length( stext ); column := 1; band := 1; index := 1; while ( index <= len ) do begin PrintChar( stext[index], band, column ); { Draw characters } inc( column ); { in next column } inc( index ); { Process next character } if ( column > ( COLUMNS div CWIDTH ) ) then { Band change? } begin { Yes } column := 1; { Restart in column 1 } inc( band ); { Next band } dec( index, ( 80 div CWIDTH ) ); { Character one page back } end end; {-- Move scroll text from right to left on the screen --------------} column := 0; { Start in column 0 with band 1 } band := 1; for i := 1 to (len-( 80 div CWIDTH )) * CWIDTH do begin k := 1; while ( steptable[vc, speed, k] <> 255 ) do begin SetOrigin( band, column, 0, steptable[vc, speed, k], 0 ); inc( k ); end; inc( column ); { Next column } if ( column = COLUMNS - 80 ) then { Band change? } begin { Yes } column := 0; { Restart in column 0 } inc( band ); { Increment band } end end; {-- Revert to 80 characters per row in video RAM -------------------} portw[ CrtAdr ] := 40 shl 8 + $13; {-- Reset border colors --------------------------------------------} Regs.AH := $10; { Function number: Set border color } Regs.AL := $01; { Sub-function number } Regs.BH := 0; { Black border } intr( $10, Regs ); if ( vc = EGA ) then { Revert to default } SetOrigin( 1, 0, 0, 0, 0 ) { for EGA } else SetOrigin( 1, 0, 0, 8, 0 ); { for VGA } ClrScr; end; {*********************************************************************} {** M A I N P R O G R A M **} {*********************************************************************} var ch : char; i : integer; vc : crdtype; begin vc := IsEgaVga; { Get video card type } if vc = EGA then halt; if ( vc = NEITHERNOR ) then begin writeln( 'SOFSCRP - (c) 1992 by Michael Tischer' ); writeln( #13#10'Warning: No EGA or VGA card found'); end else ShowScrlText( '++ PC Intern...........Published by Abacus ++'+ ' ', FAST, vc ); while keypressed do ch := readkey; end.