;
; *** Listing 5.1 ***
;
; Program to illustrate one use of write mode 2 of the VGA and EGA by
; animating the image of an "A" drawn by copying it from a chunky
; bit-map in system memory to a planar bit-map in VGA or EGA memory.
;
; Assembled with TASM 4.0, linked with TLINK 6.10
; Checked by Jim Mischel 11/21/94
;
Stack   segment para stack 'STACK'
        db      512 dup(0)
Stack   ends

SCREEN_WIDTH_IN_BYTES   	equ     80
DISPLAY_MEMORY_SEGMENT  	equ     0a000h
SC_INDEX        		equ     3c4h    ;Sequence Controller Index register
MAP_MASK        		equ     2       ;index of Map Mask register
GC_INDEX        		equ     03ceh   ;Graphics Controller Index reg
GRAPHICS_MODE   		equ     5       ;index of Graphics Mode reg
BIT_MASK			equ     8       ;index of Bit Mask reg

Data    segment para common 'DATA'
;
; Current location of "A" as it is animated across the screen.
;
CurrentX        dw      ?
CurrentY        dw      ?
RemainingLength dw      ?
;
; Chunky bit-map image of a yellow "A" on a bright blue background
;
AImage          label   byte
                dw      13, 13          ;width, height in pixels
                db      000h, 000h, 000h, 000h, 000h, 000h, 000h
                db      009h, 099h, 099h, 099h, 099h, 099h, 000h
                db      009h, 099h, 099h, 099h, 099h, 099h, 000h
                db      009h, 099h, 099h, 0e9h, 099h, 099h, 000h
                db      009h, 099h, 09eh, 0eeh, 099h, 099h, 000h
                db      009h, 099h, 0eeh, 09eh, 0e9h, 099h, 000h
                db      009h, 09eh, 0e9h, 099h, 0eeh, 099h, 000h
                db      009h, 09eh, 0eeh, 0eeh, 0eeh, 099h, 000h
                db      009h, 09eh, 0e9h, 099h, 0eeh, 099h, 000h
                db      009h, 09eh, 0e9h, 099h, 0eeh, 099h, 000h
                db      009h, 099h, 099h, 099h, 099h, 099h, 000h
                db      009h, 099h, 099h, 099h, 099h, 099h, 000h
                db      000h, 000h, 000h, 000h, 000h, 000h, 000h
Data    ends

Code    segment para public 'CODE'
        assume  cs:Code, ds:Data
Start   proc    near
        mov     ax,Data
        mov     ds,ax
        mov     ax,10h
        int     10h             		;select video mode 10h (640x350)
;
; Prepare for animation.
;
        mov     [CurrentX],0
        mov     [CurrentY],200
        mov     [RemainingLength],600   	;move 600 times
;
; Animate, repeating RemainingLength times. It's unnecessary to erase
; the old image, since the one pixel of blank fringe around the image
; erases the part of the old image not overlapped by the new image.
;
AnimationLoop:
        mov     bx,[CurrentX]
        mov     cx,[CurrentY]
        mov     si,offset AImage
        call    DrawFromChunkyBitmap    	;draw the "A" image
        inc     [CurrentX]              	;move one pixel to the right

        mov     cx,0                    	;delay so we don't move the
DelayLoop:                              	; image too fast; adjust as
                                        	; needed
        loop    DelayLoop

        dec     [RemainingLength]
        jnz     AnimationLoop
;
; Wait for a key before returning to text mode and ending.
;
        mov     ah,01h
        int     21h
        mov     ax,03h
        int     10h
        mov     ah,4ch
        int     21h
