;
;	vesacopy.asm
;
;	copies from video memory to video memory for VESA VGA cards.
;	needs to do a shift before calling setpage
;

;	void _Near copy(srcx, srcy, dstx, dsty, width, height, scrwidth, gran)
;	int srcx;	/* EAX */
;	int srcy;	/* EDX */
;	int dstx;	/* EBX */
;	int dsty;	/* ECX */
;	int width, height;	/* pushed on stack */
;	int scrwidth;		/* pushed on stack */
;	char gran;		/* window granularity: pushed on stack */
;
;	copy rectangles
;
c_buf	=	-1024		; 1024 bytes of stack buffer
c_width	=	8
c_height =	12
c_scrwidth =	16
c_gran =	20
VGA_SEG =	0a0000h

CCOPY	PROC NEAR
	push	ebp
	mov	ebp,esp
	add	esp,c_buf	; reserve bytes on the stack
	push	esi
	push	edi

	mov	edi,ebx		; save EBX (dstx)
	mov	esi,eax		; save EAX (srcx)

	mov	ebx,c_scrwidth[ebp]

	movzx	eax,dx		; srcy
	mul	bx		; multiply it by screen width
	add	ax,si		; srcy * screen_width + srcx
	adc	dl,0		; adjust page
	add	eax,VGA_SEG
	mov	esi,eax		; put psrc into esi

	movzx	eax,cx		; dsty destination
	mov	cl,dl		; save src page
	mul	bx		; multiply it by screen width
	add	ax,di
	adc	dl,0		; adjust page
	add	eax,VGA_SEG
	mov	edi,eax
	mov	dh,cl		; dh = src page
				; dl = dst page
	;	reg DL has the dst page number
	;	reg DH has the src page number
	;	reg SI has the src data pointer
	;	reg DI has the dst data pointer

	cmp	dh,dl		; compare src and dst page numbers
	ja	short $C10
	jb	short reverse
	cmp	edi,esi		; overlap can occur
	ja	short reverse		; if dst < src, no overlap
$C10:				; reverse it
	sub	ebx,c_width[ebp]	; bytes to next scan line

	mov	cl,0ffh
	jmp	forward

reverse:
	mov	ecx,edx		; save page info in cx
	mov	ax,c_height[ebp]	; get height
	dec	ax
	mul	bx		; (height - 1) * screen_width
	add	ebx,c_width[ebp] ; bx = number of bytes to previous scan line

	; BX = screen_width + width (number of bytes to previous scan line)

	add	si,ax		; have src point to last scan line
	adc	ch,dl		; fixup src page number
	add	di,ax		; have dest point to last scan line
	adc	cl,dl		; fixup dst page number
	mov	edx,ecx		; dx has the current page info
	mov	cl,0ffh

again:
	cmp	cl,dh
	je	$R15		; does page need changing?
	mov	cl,c_gran[ebp]
	movzx	eax,dh		; src page
	shl	eax,cl
	setpage	ax		; set the page
$R15:

	push	edi		; save dst
	lea	edi,c_buf[ebp]
	mov	ecx,c_width[ebp]
	movzx	eax,si		; if (srcoff + width > 0xffffL)
	add	ax,cx		; psrc + width
	jnc	short $R20		; branch if no split page at src
	movsx	ecx,si
	neg	ecx

	push	ecx
	shr	ecx,2
	rep	movsd
	pop	ecx
	and	ecx,3
	rep	movsb		; this causes an overflow to b0000
	mov	esi,VGA_SEG	; zero psrc
	mov	ecx,eax

	inc	dh		; next src page
	push	ecx
	mov	cl,c_gran[ebp]
	movzx	eax,dh
	shl	eax,cl
	setpage	ax
	pop	ecx

$R20:
	shrd	eax,ecx,2	; save 2 lsb's in ax
	shr	ecx,2
	rep	movsd
	shld	ecx,eax,2	; get them back
	rep	movsb

	mov	cl,dh		; save src page for compare below
	sub	si,bx		; point to next scan line
	jnc	short $R30
	dec	dh		; next page
$R30:
	pop	edi

	cmp	cl,dl
	je	$R31
	mov	cl,c_gran[ebp]
	movzx	eax,dl
	shl	eax,cl
	setpage	ax		; set dst page
