Metropoli BBS
VIEWER: lst11-33.asm MODE: TEXT (ASCII)
;
; *** Listing 11-33 ***
;
; Illustrates animation based on exclusive-oring.
; Animates 10 images at once.
; Not a general animation implementation, but rather an
; example of the strengths and weaknesses of exclusive-or
; based animation.
;
; Make with LZTIME.BAT, since this program is too long to be
; handled by the precision Zen timer.
;
	jmp	Skip
;
DELAY	equ	0		;set to higher values to
				; slow down for closer
				; observation
REPETITIONS equ	500		;# of times to move and
				; redraw the images
DISPLAY_SEGMENT	equ	0b800h	;display memory segment
				; in 320x200 4-color
				; graphics mode
SCREEN_WIDTH	equ	80	;# of bytes per scan line
BANK_OFFSET	equ	2000h	;offset from the bank
				; containing the even-
				; numbered lines on the
				; screen to the bank
				; containing the odd-
				; numbered lines
;
; Used to count down # of times images are moved.
;
RepCount	dw	REPETITIONS
;
; Complete info about one image that we're animating.
;
Image	struc
XCoord		dw	?	;image X location in pixels
XInc		dw	?	;# of pixels to increment
				; location by in the X
				; direction on each move
YCoord		dw	?	;image Y location in pixels
YInc		dw	?	;# of pixels to increment
				; location by in the Y
				; direction on each move
Image	ends
;
; List of images to animate.
;
Images	label	Image
	Image	<64,4,8,4>
	Image	<144,0,56,2>
	Image	<224,-4,104,0>
	Image	<64,4,152,-2>
	Image	<144,0,8,-4>
	Image	<224,-4,56,-2>
	Image	<64,4,104,0>
	Image	<144,0,152,2>
	Image	<224,-4,8,4>
	Image	<64,4,56,2>
ImagesEnd	label	Image
;
; Pixel pattern for the one image this program draws,
; a 32x32 3-color square.
;
TheImage	label	byte
	rept	32
	dw	0ffffh, 05555h, 0aaaah, 0ffffh
	endm
IMAGE_HEIGHT	equ	32	;# of rows in the image
IMAGE_WIDTH	equ	8	;# of bytes across the image
;
; Exclusive-ors the image of a 3-color square at the
; specified screen location. Assumes images start on
; even-numbered scan lines and are an even number of
; scan lines high. Always draws images byte-aligned in
; display memory.
;
; Input:
;	CX = X coordinate of upper left corner at which to
;		draw image (will be adjusted to nearest
;		less-than or equal-to multiple of 4 in order
;		to byte-align)
;	DX = Y coordinate of upper left corner at which to
;		draw image
;	ES = display memory segment
;
; Output: none
;
; Registers altered: AX, CX, DX, SI, DI, BP
;
XorImage:
	push	bx	;preserve the main loop's pointer
	shr	dx,1	;divide the row # by 2 to compensate
			; for the 2-bank nature of 320x200
			; 4-color mode
	mov	ax,SCREEN_WIDTH
	mul	dx	;start offset of top row of image in
			; display memory
	shr	cx,1	;divide the X coordinate by 4
	shr	cx,1	; because there are 4 pixels per
			; byte
	add	ax,cx	;point to the offset at which the
			; upper left byte of the image will
			; go
	mov	di,ax
	mov	si,offset TheImage
			;point to the start of the one image
			; we always draw
	mov	bx,BANK_OFFSET-IMAGE_WIDTH
			;offset from the end of an even line
			; of the image in display memory to
			; the start of the next odd line of
			; the image
	mov	dx,IMAGE_HEIGHT/2
			;# of even/odd numbered row pairs to
			;  draw in the image
	mov	bp,IMAGE_WIDTH/2
			;# of words to draw per row of the
			; image. Note that IMAGE_WIDTH must
			; be an even number since we XOR
			; the image a word at a time
XorRowLoop:
	mov	cx,bp	;# of words to draw per row of the
			; image
