; 320x240x256 (requires register-compatible VGA+)
; Loadable driver for The Graphics Engine
; Copyright (c) 1993 by Matthew Hildebrand
; Turbo Assembler syntax

IDEAL
MODEL LARGE TGE320X240_TEXT
P386N


SCREEN_WIDE	=	320
SCREEN_DEEP	=	240
NUM_COLOURS	=	256


		CODESEG TGE320X240_TEXT
		ORG	0

;*** Signature
			db	'TGE3'
;*** Non-I/O functions
_initGraphics		dw	initGraphics		; initGraphics
			dw	?
_deInitGraphics		dw	0			; deInitGraphics
			dw	?
_setPaletteReg		dw	setPaletteReg		; setPaletteReg
			dw	?
_getPaletteReg		dw	getPaletteReg		; getPaletteReg
			dw	?
_setBlockPalette	dw	setBlockPalette		; setBlockPalette
			dw	?
_getBlockPalette	dw	getBlockPalette		; getBlockPalette
			dw	?
_colourCloseTo		dw	0			; colourCloseTo
			dw	?
_colourCloseToX		dw	0			; colourCloseToX
			dw	?
_imageSize		dw	0			; imageSize
			dw	?
_imageSizeDim		dw	0			; imageSizeDim
			dw	?
_setPage		dw	0			; setPage (not implemented yet)
			dw	?

;*** Currently active I/O functions (filled in by loadGraphDriver())
			dd	20	DUP(?)

;*** Input functions
_getImage_scr		dw	0			; getImage
			dw	?
_getImage_mem		dw	0
			dw	?
_getLine_scr		dw      getLine_scr	      	; getLine
			dw	?
_getLine_mem		dw	getLine_mem
			dw	?
_getPixel_scr		dw	getPixel_scr		; getPixel
			dw	?
_getPixel_mem		dw	getPixel_mem
			dw	?

;*** Output functions
_putImage_scr_copy	dw	0			; putImage
			dw	?
_putImage_scr_and	dw	0
			dw	?
_putImage_scr_not	dw	0
			dw	?
_putImage_scr_or	dw	0
			dw	?
_putImage_scr_xor	dw	0
			dw	?
_putImage_mem_copy	dw	0
			dw	?
_putImage_mem_and	dw	0
			dw	?
_putImage_mem_not	dw	0
			dw	?
_putImage_mem_or	dw	0
			dw	?
_putImage_mem_xor	dw	0
			dw	?
_putImageInv_scr_copy	dw	0			; putImageInv
			dw	?
_putImageInv_scr_and	dw	0
			dw	?
_putImageInv_scr_not	dw      0
			dw	?
_putImageInv_scr_or	dw      0
			dw	?
_putImageInv_scr_xor	dw	0
			dw	?
_putImageInv_mem_copy	dw	0
			dw	?
_putImageInv_mem_and	dw	0
			dw	?
_putImageInv_mem_not	dw	0
			dw	?
_putImageInv_mem_or	dw	0
			dw	?
_putImageInv_mem_xor	dw	0
			dw	?
_putLine_scr_copy      	dw	putLine_scr_copy	; putLine
			dw	?
_putLine_scr_and      	dw      0
			dw	?
_putLine_scr_not      	dw      0
			dw	?
_putLine_scr_or      	dw      0
			dw	?
_putLine_scr_xor      	dw	0
			dw	?
_putLine_mem_copy	dw      putLine_mem_copy
			dw	?
_putLine_mem_and	dw      0
			dw	?
_putLine_mem_not	dw      0
			dw	?
_putLine_mem_or		dw      0
			dw	?
_putLine_mem_xor	dw	0
			dw	?
_putLineInv_scr_copy   	dw	0			; putLineInv
			dw	?
_putLineInv_scr_and   	dw	0
			dw	?
_putLineInv_scr_not   	dw	0
			dw	?
_putLineInv_scr_or   	dw	0
			dw	?
_putLineInv_scr_xor   	dw	0
			dw	?
_putLineInv_mem_copy	dw	putLineInv_mem_copy
			dw	?
_putLineInv_mem_and	dw	0
			dw	?
_putLineInv_mem_not	dw	0
			dw	?
_putLineInv_mem_or	dw	0
			dw	?
_putLineInv_mem_xor	dw	0
			dw	?
_putPixel_scr_copy	dw	putPixel_scr_copy	; putPixel
			dw	?
_putPixel_scr_and	dw      putPixel_scr_and
			dw	?
_putPixel_scr_not	dw      putPixel_scr_not
			dw	?
_putPixel_scr_or	dw      putPixel_scr_or
			dw	?
_putPixel_scr_xor	dw	putPixel_scr_xor
			dw	?
_putPixel_mem_copy	dw	putPixel_mem_copy
			dw	?
_putPixel_mem_and	dw      putPixel_mem_and
			dw	?
_putPixel_mem_not	dw      putPixel_mem_not
			dw	?
_putPixel_mem_or	dw      putPixel_mem_or
			dw	?
_putPixel_mem_xor	dw	putPixel_mem_xor
			dw	?
_line_scr_copy		dw	0			; line
			dw	?
_line_scr_and		dw      0
			dw	?
_line_scr_not		dw      0
			dw	?
_line_scr_or		dw      0
			dw	?
_line_scr_xor		dw	0
			dw	?
_line_mem_copy		dw	0
			dw	?
_line_mem_and		dw	0
			dw	?
_line_mem_not		dw	0
			dw	?
_line_mem_or		dw	0
			dw	?
_line_mem_xor		dw	0
			dw	?
_horizLine_scr_copy	dw	horizLine_scr_copy  	; horizLine
			dw	?
_horizLine_scr_and	dw      0
			dw	?
_horizLine_scr_not	dw      0
			dw	?
_horizLine_scr_or	dw      0
			dw	?
_horizLine_scr_xor	dw	0
			dw	?
_horizLine_mem_copy	dw	horizLine_mem_copy
			dw	?
_horizLine_mem_and	dw      0
			dw	?
_horizLine_mem_not	dw      0
			dw	?
_horizLine_mem_or	dw      0
			dw	?
_horizLine_mem_xor	dw	0
			dw	?
_vertLine_scr_copy	dw	0		 	; vertLine
			dw	?
_vertLine_scr_and	dw	0
			dw	?
_vertLine_scr_not	dw	0
			dw	?
_vertLine_scr_or	dw	0
			dw	?
_vertLine_scr_xor	dw	0
			dw	?
