;----------------------------vga.asm--------------------------------
; Modified for CIRRUS bank set and rgb input values 12/30/92
;
; Title: vga.asm   ren vga41.asm  ren vga24.asm by Don Lewis
; Date: 6/18/92
; Author: Randy Buckland (randy@ncsu.edu)
;
; Description:
;	This is a VERY basic set of routines to provide high speed SVGA
; graphics for IBM-PC compatibiles that have a VGA interface that supports
; a VESA driver. These routines assume a 256-color mode and will not work
; for any type of mode. The following routines are provided:
;
; vgainit(int vesa_mode)
; vgapoint(int row, int column, int pixel_value)
; vgahline(int row, int start_column, int end_column, int pixel_value)
; vgaline(int x1, int y1, int x2, int y2, int pixel_value)
; vgasetcolor(char *colors, int start, int count)
; vgafill(int row, int column, int width, int height, int pixel_value)
; vgarect(char *source, int source_width, int row, int column,
;		int width, int height)
;
;******** ADDED by Don Lewis, (djlewis@ualr.edu or djlewis@spider.ualr.edu)
; This works fine with 8bit VGA. Just pass color in red and rest is ignored.
; The original vgafill() was simply modified and vgapoint probably will be to.
; These modifications works with 8,15,16 and 24 bit VESA modes.
;
; vga_point(int,int,uchar r,uchar g,uchar b)
; vgapoint_rgb(int row, int column, uchar r, uchar g, uchar b)
; vgafill(int,int,int,int,uchar r,uchar g,uchar b)
; vgaline(int,int,int,int,uchar r,uchar g,uchar b)
;
.model	large,c
include macros.asm

;
; Global data for the VGA support routines
;
vgadata	segment word public 'VGADATA'

Block		dw	0		; Current video memory block accessable
BlockSz		dw	0		; Size of a video block in K
BlockShift	dw	0		; Amount to shift bits by
BlockEnd	dw	0		; Last valid address in block
BlockMask	dw	0		; Mask used for block/offset operations

WinAddr		dw	0		; Segment addr of window A block
WinGran		dw	0		; Window Granularity 12/10/92 djl
;WinFunc	dd	0		; Far pointer to windowing function
ScanWidth	dw	0		; Width of a scan line
BytesPerPixel   dw      0		; BytesPerPixel  12/30/92 djl
BitsPerPixel	dw	0		; BitsPerPixel value

ShiftMask	dw	0		; pixel shift mask 15 and 16bit modes
shift		dw	0		; pixel adjustment 15 and 16 bit modes

public screen_width,screen_height
screen_width	dw	640		; Width of screen
screen_height	dw	480		; Height of screen

public mouse_x, mouse_y
mouse_x		dw	0
mouse_y		dw	0

public text_height, text_drop
text_height     dw      16
text_drop       dw      4

vgadata	ends

vgacode segment word public 'VGACODE'
	assume  cs:vgacode,ds:vgadata

;
; Set current video memory block. This procedure assumes that ds already
; points to the vgadata segment. This routine will not modify any registers.
;
; Parameters:
;	- block number to change to
;
vgablock proc near
	push bp
	mov bp,sp
	push cx		; stay with no register modification. djl
	push dx

	mov dx,[bp+4]	; Start of video memory
	cmp dx,Block
	je l1
			;Window Granularity must be used to adjust bank. djl
	mov cx,WinGran  ;BankNum offset adjustment for cards of
	shl dl,cl	;varying window granularity. djl
	mov Block,dx

	push ax
	push bx

	mov ax,4f05h	; VESA set memory block
	mov bx,0000h	; Set window A
	int 10h

	pop bx
	pop ax
l1:
	pop dx
	pop cx		; stay with no register modification. djl
	mov sp,bp
	pop bp
	ret
vgablock endp



