home *** CD-ROM | disk | FTP | other *** search
- ; Sample EGA program.
- ; Animates four balls bouncing around a playfield by using
- ; page flipping. Playfield is panned smoothly both horizontally
- ; and vertically.
- ; Assembled with MASM 4.0, linked with LINK 3.51.
- ; Copyright by Michael Abrash, 11/2/86.
- ;
- stack segment para stack 'STACK'
- db 512 dup(?)
- stack ends
- ;
- HIRES_VIDEO_MODE equ 0 ;define for 640x350 video mode
- ; comment out for 640x200 mode
- VIDEO_SEGMENT equ 0a000h ;display memory segment for
- ; true EGA graphics modes
- LOGICAL_SCREEN_WIDTH equ 672/8 ;width in bytes and height in scan
- LOGICAL_SCREEN_HEIGHT equ 384 ; lines of the virtual screen
- ; we'll work with
- PAGE0 equ 0 ;flag for page 0 when page flipping
- PAGE1 equ 1 ;flag for page 1 when page flipping
- PAGE0_OFFSET equ 0 ;start offset of page 0 in EGA memory
- PAGE1_OFFSET equ LOGICAL_SCREEN_WIDTH * LOGICAL_SCREEN_HEIGHT
- ;start offset of page 1 (both pages
- ; are 672x384 virtual screens)
- BALL_WIDTH equ 24/8 ;width of ball in display memory bytes
- BALL_HEIGHT equ 24 ;height of ball in scan lines
- BLANK_OFFSET equ PAGE1_OFFSET * 2 ;start of blank image
- ; in EGA memory
- BALL_OFFSET equ BLANK_OFFSET + (BALL_WIDTH * BALL_HEIGHT)
- ;start offset of ball image in EGA memory
- NUM_BALLS equ 4 ;number of balls to animate
- ;
- ; EGA register equates.
- ;
- TS_INDEX equ 3c4h ;TS index register
- MAP_MASK equ 2 ;TS map mask register
- GDC_INDEX equ 3ceh ;GDC index register
- GDC_MODE equ 5 ;GDC mode register
- CRTC_INDEX equ 03d4h ;CRTC index register
- START_ADDRESS_HIGH equ 0ch ;CRTC start address high byte
- START_ADDRESS_LOW equ 0dh ;CRTC start address low byte
- CRTC_OFFSET equ 13h ;CRTC offset register
- STATUS_REGISTER_1 equ 03dah ;EGA status register
- VSYNC_MASK equ 08h ;vertical sync bit in status register 1
- ATC_INDEX equ 03c0h ;ATC index register
- HPELPAN equ 20h OR 13h ;ATC horizontal pel panning register
- ; (bit 7 is high to keep palette RAM
- ; addressing on)
- dseg segment para common 'DATA'
- CurrentPage db PAGE1 ;page to draw to
- CurrentPageOffset dw PAGE1_OFFSET
- ;
- ; Four plane's worth of multicolored ball image.
- ;
- BallPlane0Image label byte ;blue plane image
- db 000h, 03ch, 000h, 001h, 0ffh, 080h
- db 007h, 0ffh, 0e0h, 00fh, 0ffh, 0f0h
- db 4 * 3 dup(000h)
- db 07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh
- db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
- db 4 * 3 dup(000h)
- db 07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch
- db 03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h
- db 4 * 3 dup(000h)
- BallPlane1Image label byte ;green plane image
- db 4 * 3 dup(000h)
- db 01fh, 0ffh, 0f8h, 03fh, 0ffh, 0fch
- db 03fh, 0ffh, 0fch, 07fh, 0ffh, 0feh
- db 07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh
- db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
- db 8 * 3 dup(000h)
- db 00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h
- db 001h, 0ffh, 080h, 000h, 03ch, 000h
- BallPlane2Image label byte ;red plane image
- db 12 * 3 dup(000h)
- db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
- db 0ffh, 0ffh, 0ffh, 07fh, 0ffh, 0feh
- db 07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch
- db 03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h
- db 00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h
- db 001h, 0ffh, 080h, 000h, 03ch, 000h
- BallPlane3Image label byte ;intensity on for all planes,
- ; to produce high-intensity colors
- db 000h, 03ch, 000h, 001h, 0ffh, 080h
- db 007h, 0ffh, 0e0h, 00fh, 0ffh, 0f0h
- db 01fh, 0ffh, 0f8h, 03fh, 0ffh, 0fch
- db 03fh, 0ffh, 0fch, 07fh, 0ffh, 0feh
- db 07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh
- db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
- db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
- db 0ffh, 0ffh, 0ffh, 07fh, 0ffh, 0feh
- db 07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch
- db 03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h
- db 00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h
- db 001h, 0ffh, 080h, 000h, 03ch, 000h
- ;
- BallX dw 15, 50, 40, 70 ;array of ball x coords
- BallY dw 40, 200, 110, 300 ;array of ball y coords
- LastBallX dw 15, 50, 40, 70 ;previous ball x coords
- LastBallY dw 40, 100, 160, 30 ;previous ball y coords
- BallXInc dw 1, 1, 1, 1 ;x move factors for ball
- BallYInc dw 8, 8, 8, 8 ;y move factors for ball
- BallRep dw 1, 1, 1, 1 ;# times to keep moving
- ; ball according to current
- ; increments
- BallControl dw Ball0Control, Ball1Control ;pointers to current
- dw Ball2Control, Ball3Control ; locations in ball
- ; control strings
- BallControlString dw Ball0Control, Ball1Control ;pointers to
- dw Ball2Control, Ball3Control ; start of ball
- ; control strings
- ;
- ; Ball control strings.
- ;
- Ball0Control label word
- dw 10, 1, 4, 10, -1, 4, 10, -1, -4, 10, 1, -4, 0
- Ball1Control label word
- dw 12, -1, 1, 28, -1, -1, 12, 1, -1, 28, 1, 1, 0
- Ball2Control label word
- dw 20, 0, -1, 40, 0, 1, 20, 0, -1, 0
- Ball3Control label word
- dw 8, 1, 0, 52, -1, 0, 44, 1, 0, 0
- ;
- ; Panning control string.
- ;
- ifdef HIRES_VIDEO_MODE
- PanningControlString dw 32, 1, 0, 34, 0, 1, 32, -1, 0, 34, 0, -1, 0
- else
- PanningControlString dw 32, 1, 0, 184, 0, 1, 32, -1, 0, 184, 0, -1, 0
- endif
- PanningControl dw PanningControlString ;pointer to current location
- ; in panning control string
- PanningRep dw 1 ;# times to pan according to current
- ; panning increments
- PanningXInc dw 1 ;x panning factor
- PanningYInc dw 0 ;y panning factor
- HPan db 0 ;horizontal pel panning setting
- PanningStartOffset dw 0 ;start offset adjustment to produce vertical
- ; panning & coarse horizontal panning
- dseg ends
- ;
- ; Macro to set indexed register P2 of chip with index register
- ; at P1 to AL.
- ;
- SETREG macro P1, P2
- mov dx,P1
- mov ah,al
- mov al,P2
- out dx,ax
- endm
- ;
- cseg segment para public 'CODE'
- assume cs:cseg, ds:dseg
- start proc near
- mov ax,dseg
- mov ds,ax
- ;
- ; Select graphics mode.
- ;
- ifdef HIRES_VIDEO_MODE
- mov ax,010h
- else
- mov ax,0eh
- endif
- int 10h
- ;
- ; ES always points to EGA memory.
- ;
- mov ax,VIDEO_SEGMENT
- mov es,ax
- ;
- ; Draw border around playfield in both pages.
- ;
- mov di,PAGE0_OFFSET
- call DrawBorder ;page 0 border
- mov di,PAGE1_OFFSET
- call DrawBorder ;page 1 border
- ;
- ; Draw all four plane's worth of the ball to undisplayed EGA memory.
- ;
- mov al,01h ;enable plane 0
- SETREG TS_INDEX, MAP_MASK
- mov si,offset BallPlane0Image
- mov di,BALL_OFFSET
- mov cx,BALL_WIDTH * BALL_HEIGHT
- rep movsb
- mov al,02h ;enable plane 1
- SETREG TS_INDEX, MAP_MASK
- mov si,offset BallPlane1Image
- mov di,BALL_OFFSET
- mov cx,BALL_WIDTH * BALL_HEIGHT
- rep movsb
- mov al,04h ;enable plane 2
- SETREG TS_INDEX, MAP_MASK
- mov si,offset BallPlane2Image
- mov di,BALL_OFFSET
- mov cx,BALL_WIDTH * BALL_HEIGHT
- rep movsb
- mov al,08h ;enable plane 3
- SETREG TS_INDEX, MAP_MASK
- mov si,offset BallPlane3Image
- mov di,BALL_OFFSET
- mov cx,BALL_WIDTH * BALL_HEIGHT
- rep movsb
- ;
- ; Draw a blank image the size of the ball to undisplayed EGA memory.
- ;
- mov al,0fh ;enable all memory planes, since the
- SETREG TS_INDEX, MAP_MASK ; blank has to erase all planes
- mov di,BLANK_OFFSET
- mov cx,BALL_WIDTH * BALL_HEIGHT
- sub al,al
- rep stosb
- ;
- ; Set EGA to write mode 1, for block copying ball and blank images.
- ;
- mov al,1
- SETREG GDC_INDEX, GDC_MODE
- ;
- ; Set EGA offset register in words to define logical screen width.
- ;
- mov al,LOGICAL_SCREEN_WIDTH / 2
- SETREG CRTC_INDEX, CRTC_OFFSET
- ;
- ; Move the balls by erasing each ball, moving it, and
- ; redrawing it, then switching pages when they're all moved.
- ;
- BallAnimationLoop:
- mov bx,( NUM_BALLS * 2 ) - 2
- EachBallLoop:
- ;
- ; Erase old image of ball in this page (at location from one more earlier).
- ;
- mov si,BLANK_OFFSET ;point to blank image
- mov cx,[LastBallX+bx]
- mov dx,[LastBallY+bx]
- call DrawBall
- ;
- ; Set new last ball location.
- ;
- mov ax,[BallX+bx]
- mov [LastballX+bx],ax
- mov ax,[BallY+bx]
- mov [LastballY+bx],ax
- ;
- ; Change the ball movement values if it's time to do so.
- ;
- dec [BallRep+bx] ;has current repeat factor run out?
- jnz MoveBall
- mov si,[BallControl+bx] ;it's time to change movement values
- lodsw ;get new repeat factor from
- ; control string
- and ax,ax ;at end of control string?
- jnz SetNewMove
- mov si,[BallControlString+bx] ;reset control string
- lodsw ;get new repeat factor
- SetNewMove:
- mov [BallRep+bx],ax ;set new movement repeat factor
- lodsw ;set new x movement increment
- mov [BallXInc+bx],ax
- lodsw ;set new y movement increment
- mov [BallYInc+bx],ax
- mov [BallControl+bx],si ;save new control string pointer
- ;
- ; Move the ball.
- ;
- MoveBall:
- mov ax,[BallXInc+bx]
- add [BallX+bx],ax ;move in x direction
- mov ax,[BallYInc+bx]
- add [BallY+bx],ax ;move in y direction
- ;
- ; Draw ball at new location.
- ;
- mov si,BALL_OFFSET ;point to ball's image
- mov cx,[BallX+bx]
- mov dx,[BallY+bx]
- call DrawBall
- ;
- dec bx
- dec bx
- jns EachBallLoop
- ;
- ; Pan and flip displayed page to the one we've been working on, as soon
- ; as leading edge of vertical sync comes around.
- ;
- call WaitVSync
- ;
- ; Perform whatever panning's in effect.
- ;
- call AdjustPanning
- ;
- ; Flip to new page by changing start address.
- ;
- mov ax,[CurrentPageOffset]
- add ax,[PanningStartOffset]
- push ax
- SETREG CRTC_INDEX, START_ADDRESS_LOW
- mov al,byte ptr [CurrentPageOffset+1]
- pop ax
- mov al,ah
- SETREG CRTC_INDEX, START_ADDRESS_HIGH
- ;
- ; Wait for sync again so the new start address has a chance
- ; to take effect.
- ;
- call WaitVSync
- ;
- ; Set horizontal panning now, just as new start address takes effect.
- ;
- mov al,[HPan]
- mov dx,STATUS_REGISTER_1
- in al,dx ;reset ATC addressing to index reg
- mov al,[HPan]
- SETREG ATC_INDEX, HPELPAN
- ;
- ; Flip the page to draw to to the undisplayed page.
- ;
- xor [CurrentPage],1
- jnz IsPage1
- mov [CurrentPageOffset],PAGE0_OFFSET
- jmp short EndFlipPage
- IsPage1:
- mov [CurrentPageOffset],PAGE1_OFFSET
- EndFlipPage:
- ;
- ; Exit if a key's been hit.
- ;
- mov ah,1
- int 16h
- jnz Done
- jmp BallAnimationLoop
- ;
- ; Finished, clear key, reset screen mode and exit.
- ;
- Done:
- mov ah,0 ;clear key
- int 16h
- ;
- mov ax,3 ;reset to text mode
- int 10h
- ;
- mov ah,4ch ;exit to DOS
- int 21h
- ;
- start endp
- ;
- ; Routine to draw a ball-sized image to all planes, copying from
- ; offset SI in EGA memory to offset CX,DX (x,y) in EGA memory in
- ; the current page.
- ;
- DrawBall proc near
- mov ax,LOGICAL_SCREEN_WIDTH
- mul dx ;offset of start of top image scan line
- add ax,cx ;offset of upper left of image
- add ax,[CurrentPageOffset] ;offset of start of page
- mov di,ax
- mov bp,BALL_HEIGHT
- push ds
- push es
- pop ds ;move from EGA memory to EGA memory
- DrawBallLoop:
- push di
- mov cx,BALL_WIDTH
- rep movsb ;draw a scan line of image
- pop di
- add di,LOGICAL_SCREEN_WIDTH ;point to next destination scan line
- dec bp
- jnz DrawBallLoop
- pop ds
- ret
- DrawBall endp
- ;
- ; Wait for the leading edge of vertical sync pulse.
- ;
- WaitVSync proc near
- mov dx,STATUS_REGISTER_1
- WaitNotVSyncLoop:
- in al,dx
- and al,VSYNC_MASK
- jnz WaitNotVSyncLoop
- WaitVSyncLoop:
- in al,dx
- and al,VSYNC_MASK
- jz WaitVSyncLoop
- ret
- WaitVSync endp
- ;
- ; Perform horizontal/vertical panning.
- ;
- AdjustPanning proc near
- dec [PanningRep] ;time to get new panning values?
- jnz DoPan
- mov si,[PanningControl] ;point to current location in
- ; panning control string
- lodsw ;get panning repeat factor
- and ax,ax ;at end of panning control string?
- jnz SetnewPanValues
- mov si,offset PanningControlString ;reset to start of string
- lodsw ;get panning repeat factor
- SetNewPanValues:
- mov [PanningRep],ax ;set new panning repeat value
- lodsw
- mov [PanningXInc],ax ;horizontal panning value
- lodsw
- mov [PanningYInc],ax ;vertical panning value
- mov [PanningControl],si ;save current location in panning
- ; control string
- ;
- ; Pan according to panning values.
- ;
- DoPan:
- mov ax,[PanningXInc] ;horizontal panning
- and ax,ax
- js PanLeft ;negative means pan left
- jz CheckVerticalPan
- mov al,[HPan]
- inc al ;pan right; if pel pan reaches
- cmp al,8 ; 8, it's time to move to the
- jb SetHPan ; next byte with a pel pan of 0
- sub al,al ; and a start offset that's one
- inc [PanningStartOffset] ; higher
- jmp short SetHPan
- PanLeft:
- mov al,[HPan]
- dec al ;pan left; if pel pan reaches -1,
- jns SetHPan ; it's time to move to the next
- mov al,7 ; byte with a pel pan of 7 and a
- dec [PanningStartOffset] ; start offset that's one lower
- SetHPan:
- mov [HPan],al ;save new pel pan value
- CheckVerticalPan:
- mov ax,[PanningYInc] ;vertical panning
- and ax,ax
- js PanUp ;negative means pan up
- jz EndPan
- add [PanningStartOffset],LOGICAL_SCREEN_WIDTH
- ;pan down by advancing the start
- ; address by a scan line
- jmp short EndPan
- PanUp:
- sub [PanningStartOffset],LOGICAL_SCREEN_WIDTH
- ;pan up by retarding the start
- ; address by a scan line
- EndPan:
- ret
- ;
- ; Draw textured border around playfield that starts at DI.
- ;
- DrawBorder proc near
- ;
- ; Draw the left border.
- ;
- push di
- mov cx,LOGICAL_SCREEN_HEIGHT / 16
- DrawLeftBorderLoop:
- mov al,0ch ;select red color for block
- call DrawBorderBlock
- add di,LOGICAL_SCREEN_WIDTH * 8
- mov al,0eh ;select yellow color for block
- call DrawBorderBlock
- add di,LOGICAL_SCREEN_WIDTH * 8
- loop DrawLeftBorderLoop
- pop di
- ;
- ; Draw the left border.
- ;
- push di
- add di,LOGICAL_SCREEN_WIDTH - 1
- mov cx,LOGICAL_SCREEN_HEIGHT / 16
- DrawRightBorderLoop:
- mov al,0eh ;select yellow color for block
- call DrawBorderBlock
- add di,LOGICAL_SCREEN_WIDTH * 8
- mov al,0ch ;select red color for block
- call DrawBorderBlock
- add di,LOGICAL_SCREEN_WIDTH * 8
- loop DrawRightBorderLoop
- pop di
- ;
- ; Draw the top border.
- ;
- push di
- mov cx,(LOGICAL_SCREEN_WIDTH - 2) / 2
- DrawTopBorderLoop:
- inc di
- mov al,0eh ;select yellow color for block
- call DrawBorderBlock
- inc di
- mov al,0ch ;select red color for block
- call DrawBorderBlock
- loop DrawTopBorderLoop
- pop di
- ;
- ; Draw the bottom border.
- ;
- add di,(LOGICAL_SCREEN_HEIGHT - 8) * LOGICAL_SCREEN_WIDTH
- mov cx,(LOGICAL_SCREEN_WIDTH - 2) / 2
- DrawBottomBorderLoop:
- inc di
- mov al,0ch ;select red color for block
- call DrawBorderBlock
- inc di
- mov al,0eh ;select yellow color for block
- call DrawBorderBlock
- loop DrawBottomBorderLoop
- ret
- DrawBorder endp
- ;
- ; Draws an 8x8 border block in color in AL at location DI.
- ; DI preserved.
- ;
- DrawBorderBlock proc near
- push di
- SETREG TS_INDEX, MAP_MASK
- mov al,0ffh
- rept 8
- stosb
- add di,LOGICAL_SCREEN_WIDTH - 1
- endm
- pop di
- ret
- DrawBorderBlock endp
- AdjustPanning endp
- cseg ends
- end start
-