_vertLine_mem_copy	dw	0
			dw	?
_vertLine_mem_and	dw	0
			dw	?
_vertLine_mem_not	dw	0
			dw	?
_vertLine_mem_or	dw	0
			dw	?
_vertLine_mem_xor	dw	0
			dw	?
_drawRect_scr_copy	dw	0			; drawRect
			dw	?
_drawRect_scr_and	dw	0
			dw	?
_drawRect_scr_not	dw	0
			dw	?
_drawRect_scr_or	dw	0
			dw	?
_drawRect_scr_xor	dw	0
			dw	?
_drawRect_mem_copy	dw	0
			dw	?
_drawRect_mem_and	dw	0
			dw	?
_drawRect_mem_not	dw	0
			dw	?
_drawRect_mem_or	dw	0
			dw	?
_drawRect_mem_xor	dw	0
			dw	?
_filledRect_scr_copy	dw	0			; filledRect
			dw	?
_filledRect_scr_and	dw      0
			dw	?
_filledRect_scr_not	dw      0
			dw	?
_filledRect_scr_or	dw      0
			dw	?
_filledRect_scr_xor	dw	0
			dw	?
_filledRect_mem_copy	dw	0
			dw	?
_filledRect_mem_and	dw	0
			dw	?
_filledRect_mem_not	dw	0
			dw	?
_filledRect_mem_or	dw	0
			dw	?
_filledRect_mem_xor	dw	0
			dw	?
_clearGraphics_scr_copy	dw	clearGraphics_scr_copy	; clearGraphics
			dw	?
_clearGraphics_scr_and	dw      0
			dw	?
_clearGraphics_scr_not	dw      0
		      	dw	?
_clearGraphics_scr_or	dw      0
			dw	?
_clearGraphics_scr_xor	dw	0
			dw	?
_clearGraphics_mem_copy	dw	0
			dw	?
_clearGraphics_mem_and	dw	0
			dw	?
_clearGraphics_mem_not	dw	0
			dw	?
_clearGraphics_mem_or	dw	0
			dw	?
_clearGraphics_mem_xor	dw	0
			dw	?
_ellipse_scr_copy	dw	0			; ellipse
			dw	?
_ellipse_scr_and	dw	0
			dw	?
_ellipse_scr_not	dw	0
			dw	?
_ellipse_scr_or		dw	0
			dw	?
_ellipse_scr_xor	dw	0
			dw	?
_ellipse_mem_copy	dw	0
			dw	?
_ellipse_mem_and	dw	0
			dw	?
_ellipse_mem_not	dw	0
			dw	?
_ellipse_mem_or		dw	0
			dw	?
_ellipse_mem_xor	dw	0
			dw	?
_filledEllipse_scr_copy	dw	0			; filledEllipse
			dw	?
_filledEllipse_scr_and	dw	0
			dw	?
_filledEllipse_scr_not	dw	0
			dw	?
_filledEllipse_scr_or	dw	0
			dw	?
_filledEllipse_scr_xor	dw	0
			dw	?
_filledEllipse_mem_copy	dw	0
			dw	?
_filledEllipse_mem_and	dw	0
			dw	?
_filledEllipse_mem_not	dw	0
			dw	?
_filledEllipse_mem_or	dw	0
			dw	?
_filledEllipse_mem_xor	dw	0
			dw	?
_circle_scr_copy	dw	0			; circle
			dw	?
_circle_scr_and		dw	0
			dw	?
_circle_scr_not		dw	0
			dw	?
_circle_scr_or		dw	0
			dw	?
_circle_scr_xor		dw	0
			dw	?
_circle_mem_copy	dw	0
			dw	?
_circle_mem_and		dw	0
			dw	?
_circle_mem_not		dw	0
			dw	?
_circle_mem_or		dw	0
			dw	?
_circle_mem_xor		dw	0
			dw	?
_filledCircle_scr_copy	dw	0			; filledCircle
			dw	?
_filledCircle_scr_and	dw	0
			dw	?
_filledCircle_scr_not	dw	0
			dw	?
_filledCircle_scr_or	dw	0
			dw	?
_filledCircle_scr_xor	dw	0
			dw	?
_filledCircle_mem_copy	dw	0
			dw	?
_filledCircle_mem_and	dw	0
			dw	?
_filledCircle_mem_not	dw	0
			dw	?
_filledCircle_mem_or	dw	0
			dw	?
_filledCircle_mem_xor	dw	0
			dw	?
_fillRegion_scr_copy	dw	0			; fillRegion
			dw	?
_fillRegion_scr_and	dw	0
			dw	?
_fillRegion_scr_not	dw	0
			dw	?
_fillRegion_scr_or	dw	0
			dw	?
_fillRegion_scr_xor	dw	0
			dw	?
_fillRegion_mem_copy	dw	0
			dw	?
_fillRegion_mem_and	dw	0
			dw	?
_fillRegion_mem_not	dw	0
			dw	?
_fillRegion_mem_or	dw	0
			dw	?
_fillRegion_mem_xor	dw	0
			dw	?
_fillLine_scr_copy	dw	horizLine_scr_copy	; fillLine
			dw	?
_fillLine_scr_and	dw      0
			dw	?
_fillLine_scr_not	dw      0
			dw	?
_fillLine_scr_or	dw      0
			dw	?
_fillLine_scr_xor	dw	0
			dw	?
_fillLine_mem_copy	dw	horizLine_mem_copy
			dw	?
_fillLine_mem_and	dw      0
			dw	?
_fillLine_mem_not	dw      0
			dw	?
_fillLine_mem_or	dw      0
			dw	?
_fillLine_mem_xor	dw	0
			dw	?
;*** Mode information
scrnMaxX		dw	319	; physical dimensions
scrnMaxY		dw	239
maxColour		dw	255	; maximum colour number
xRatio		       	dw	4	; aspect ratio 4:3 (320:240 in
yRatio			dw	3	;   lowest terms)
bitsPerPixel		dw	8	; 8 bits per pixel
inMaxX			dw	319	; current input screen dimensions
inMaxY			dw	239
outMaxX			dw	319	; current output screen dimensions
outMaxY			dw	239
inScreenWide		dw	?	; needed only for virtual screens
outScreenWide		dw	?
;*** Viewport information
inViewportULX		dw	0
inViewportULY		dw	0
inViewportLRX		dw	319
inViewportLRY		dw	239
outViewportULX		dw	0
outViewportULY		dw	0
outViewportLRX		dw	319
outViewportLRY		dw	239
;*** Paging information
pagingSupported		dw	?	; not implemented yet
curPage			dw	?	; not implemented yet
maxPage			dw	?	; not implemented yet
;*** Force (image width MOD imageWideAdjust) = 0.
imageWideAdjust		dw	?	; not implemented yet
;*** Current and screen addresses
	LABEL	inAddr	DWORD		; current input address