;
; Calculate block and offset values for a given row/column. Assumes that ds
; points to vgadata. Does NOT preserve registers. Returns block value in
; dx and offset in ax.
;
; Parameters:
;	- row value
;	- column value
;
vgaoffset proc near
	push bp
	mov bp,sp

	mov ax,[bp+4]		; Get row
	mul ScanWidth		; Get starting block and offset in dx:ax

; New code for 24bit pixel offset
	push dx
	mov bx,ax		; Save old ax
	xor ax,ax
	mov ax,[bp+6]             ; get column
;	mul word PTR BytesPerPixel
	mul BytesPerPixel
	and ax,7FFFh
	add ax,bx		; Add column offset
	pop dx

	;add ax,[bp+6]	; Add start column offset
	jnc la1
	inc dx		; Just crossed block boundery
la1:
	mov cx,BlockShift ; Get block size mask
	cmp cx,0        ; Is block size 64K?
	je la2           ; Yes, skip this section

	mov bx,ax	; Save old ax
	rol ax,cl
	and ax,BlockMask ; Save high bits
	rol dx,cl
	add dx,ax	; Add high bits to block value.

	mov ax,bx
	rol ax,cl
	or ax,BlockMask	; Set undesirable bits
	xor ax,BlockMask ; Clear bad bits
	ror ax,cl
;
; Set active block to calculated block if needed
;
la2:
	cmp dx,Block
	je la3
	push dx
	call vgablock
	pop dx
la3:

	mov sp,bp
	pop bp
	ret
vgaoffset endp

;
; Draw a single point in Red, Green, Blue for 15, 16 and 24 bit colour
; Added by Don Lewis to work with internal functions
; Parameters:
;	- Row of point
;	- Column of point
;	- r,g,b
;
; 24bit format bit pattern 'bbbbbbbbggggggggrrrrrrrr' 3 bytes
; 16bit                    '00000000bbbbbggggggrrrrr' 2 bytes
; 15bit                    '        0bbbbbgggggrrrrr' 2 bytes
;
draw_rgb proc near
	Prefix
	push bx
	push cx
	push dx
;
; Draw point
;
	cmp BitsPerPixel,24     ; Is it 24bits per pixel
	jne isit15_16		; if not goto isit15_16
	mov ax,[bp+8]		; al has blue pixel value
	cld                     ; clear direction flag to increment
	stosb                   ; write a byte in al to address in es:di
	mov ax,[bp+6] 		; al has green pixel value
	stosb
	mov ax,[bp+4]  		; al has red pixel value
	stosb
	jmp fini                ; All three bytes written. Finish
;
isit15_16:
	cmp BitsPerPixel,16	; Is it 16bits per pixel
	mov Shift,3		; adjust red bits shift factor
	mov ShiftMask,255	; adjust red/green bits mask
	je drawit               ; Go write the color data else its 15bit
	mov Shift,2             ; adjust for 15bits per pixel
	mov ShiftMask,127       ; adjust red/green bit mask
drawit:
	mov cl,5		; shift bits up factor
	xor ax,ax		; clear reg
	mov bx,[bp+6]		; get green value
	and bx,00ffh
	shl bx,cl		; shift green up 5bits
	mov ax,[bp+8]		; get blue value
	and ax,00FFh
	add ax,bx		; put portion of green with blue
	cld
	stosb			; write the blue green value
	mov ax,[bp+4]		; get red value
	and ax,00FFh
	mov cx,Shift		; get 15 or 16 bit shift factor
	shl ax,cl		; move red to correct position
	add al,bh		; put remaining green value with red
	and ax,Shiftmask	; mask unwanted bits
	stosb			; write the red green value
fini:
	pop dx                  ; Clean house and leave
	pop cx
	pop bx
	Postfix
draw_rgb endp


;
; Initialize the display
; Parameters:
;	Mode value to use
;
public vgainit
vgainit	proc far
;
; Set up call frame
;
	Prefix
	sub sp,256	; Make local variable space
;
	mov ax,vgadata	; Load address of data segment
	mov ds,ax	; Set DS register

