235 lines
5.7 KiB
NASM
235 lines
5.7 KiB
NASM
; 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
|