COPY	PROC FAR
; copy rectangles
; copy(srcx, srcy, dstx, dsty, width, height)
;
copy640:
	push	bp
	mov	bp,sp
	push	si
	push	di
	mov	ax,8[bp]
			; multiply it by 640
	mov	dx,ax
	shl	ax,2
	add	ax,dx	; y = (y << 2) + y
	rol	ax,7
	mov	dx,ax
	and	ax,0ff80h
	and	dx,0007fh	; y * 640
	add	ax,6[bp]
	adc	dx,0		; dx = page number of src
	mov	si,ax
	; destination
	mov	ax,12[bp]
			; multiply it by 640
	mov	bx,ax
	shl	ax,2
	add	ax,bx	; y = (y << 2) + y
	rol	ax,7
	mov	bx,ax
	and	ax,0ff80h
	and	bx,0007fh	; y * 640
	add	ax,10[bp]
	adc	bx,0		; bx = page number of dst
	mov	di,ax
	mov	bh,dl		; bh = src page, bl = dst page
	cmp	bh,bl		; compare source and dst page numbers
	ja	$C10
	jb	$C11
	cmp	di,si		; overlap can occur
	ja	$C11		; if dst < src, no overlap
$C10:				; reverse it
	mov	dx,640		; 640 bytes per scanline
	jmp	no_overlap
$C11:
	mov	ax,16[bp]	; get height
	dec	ax
	mov	cx,ax
	shl	ax,2
	add	ax,cx		; temp = (height << 2) + height
	rol	ax,7		; 640 * height
	mov	cl,al
	and	ax,0ff80h	; low word of 640 * height
	and	cl,07fh		; high word of 640 * height
	add	ax,14[bp]	; add in the width
	adc	cl,0		; fixup the carry
	sub	ax,1		; subtract one
	sbb	cl,0
	add	si,ax		; have source point to end
	adc	bh,cl		; fixup the page also
	add	di,ax		; have dest point to end
	adc	bl,cl		; fixup the page also
	mov	dx,640		; 640 bytes per scanline
	jmp	overlap
copy800:
	push	bp
	mov	bp,sp
	push	si
	push	di
	mov	ax,8[bp]
	mov	dx,ax
	shl	ax,1
	add	ax,dx
	shl	ax,3
	add	ax,dx
	rol	ax,5
	mov	dx,ax
	and	ax,0ffe0h
	and	dx,0001fh
	add	ax,6[bp]
	adc	dx,0		; dx = page number of src
	mov	si,ax
	; destination
	mov	ax,12[bp]
	mov	bx,ax
	shl	ax,1
	add	ax,bx
	shl	ax,3
	add	ax,bx
	rol	ax,5
	mov	bx,ax
	and	ax,0ffe0h
	and	bx,0001fh
	add	ax,10[bp]
	adc	bx,0		; bx = page number of dst
	mov	di,ax
	mov	bh,dl		; bh = src page, bl = dst page
	cmp	bh,bl		; compare source and dst page numbers
	ja	$C20
	jb	$C21
	cmp	di,si		; overlap can occur
	ja	$C21		; if dst < src, no overlap
$C20:				; reverse it
	mov	dx,800		; 800 bytes per scanline
	jmp	no_overlap
$C21:
	mov	ax,16[bp]	; get height
	dec	ax
	mov	cx,ax
	shl	ax,1
	add	ax,cx
	shl	ax,3
	add	ax,cx
	rol	ax,5
	mov	cl,al
	and	ax,0ffe0h
	and	cl,01fh
	add	ax,14[bp]	; add in the width
	adc	cl,0		; fixup the carry
	sub	ax,1
	sbb	cl,0
	add	si,ax		; have source point to end
	adc	bh,cl		; fixup the page also
	add	di,ax		; have dest point to end
	adc	bl,cl		; fixup the page also
	mov	dx,800		; 800 bytes per scanline
	jmp	short overlap