;
; Get VGA information and set desired mode
;
	mov ax,4f02h	; VESA set mode function
	mov bx,[bp+6]	; Any mode I want !
	int 10h

	push ss
	pop es		; Load es with value of ss
	mov di,sp	; Point index at 256 byte temp space
	mov cx,[bp+6]
	mov ax,4f01h	; VESA get Super VGA mode information
	int 10h

	mov ax,es:[di+4]  ;WinGranularity in k added 12/10/1992 djl
	mov WinGran,ax
	mov ax,es:[di+6]  ;WinSize in k
	mov BlockSz,ax

	mov ax,es:[di+8]
	mov WinAddr,ax    ;WinASegment  usually a000h

;	mov ax,es:[di+12]        ;was rem ed from here by R.B.
;	mov word ptr WinFunc,ax  ;

;	mov ax,es:[di+14]        ;
;	mov word ptr WinFunc+2,ax  ; to here

	mov ax,es:[di+16]
	mov ScanWidth,ax  	;BytesPerScanLine

	mov ax,es:[di+25] 	;BitsPerPixel added 12/30/92 djl
	and ax,255        	; djl
	mov BitsPerPixel,ax	; djl
	cmp ax,15         	;is it a 15 bit mode? djl
	jne lb0           	;skip if not 15 bit mode. djl
	inc al            	;else force 15 bit modes to 16 bit modes. djl
lb0:                      	;
	shr al,3          	;convert BitsPerPixel to BytesPerPixel, djl
	mov BytesPerPixel,ax    ;end of addition 12/30/92 djl
;
; Calculate block shift and end values
;
	mov ax,BlockSz    ;ax = WinSize
	mov bx,10
	mov cx,03ffh
lb1:
	sar ax,1          ;divide ax by 2
	inc bx            ;bx + 1
	sal cx,1          ;multiply cx by 2
	inc cx            ;cx + 1
	cmp ax,1          ;compare ax to 1
	ja lb1            ;jump short if above(CF=0 and ZF=0)

	mov ax,16
	sub ax,bx         ;ax - bx = ax
	mov BlockShift, ax
	mov BlockEnd, cx
	not cx
	xchg ax,cx
	rol ax,cl
	mov BlockMask,ax

;
; Set to start block
;
	xor ax,ax
	push ax
	call vgablock
	pop ax

;
; Remove call frame and exit
;
	add sp,256
	Postfix
vgainit	endp

;
; Draw a single point
;
; Parameters:
;	- Row of point
;	- Column of point
;	- Pixel value to use
;
public vgapoint
vgapoint proc far
	Prefix

	mov ax,vgadata	; Load address of data segment
	mov ds,ax	; Set DS register
;
; Load window pointers
;
	mov ax,WinAddr
	mov es,ax		; Set ES to point to video memory
	push [bp+8] ; Column
	push [bp+6] ; Row
	call vgaoffset
	add sp,4

;
; Draw point in 8bit modes
;
	mov di,ax	; Put offset in index regester
	mov ax,[bp+10]	; bl has pixel value
	cld
	stosb
;
	Postfix
vgapoint endp

;
; Draw a single point Red, Green, Blue. BY Don Lewis
; to be called from external C routine
;
; Parameters:
;	- Row of point
;	- Column of point
;	- r,g,b
;
public vgapoint_rgb
vgapoint_rgb proc far
	Prefix

	mov ax,vgadata	; Load address of data segment
	mov ds,ax	; Set DS register
;
; Load window pointers
;
	mov ax,WinAddr  ; Get video memory start
	mov es,ax	; Set ES to point to video memory

	push [bp+8] ; Column
	push [bp+6] ; Row
	call vgaoffset
	add sp,4

;
; Draw point
;
	mov di,ax		; Put offset in index regester
	push [bp+14]
	push [bp+12]
	push [bp+10]
	call draw_rgb
	add sp,6