inOff	dw	0
inSeg	dw	0A000h
	LABEL	outAddr	DWORD		; current output address
outOff	dw	0
outSeg	dw	0A000h
	LABEL	scrAddr	DWORD		; screen address
scrOff	dw	0
scrSeg	dw	0A000h
;*** Copyright string
	db	'The Graphics Engine -- Copyright (c) 1993 by Matthew Hildebrand'


inited		db	0
colourPalette	db	768	DUP(?)
lineOffs	dw	240	DUP(?)

; Plane masks for horizLine
leftEdgeMask	db	1111b, 1110b, 1100b, 1000b
rightEdgeMask	db	0001b, 0011b, 0111b, 1111b


SC_INDEX	EQU	3C4h    ; Sequence Controller Index
GC_INDEX	EQU	3CEh	; Graphics Controller Index register
CRTC_INDEX	EQU	3D4h    ; CRT Controller Index
MISC_OUTPUT	EQU	3C2h    ; Miscellaneous Output register
MAP_MASK	EQU     02h     ; index in SC of Map Mask register
READ_MAP	EQU	4	; Read Map register index in GC
MEMORY_MODE	EQU	4	; Memory mode register in SC
GRAPHICS_MODE	EQU	5	; Graphics Mode register index in GC
MISCELLANEOUS	EQU	6	; Miscellaneous register index in GC
MAX_SCAN_LINE	EQU	9      	; Maximum Scan Line reg index in CRTC
START_ADDR_HIGH	EQU	0Ch	; Start Address High reg index in CRTC
UNDERLINE	EQU	14h	; Underline Location reg index in CRTC
MODE_CONTROL	EQU	17h	; Mode Control register index in CRTC
INPUT_STATUS_1  EQU     03DAh   ; Input Status 1 register
START_ADDR_HIGH EQU	0Ch     ; start address high byte
START_ADDR_LOW  EQU	0Dh     ; start address low byte
WORD_OUTS_OK	EQU	1	; Set to 0 for VGAs that can't handle
				; word OUTs to indexed VGA registers


MACRO	OUT_WORD
if WORD_OUTS_OK
  out	dx,ax
else
  out	dx,al
  inc	dx
  xchg	ah,al
  out	dx,al
  dec	dx
  xchg	ah,al
endif
ENDM


;*****
;***** initGraphics
;*****

PROC	C	initGraphics
  push	si di

  mov   ax,0013h			; set mode 13h
  int   10h

  mov   dx,SC_INDEX
  mov   ax,0604h
  out   dx,ax   			; disable chain4 mode
  mov   ax,0100h
  out   dx,ax   			; synchronous reset while setting
  					; Misc Output for safety, even
					; though clock unchanged

  mov   dx,MISC_OUTPUT
  mov   al,0E3h
  out   dx,al				; select 25 MHz dot clock & 60 Hz
  					; scanning rate

  mov   dx,SC_INDEX
  mov   ax,0300h
  out   dx,ax				; undo reset (restart sequencer)

  mov   dx,CRTC_INDEX 			; reprogram the CRT Controller
  mov   al,11h  			; VSync End reg contains register
  out   dx,al   			; write protect bit
  inc   dx      			; CRT Controller Data register
  in    al,dx   			; get current VSync End register setting
  and   al,7Fh  			; remove write protect on various
  out   dx,al   			; CRTC registers
  dec   dx      			; CRT Controller Index

  mov	ax,00D06h			; set CRT parameters
  out	dx,ax
  mov	ax,03E07h
  out	dx,ax
  mov	ax,04109h
  out	dx,ax
  mov	ax,0EA10h
  out	dx,ax
  mov	ax,0AC11h
  out	dx,ax
  mov	ax,0DF12h
  out	dx,ax
  mov	ax,00014h
  out	dx,ax
  mov	ax,0E715h
  out	dx,ax
  mov	ax,00616h
  out	dx,ax
  mov	ax,0E317h
  out	dx,ax

  mov   dx,SC_INDEX
  mov   ax,0F02h
  out   dx,ax   			; enable writes to all four planes
  mov   ax,0A000h  			; now clear all display memory, 8
  mov   es,ax         			; pixels at a time
  xor   di,di   			; point ES:DI to display memory
  xor   ax,ax   			; clear to zero-value pixels
  mov   cx,8000h 			; # of words in display memory
  rep   stosw   			; clear all of display memory

  cmp	[inited],0			; restore palette if necessary
  je	@@notInited
  pop	di si
  mov	ax,1
  retf

	@@notInited:
  mov	[inited],1
  mov	si,OFFSET lineOffs
  mov	cx,SCREEN_DEEP
  xor	bx,bx

	@@LLoop:
  mov	ax,SCREEN_WIDE/4
  mul	bx
  mov	[cs:si],ax
  add	si,2
  inc	bx
  loop	@@LLoop

  pop   di si
  mov	ax,1
  retf
ENDP


;*****
;***** putLine
;*****

PROC	C	putLine_scr_copy
	ARG	lineNum:WORD, xOff:WORD, lineLen:WORD, buf:DWORD
        LOCAL	x2:WORD
  push	ds si di

  mov	bx,[lineNum]			; start address in ES:DI
  shl	bx,1
  mov	di,[lineOffs+bx]
  mov	dx,[xOff]
  shr	dx,2
  add	di,dx
  mov	ax,0A000h
  mov	es,ax
  lds	si,[buf]			; source in DS:SI
  cld

  mov	bx,[xOff]
  add	bx,[lineLen]			; calculate x2
  dec	bx
  mov	[x2],bx

  mov	cx,[lineLen]			; line is short
  cmp	cx,4
JUMPS
  jle	@@ShortLine
