; Program to illustrate the use of the Read Map register in read mode 0. ; Animates by copying a 16-color image from VGA memory to system memory, ; one plane at a time, then copying the image back to a new location ; in VGA memory. ; ; By Michael Abrash ; stack segment word stack 'STACK' db 512 dup (?) stack ends ; data segment word 'DATA' IMAGE_WIDTH EQU 4 ;in bytes IMAGE_HEIGHT EQU 32 ;in pixels LEFT_BOUND EQU 10 ;in bytes RIGHT_BOUND EQU 66 ;in bytes VGA_SEGMENT EQU 0a000h SCREEN_WIDTH EQU 80 ;in bytes SC_INDEX EQU 3c4h ;Sequence Controller Index register GC_INDEX EQU 3ceh ;Graphics Controller Index register MAP_MASK EQU 2 ;Map Mask register index in SC READ_MAP EQU 4 ;Read Map register index in GC ; ; Base pattern for 16-color image. ; PatternPlane0 label byte db 32 dup (0ffh,0ffh,0,0) PatternPlane1 label byte db 32 dup (0ffh,0,0ffh,0) PatternPlane2 label byte db 32 dup (0f0h,0f0h,0f0h,0f0h) PatternPlane3 label byte db 32 dup (0cch,0cch,0cch,0cch) ; ; Temporary storage for 16-color image during animation. ; ImagePlane0 db 32*4 dup (?) ImagePlane1 db 32*4 dup (?) ImagePlane2 db 32*4 dup (?) ImagePlane3 db 32*4 dup (?) ; ; Current image location & direction. ; ImageX dw 40 ;in bytes ImageY dw 100 ;in pixels ImageXDirection dw 1 ;in bytes data ends ; code segment word 'CODE' assume cs:code,ds:data Start proc near cld mov ax,data mov ds,ax ; ; Select graphics mode 10h. ; mov ax,10h int 10h ; ; Draw the initial image. ; mov si,offset PatternPlane0 call DrawImage ; ; Loop to animate by copying the image from VGA memory to system memory, ; erasing the image, and copying the image from system memory to a new ; location in VGA memory. Ends when a key is hit. ; AnimateLoop: ; ; Copy the image from VGA memory to system memory. ; mov di,offset ImagePlane0 call GetImage ; ; Clear the image from VGA memory. ; call EraseImage ; ; Advance the image X coordinate, reversing direction if either edge ; of the screen has been reached. ; mov ax,[ImageX] cmp ax,LEFT_BOUND jz ReverseDirection cmp ax,RIGHT_BOUND jnz SetNewX ReverseDirection: neg [ImageXDirection] SetNewX: add ax,[ImageXDirection] mov [ImageX],ax ; ; Draw the image by copying it from system memory to VGA memory. ; mov si,offset ImagePlane0 call DrawImage ; ; Slow things down a bit for visibility (adjust as needed). ; mov cx,0 DelayLoop: loop DelayLoop ; ; See if a key has been hit, ending the program. ; mov ah,1 int 16h jz AnimateLoop ; ; Clear the key, return to text mode, and return to DOS. ; sub ah,ah int 16h mov ax,3 int 10h mov ah,4ch int 21h Start endp ; ; Draws the image at offset DS:SI to the current image location in ; VGA memory. ; DrawImage proc near mov ax,VGA_SEGMENT mov es,ax call GetImageOffset ;ES:DI is the destination address for the ; image in VGA memory mov dx,SC_INDEX mov al,1 ;do plane 0 first DrawImagePlaneLoop: push di ;image is drawn at the same offset in ; each plane push ax ;preserve plane select mov al,MAP_MASK ;Map Mask index out dx,al ;point SC Index to the Map Mask register pop ax ;get back plane select inc dx ;point to SC index register out dx,al ;set up the Map Mask to allow writes to ; the plane of interest dec dx ;point back to SC Data register mov bx,IMAGE_HEIGHT ;# of scan lines in image DrawImageLoop: mov cx,IMAGE_WIDTH ;# of bytes across image rep movsb add di,SCREEN_WIDTH-IMAGE_WIDTH ;point to next scan line of image dec bx ;any more scan lines? jnz DrawImageLoop pop di ;get back image start offset in VGA memory shl al,1 ;Map Mask setting for next plane cmp al,10h ;have we done all four planes? jnz DrawImagePlaneLoop ret DrawImage endp ; ; Copies the image from its current location in VGA memory into the ; buffer at DS:DI. ; GetImage proc near mov si,di ;move destination offset into SI call GetImageOffset ;DI is offset of image in VGA memory xchg si,di ;SI is offset of image, DI is destination offset push ds pop es ;ES:DI is destination mov ax,VGA_SEGMENT mov ds,ax ;DS:SI is source ; mov dx,GC_INDEX sub al,al ;do plane 0 first GetImagePlaneLoop: push si ;image comes from same offset in each plane push ax ;preserve plane select mov al,READ_MAP ;Read Map index out dx,al ;point GC Index to Read Map register pop ax ;get back plane select inc dx ;point to GC Index register out dx,al ;set up the Read Map to select reads from ; the plane of interest dec dx ;point back to GC data register mov bx,IMAGE_HEIGHT ;# of scan lines in image GetImageLoop: mov cx,IMAGE_WIDTH ;# of bytes across image rep movsb add si,SCREEN_WIDTH-IMAGE_WIDTH ;point to next scan line of image dec bx ;any more scan lines? jnz GetImageLoop pop si ;get back image start offset inc al ;Read Map setting for next plane cmp al,4 ;have we done all four planes? jnz GetImagePlaneLoop push es pop ds ;restore original DS ret GetImage endp ; ; Erases the image at its current location. ; EraseImage proc near mov dx,SC_INDEX mov al,MAP_MASK out dx,al ;point SC Index to the Map Mask register inc dx ;point to SC Data register mov al,0fh out dx,al ;set up the Map Mask to allow writes to go to ; all 4 planes mov ax,VGA_SEGMENT mov es,ax call GetImageOffset ;ES:DI points to the start address ; of the image sub al,al ;erase with zeros mov bx,IMAGE_HEIGHT ;# of scan lines in image EraseImageLoop: mov cx,IMAGE_WIDTH ;# of bytes across image rep stosb add di,SCREEN_WIDTH-IMAGE_WIDTH ;point to next scan line of image dec bx ;any more scan lines? jnz EraseImageLoop ret EraseImage endp ; ; Returns the current offset of the image in the VGA segment in DI. ; GetImageOffset proc near mov ax,SCREEN_WIDTH mul [ImageY] add ax,[ImageX] mov di,ax ret GetImageOffset endp code ends end Start