;	mov di,ax		; Put offset in index regester
;	cmp BitsPerPixel,24     ; Is it 24bits per pixel
;	jne dr1516		; if not goto dr1516
;	mov ax,[bp+14]		; bl has blue pixel value
;	cld
;	stosb
;	mov ax,[bp+12] 		; bl has green pixel value
;	stosb
;	mov ax,[bp+10]  	; bl has red pixel value
;	stosb
;	jmp finish
;dr1516:
;	cmp BitsPerPixel,16	; Is it 16bits per pixel
;	mov Shift,3		; adjust red bits shift factor
;	mov ShiftMask,255	; adjust red bits mask
;	je draw
;	mov Shift,2             ; adjust for 15bits per pixel
;	mov ShiftMask,127
;draw:
;	mov cl,5		; shift up factor
;	xor ax,ax		; clear reg
;	mov bx,[bp+12]		; get green value
;	shl bx,cl		; shift green up 5bits
;	mov ax,[bp+14]		; get blue value
;	add ax,bx		; put portion of green with blue
;	cld
;	stosb			; write the blue green value
;	mov ax,[bp+10]		; get red value
;	mov cx,Shift		; get 15 or 16 bit shift factor
;	shl ax,cl		; move red to correct position
;	add al,bh		; put remaining green value with red
;	and ax,Shiftmask	; mask unwanted bits
;	stosb			; write the red green value
finish:
	Postfix
vgapoint_rgb endp



;
; Draw a horizontal line. Line is assumed to start on even boundry and
; have length be an even value for speed.
;
; Parameters:
;	- Row for line
;	- Start column
;	- End column
;	- Pixel value
;
public vgahline
vgahline proc far
	Prefix
;
	mov	ax,vgadata	; Load address of data segment
	mov	ds,ax		; Set DS register
;
; Load window pointers
;
	mov ax,WinAddr
	mov es,ax		; Set ES to point to video memory

	push [bp+8]             ; Beginning Column
	push [bp+6]             ; Row
	call vgaoffset
	add sp,4

;
; Setup control parameters for line draw.
;
	mov di, ax		; Offset in di
	mov ax,[bp+12]          ; Pixel color
	mov ah,al		; ax has duplicated pixel value in bl and bh

	mov cx,BlockEnd		; Last point in counter
	sub cx,di		; cx has number of legal bytes-1

	mov bx,[bp+10]          ; Ending column
	sub bx,[bp+8]		; bx has number to write - 1

	cmp bx,cx
	ja lc1
	mov cx,bx		; Won't need a block change
lc1:
	sub bx,cx		; ax has number of words after block change
	inc cx
	ror cx,1
	ror bx,1

;
; Draw the line
;
	even
lc4:
	cld
	rep stosw

	cmp bx,0
	je lc5

;
; Handle block change and continue
;
	inc dx
	push dx
	call vgablock
	pop dx

	mov cx,bx
	xor bx,bx
	xor di,di
	jmp lc4

;
; Finish up
;
lc5:
	Postfix
vgahline endp



;
; Draw a line using bresenham's algorithm.
;
; Parameters:
;	- x1
;	- y1
;	- x2
;	- y2
;	- Pixel value
;
; Locals:
;	[bp-10] DX
;	[bp-12] DY
;	[bp-14] incr1
;	[bp-16] incr2
;
public vgaline
vgaline proc far
	Prefix
	sub sp,8
;
	mov	ax,vgadata	; Load address of data segment
	mov	ds,ax		; Set DS register
;
; Load window pointers
;
	mov ax,WinAddr
	mov es,ax		; Set ES to point to video memory

	push [bp+8]
	push [bp+6]
	call vgaoffset
	add sp,4
	mov di,ax

;
; Initialize for line draw
;
	mov ax,[bp+8]		; Get x1
	sub ax,[bp+12]		; Sub x2
	jg ld1			; Skip if positive
	neg ax
ld1:	mov [bp-10],ax		; Save DX

	mov ax,[bp+6]		; Get y1
	sub ax,[bp+10]		; sub y2
	jg ld2			; Skip if positive
	neg ax
