
	ASSUME	cs:_text, ds:nothing, es:nothing, ss:nothing

;	void far copy(srcx, srcy, dstx, dsty, width, height)
;
;	copy rectangles
;
c_page =	-2		; page number, low byte of word
c_srcx	=	6
c_srcy	=	8
c_dstx	=	10
c_dsty	=	12
c_width	=	14
c_height =	16
COPY	PROC FAR
copy640:
	push	bp
	mov	bp,sp
	sub	sp,2		; reserve 2 bytes on the stack
	push	ds
	push	es
	push	si
	push	di

	mov	bx,640		; 640 bytes per scan line
	call	setup
	jmp	short copy_it

copy800:
	push	bp
	mov	bp,sp
	sub	sp,2		; reserve 2 bytes on the stack
	push	ds
	push	es
	push	si
	push	di

	mov	bx,800		; 800 bytes per scan line
	call	setup
	jmp	short copy_it

copy1024:
	push	bp
	mov	bp,sp
	sub	sp,2		; reserve 2 bytes on the stack
	push	ds
	push	es
	push	si
	push	di

	mov	bx,1024		; 1024 bytes per scan line
	call	setup

copy_it:
	cmp	ch,cl		; compare src and dst page numbers
	ja	$C10
	jb	overlap
	cmp	di,si		; overlap can occur
	ja	overlap		; if dst < src, no overlap
$C10:				; reverse it
	page_setup	ch,cl
	save_page		; save the current page info
	write_page		; setup VGA paging register
	sub	bx,c_width[bp]	; bytes to next scan line
	jmp	no_overlap

overlap:
	mov	ax,c_height[bp]	; get height
	dec	ax
	mul	bx		; (height - 1) * screen_width
	sub	bx,c_width[bp]	; bx = number of bytes to next scan line
	dec	word ptr c_width[bp]	; width - 1
	add	ax,c_width[bp]	; add in (width - 1)
	adc	dl,0

	add	si,ax		; have source point to end
	adc	ch,dl		; fixup src page number
	add	di,ax		; have dest point to end
	adc	cl,dl		; fixup dst page number

	page_setup	ch,cl
	save_page		; save the current page info
	write_page		; setup VGA paging register

	std			; copy backwords