$R31:

	push	esi		; save src
	lea	esi,c_buf[ebp]
	mov	ecx,c_width[ebp]
	movzx	eax,di		; if (srcoff + width > 0xffffL)
	add	ax,cx		; pdst + width
	jnc	short $R40		; branch if no split page at dst
	movsx	ecx,di
	neg	ecx

	push	ecx
	shr	ecx,2
	rep	movsd		; copy to end of page
	pop	ecx
	and	ecx,3
	rep	movsb		; copy to end of page
	mov	edi,VGA_SEG	; zero pdst
	mov	ecx,eax

	inc	dl		; next dst page
	push	ecx
	mov	cl,c_gran[ebp]
	movzx	eax,dl
	shl	eax,cl
	setpage	ax		; set dst page
	pop	ecx

$R40:
	shrd	eax,ecx,2	; save 2 lsb's in ax
	shr	ecx,2
	rep	movsd		; copy to end of page
	shld	ecx,eax,2	; get them back
	rep	movsb		; copy to end of page

	sub	di,bx		; point to next scan line
	mov	cl,dl		; save current page
	jnc	short $R50
	dec	dl		; next page
$R50:
	pop	esi

	dec	word ptr c_height[ebp]	; decrement the height
	jnz	again
	jmp	$C90		; we're done

forward:			; bx = bytes to next scan line
	cmp	cl,dh
	je	$C15
	mov	cl,c_gran[ebp]
	movzx	eax,dh
	shl	eax,cl
	setpage	ax		; set src page
$C15:

	push	edi		; save dst
	lea	edi,c_buf[ebp]
	mov	ecx,c_width[ebp]
	movzx	eax,si		; if (srcoff + width > 0xffffL)
	add	ax,cx		; psrc + width
	jnc	short $C20		; branch if no split page at src
	movsx	ecx,si
	neg	ecx

	push	ecx
	shr	ecx,2
	rep	movsd		; copy to end of page
	pop	ecx
	and	ecx,3
	rep	movsb		; copy to end of page
	mov	esi,VGA_SEG	; zero psrc
	mov	ecx,eax

	inc	dh		; next src page
	push	ecx
	mov	cl,c_gran[ebp]
	movzx	eax,dh
	shl	eax,cl
	setpage	ax		; set src page
	pop	ecx

$C20:
	shrd	eax,ecx,2	; save 2 lsb's in ax
	shr	ecx,2
	rep	movsd		; copy a scan line
	shld	ecx,eax,2	; get them back
	rep	movsb		; copy a scan line

	add	si,bx		; point to next scan line
	mov	cl,dh		; save current page
	jnc	short $C30
	inc	dh		; next page
$C30:
	pop	edi

	cmp	cl,dl
	je	$C31
	mov	cl,c_gran[ebp]
	movzx	eax,dl
	shl	eax,cl
	setpage	ax		; set dst page
$C31:

	push	esi		; save src
	lea	esi,c_buf[ebp]
	mov	ecx,c_width[ebp]
	movzx	eax,di		; if (srcoff + width > 0xffffL)
	add	ax,cx
	jnc	short $C40		; branch if no split page at src
	movsx	ecx,di
	neg	ecx

	push	ecx
	shr	ecx,2
	rep	movsd		; copy to end of page
	pop	ecx
	and	ecx,3
	rep	movsb		; copy to end of page
	mov	edi,VGA_SEG	; zero pdst
	mov	ecx,eax

	inc	dl		; next dst page
	push	ecx
	mov	cl,c_gran[ebp]
	movzx	eax,dl
	shl	eax,cl
	setpage	ax		; set dst page
	pop	ecx

$C40:
	shrd	eax,ecx,2	; save 2 lsb's in ax
	shr	ecx,2
	rep	movsd
	shld	ecx,eax,2	; get them back
	rep	movsb

	add	di,bx		; point to next scan line
	mov	cl,dl		; save current page
	jnc	short $C50
	inc	dl		; next page
$C50:
	pop	esi

	dec	word ptr c_height[ebp]	; decrement the height
	jz	short $C90
	jmp	forward
$C90:				; were done, go home
	pop	edi
	pop	esi
	leave
	ret	16
ccl	EQU	$ - offset CCOPY
CCOPY	ENDP