Start   endp
;
; Draw an image stored in a chunky-bit map into planar VGA/EGA memory
; at the specified location.
;
; Input:
;       BX = X screen location at which to draw the upper left corner
;               of the image
;       CX = Y screen location at which to draw the upper left corner
;               of the image
;       DS:SI = pointer to chunky image to draw, as follows:
;               word at 0: width of image, in pixels
;               word at 2: height of image, in pixels
;               byte at 4: msb/lsb = first & second chunky pixels,
;                       repeating for the remainder of the scan line
;                       of the image, then for all scan lines. Images
;                       with odd widths have an unused null nibble
;                       padding each scan line out to a byte width
;
; AX, BX, CX, DX, SI, DI, ES destroyed.
;
DrawFromChunkyBitmap    proc    near
        cld
;
; Select write mode 2.
;
        mov     dx,GC_INDEX
        mov     al,GRAPHICS_MODE
        out     dx,al
        inc     dx
        mov     al,02h
        out     dx,al
;
; Enable writes to all 4 planes.
;
        mov     dx,SC_INDEX
        mov     al,MAP_MASK
        out     dx,al
        inc     dx
        mov     al,0fh
        out     dx,al
;
; Point ES:DI to the display memory byte in which the first pixel
; of the image goes, with AH set up as the bit mask to access that
; pixel within the addressed byte.
;
        mov     ax,SCREEN_WIDTH_IN_BYTES        
        mul     cx              		;offset of start of top scan line
        mov     di,ax
        mov     cl,bl
        and     cl,111b
        mov     ah,80h          		;set AH to the bit mask for the
        shr     ah,cl           		; initial pixel
        shr     bx,1
        shr     bx,1
        shr     bx,1            		;X in bytes
        add     di,bx           		;offset of upper left byte of image
        mov     bx,DISPLAY_MEMORY_SEGMENT
        mov     es,bx           		;ES:DI points to the byte at which the
                                		; upper left of the image goes
;
; Get the width and height of the image.
;
        mov     cx,[si]         	;get the width
        inc     si
        inc     si
        mov     bx,[si]      	;get the height
        inc     si
        inc     si
        mov     dx,GC_INDEX
        mov     al,BIT_MASK
        out     dx,al           	;leave the GC Index register pointing
        inc     dx              	; to the Bit Mask register
RowLoop:

        push    ax              	;preserve the left column's bit mask
        push    cx              	;preserve the width
        push    di              	;preserve the destination offset

ColumnLoop:
        mov     al,ah
        out     dx,al           	;set the bit mask to draw this pixel
        mov     al,es:[di]      	;load the latches
        mov     al,[si]         	;get the next two chunky pixels
        shr     al,1
        shr     al,1
        shr     al,1
        shr     al,1            	;move the first pixel into the lsb
        stosb                   	;draw the first pixel
        ror     ah,1            	;move mask to next pixel position
        jc      CheckMorePixels 	;is next pixel in the adjacent byte?
        dec     di              	;no

CheckMorePixels:
        dec     cx              	;see if there are any more pixels
        jz      AdvanceToNextScanLine ; across in image
        mov     al,ah
        out     dx,al           	;set the bit mask to draw this pixel
        mov     al,es:[di]      	;load the latches
        lodsb                   	;get the same two chunky pixels again
                                	; and advance pointer to the next
                                	; two pixels
        stosb                   	;draw the second of the two pixels
        ror     ah,1            	;move mask to next pixel position
        jc      CheckMorePixels2 ;is next pixel in the adjacent byte?
        dec     di              	;no

CheckMorePixels2:
        loop    ColumnLoop      	;see if there are any more pixels
                                	; across in the image
        jmp     short CheckMoreScanLines

AdvanceToNextScanLine:
        inc     si              ;advance to the start of the next
                                ; scan line in the image

CheckMoreScanLines:
        pop     di              ;get back the destination offset
        pop     cx              ;get back the width
        pop     ax              ;get back the left column's bit mask
        add     di,SCREEN_WIDTH_IN_BYTES
                                ;point to the start of the next scan
                                ; line of the image
        dec     bx              ;see if there are any more scan lines
        jnz     RowLoop         ; in the image
        ret
DrawFromChunkyBitmap    endp
Code    ends
        end     Start