copy1024:
	push	bp
	mov	bp,sp
	push	si
	push	di
	mov	ax,8[bp]
	ror	ax,6		; same as rol ax,10
	mov	dx,ax
	and	ax,0fc00h
	and	dx,003ffh	; dx = page number of src
	add	ax,6[bp]
	mov	si,ax
	;destination
	mov	ax,12[bp]
	ror	ax,6		; same as rol ax,10
	mov	bx,ax
	and	ax,0fc00h
	and	bx,003ffh	; bx = page number of dst
	add	ax,10[bp]
	mov	di,ax
	mov	bh,dl		; bh = src page, bl = dst page
	cmp	bh,bl		; compare source and dst page numbers
	ja	$C30
	jb	$C31
	cmp	di,si		; overlap can occur
	ja	$C31		; if dst < src, no overlap
$C30:				; reverse it
	mov	dx,1024		; 1024 bytes per scanline
	jmp	no_overlap
$C31:
	mov	ax,16[bp]	; get height
	dec	ax
	ror	ax,6		; same as rol ax,10
	mov	cl,al
	and	ax,0fc00h
;	and	cx,003ffh	we only use cl anyway
	add	ax,14[bp]	; add in the width
	adc	cl,0		; fixup the carry
	sub	ax,1
	sbb	cl,0
	add	si,ax		; have source point to end
	adc	bh,cl		; fixup the page also
	add	di,ax		; have dest point to end
	adc	bl,cl		; fixup the page also
	mov	dx,1024		; 1024 bytes per scanline
				; goto overlap copy
overlap:
	std
	push	es
	push	ds
	mov	cx,0a000h
	mov	es,cx		; point to video area
	mov	ds,cx
	sub	dx,14[bp]	; dx is number of bytes to next scanline

$do_again:
	mov	cx,dx		; save number of bytes to next scanline
	setpage	bh,bl
	mov	dx,cx