NOJUMPS

  mov	cx,[xOff]			; calculate starting plane
  mov	bx,cx
  mov	ax,0102h
  and	cl,3
  shl	ah,cl
  mov	dx,SC_INDEX
  OUT_WORD
  push	si
  mov	bx,[x2]
  mov	cx,[xOff]
  	@@Loop1:
  cmp	cx,bx
  jg	@@Loop1Done
  lodsb
  stosb
  add	cx,4
  add	si,3
  jmp	short	@@Loop1

	@@Loop1Done:
  pop	si
  inc	si
  push	si
  mov	bx,[xOff]
  inc	bx
  mov	cx,bx
  mov	ax,0102h
  and	cl,3
  shl	ah,cl
  mov	dx,SC_INDEX
  OUT_WORD
  mov	cx,bx
  mov	bx,[lineNum]			; start address in ES:DI
  shl	bx,1
  mov	di,[lineOffs+bx]
  shr	cx,2
  add	di,cx
  mov	bx,[x2]
  mov	cx,[xOff]
  inc	cx
  	@@Loop2:
  cmp	cx,bx
  jg	@@Loop2Done
  lodsb
  stosb
  add	cx,4
  add	si,3
  jmp	short	@@Loop2

  	@@Loop2Done:
  pop	si
  inc	si
  push	si
  mov	bx,[xOff]
  add	bx,2
  mov	cx,bx
  mov	ax,0102h
  and	cl,3
  shl	ah,cl
  mov	dx,SC_INDEX
  OUT_WORD
  mov	cx,bx
  mov	bx,[lineNum]
  shl	bx,1
  mov	di,[lineOffs+bx]
  shr	cx,2
  add	di,cx
  mov	bx,[x2]
  mov	cx,[xOff]
  add	cx,2
  	@@Loop3:
  cmp	cx,bx
  jg	@@Loop3Done
  lodsb
  stosb
  add	cx,4
  add	si,3
  jmp	short	@@Loop3

	@@Loop3Done:
  pop	si
  inc	si
  mov	bx,[xOff]
  add	bx,3
  mov	cx,bx
  mov	ax,0102h
  and	cl,3
  shl	ah,cl
  mov	dx,SC_INDEX
  OUT_WORD
  mov	cx,bx
  mov	bx,[lineNum]
  shl	bx,1
  mov	di,[lineOffs+bx]
  shr	cx,2
  add	di,cx
  mov	bx,[x2]
  mov	cx,[xOff]
  add	cx,3
	@@Loop4:
  cmp	cx,bx
  jg	@@Exit
  lodsb
  stosb
  add	cx,4
  add	si,3
  jmp	short	@@Loop4

  	@@ShortLine:
  mov	cx,[xOff]
  mov	bx,cx
  and	cl,3
  mov	ax,0102h
  shl	ah,cl
  mov	dx,SC_INDEX
  OUT_WORD
  mov	cx,bx
  shr	bx,2
  mov	di,bx
  mov	bx,[lineNum]
  shl	bx,1
  add	di,[lineOffs+bx]
  movsb
  cmp	cx,[x2]
  jge	@@Exit
  inc	[xOff]
  jmp	short	@@ShortLine

  	@@Exit:
  pop   di si ds
  leave
  retf
ENDP

PROC	C	putLine_mem_copy
	ARG	y:WORD, xOff:WORD, lineLen:WORD, buf:DWORD
  push	ds si di			; save these registers

  xor	eax,eax				; clear EAX
  xor	edx,edx				; clear EDX
  xor	edi,edi				; clear EDI

  les	di,[outAddr]			; load output address
  mov	ax,[y]
  mov	dx,[outScreenWide]
  mul	edx			    	; EDX:EAX = offset - EDI - x
  add	edi,eax				; EDI = offset - x
  mov	dx,[xOff]
  add	edi,edx				; EDI = offset
  mov	edx,edi				; EDX = offset
  shr	edx,4				; EDX = # of paragraphs (segments)
  add	dx,[outSeg]			; DX = new segment
  mov	es,dx				; ES = new segment
  and	di,0000000000001111b	     	; DI = offset within new segment

  lds	si,[buf]			; load input address
  mov	dx,si				; DX = offset
  shr	dx,4				; DX = # of paragraphs (segments)
  mov	ax,ds				; AX = DS
  add	ax,dx				; AX = new DS
  mov	ds,ax				; DS = new DS
  and	si,0000000000001111b		; SI = offset within new segment

  cld
  mov	cx,[lineLen]			; CX = line length
  mov	dx,cx				; DX = line length
  shr	cx,2				; CX = line length in dwords
  rep	movsd			     	; move the dwords if necessary
  mov	cx,dx				; CX = line length in bytes
  and	cx,0000000000000011b		; CX = any residual bytes
  rep	movsb				; move the bytes if necessary

  pop	di si ds			; restore registers
  leave					; clean up
  retf					; return
ENDP


;*****
;***** putLineInv
;*****

PROC	C	putLineInv_mem_copy
	ARG	y:WORD, xOff:WORD, lineLen:WORD, buf:DWORD
  push	ds si di			; save these registers

  xor	eax,eax				; clear EAX
  xor	edx,edx				; clear EDX
  xor	edi,edi				; clear EDI

  les	di,[outAddr]			; load output address
  mov	ax,[y]
  mov	dx,[outScreenWide]
  mul	edx			    	; EDX:EAX = offset - EDI - x
  add	edi,eax				; EDI = offset - x
  mov	dx,[xOff]
  add	edi,edx				; EDI = offset
  mov	edx,edi				; EDX = offset
  shr	edx,4				; EDX = # of paragraphs (segments)
  add	dx,[outSeg]			; DX = new segment
  mov	es,dx				; ES = new segment
  and	di,0000000000001111b	     	; DI = offset within new segment

  lds	si,[buf]			; load input address
  mov	dx,si				; DX = offset
  shr	dx,4				; DX = # of paragraphs (segments)
  mov	ax,ds				; AX = DS
  add	ax,dx				; AX = new DS
  mov	ds,ax				; DS = new DS
  and	si,0000000000001111b		; SI = offset within new segment

  cld
  mov	cx,[lineLen]			; CX = line length

	@@loopStart:
  lodsb					; grab a pixel
  or	al,al				; is it a zero pixel?
  jz	@@invisible			; yes, don't copy it
  stosb					; no, copy it ...
  loop	@@loopStart			; ... and start loop again
  jmp	short	@@loopDone		; quit loop when completed
	@@invisible:
  inc	di				; skip past pixel ...
  loop	@@loopStart			; ... and start loop again

	@@loopDone:
  pop	di si ds			; restore registers
  leave					; clean up
  retf					; return
ENDP


;*****
;***** getLine
;*****