$again:
	mov	ax,c_width[bp]	; width - 1
	cmp	si,ax		; if (srcoff < width - 1)
	jb	$R70		; jmp if src overlap
	cmp	di,ax		; if (dstoff < width - 1) {
	jb	$R80		; jmp if split page at dst
	mov	cx,ax
	inc	cx

	rep	movsb		; copy a scan line
$R90:
	sub	si,bx		; goto next scan line
	jc	$R91		; need to fixup page number
	sub	di,bx
	jc	$R92
$R95:
	dec	word ptr c_height[bp]	; decrement the height
	jnz	$again
$R99:				; were done, go home
	pop	di
	pop	si
	pop	es
	pop	ds
	leave
	cld
	ret

$R91:
	load_page
	dec_src_page		; fixup src page
	sub	di,bx
	jc	$R93
	jmp	short $R94
$R92:
	load_page
$R93:
	dec_dst_page		; fixup dst page
$R94:
	save_page
	write_page
	jmp	short $R95

$R80:				; dstoff split page
	mov	cx,di		; get dstoff
	sub	ax,cx		; ax has rest of scan line
	inc	cx		; cx has bytes to copy

	rep	movsb		; copy to end of page
	mov	cx,ax		; cx = rest of scan line

	load_page
	dec_dst_page
	save_page
	write_page

	rep	movsb		; finish scan line

	sub	di,bx		; CY can't occur
	sub	si,bx
	jnc	$R95

	dec_src_page		; fixup src page, ah still has page info
	save_page
	write_page

	jmp	short $R95

$R70:				; split page at src
	cmp	di,ax		; if (dstoff < width - 1)
	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_dst_page_in_mem	; goto next dest page
$R60:				; break occurs only at srcoff
	mov	cx,si		; get srcoff
	sub	ax,cx		; ax has rest of scan line
	inc	cx		; cx has bytes to copy

	rep	movsb		; copy to end of page
	mov	cx,ax		; ax has number of bytes left to copy

	load_page
	dec_src_page		; goto next src page
	save_page

	write_page

	rep	movsb		; finish scan line

	jmp	$R90

$R50:
				; break occurs at dstoff first
	mov	cx,di		; get srcoff
	sub	ax,cx		; ax has rest of scan line
	inc	cx		; cx has bytes to copy

	rep	movsb		; copy to end of page
	mov	cx,ax

	load_page
	dec_dst_page		; goto next dst page
	save_page
	write_page

	mov	ax,cx		; setup count info
	dec	ax		; fixup count
	jmp	short $R60	; do srcoff part

$R40:				; break occurs at srcoff, then dstoff
	mov	cx,si		; get srcoff
	sub	ax,cx		; ax has rest of scan line
	inc	cx		; cx has bytes to copy

	rep	movsb		; copy to end of page
	mov	cx,ax

	load_page
	dec_src_page		; goto next src page
	save_page
	write_page

	mov	ax,cx
	dec	ax		; fixup count
	jmp	$R80		; do dstoff part

no_overlap:			; bx = bytes to next scan line
	mov	cx,c_width[bp]
	mov	dx,si		; if (srcoff + width > 0xffffL)
	add	dx,cx
	jc	$C70		; branch if split page at src
	mov	dx,di		; if (dstoff + width > 0xffffL)
	add	dx,cx		; dx = dstoff + width
	jc	$C80		; branch if split page at dst

	shr	cx,1
	rep	movsw		; copy a scan line
	adc	cx,cx
	rep	movsb		; copy a scan line
$C90:
	add	si,bx		; goto next scan line
	jc	$C91		; need to fixup page number
	add	di,bx
	jc	$C92
$C95:
	dec	word ptr c_height[bp]	; decrement the height
	jnz	no_overlap
				; were done, go home
	pop	di
	pop	si
	pop	es
	pop	ds
	leave
	ret

$C91:
	load_page		; get current page info
	inc_src_page		; fixup src page info
	add	di,bx
	jc	$C93
	jmp	short $C94
$C92:				; just bump up dst page
	load_page		; get current page info
$C93:
	inc_dst_page		; fixup dst page
$C94:
	save_page		; save the current page info
	write_page
	jmp	short $C95

$C80:				; dstoff split page only, ax has what's left
	mov	cx,di		; get dstoff
	neg	cx

	shr	cx,1
	rep	movsw		; copy to end of page
	adc	cx,cx
	rep	movsb		; copy to end of page

	load_page
	inc_dst_page		; goto next dest page
	save_page

	mov	cx,dx		; cx has number of bytes left to copy
$C85:
	write_page		; assumes ah = page

	shr	cx,1
	rep	movsw		; finish the scan line
	adc	cx,cx
	rep	movsb		; finish the scan line

	add	di,bx		; goto next scan line, can't CY
	add	si,bx
	jnc	$C95
	load_page
	inc_src_page		; goto next src page
	jmp	short $C94

$C70:				; split page at src
				; dx has number of bytes after src page
	mov	ax,di		; if (dstoff + width > 0xffffL)
	add	ax,cx		; ax = dstoff + width
	jnc	$C60		; branch if no split page at dst

	cmp	dx,ax		; if (srcoff == dstoff)
	ja	$C40		; break occurs at srcoff then dstoff
	jb	$C50		; break occurs at dstoff then srcoff
				; break occurs at the same place
	inc_dst_page_in_mem	; goto next dst page

$C60:				; break occurs only at srcoff
	mov	cx,si		; get srcoff
	neg	cx

	shr	cx,1
	rep	movsw		; copy to end of page
	adc	cx,cx
	rep	movsb		; copy to end of page

	load_page
	inc_src_page		; goto next src page
	save_page

	mov	cx,dx		; dx has number of bytes left to copy

	write_page		; assumes ah = page

	shr	cx,1
	rep	movsw		; finish the scan line
	adc	cx,cx
	rep	movsb		; finish the scan line

	add	si,bx		; can't cause a CY
	add	di,bx
	jc	$C93		; ah already has the page info
;	jmp	short $C95
	jmp	$C95

$C50:
				; break occurs at dstoff first
	mov	cx,di		; get dstoff
	neg	cx

	shr	cx,1
	rep	movsw		; copy to end of page
	adc	cx,cx
	rep	movsb		; copy to end of page
	mov	cx,ax		; cx has number of bytes left to copy
	sub	cx,dx		; cx = bytes left in dst - bytes left in src

	load_page
	inc_dst_page		; goto next dest page
	save_page

	write_page
	mov	dx,cx		; dx if bytes left after copying srcoff
	jmp	short $C60	; do srcoff part

$C40:				; break occurs at srcoff, then dstoff
	mov	cx,si		; get srcoff
	neg	cx

	shr	cx,1
	rep	movsw		; copy to end of page
	adc	cx,cx
	rep	movsb		; copy to end of page
	mov	cx,dx
	sub	cx,ax		; cx = bytes left in src - bytes left in dst

	load_page
	inc_src_page		; goto next src page
	save_page

	write_page

	mov	dx,cx		; dx if bytes left after copying dstoff
	mov	cx,di		; get dstoff
	neg	cx

	shr	cx,1
	rep	movsw		; copy to end of page
	adc	cx,cx
	rep	movsb		; copy to end of page
	mov	cx,dx		; cx has number of bytes left to copy

	load_page
	inc_dst_page		; goto next dst page
	save_page

	write_page

	shr	cx,1
	rep	movsw		; copy to end of page
	adc	cx,cx
	rep	movsb		; copy to end of page

	add	si,bx
	add	di,bx

	jmp	$C95
COPY	ENDP

;
;	routine for setting up all the necessary registers.
;	called with:
;		bx = number of bytes per scan line
;		bp = appropriate frame information
;	scratch registers:
;		ax, dx
;	return:
;		ch = src_page
;		cl = dst_page
;
setup	PROC NEAR
	mov	ax,VGA_SEG	; point to video area
	mov	es,ax		; point to video area
	mov	ds,ax	

	mov	ax,c_srcy[bp]
	mul	bx		; multiply it by screen width
	add	ax,c_srcx[bp]	; srcy * screen_width + srcx
	adc	dl,0		; adjust page
	mov	ch,dl		; save src page number
	mov	si,ax

	mov	ax,c_dsty[bp]	; destination
	mul	bx		; multiply it by 640
	add	ax,c_dstx[bp]
	adc	dl,0		; adjust page
	mov	cl,dl		; dst page number
	mov	di,ax

	ret
setup	ENDP
