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

{
> I'd like to do left & right screen scrolling, like the INT 10 functions
> for up & down screen scrolling.
}

procedure scroll_left(x1,y1,x2,y2:byte); assembler; 
 
asm 
   mov al,[y1]     {put y1 coordinate in al} 
   xor ah,ah       {set ah to 0 so we can deal with ax} 
   mov bx,80       {set bx=80} 
   mul bl          {multiply by bl, which equals 80 by the previous statement} 
   mov bl,[x1]     {put x1 coordinate in bl} 
   add ax,bx       {add the x1 coord. to y1*80 since there are 80 cols in a row
   shl ax,1        {multiply by 2 because info is stored as words, attribute 
                    in the high byte and the ASCII code for the character in 
                    the low byte} 
   mov si,ax       {all this calculated the offset in video memory of the
upper}                    {left-hand corner, which is put in si for later use} 
   mov al,[x2]     {put x2 coord. in al} 
   xor ah,ah       {set ah=0 so we can deal with ax} 
   sub al,bl       {subtract bl, which still contains x1, from al} 
   mov dx,ax       {put this in dx, this is the number of cols to copy at 
                    to move} 
   mov bx,80       {put 80 in bx} 
   sub bx,ax       {subtract this from ax, this value is the number of columns 
                    we will skip over to get to the next value} 
   shl bx,1        {multiply by 2 since the data is stored as words} 
   mov di,si       {set di=si, di points to the offset in memory to move the 
                    characters to, in this case to the left} 
   inc si          {add one to si} 
   inc si          {add one to si, this places si one character ahead of di} 
   mov cl,[y2]     {put y2 coord. in cl} 
   mov ch,[y1]     {put y1 coord. in ch} 
   sub cl,ch       {subtract ch from cl, this value is the number of lines to 
                    scroll} 
   xor ch,ch       {set ch=0 since we don't need that anymore, and because the 
                    the CPU will use all of cx to calculate the number of
lines}    inc cx          {add one to cx because the subtraction only counts
one of                     the y-coords., this accounts for the other} 
   push ds         {save the ds register, which points to the data segment} 
   mov ax,0b800h   {put $b800, the video segment for 80x25 text mode on color 
                    monitors in ax, if the mode you are using has its video 
                    segment different from $b800, put the other value here} 
   mov es,ax       {put ax into es because one cannot move a value into a 
                    segment register, nor can one move one segment register 
                    into another} 
   mov ds,ax       {put ax in ds} 
   cld             {clear direction flag so we will write forward in memory} 
@copyloopl:        {this loops scrolls one line from x1 to x2 left one space}
   push cx         {save cx (number of lines to do)}
   mov cx,dx       {put dx (number of cols to scroll) in cx}
   rep movsw       {movsw moves a word from ds:si to es:di, the first register
                    being the segment in memory and the second the offset, rep
                    repeats the following instruction, in this case movsw, the
                    number of times in cx}
   mov [WORD PTR ds:si-2],0720h  {this puts a word with the value $0720 at
                                  ds:si-2, this puts a space with attribute
                                  lightgray on black at the beginning of the
                                  line, to change the character output,
                                  replace the 20 part with the hex number
                                  for the character, to change the color,
                                  change the 07 to the hex number for the
                                  attribute you want}
   pop cx          {restores cx from where we saved it earlier}
   add si,bx       {adds bx to si to make get ready to do the next line}
   add di,bx       {do the same for di}
   loop @copyloopl {loop loops to the label after it cx number of times}
   pop ds          {restore ds from where we saved it earlier}
end;


procedure scroll_right(x1,y1,x2,y2:byte); assembler; 
 
asm 
   mov al,[y1]     {put y1 into al} 
   xor ah,ah       {set ah to 0 so we can work with ax} 
   mov bx,80       {set bx=80} 
   mul bl          {mulitiply ax by bl} 
   mov bl,[x2]     {put x2 in bl} 
   add ax,bx       {add ax to bx} 
   shl ax,1        {multiply ax by 2 since data stored as words} 
   mov si,ax       {set si (source index) equal to ax} 
   mov al,[x1]     {put x1 into al} 
   xor ah,ah       {set ah=0} 
   sub bl,al       {subtract bl from al to get number of characters to scroll} 
   xchg ax,bx      {switch ax with bx} 
   mov dx,ax       {put ax (# of cols to scroll) in dx} 
   mov bx,ax       {put ax in bx} 
   shl bx,1        {multiply bx by 2 since dealing with words} 
   add bx,0a0h     {add $00A0 to bx, this is the number of bytes in one row 
                    of data, the reason being that in scroll_left we wrote 
                    forward in video memory, in scroll_right we have to write 
                    backward since otherwise we would destroy the data we were 
                    scrolling and fill the window with the first row of 
                    characters.  When we add this to si and di as in 
                    scroll_left, the # of cols part will take si and di back 
                    to where they started, and the $00a0 part will send them 
                    down one line} 
   mov di,si       {set di = si} 
   dec si          {decrement si because si needs to be behind di one 
                    character, since we are going backwards, si will be 
                    "ahead" of di which is how we keep from losing data} 
   dec si          {decrement si again since we are dealing with words} 
   mov cl,[y2]     {put y2 in cl} 
   mov ch,[y1]     {put y1 in ch} 
   sub cl,ch       {subtract ch (y1) from cl (y2) to get # or rows} 
   xor ch,ch       {clear ch since CPU uses all of cx} 
   inc cx          {increment cx to include both y-coords.} 
   push ds         {save ds so your program want lose its data segment, 
                    which would be REALLY bad} 
   mov ax,0b800h   {set ax = $B800, video memory segment} 
   mov es,ax       {set es = ax} 
   mov ds,ax       {set ds = ax} 
   std             {set direction flag since we want to go backwards in 
                    memory this time} 
@copyloopr:        {label for loop that scrolls one line right}
   push cx         {save cx}
   mov cx,dx       {put dx (#of cols) in cx so the rep instruction will
                    repeat the right number of times}
   rep movsw       {scroll one line right}
   mov [WORD PTR ds:si+2],0720h {Put a space in the character at col x1,
                                 ds:si points to col x1+1 at the end of the
                                 movsw stuff, so ds:si+2 = col x1}
   pop cx          {restore cx from where it was saved earlier}
   add si,bx       {add bx to si to send si to the next line}
   add di,bx       {ditto for di}
   loop @copyloopr {loop back to @copyloopr to do the next line until done}
   pop ds          {restore ds so your program will know where all its data
                    is}
end;

{
These procedures scroll the text in the window with the upper righthand
corner being (x1,y1) and the lower lefthand corner being (x1,y2).  The text
will not scroll outside of the window and the empty columns will be filled
with spaces with an attribute of lightgray on black.  To change what
character and color to put in the new columns, determine the hex number
for the character and color you want, then put the color byte in front of
the character byte and replace the 0720h with it.  For example, to select
character $20 with a color of $04, change the 0720h to 0420h like so:

   mov [WORD PTR ds:si+2],0420h  (in scroll_right)
      or
   mov [WORD PTR ds:si-2],0420h  (in scroll_left)

these procs simply copy chunks of video memory.  One thing that might help
understand the value for bx and other stuff: the movsw copys the word from
ds:si to es:di, then if the direction flag is clear, it adds 2 to si and to
di, if the direction flag is set, it subtracts 2 from si and di.
}

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