PROC	C	getLine_scr
	ARG	lineNum:WORD, xOff:WORD, lineLen:WORD, buf:DWORD
	LOCAL	x2:WORD
  push	ds si di

  mov	bx,[lineNum]			; start address in ES:DI
  shl	bx,1
  mov	si,[lineOffs+bx]
  mov	dx,[xOff]
  shr	dx,2
  add	si,dx
  mov	ax,0A000h
  mov	ds,ax
  les	di,[buf]			; buffer addr in DS:SI
  cld

  mov	bx,[xOff]
  add	bx,[lineLen]			; calculate x2
  dec	bx
  mov	[x2],bx

  mov	cx,[lineLen]			; line is short
  cmp	cx,4
JUMPS
  jle	@@ShortLine
NOJUMPS

  mov	ax,[xOff]			; calculate starting plane
  mov	bx,ax
  and	al,3
  mov	ah,al
  mov	al,READ_MAP
  mov	dx,GC_INDEX
  OUT_WORD
  push	di
  mov	bx,[x2]
  mov	cx,[xOff]
	@@Loop1:
  cmp	cx,bx
  jg	@@Loop1Done
  lodsb
  stosb
  add	cx,4
  add	di,3
  jmp	short	@@Loop1

	@@Loop1Done:
  pop	di
  inc	di
  push	di
  mov	bx,[xOff]
  inc	bx
  mov	ax,bx
  and	al,3
  mov	ah,al
  mov	al,READ_MAP
  mov	dx,GC_INDEX
  OUT_WORD
  mov	cx,bx
  mov	bx,[lineNum]			; start address in ES:DI
  shl	bx,1
  mov	si,[lineOffs+bx]
  shr	cx,2
  add	si,cx
  mov	bx,[x2]
  mov	cx,[xOff]
  inc	cx
	@@Loop2:
  cmp	cx,bx
  jg	@@Loop2Done
  lodsb
  stosb
  add	cx,4
  add	di,3
  jmp	short	@@Loop2

	@@Loop2Done:
  pop	di
  inc	di
  push	di
  mov	bx,[xOff]
  add	bx,2
  mov	ax,bx
  and	al,3
  mov	ah,al
  mov	al,READ_MAP
  mov	dx,GC_INDEX
  OUT_WORD
  mov	cx,bx
  mov	bx,[lineNum]
  shl	bx,1
  mov	si,[lineOffs+bx]
  shr	cx,2
  add	si,cx
  mov	bx,[x2]
  mov	cx,[xOff]
  add	cx,2
	@@Loop3:
  cmp	cx,bx
  jg	@@Loop3Done
  lodsb
  stosb
  add	cx,4
  add	di,3
  jmp	short	@@Loop3

	@@Loop3Done:
  pop	di
  inc	di
  mov	bx,[xOff]
  add	bx,3
  mov	ax,bx
  and	al,3
  mov	ah,al
  mov	al,READ_MAP
  mov	dx,GC_INDEX
  OUT_WORD
  mov	cx,bx
  mov	bx,[lineNum]
  shl	bx,1
  mov	si,[lineOffs+bx]
  shr	cx,2
  add	si,cx
  mov	bx,[x2]
  mov	cx,[xOff]
  add	cx,3
	@@Loop4:
  cmp	cx,bx
  jg	@@Exit
  lodsb
  stosb
  add	cx,4
  add	di,3
  jmp	short	@@Loop4

	@@ShortLine:
  mov	ax,[xOff]
  mov	bx,ax
  and	al,3
  mov	ah,al
  mov	al,READ_MAP
  mov	dx,GC_INDEX
  OUT_WORD
  mov	cx,bx
  shr	bx,2
  mov	si,bx
  mov	bx,[lineNum]
  shl	bx,1
  add	si,[lineOffs+bx]
  movsb
  cmp	cx,[x2]
  jge	@@Exit
  inc	[xOff]
  jmp	short	@@ShortLine

	@@Exit:
  pop   di si ds
  leave
  retf
ENDP

PROC	C	getLine_mem
	ARG	y:WORD, xOff:WORD, lineLen:WORD, buf:DWORD
  push	ds si di			; save these registers

  xor	eax,eax				; clear EAX
  xor	edx,edx				; clear EDX
  xor	esi,esi				; clear ESI

  les	si,[inAddr]			; load input address
  mov	ax,[y]
  mov	dx,[inScreenWide]
  mul	edx			    	; EDX:EAX = offset - ESI - x
  add	esi,eax				; ESI = offset - x
  mov	dx,[xOff]
  add	esi,edx				; ESI = offset
  mov	edx,esi				; EDX = offset
  shr	edx,4				; EDX = # of paragraphs (segments)
  add	dx,[inSeg]			; DX = new segment
  mov	ds,dx				; ES = new segment
  and	si,0000000000001111b	     	; SI = offset within new segment

  les	di,[buf]			; load output address
  mov	dx,di				; DX = offset
  shr	dx,4				; DX = # of paragraphs (segments)
  mov	ax,es				; AX = ES
  add	ax,dx				; AX = new ES
  mov	es,ax				; ES = new ES
  and	di,0000000000001111b		; DI = offset within new segment

  cld
  mov	cx,[lineLen]			; CX = line length
  mov	dx,cx				; DX = line length
  shr	cx,2				; CX = line length in dwords
  rep	movsd			     	; move the dwords if necessary
  mov	cx,dx				; CX = line length in bytes
  and	cx,0000000000000011b		; CX = any residual bytes
  rep	movsb				; move the bytes if necessary

  pop	di si ds			; restore registers
  leave					; clean up
  retf					; return
ENDP


;*****
;***** putPixel
;*****

; Copy a pixel to the screen
PROC	C	putPixel_scr_copy
	ARG	x:WORD, y:WORD, colour:BYTE
  mov	ax,0A000h			; point ES:BX to screen
  mov	es,ax
  mov	bx,[y]				; point BX to start of desired row
  shl	bx,1
  mov	bx,[lineOffs+bx]
  mov	dx,[x]				; DX = x coordinate of pixel
  mov	cx,dx				; CX = x coordinate of pixel
  shr	dx,2				; DX = x coordinate of pixel / 4
  add	bx,dx				; ES:BX points to pixel
  and	cl,3				; get the plane # of the pixel
  mov	ax,102h				; set the bit corresponding to ...
  shl	ah,cl				; ... the pixel's plane
  mov	dx,SC_INDEX
  OUT_WORD
  mov	al,[colour]			; AL = pixel value
  mov	[es:bx],al			; store pixel value
  leave					; clean up call stack
  retf					; return
ENDP