XorColumnLoopEvenRows:
	lodsw		;next word of the image pattern
	xor	es:[di],ax	;XOR the next word of the
				; image into the screen
	inc	di	;point to the next word in display
	inc	di	; memory
	loop	XorColumnLoopEvenRows
	add	di,bx	;point to the start of the next
			; (odd) row of the image, which is
			; in the second bank of display
			; memory
	mov	cx,bp	;# of words to draw per row of the
			; image
XorColumnLoopOddRows:
	lodsw		;next word of the image pattern
	xor	es:[di],ax	;XOR the next word of the
				; image into the screen
	inc	di	;point to the next word in display
	inc	di	; memory
	loop	XorColumnLoopOddRows
	sub	di,BANK_OFFSET-SCREEN_WIDTH+IMAGE_WIDTH
			;point to the start of the next
			; (even) row of the image, which is
			; in the first bank of display
			; memory
	dec	dx	;count down the row pairs
	jnz	XorRowLoop
	pop	bx	;restore the main loop's pointer
	ret
;
; Main animation program.
;
Skip:
;
; Set the mode to 320x200 4-color graphics mode.
;
	mov	ax,0004h	;AH=0 is mode select fn
				;AL=4 selects mode 4,
				; 320x200 4-color mode
	int	10h		;invoke the BIOS video
				; interrupt to set the mode
;
; Point ES to display memory for the rest of the program.
;
	mov	ax,DISPLAY_SEGMENT
	mov	es,ax
;
; We'll always want to count up.
;
	cld
;
; Start timing.
;
	call	ZTimerOn
;
; Draw all the images initially.
;
	mov	bx,offset Images	;list of images
InitialDrawLoop:
	mov	cx,[bx+XCoord]	;X coordinate
	mov	dx,[bx+YCoord]	;Y coordinate
	call	XorImage	;draw this image
	add	bx,size Image	;point to next image
	cmp	bx,offset ImagesEnd
	jb	InitialDrawLoop	;draw next image, if
				; there is one
;
; Erase, move, and redraw each image in turn REPETITIONS
; times.
;
MainMoveAndDrawLoop:
	mov	bx,offset Images	;list of images
ImageMoveLoop:
	mov	cx,[bx+XCoord]	;X coordinate
	mov	dx,[bx+YCoord]	;Y coordinate
	call	XorImage	;erase this image (it's
				; already drawn at this
				; location, so this XOR
				; erases it)
	mov	cx,[bx+XCoord]	;X coordinate
	cmp	cx,4		;at left edge?
	ja	CheckRightMargin ;no
	neg	[bx+XInc]	;yes, so bounce
CheckRightMargin:
	cmp	cx,284		;at right edge?
	jb	MoveX		;no
	neg	[bx+XInc]	;yes, so bounce
MoveX:
	add	cx,[bx+XInc]	;move horizontally
	mov	[bx+XCoord],cx	;save the new location
	mov	dx,[bx+YCoord]	;Y coordinate
	cmp	dx,4		;at top edge?
	ja	CheckBottomMargin ;no
	neg	[bx+YInc]	;yes, so bounce
CheckBottomMargin:
	cmp	dx,164		;at bottom edge?
	jb	MoveY		;no
	neg	[bx+YInc]	;yes, so bounce
MoveY:
	add	dx,[bx+YInc]	;move horizontally
	mov	[bx+YCoord],dx	;save the new location
	call	XorImage	;draw the image at its
				; new location
	add	bx,size Image	;point to the next image
	cmp	bx,offset ImagesEnd
	jb	ImageMoveLoop	;move next image, if there
				; is one

if DELAY
	mov	cx,DELAY	;slow down as specified
	loop	$
endif
	dec	[RepCount]	;animate again?
	jnz	MainMoveAndDrawLoop ;yes
; 
	call	ZTimerOff	;done timing
;
; Return to text mode.
;
	mov	ax,0003h	;AH=0 is mode select fn
				;AL=3 selects mode 3,
				; 80x25 text mode
	int	10h		;invoke the BIOS video
				; interrupt to set the mode

[ RETURN TO DIRECTORY ]