$again:
	mov	cx,14[bp]	; width
	mov	ax,cx		; ax has width
	cmp	si,cx		; if (srcoff < width)
	jb	$R70		; jmp if src overlap
	cmp	di,cx		; if (dstoff < width) {
	jb	$R80		; continue if split page at dst
	mov	cx,ax		; cx = width
$R75:
	rep	movsb		; copy a scan line
	jmp	$R89
$R80:				; dstoff split page
	mov	cx,di		; get dstoff
	inc	cx		; cx has bytes to copy
	sub	ax,cx		; ax has rest of scan line
	rep	movsb		; copy to end of page
	dec	bl		; goto next dest page
$R82:
	push	ax		; save count of whats left
	mov	cx,dx		; save dx
	setpage	bh,bl
	mov	dx,cx
	pop	cx		; restore count
	rep	movsb		; finish scan line
	jmp	$R89

$R70:				; split page at src
	cmp	di,cx		; if (dstoff < width)
	jae	$R60		; jump if no dest overlap
	cmp	di,si		; if (srcoff == dstoff)
	ja	$R40		; break occurs twice, at srcoff and dstoff
	jb	$R50
				; break occurs at the same place
	dec	bl		; goto next dest page
$R60:				; break occurs only at srcoff
	mov	cx,si		; get srcoff
	inc	cx		; cx has bytes to copy
	sub	ax,cx		; ax has rest of scan line
	rep	movsb		; copy to end of page
	dec	bh		; goto next src page
	jmp	short $R82	; update page and do rest of scan line

$R50:
				; break occurs at dstoff first
	mov	cx,di		; get srcoff
	inc	cx		; cx has bytes to copy
	sub	ax,cx		; ax has rest of scan line
	rep	movsb		; copy to end of page
	dec	bl		; goto next dst page
	push	ax		; save count of whats left
	mov	cx,dx
	setpage	bh,bl
	mov	dx,cx
	pop	ax		; restore count
	jmp	short $R60	; do srcoff part

$R40:				; break occurs at srcoff, then dstoff
	mov	cx,si		; get srcoff
	inc	cx		; cx has bytes to copy
	sub	ax,cx		; ax has rest of scan line
	rep	movsb		; copy to end of page
	dec	bh		; goto next src page
	push	ax		; save count of whats left
	mov	cx,dx
	setpage	bh,bl
	mov	dx,cx
	pop	ax		; restore count
	jmp	$R80		; do dstoff part

$R89:
	dec	word ptr 16[bp]	; decrement the height
	jz	$R99		; were done
$R90:
	sub	si,dx		; goto next scan line
	jc	$R91		; need to fixup page number
	sub	di,dx
	jc	$R92
	jmp	$again
$R91:
	dec	bh		; fixup source page
	sub	di,dx
$R92:
	sbb	bl,0		; fixup dest page
	jmp	$do_again
$R99:				; were done, go home
	pop	ds
	pop	es
	pop	di
	pop	si
	pop	bp
	cld
	ret

no_overlap:			; reg cx & ax are scratch
	push	es
	push	ds
	mov	cx,0a000h
	mov	es,cx		; point to video area
	mov	ds,cx
	sub	dx,14[bp]	; dx is number of bytes to next scanline

$do_no_again:
	mov	cx,dx		; save number of bytes to next scanline
	setpage	bh,bl
	mov	dx,cx

$no_again:
	mov	cx,14[bp]	; width
	mov	ax,cx		; ax has width
	neg	cx
	cmp	si,cx		; if (srcoff > -width)
	ja	$C70
	cmp	di,cx		; if (dstoff > -width) {
	ja	$C80		; continue if split page at dst
	mov	cx,ax		; cx = width
$C75:
	shr	cx,1
	rep	movsw
	adc	cx,cx
	rep	movsb		; copy a scan line
	jmp	$C89
$C80:				; dstoff split page
	mov	cx,di		; get dstoff
	neg	cx		; cx has bytes to copy
	sub	ax,cx		; ax has rest of scan line
	shr	cx,1
	rep	movsw
	adc	cx,cx
	rep	movsb		; copy to end of page
	inc	bl		; goto next dest page
$C82:
	push	ax		; save count of whats left
	mov	cx,dx		; save dx
	setpage	bh,bl
	mov	dx,cx
	pop	cx		; restore count
	jmp	short $C75	; to finish scan line

$C70:				; split page at src
	cmp	di,cx		; if (dstoff > -width)
	jbe	$C60
	cmp	di,si		; if (srcoff == dstoff)
	jb	$C40		; break occurs twice, at srcoff and dstoff
	ja	$C50
				; break occurs at the same place
	inc	bl		; goto next dest page
$C60:				; break occurs only at srcoff
	mov	cx,si		; get srcoff
	neg	cx		; cx has bytes to copy
	sub	ax,cx		; ax has rest of scan line
	rep	movsb		; copy to end of page
	inc	bh		; goto next src page
	jmp	short $C82	; update page and do rest of scan line

$C50:
				; break occurs at dstoff first
	mov	cx,di		; get srcoff
	neg	cx		; cx has bytes to copy
	sub	ax,cx		; ax has rest of scan line
	shr	cx,1
	rep	movsw
	adc	cx,cx
	rep	movsb		; copy to end of page
	inc	bl		; goto next dst page
	push	ax		; save count of whats left
	mov	cx,dx
	setpage	bh,bl
	mov	dx,cx
	pop	ax		; restore count
	jmp	short $C60	; do srcoff part

$C40:				; break occurs at srcoff, then dstoff
	mov	cx,si		; get srcoff
	neg	cx		; cx has bytes to copy
	sub	ax,cx		; ax has rest of scan line
	shr	cx,1
	rep	movsw
	adc	cx,cx
	rep	movsb		; copy to end of page
	inc	bh		; goto next src page
	push	ax		; save count of whats left
	mov	cx,dx
	setpage	bh,bl
	mov	dx,cx
	pop	ax		; restore count
	jmp	$C80		; do dstoff part

$C89:
	dec	word ptr 16[bp]	; decrement the height
	jz	$C99		; were done
$C90:
	add	si,dx		; goto next scan line
	jc	$C91		; need to fixup page number
	add	di,dx
	jc	$C92
	jmp	$no_again
$C91:
	inc	bh		; fixup source page
	add	di,dx
$C92:
	adc	bl,0		; fixup dest page
	jmp	$do_no_again
$C99:				; were done, go home
	pop	ds
	pop	es
	pop	di
	pop	si
	pop	bp
	ret
COPY	ENDP