; AND a pixel to the screen
PROC	C	putPixel_scr_and
	ARG	x:WORD, y:WORD, colour:BYTE
  mov	ax,0A000h			; point ES:BX to screen
  mov	es,ax
  mov	bx,[y]				; point BX to start of desired row
  shl	bx,1
  mov	bx,[lineOffs+bx]
  mov	dx,[x]				; DX = x coordinate of pixel
  mov	cx,dx				; CX = x coordinate of pixel
  shr	dx,2				; DX = x coordinate of pixel / 4
  add	bx,dx				; ES:BX points to pixel
  and	cl,3				; get the plane # of the pixel
  mov	ax,102h				; set the bit corresponding to ...
  shl	ah,cl				; ... the pixel's plane
  mov	dx,SC_INDEX
  OUT_WORD
  mov	al,[colour]			; AL = pixel value
  and	[es:bx],al			; AND pixel value
  leave					; clean up call stack
  retf					; return
ENDP

; NOT a pixel to the screen
PROC	C	putPixel_scr_not
	ARG	x:WORD, y:WORD, colour:BYTE
  mov	ax,0A000h			; point ES:BX to screen
  mov	es,ax
  mov	bx,[y]				; point BX to start of desired row
  shl	bx,1
  mov	bx,[lineOffs+bx]
  mov	dx,[x]				; DX = x coordinate of pixel
  mov	cx,dx				; CX = x coordinate of pixel
  shr	dx,2				; DX = x coordinate of pixel / 4
  add	bx,dx				; ES:BX points to pixel
  and	cl,3				; get the plane # of the pixel
  mov	ax,102h				; set the bit corresponding to ...
  shl	ah,cl				; ... the pixel's plane
  mov	dx,SC_INDEX
  OUT_WORD
  mov	al,[colour]			; AL = pixel value
  not	al				; NOT pixel value
  mov	[es:bx],al			; store NOTed pixel value
  leave					; clean up call stack
  retf					; return
ENDP

; OR a pixel to the screen
PROC	C	putPixel_scr_or
	ARG	x:WORD, y:WORD, colour:BYTE
  mov	ax,0A000h			; point ES:BX to screen
  mov	es,ax
  mov	bx,[y]				; point BX to start of desired row
  shl	bx,1
  mov	bx,[lineOffs+bx]
  mov	dx,[x]				; DX = x coordinate of pixel
  mov	cx,dx				; CX = x coordinate of pixel
  shr	dx,2				; DX = x coordinate of pixel / 4
  add	bx,dx				; ES:BX points to pixel
  and	cl,3				; get the plane # of the pixel
  mov	ax,102h				; set the bit corresponding to ...
  shl	ah,cl				; ... the pixel's plane
  mov	dx,SC_INDEX
  OUT_WORD
  mov	al,[colour]			; AL = pixel value
  or	[es:bx],al			; OR pixel value
  leave					; clean up call stack
  retf					; return
ENDP

; XOR a pixel to the screen
PROC	C	putPixel_scr_xor
	ARG	x:WORD, y:WORD, colour:BYTE
  mov	ax,0A000h			; point ES:BX to screen
  mov	es,ax
  mov	bx,[y]				; point BX to start of desired row
  shl	bx,1
  mov	bx,[lineOffs+bx]
  mov	dx,[x]				; DX = x coordinate of pixel
  mov	cx,dx				; CX = x coordinate of pixel
  shr	dx,2				; DX = x coordinate of pixel / 4
  add	bx,dx				; ES:BX points to pixel
  and	cl,3				; get the plane # of the pixel
  mov	ax,102h				; set the bit corresponding to ...
  shl	ah,cl				; ... the pixel's plane
  mov	dx,SC_INDEX
  OUT_WORD
  mov	al,[colour]			; AL = pixel value
  xor	[es:bx],al			; XOR pixel value
  leave					; clean up call stack
  retf					; return
ENDP

; Copy a pixel to memory
PROC	C	putPixel_mem_copy
	ARG	x:WORD,y:WORD,colour:BYTE
  xor	eax,eax				; clear EAX
  xor	ebx,ebx				; clear EBX
  xor	edx,edx				; clear EDX

  les	bx,[outAddr]			; load output address
  mov	ax,[y]
  mov	dx,[outScreenWide]
  mul	edx			    	; EDX:EAX = offset - EBX - x
  add	ebx,eax				; EBX = offset - x
  mov	dx,[x]
  add	ebx,edx				; EBX = offset

  mov	edx,ebx				; EDX = offset
  shr	edx,4				; EDX = # of paragraphs (segments)
  add	dx,[outSeg]			; DX = new segment
  mov	es,dx				; ES = new segment
  and	bx,0000000000001111b	     	; BX = offset within new segment

  mov	al,[colour]			; colour in AL
  mov	[es:bx],al			; store pixel
  leave					; clean up
  retf					; return
ENDP

; AND a pixel to memory
PROC	C	putPixel_mem_and
	ARG	x:WORD,y:WORD,colour:BYTE
  xor	eax,eax				; clear EAX
  xor	ebx,ebx				; clear EBX
  xor	edx,edx				; clear EDX

  les	bx,[outAddr]			; load output address
  mov	ax,[y]
  mov	dx,[outScreenWide]
  mul	edx			    	; EDX:EAX = offset - EBX - x
  add	ebx,eax				; EBX = offset - x
  mov	dx,[x]
  add	ebx,edx				; EBX = offset

  mov	edx,ebx				; EDX = offset
  shr	edx,4				; EDX = # of paragraphs (segments)
  add	dx,[outSeg]			; DX = new segment
  mov	es,dx				; ES = new segment
  and	bx,0000000000001111b	     	; BX = offset within new segment

  mov	al,[colour]			; colour in AL
  and	[es:bx],al			; AND pixel
  leave					; clean up
  retf					; return
ENDP

; NOT a pixel to memory
PROC	C	putPixel_mem_not
	ARG	x:WORD,y:WORD,colour:BYTE
  xor	eax,eax				; clear EAX
  xor	ebx,ebx				; clear EBX
  xor	edx,edx				; clear EDX

  les	bx,[outAddr]			; load output address
  mov	ax,[y]
  mov	dx,[outScreenWide]
  mul	edx			    	; EDX:EAX = offset - EBX - x
  add	ebx,eax				; EBX = offset - x
  mov	dx,[x]
  add	ebx,edx				; EBX = offset

  mov	edx,ebx				; EDX = offset
  shr	edx,4				; EDX = # of paragraphs (segments)
  add	dx,[outSeg]			; DX = new segment
  mov	es,dx				; ES = new segment
  and	bx,0000000000001111b	     	; BX = offset within new segment

  mov	al,[colour]			; colour in AL
  not	al				; NOT it
  mov	[es:bx],al			; store NOTed pixel
  leave					; clean up
  retf					; return
