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

{
> Does anybody know if it is possible to accomplish a smooth-text scroller
> (like in the old c64 dayz) in text mode? If so, please let me know and

> Well, it's impossible, you'll have to switch to a graphic mode.

        No, it's possible in text mode... it's just a pain in the
arse.  I know of two ways.  The first is to use an alternate
character set (the EGA can have 2 on screen at once, the VGA can
have 4).  You use one character set as normal text, and use the
other as a pseudo-graphics window.  Put the text you need to
scroll in the window and move (copy) it a pixel at a time.  The
second way is to use the 8253 timer to time the scanline.  When
the scanline gets to the portion of the screen you want, turn off
v-retrace, set v-retrace on the next scan line, and set the
horizontal pel pan to the value you need for your smooth pan.
When the card gets to the line that the v-retrace would occur, it
resets the pan but doesn't retrace because you turned it off.
After this, reset the registers you changed back to their default
values so the card builds the screen correctly.  This is done on
EVERY screen build.  Needless to say, the pseudo-graphics window
version is easier so that's the one I used to program the example
that follows.
}

Program SmoothTextScrollExample1;

{==============================================

       Smooth Scroll In Text Mode Example
           Programmed by David Dahl
                   12/21/93
   This program and source are PUBLIC DOMAIN

 ----------------------------------------------

   This example uses a second font to scroll
   the text.  The font definition is changed
   to make the text scroll.  This program
   requires VGA.

 ==============================================}

Uses  CRT;

Type  FontDefType = Array[0..255, 0..31] of Byte;

Var   ScrollText : String;

      FontDef    : FontDefType;

Procedure SetCharWidthTo8; Assembler;
Asm
   { Change To 640 Horz Res }
   MOV DX, $3CC
   IN  AL, DX
   AND AL, Not(4 OR 8)
   MOV DX, $3C2
   OUT DX, AL

   { Turn Off Sequence Controller }
   MOV DX, $3C4
   MOV AL, 0
   OUT DX, AL
   MOV DX, $3C5
   MOV AL, 0
   OUT DX, AL

   { Reset Sequence Controller }
   MOV DX, $3C4
   MOV AL, 0
   OUT DX, AL
   MOV DX, $3C5
   MOV AL, 3
   OUT DX, AL

   { Switch To 8 Pixel Wide Fonts }
   MOV DX, $3C4
   MOV AL, 1
   OUT DX, AL
   MOV DX, $3C5
   IN  AL, DX
   OR  AL, 1
   OUT DX, AL

   { Turn Off Sequence Controller }
   MOV DX, $3C4
   MOV AL, 0
   OUT DX, AL
   MOV DX, $3C5
   MOV AL, 0
   OUT DX, AL

   { Reset Sequence Controller }
   MOV DX, $3C4
   MOV AL, 0
   OUT DX, AL
   MOV DX, $3C5
   MOV AL, 3
   OUT DX, AL

   { Center Screen }
   MOV DX, $3DA
   IN  AL, DX
   MOV DX, $3C0
   MOV AL, $13 OR 32
   OUT DX, AL
   MOV AL, 0
   OUT DX, AL
End;

Procedure WriteScrollTextCharacters(Row : Byte);
Var Counter : Word;
Begin
     { Set Fonts 0 & 1 }
     ASM
        MOV BL, 4
        MOV AX, $1103
        INT $10
     END;

     { Write Characters }
     For Counter := 0 to 79 do
     Begin
          { Set Characters }

          MEM[$B800:(80*2)*Row+(Counter*2)]   := Counter;
          { Set Attribute To Secondary Font }
          MEM[$B800:(80*2)*Row+(Counter*2)+1] :=
             MEM[$B800:(80*2)*Row+(Counter*2)+1] OR 8;

     End;

End;

Procedure FlushKeyBoardBuffer;
Var Key : Char;
Begin
     While KeyPressed do
           Key := ReadKey;
End;

Procedure SetAccessToFontMemory; Assembler;
ASM
   { Turn Off Sequence Controller }
   MOV DX, $3C4
   MOV AL, 0
   OUT DX, AL
   MOV DX, $3C5
   MOV AL, 1
   OUT DX, AL

   { Reset Sequence Controller }
   MOV DX, $3C4
   MOV AL, 0
   OUT DX, AL
   MOV DX, $3C5
   MOV AL, 3
   OUT DX, AL

   { Change From Odd/Even Addressing to Linear }
   MOV DX, $3C4
   MOV AL, 4
   OUT DX, AL
   MOV DX, $3C5
   MOV AL, 7
   OUT DX, AL

   { Switch Write Access To Plane 2 }
   MOV DX, $3C4
   MOV AL, 2
   OUT DX, AL
   MOV DX, $3C5
   MOV AL, 4
   OUT DX, AL

   { Set Read Map Reg To Plane 2 }
   MOV DX, $3CE
   MOV AL, 4
   OUT DX, AL
   MOV DX, $3CF
   MOV AL, 2
   OUT DX, AL

   { Set Graphics Mode Reg }
   MOV DX, $3CE
   MOV AL, 5
   OUT DX, AL
   MOV DX, $3CF
   MOV AL, 0
   OUT DX, AL

   { Set Misc. Reg }
   MOV DX, $3CE
   MOV AL, 6
   OUT DX, AL
   MOV DX, $3CF
   MOV AL, 12
   OUT DX, AL