ld2:	mov [bp-12],ax		; Save DY

	cmp ax,[bp-10]		; See if DY>DX
	jle xline		; Go do X oriented version
	jmp yline		; Go do Y oriented version

;
; X oriented version of draw line. Slope must be between -1 and 1 inclusive
;
xline:
	mov cx, [bp-10]		; cx has increment control

	sal ax,1		; DY*2
	mov [bp-14],ax		; Save incr1
	sub ax,[bp-10]		; 2*dy - dx
	mov bx,ax		; bx has D value

	mov ax,[bp-12]		; Get DY
	sub ax,[bp-10]		; (DY-DX)
	sal ax,1		; 2*(DY-DX)
	mov [bp-16],ax		; Save incr2

	mov word ptr [bp-10],0  ; Assume going to left
	mov ax,[bp+8]		; Get x1
	sub ax,[bp+12]		; x1-x2
	jg ld3
	mov word ptr [bp-10],1	; Going to right
ld3:
	mov word ptr [bp-12],0	; Assume going up
	mov ax,[bp+6]		; Get y1
	sub ax,[bp+10]		; y1-y2
	jg ld5
	mov word ptr [bp-12],1	; Going down
ld5:

;
; Main X oriented drawing loop.
;	ax = pixel value
;	bx = d
;	cx = loop control
;	dx = block number
;	di = block offset
;
	cmp BitsPerPixel,8      ; If 8bit mode continue else goto
	jne drwrgb1             ; draw_rgb routine
	mov ax,[bp+14]
	mov es:[di],al		; Write first pixel
	jmp ldd5
drwrgb1:
	push [bp+18]
	push [bp+16]
	push [bp+14]
	call draw_rgb
	add sp,6
ldd5:
	cmp cx,0		; Check if done
	je xloopend

xloop:
	cmp word ptr [bp-10],0	; See if going left?
	je ld7
;	inc di			; going right
	add di,BytesPerPixel
	jnc ld8
	inc dx
	push dx
	call vgablock
	pop dx
	jmp ld8
ld7:
;	dec di			; going left
	sub di,BytesPerPixel
	jnc ld8
	dec dx
	push dx
	call vgablock
	pop dx
ld8:
	cmp bx,0		; test d<0
	jge ld9
	add bx,[bp-14]		; d = d + incr1
	jmp ld11
ld9:
	add bx,[bp-16]		; d = d + incr2
	cmp word ptr [bp-12],0	; See if going up
	je ld10
	add di,ScanWidth	; Go to next line
	jnc ld11
	inc dx
	push dx
	call vgablock
	pop dx
	jmp ld11
ld10:
	sub di,ScanWidth	; Go to previous line
	jnc ld11
	dec dx
	push dx
	call vgablock
	pop dx
ld11:
	cmp BitsPerPixel,8      ; If 8bit continue else
	jne drwrgb2             ; call draw_rgb
	mov es:[di],al		; Write next pixel
	jmp ldd11
drwrgb2:
	push [bp+18]
	push [bp+16]
	push [bp+14]
	call draw_rgb
	add sp,6
ldd11:
	loop xloop
xloopend:
	jmp done


;
; Y oriented version of draw line. Slope must be outside -1 and 1 inclusive
;
yline:
	mov cx, [bp-12]		; cx has increment control

	mov ax, [bp-10]
	sal ax,1		; DX*2
	mov [bp-14],ax		; Save incr1
	sub ax,[bp-12]		; 2*dx - dy
	mov bx,ax		; bx has D value

	mov ax,[bp-10]		; Get DX
	sub ax,[bp-12]		; (DX-DY)
	sal ax,1		; 2*(DX-DY)
	mov [bp-16],ax		; Save incr2

	mov word ptr [bp-10],0  ; Assume going to left
	mov ax,[bp+8]		; Get x1
	sub ax,[bp+12]		; x1-x2
	jg ld12
	mov word ptr [bp-10],1	; Going to right