ENDP

; OR a pixel to memory
PROC	C	putPixel_mem_or
	ARG	x:WORD,y:WORD,colour:BYTE
  xor	eax,eax				; clear EAX
  xor	ebx,ebx				; clear EBX
  xor	edx,edx				; clear EDX

  les	bx,[outAddr]			; load output address
  mov	ax,[y]
  mov	dx,[outScreenWide]
  mul	edx			    	; EDX:EAX = offset - EBX - x
  add	ebx,eax				; EBX = offset - x
  mov	dx,[x]
  add	ebx,edx				; EBX = offset

  mov	edx,ebx				; EDX = offset
  shr	edx,4				; EDX = # of paragraphs (segments)
  add	dx,[outSeg]			; DX = new segment
  mov	es,dx				; ES = new segment
  and	bx,0000000000001111b	     	; BX = offset within new segment

  mov	al,[colour]			; colour in AL
  or	[es:bx],al			; OR pixel
  leave					; clean up
  retf					; return
ENDP

; XOR a pixel to memory
PROC	C	putPixel_mem_xor
	ARG	x:WORD,y:WORD,colour:BYTE
  xor	eax,eax				; clear EAX
  xor	ebx,ebx				; clear EBX
  xor	edx,edx				; clear EDX

  les	bx,[outAddr]			; load output address
  mov	ax,[y]
  mov	dx,[outScreenWide]
  mul	edx			    	; EDX:EAX = offset - EBX - x
  add	ebx,eax				; EBX = offset - x
  mov	dx,[x]
  add	ebx,edx				; EBX = offset

  mov	edx,ebx				; EDX = offset
  shr	edx,4				; EDX = # of paragraphs (segments)
  add	dx,[outSeg]			; DX = new segment
  mov	es,dx				; ES = new segment
  and	bx,0000000000001111b	     	; BX = offset within new segment

  mov	al,[colour]			; colour in AL
  xor	[es:bx],al			; XOR pixel
  leave					; clean up
  retf					; return
ENDP


;*****
;***** getPixel
;*****

; Get a pixel from the screen
PROC	C	getPixel_scr
	ARG	x:WORD, y:WORD
  push	di

  mov	ax,0A000h
  mov	es,ax
  mov	bx,[y]				; point to start of desired row
  shl	bx,1
  mov	bx,[lineOffs+bx]
  mov	dx,[x]
  mov	cx,dx				; store x coord
  shr	dx,2
  add	bx,dx
  mov	di,bx				; ES:DI points to pixel
  and	cl,3				; get the plane # of the pixel
  mov	al,READ_MAP
  mov	ah,cl
  mov	dx,GC_INDEX			; set the bit corresponding to plane
  OUT_WORD
  xor	ax,ax
  mov	al,[es:di]

  pop	di
  leave
  retf
ENDP

; Get a pixel from memory
PROC	C	getPixel_mem
	ARG	x:WORD,y:WORD
  xor	eax,eax				; clear EAX
  xor	ebx,ebx				; clear EBX
  xor	edx,edx				; clear EDX

  les	bx,[inAddr]			; load input address
  mov	ax,[y]
  mov	dx,[inScreenWide]
  mul	edx			    	; EDX:EAX = offset - EBX - x
  add	ebx,eax				; EBX = offset - x
  mov	dx,[x]
  add	ebx,edx				; EBX = offset

  mov	edx,ebx				; EDX = offset
  shr	edx,4				; EDX = # of paragraphs (segments)
  add	dx,[inSeg]			; DX = new segment
  mov	es,dx				; ES = new segment
  and	bx,0000000000001111b	     	; BX = offset within new segment

  xor	ax,ax				; clear AX
  mov	al,[es:bx]			; store pixel in AX for return
  leave					; clean up
  retf					; return
ENDP


;*****
;***** horizLine
;*****

PROC	C	horizLine_scr_copy
	ARG	y:WORD, x1:WORD, x2:WORD, colour:BYTE
	LOCAL	adj1:WORD, adj2:WORD
  push	si di
  cld

  mov	ax,[x1]				; set up adj1
  and	ax,3
  jz	@@adj1A
  mov	bx,4
  sub	bx,ax
  mov	ax,[x1]
  add	ax,bx
  mov	[adj1],ax
  jmp	short	@@adj1B
	@@adj1A:
  mov	ax,[x1]
  mov	[adj1],ax
	@@adj1B:

  mov	ax,[x2]				; set up adj2
  mov	[adj2],ax
  and	ax,3
  sub	[adj2],ax

  mov	ax,[x1]				; ensure x1 <= x2
  cmp	ax,[x2]
  jbe	@@setup
  mov	bx,[x2]
  mov	[x1],bx
  mov	[x2],ax

	@@setup:
  mov	ax,0A000h			; set ES:DI to line start address
  mov	es,ax
  mov	bx,[y]
  shl	bx,1
  mov	di,[lineOffs+bx]
  mov	bx,[x1]				; current x counter
  shr	bx,2
  add	di,bx

  mov	cx,[adj2]			; CX = # of 4-pixel sets starting
  shr	cx,2                            ; on plane 0
  mov	bx,[adj1]
  shr	bx,2
  sub	cx,bx

  cmp	cx,1
  jl	@@shortLine

  ; Draw the left edge
  mov	ax,[x1]				; get plane number of pixel #1
  and	ax,3
  jz	@@planeZeroStart		; starts at plane zero
  mov	si,ax				; set for pixels
  mov	ah,[leftEdgeMask+si]
  mov	al,MAP_MASK
  mov	dx,SC_INDEX
  OUT_WORD
  mov	al,[colour]
  stosb

  ; Draw the interior stretch
	@@planeZeroStart:
  mov	ax,0F02h			; enable writes to all planes
  mov	dx,SC_INDEX
  OUT_WORD
  mov	al,[colour]			; EAX = colour:colour:colour:colour
  mov	ah,al
  mov	dx,ax
  shl	eax,16
  mov	ax,dx
  mov	dx,cx				; DX = CX
  shr	cx,2				; CX = line length in dwords
  rep	stosd				; store the dwords
  mov	cx,dx				; CX = line length in bytes
  and	cx,0000000000000011b		; CX = number of residual bytes
  rep	stosb				; store the residual bytes

  ; Draw the right edge
	@@rightEdge:
  mov	ax,[x2]				; get plane number of last pixel
  and	ax,3
  mov	si,ax				; set for pixels
  mov	ah,[rightEdgeMask+si]
  mov	al,MAP_MASK
  mov	dx,SC_INDEX
  OUT_WORD
  mov	al,[colour]
  stosb

	@@Exit:
  pop	di si				; clean up and go home
  leave
  retf

	@@shortLine:			; for very small lines
  mov	al,[colour]
  mov	cx,[x1]
  mov	dx,[y]
	@@Loop:
  push	ax cx dx			; slow loop until done
  call	putPixel_scr_copy C, cx, dx, ax
  pop	dx cx ax
  inc	cx
  cmp	cx,[x2]
  jle	@@Loop

  pop 	di si
  leave
  retf