End;

Procedure SetAccessToTextMemory; Assembler;
ASM
   { Turn Off Sequence Controller }
   MOV DX, $3C4
   MOV AL, 0
   OUT DX, AL
   MOV DX, $3C5
   MOV AL, 1
   OUT DX, AL

   { Reset Sequence Controller }
   MOV DX, $3C4
   MOV AL, 0
   OUT DX, AL
   MOV DX, $3C5
   MOV AL, 3
   OUT DX, AL

   { Change To Odd/Even Addressing }
   MOV DX, $3C4
   MOV AL, 4
   OUT DX, AL
   MOV DX, $3C5
   MOV AL, 3
   OUT DX, AL

   { Switch Write Access }
   MOV DX, $3C4
   MOV AL, 2
   OUT DX, AL
   MOV DX, $3C5
   MOV AL, 3  {?}
   OUT DX, AL

   { Set Read Map Reg }
   MOV DX, $3CE
   MOV AL, 4
   OUT DX, AL
   MOV DX, $3CF
   MOV AL, 0
   OUT DX, AL

   { Set Graphics Mode Reg }
   MOV DX, $3CE
   MOV AL, 5
   OUT DX, AL
   MOV DX, $3CF
   MOV AL, $10
   OUT DX, AL

   { Set Misc. Reg }
   MOV DX, $3CE
   MOV AL, 6
   OUT DX, AL
   MOV DX, $3CF
   MOV AL, 14
   OUT DX, AL
End;

Procedure MakeFontDefTable;
Var  CounterX,
     CounterY  : Word;
Begin
     SetAccessToFontMemory;

     For CounterY := 0 to 255 do
         For CounterX := 0 to 31 do
             FontDef[CounterY, CounterX] :=
                 MEM[$B800:(CounterY * 32)+CounterX];

     SetAccessToTextMemory;
End;

Procedure ClearSecondFontMemory;
Var Counter : Word;
Begin
     SetAccessToFontMemory;

     For Counter := 0 to 32 * 256 do
         MEM[$B800:$4000 + Counter] := 0;

     SetAccessToTextMemory;
End;

Procedure ScrollMessage;
Const CharCol  : Integer = 8;
      Counter  : Byte = 1;
      COUNTERY : Byte = 0;
      PWRTbl   : Array [0..7] of Byte = (1,2,4,8,16,32,64,128);
Begin
     SetAccessToFontMemory;

     ASM
        { Wait For Retrace }
        MOV DX, $3DA
        @RT:
         IN   AL, DX
         TEST AL, 8
        JZ @RT

        { Scroll Text One Pixel To The Left }
        MOV AX, $B800 + ($4000 / 16)
        MOV ES, AX
        MOV CX, 32
        @Row:
         MOV DI, (79 * 32) - 1
         ADD DI, CX
         SHL byte ptr ES:[DI], 1
         PUSHF
         SUB DI, 32
         POPF
         PUSH CX
         MOV CX, 79
         @Chrs:
          RCL byte ptr ES:[DI], 1
          PUSHF
          SUB DI, 32
          POPF
         Loop @Chrs
         POP CX
        Loop @Row
     END;

     If CharCol < 0
     Then

     Begin
          CharCol := 7;
          Inc(Counter);
     End
     Else
         Dec(CharCol);

     If Counter > Length(ScrollText)
     Then
         Counter := 1;

     { Write New Column Of Pixels }
     For CounterY := 0 to 31 do
     MEM[$B800:$4000 + (79 * 32) + CounterY] :=
         MEM[$B800:$4000 + (79 * 32) + CounterY] OR
          ((FontDef[Ord(ScrollText[Counter]), CounterY] AND PwrTbl[CharCol])
            SHR CharCol);

     SetAccessToTextMemory;
End;

Procedure TurnCursorOff; Assembler;
ASM
   MOV DX, $3D4
   MOV AL, $0A
   OUT DX, AL
   MOV DX, $3D5
   IN  AL, DX
   OR  AL, 32
   OUT DX, AL
End;

Procedure TurnCursorOn; Assembler;
ASM
   MOV DX, $3D4
   MOV AL, $0A
   OUT DX, AL
   MOV DX, $3D5
   IN  AL, DX
   AND AL, Not(32)
   OUT DX, AL
End;

Begin
     TextMode (C80);
     TurnCursorOff;
     SetCharWidthTo8;
     MakeFontDefTable;
     ClearSecondFontMemory;
     TextColor(Red);
     ClrScr;

     ScrollText := 'This program is one example of how a smooth '+
                   'scroll can be done in text mode.            ';

     WriteScrollTextCharacters(10);

     TextColor(Blue);
     GoToXY (26,10);
     Write  ('Text Mode Smooth Scroll Example');
     GoToXY (34,11);
     Write  ('By David Dahl');

     FlushKeyBoardBuffer;

     Repeat
           ScrollMessage;
     Until Keypressed;

     FlushKeyboardBuffer;

     TextMode (C80);
     TurnCursorOn;
End.

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