ld12:
	mov word ptr [bp-12],0	; Assume going up
	mov ax,[bp+6]		; Get y1
	sub ax,[bp+10]		; y1-y2
	jg ld13
	mov word ptr [bp-12],1	; Going down
ld13:

;
; Main Y oriented drawing loop.
;	ax = pixel value
;	bx = d
;	cx = loop control
;	dx = block number
;	di = block offset
;
	cmp BitsPerPixel,8      ; Is it 8bit mode
	jne drwrgb3             ;  no. call draw_rgb
	mov ax,[bp+14]
	mov es:[di],al		; Write first pixel
	jmp ldd13
drwrgb3:
	push [bp+18]
	push [bp+16]
	push [bp+14]
	call draw_rgb
	add sp,6
ldd13:	cmp cx,0		; Check if done
	je yloopend

yloop:
	cmp word ptr [bp-12],0	; See if going up?
	je ld14
	add di,ScanWidth	; going down
	jnc ld15
	inc dx
	push dx
	call vgablock
	pop dx
	jmp ld15
ld14:
	sub di,ScanWidth	; going up
	jnc ld15
	dec dx
	push dx
	call vgablock
	pop dx
ld15:
	cmp bx,0		; test d<0
	jge ld16
	add bx,[bp-14]		; d = d + incr1
	jmp ld18
ld16:
	add bx,[bp-16]		; d = d + incr2
	cmp word ptr [bp-10],0	; See if going left
	je ld17
;	inc di			; Go right
	add di,BytesPerPixel
	jnc ld18
	inc dx
	push dx
	call vgablock
	pop dx
	jmp ld18
ld17:
;	dec di			; Go left
	sub di,BytesPerPixel
	jnc ld18
	dec dx
	push dx
	call vgablock
	pop dx
ld18:
	cmp BitsPerPixel,8      ; Is it 8bit mode
	jne drwrgb4
	mov es:[di],al		; Write next pixel
	jmp ld18
drwrgb4:
	push [bp+18]
	push [bp+16]
	push [bp+14]
	call draw_rgb
	add sp,6
ldd18:
	loop yloop
yloopend:

;
; Clear stack and exit
;
done:
	add sp,8
	Postfix
vgaline endp



;
; Set colors from an array of rgb values.
;
; Parameters:
;	- Array of colors
;	- Start index
;	- Number of colors
;
public vgasetcolor
vgasetcolor proc far
	Prefix

	les dx,[bp+6]		; Get address of colormap
	mov bx,[bp+10]		; Get first color index
	mov cx,[bp+12]		; Get Number of indexes
	mov ax,1012h		; Set block of color registers function
	int 10h

	Postfix
vgasetcolor endp



;
; Fill a rectangular region with a given pixel value. Region is assumed to
; start on a even address and be an even width. Width and height values
; must be positive. Width and height values get modified.
;
; Parameters:
;	- Row for upper left corner
;	- Column for upper left corner
;	- Width of rectangle
;	- Height of rectangle
;	- Pixel value
;
; Locals
;	[bp-10] LineSkip
;
public vgafill
vgafill proc far
	Prefix
	sub sp,2
;
	mov	ax,vgadata	; Load address of data segment
	mov	ds,ax		; Set DS register

;
; Load window pointers
;
	mov ax,WinAddr
	mov es,ax		; Set ES to point to video memory

	push [bp+8]
	push [bp+6]
	call vgaoffset
	add sp,4
	mov di, ax		; Offset in di


;
; Setup control parameters for line draw.
;
	mov bx,ScanWidth        ; Get BytesPerScanLine
;
	push dx			; save for later
   ; added 1/2/92, djl, Adjust line offset value
	mov ax,[bp+10]          ; added to adjust for 15 16 or 24bit modes
	mul BytesPerPixel       ; columns times BytesPerPixel, djl

	sub bx,ax
   ;
	mov [bp-10], bx		; Amount to skip to get to next line

	mov ax,[bp+14]          ; Get 8bit pixel value
	mov ah,al		; ax has duplicated pixel value in al and ah
	pop dx
	even