ENDP

PROC	C	horizLine_mem_copy
	ARG	y:WORD, x1:WORD, x2:WORD, colour:BYTE
  push	edi				; store EDI

  xor	eax,eax				; clear EAX
  xor	edi,edi				; clear EDI
  xor	edx,edx				; clear EDX

  les	di,[outAddr]			; load output address
  mov	ax,[y]
  mov	dx,[outScreenWide]
  mul	edx			    	; EDX:EAX = offset - EDI - x
  add	edi,eax				; EDI = offset - x
  mov	dx,[x1]
  add	edi,edx				; EDI = offset
  mov	edx,edi				; EDX = offset
  shr	edx,4				; EDX = # of paragraphs (segments)
  add	dx,[outSeg]			; DX = new segment
  mov	es,dx				; ES = new segment
  and	di,0000000000001111b	     	; DI = offset within new segment

  mov	al,[colour]			; colour in AL
  mov	ah,al				; colour in AH
  mov	bx,ax
  shl	eax,16
  mov	ax,bx 				; colour in each byte of EAX

  mov	cx,[x2]
  sub	cx,[x1]
  inc	cx				; CX = line length in pixels
  mov	dx,cx				; DX = line length in bytes

  shr	cx,2				; CX = line length in dwords
  rep	stosd				; store four bytes at a time
  mov	cx,dx				; CX = line length in pixels
  and	cx,0000000000000011b		; CX = any remaining bytes
  rep	stosb				; store the remaining bytes

  pop	edi			    	; restore EDI
  leave					; clean up
  retf					; return
ENDP


;*****
;***** setPaletteReg
;*****

PROC	C	setPaletteReg
	ARG	palNum:WORD,red:BYTE,green:BYTE,blue:BYTE
  mov	bx,[palNum]

  mov	dx,3C8h				; set for the right palette register
  mov	ax,[palNum]
  out	dx,al
  inc	dx

  mov	al,[red]			; red
  shr	al,2
  jnc	@@L1
  cmp	al,63
  je	@@L1
  inc	al
	@@L1:
  out	dx,al

  mov	al,[green]			; green
  shr	al,2
  jnc	@@L2
  cmp	al,63
  je	@@L2
  inc	al
	@@L2:
  out	dx,al

  mov	al,[blue]			; blue
  shr	al,2
  jnc	@@L3
  cmp	al,63
  je	@@L3
  inc	al
	@@L3:
  out	dx,al

  leave
  retf
ENDP


;*****
;***** getPaletteReg
;*****

PROC	C	getPaletteReg
	ARG	palNum:WORD,red:DWORD,green:DWORD,blue:DWORD
  push	ds si

  mov	dx,3C7h				; set for right palette register
  mov	ax,[palNum]
  out	dx,al
  mov	dx,3C9h

  in	al,dx				; red
  lds	si,[red]
  shl	al,2
  mov	[ds:si],al
  in	al,dx				; green
  lds	si,[green]
  shl	al,2
  mov	[ds:si],al
  in	al,dx				; blue
  lds	si,[blue]
  shl	al,2
  mov	[ds:si],al

  pop	si ds
  leave
  retf
ENDP


;*****
;***** setBlockPalette
;*****

PROC	C	setBlockPalette
	ARG	firstReg:WORD,lastReg:WORD,paletteData:DWORD
  push	ds si

  lds	si,[paletteData]		; set up
  mov	dx,3C8h
  mov	ax,[firstReg]
  out	dx,al
  inc	dx
  mov	cx,[lastReg]			; CX = number of registers
  sub	cx,ax
  inc	cx
  cld

	@@LLoop:
  lodsb			; red
  shr	al,2
  jnc	@@L1
  cmp	al,63
  je	@@L1
  inc	al
  	@@L1:
  out	dx,al

  lodsb			; green
  shr	al,2
  jnc	@@L2
  cmp	al,63
  je	@@L2
  inc	al
  	@@L2:
  out	dx,al

  lodsb			; blue
  shr	al,2
  jnc	@@L3
  cmp	al,63
  je	@@L3
  inc	al
  	@@L3:
  out	dx,al

  loop	@@LLoop

	@@LExit:
  pop	si ds
  leave
  retf
ENDP


;*****
;***** getBlockPalette
;*****

PROC	C	getBlockPalette
	ARG	firstReg:WORD,lastReg:WORD,paletteData:DWORD
  push	di

  les	di,[paletteData]		; set up
  mov	dx,3C7h
  mov	ax,[firstReg]
  out	dx,al
  mov	dx,3C9h
  mov	cx,[lastReg]			; CX = number of registers
  sub	cx,ax
  inc	cx
  cld

	@@L1:
  in	al,dx
  shl	al,2
  stosb			; red
  in	al,dx
  shl	al,2
  stosb			; green
  in	al,dx
  shl	al,2
  stosb			; blue
  loop	@@L1

	@@LExit:
  pop	di
  leave
  retf
ENDP


;*****
;***** clearGraphics
;*****

PROC	C	clearGraphics_scr_copy
	ARG	colour:BYTE
  push	di				; store DI

  mov   dx,SC_INDEX			; enable writes to all four planes
  mov   ax,0F02h
  out   dx,ax

  mov	ax,0A000h			; point ES:DI to screen
  mov	es,ax
  xor	di,di
  mov	al,[colour]			; EAX = colour:colour:colour:colour
  mov	ah,al
  mov	bx,ax
  shl	eax,16
  mov	ax,bx
  mov	cx,4800				; clear the screen
  cld
  rep	stosd

  pop	di				; restore DI
  leave					; clean up call stack
  retf					; return
ENDP


	ENDS
END
