;=============================================================================
;Here's a simple bouncing ball program, 250 bytes of code including
;the text at the end.  Without the text its only 193 bytes but could still
;be done much faster and smaller.  Can anyone do a program like this in less
;than 100 bytes?  This program will work on a system as low as an XT, all
;it needs is a CGA graphics card.  It runs fast, even on a V20/V30 processor
;running at a measly 2 MHz.  Not much to look at, but a good example
;showing how efficient and fast assembler is.  This should work on all CGA
;compatible graphics cards.
;=============================================================================
;
;Compile into a .COM file
TITLE	CGA bouncing square program
.MODEL TINY
.8086           ;Use 8086 code

.CODE
.STARTUP

START:
	MOV	AX,0B800h	;Set ES to start of CGA video buffer
	MOV	ES,AX

	MOV	AX,0006h	;Set video mode 640 x 200 x 1 (monochrome)
	INT     10h
PO:
	MOV	BX,INCX		;Move DELTA X to BX
	ADD	XPOS,BX 	;and add to XPOS

	MOV	BX,INCY 	;Move DELTA Y to BX
	ADD	YPOS,BX 	;and add to YPOS

	MOV	BX,XPOS
	TEST	BX,BX		;See if XPOS=0
	JNZ	PO2
	NEG	INCX		;and reverse DELTA X if so
PO2:
	MOV	BX,YPOS 	;See if YPOS = 0
	TEST	BX,BX
	JNZ	PO3
	NEG	INCY		;and reverse DELTA Y if so
	MOV	AH,1		;Lets check for a keypress now
	INT	16h
	JNZ	PROGEND 	;and exit if one was pressed
				;we could check more often, but its faster this way
PO3:
	CMP	XPOS,79 	;See if XPOS is at last 8x8 Glyph
	JNE	PO4
	NEG	INCX		;and reverse DELTA X if so
PO4:
	CMP	YPOS,91 	;And see of YPOS is near bottom
	JNE	PO5
	NEG	INCY		;You know what!
PO5:
	CALL	DRAW_BALL	;Draw the ball
	JMP	PO		;Lets do it all again
PROGEND:
	MOV	AX,0003h		;Set back to text mode
	INT     10h
	MOV     AX,4C00H         ; Send exit code to dos
	INT     21H             ; Send command to DOS

DRAW_BALL	PROC	NEAR

	XOR	DI,DI		;Set offset to 0
	MOV	CL,4
	MOV	AX,YPOS
	SHL	AX,CL	     ; Calculate Y position * 80 + XPOS
	MOV	DX,AX	     ;using bit shifts to get a screen offset
	MOV	CL,2

	SHL	AX,CL
	ADD	DX,AX
	ADD	DX,XPOS
	ADD	DI,DX	     ;Store offset in DI

	MOV	AX,0111111011111111b	   ;Draw line for part of ball
	CALL	PUT_BALL     ;Put ball on screen

	MOV	DX,03DAh     ;Wait for screen refresh
WAIT1:	IN	AL,DX
	TEST	AL,08h
	JNZ	WAIT1
WAIT2:
	IN	AL,DX
	TEST	AL,08h
	JZ	WAIT2
	XOR	AX,AX		;Clear AX
	CALL	PUT_BALL	;And remove ball
	RET

DRAW_BALL	ENDP

PUT_BALL	PROC NEAR
	PUSH	DI
	MOV	ES:[DI],AH	;Draw 4 times
	ADD	DI,80

	MOV	CX,3
LOOP1:
	MOV	ES:[DI],AL	;Draw 4 times
	ADD	DI,80
	DEC	CX
	TEST	CX,CX
	JNZ	LOOP1

	ADD	DI,TT		;Go to next 8K bank

	MOV	CX,3
LOOP2:
	MOV	ES:[DI],AL	;Fill in the blanks for a solid square
	ADD	DI,80
	DEC	CX
	TEST	CX,CX
	JNZ	LOOP2

	MOV	ES:[DI],AH	;Fill in the blanks for a solid square

	POP	DI

	RET

PUT_BALL	ENDP

XPOS		DW	49
YPOS		DW	38
INCX		DW	-1
INCY		DW	1

TT		EQU	8192-320
TG		EQU	8192-320

END