linestart:
	mov cx,BlockEnd		; Last point in counter
	sub cx,di               ; cx has number of bytes till block change
				;
	mov bx,[bp+10]		; bx has number of bytes in line
	cmp BitsPerPixel,8      ; If 8bit mode skip counter adjustment, djl
	je lee1                 ; skip if 8bit, djl
	shl bx,1		; else multiply width of fill by two, djl
lee1:
	dec bx                  ;
	cmp bx,cx               ;
	ja le1
	mov cx,bx		; Wont need a block change
le1:
	sub bx,cx		; ax has number of words after block change
	inc cx
	ror cx,1
	ror bx,1
;
; Draw the line
;

	even
le4:
	cmp BitsPerPixel,8
	jne drwit
	cld
	rep stosw
	jmp lee4
drwit:
;	mov cx,[bp+10]
loopit:
	push [bp+18]
	push [bp+16]
	push [bp+14]
	call draw_rgb
	add sp,6
	add di,BytesPerPixel
	loop loopit
lee4:
	cmp di,0		; Check for exact alignment
	je le5
	cmp bx,0
	je le6

;
; Handle block change and continue
;
le5:
	inc dx
	push dx
	call vgablock
	pop dx

	cmp bx,0
	je le6

	mov cx,bx
	xor bx,bx
	xor di,di
	jmp le4

;
; Set up for next line
;
le6:
	dec word ptr [bp+12]
	je le7

	add di,[bp-10]		; Go to start of next line
	jnc linestart

	inc dx			; Bump block pointer
	push dx
	call vgablock
	pop dx
	jmp linestart

;
; Finish up
;
le7:
	add sp,2
	Postfix
vgafill endp


;
; Copy a given rectangle into display memory at the specified address.
; All pixels from the source rectangle are copied with no masking.
; Coordinates are assumed to be correct and wraparound accounted for by
; the calling routine. The start address and rectangle width are assumed
; to be even values to permit faster copy. The passed values may be modified
; and should not be retained by the calling routine.
;
; Parameters:
;	- Far pointer to source rectangle
;	- Total width of source memory
;	- Row for upper left corner
;	- Column for upper left corner
;	- Width of rectangle
;	- Height of rectangle
;
; Locals
;	[bp-10] LineSkip
;
public vgarect
vgarect proc far
	Prefix
	sub sp,2
;
	mov	ax,vgadata	; Load address of data segment
	mov	ds,ax		; Set DS register

;
; Load window pointers
;
	mov ax,WinAddr
	mov es,ax		; Set ES to point to video memory

	push [bp+14]
	push [bp+12]
	call vgaoffset
	add sp,4

;
; Setup control parameters for line draw.
;
	mov di, ax		; Offset for output memory in di

	mov bx,ScanWidth
	sub bx,[bp+16]
	mov [bp-10], bx		; Amount to skip to get to next line on output

	mov bx,[bp+10]
	sub bx,[bp+16]
	mov [bp+10], bx		; Amount to go to next line on input data

	mov si, [bp+6]		; Offset for input memory

	even
flinestart:
	mov cx,BlockEnd		; Last point in counter
	sub cx,di               ; cx has number of bytes till block change

	mov bx,[bp+16]		; bx has number of bytes in line
	dec bx

	cmp bx,cx
	ja lf1
	mov cx,bx		; Won't need a block change
lf1:
	sub bx,cx		; bx has number of words after block change
	inc cx
	ror cx,1
	ror bx,1


;
; Draw the line
;
	even
lf4:
	push ds			; Save segment for vgadata
	mov ax, [bp+8]
	mov ds,ax		; Set segment for source rectangle

	cld
	rep movsw

	pop ds			; Get segment for vgadata
	cmp di,0		; Check for exact alignment
	je lf5
	cmp bx,0
	je lf6

;
; Handle block change and continue
;
lf5:
	inc dx
	push dx
	call vgablock
	pop dx

	cmp bx,0
	je lf6

	mov cx,bx
	xor bx,bx
	xor di,di
	jmp lf4

;
; Set up for next line
;
lf6:
	dec word ptr [bp+18]
	je lf7

	add si,[bp+10]		; Goto next line in input
	add di,[bp-10]		; Go to start of next line on output
	jnc flinestart

	inc dx			; Bump block pointer
	push dx
	call vgablock
	pop dx
	jmp flinestart

;
; Finish up
;
lf7:
	add sp,2
	Postfix
vgarect endp


;
; Copy a given rectangle into display memory at the specified address.
; All pixels from the source rectangle are copied unless they have the
; value 0. Coordinates are assumed to be correct and wraparound accounted
; for by the calling routine. The passed values may be modified
; and should not be retained by the calling routine.
;
; Parameters:
;	- Far pointer to source rectangle
;	- Total width of source memory
;	- Row for upper left corner
;	- Column for upper left corner
;	- Width of rectangle
;	- Height of rectangle
;
; Locals
;	[bp-10] LineSkip
;
public vgarect2
vgarect2 proc far
	Prefix
	sub sp,2
;
	mov	ax,vgadata	; Load address of data segment
	mov	ds,ax		; Set DS register

;
; Load window pointers
;
	mov ax,WinAddr
	mov es,ax		; Set ES to point to video memory

	push [bp+14]
	push [bp+12]
	call vgaoffset
	add sp,4

;
; Setup control parameters for line draw.
;
	mov di, ax		; Offset for output memory in di

	mov bx,ScanWidth
	sub bx,[bp+16]
	mov [bp-10], bx		; Amount to skip to get to next line on output

	mov bx,[bp+10]
	sub bx,[bp+16]
	mov [bp+10], bx		; Amount to go to next line on input data

	mov si, [bp+6]		; Offset for input memory

	even
glinestart:
	mov cx,BlockEnd		; Last point in counter
	sub cx,di               ; cx has number of bytes till block change

	mov bx,[bp+16]		; bx has number of bytes in line
	dec bx

	cmp bx,cx
	ja lg1
	mov cx,bx		; Won't need a block change
lg1:
	sub bx,cx		; bx has number of bytes after block change
	inc cx

;
; Draw the line
;
	even
lg4:
	push ds			; Save segment for vgadata
	mov ax, [bp+8]
	mov ds,ax		; Set segment for source rectangle

	cld
lg8:	lodsb
	or al,al		; Test for 0
	jz lg9
	stosb
	jmp lg10
lg9:	inc di
lg10:	loop lg8

	pop ds			; Get segment for vgadata
	cmp di,0		; Check for exact alignment
	je lg5
	cmp bx,0
	je lg6

;
; Handle block change and continue
;
lg5:
	inc dx
	push dx
	call vgablock
	pop dx

	cmp bx,0
	je lg6

	mov cx,bx
	xor bx,bx
	xor di,di
	jmp lg4

;
; Set up for next line
;
lg6:
	dec word ptr [bp+18]
	je lg7

	add si,[bp+10]		; Goto next line in input
	add di,[bp-10]		; Go to start of next line on output
	jnc glinestart

	inc dx			; Bump block pointer
	push dx
	call vgablock
	pop dx
	jmp glinestart

;
; Finish up
;
lg7:
	add sp,2
	Postfix
vgarect2 endp



;
; Handle mouse and keyboard I/O
; If a keyboard key or mouse button is pressed, return a value indicating
; what was pressed. Also, maintain the mouse position values for external
; reference.
;
vgagetbutton proc far
	mov ah,0
	int 16h
	xor ah,ah               ; Don't want scan code
	ret
vgagetbutton endp



;
; Display a text string at a given location
;
; Parameters:
;	- row
;	- column
;	- character string
;	- pixel value for foreground
;
vgatext proc far
	ret
vgatext endp


vgacode	ends
	end
