;	
;	VGA support routines for raster oriented graphics
;
;	Quincey Koziol		January 1989
;
;	National Center for Supercomputing Applications,	University of Illinois
;	153	Water Resources Building
;	605 E. Springfield Ave.
;	Champaign, Ill	61820
;	(217)244-0072
;
	TITLE	  VGA GRAPHICS SUPPORT
.model LARGE
.code
X	EQU		6
;	INCLUDE DOS.MAC
;	SETX
;	PSEG
	PUBLIC	_PUTMAPV,_GETMAP,_VGALINE1,_VGACHUNK,_VGAPT,_VGAMODE,_VGAOFF,_VGAON
	PUBLIC	_OUTLINEV,_BALL,_VGABLOCK,_INVERSEV,_INVERT13,_LINE13
	PUBLIC	_SHOWPALV,_NOPALV
	PUBLIC	_CIRCLE13,_INCIRC13

;	name:	 PIXELADDR13
;
;	FUNCTION: CALCULATE THE BUFFER ADDRESS OF PIXEL IN 320X200 256 COLOR MODE
;
;	CALLER:	AX = Y COOR. (0-199)
;			BX = X COOR. (0-319)
;
;
;	RETURNS:	BX = BYTE OFFSET IN BUFFER
;				ES = VIDEO BUFFER SEGMENT
;
ORIGINOFFSET	EQU	0
VIDEOBUFFSEG	EQU	0A000H
PIXELADDR13	PROC	NEAR
	XCHG	AH,AL
	ADD		BX,AX
	SHR		AX,1
	SHR		AX,1
	ADD		BX,AX
	ADD		BX,ORIGINOFFSET
	MOV		AX,VIDEOBUFFSEG
	MOV		ES,AX
	RET
PIXELADDR13	ENDP

;
;	take three arrays of color tables and interleave them into the
;	VGA registers in the fashion Red, Green, Blue.
;

_PUTMAPV	PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES
	PUSH	SI
	PUSH	DI
;
	LDS	SI,DWORD PTR [BP+X]		; WHERE TO GET RED
	MOV DI,[BP+X+4]		; WHERE TO GET GREEN
	MOV BP,[BP+X+8]		; WHERE TO GET BLUE
	MOV	DX,03C8H		; I/O PORT FOR PEL TABLE
	MOV AL,0			; VALUE FOR BEGINNING OF TABLE
	OUT DX,AL			; START OUTPUTTING VALUES
	INC DX				; INCREMENT DX TO OUTPUT TABLE
	MOV CX,256			; LENGTH OF THE TABLE IN BYTE TRIPLES

DORGB:
	MOV AL,DS:[SI]		; GET A RED BYTE
	SHR AL,1
	SHR AL,1			; GET RID OF TWO HIGHEST BITS
	OUT DX,AL			
	INC SI
;
	MOV AL,DS:[DI]		; GET A GREEN BYTE
	SHR	AL,1
	SHR AL,1			; GET RID OF TWO HIGHEST BITS
	OUT DX,AL
	INC DI
;
	MOV	AL,DS:[BP]		; GET A BLUE BYTE
	SHR AL,1
	SHR AL,1			; GET RID OF TWO HIGHEST BITS
	OUT DX,AL			
	INC BP
;
	LOOP DORGB			; CONTINUE PRINTING UNTIL ALL 768 BYTES ARE WRITTEN
;
	POP		DI
	POP		SI
	POP	ES
	POP	DS
	POP	BP
	RET

_PUTMAPV	ENDP

_GETMAP	PROC	FAR
	RET
_GETMAP	ENDP

;
;  Transfer line to vga screen
;
;   usage : vgaline1(x,y,buf,xoff,linelen)
;
_VGALINE1	PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES
	PUSH	SI
	PUSH	DI

	LDS	SI,DWORD PTR [BP+X+4]	; WHERE DATA WILL COME FROM
	ADD	SI,[BP+X+8]		; ADD THE OFFSET TO THE OFFSET OF THE ARRAY
;

	MOV	AX,[BP+X+2]	; GET THE Y VALUE
	MOV	BX,[BP+X]	; GET THE X VALUE
	CALL	PIXELADDR13	; CALCULATE THE ADDRESS OF THE PIXEL
	MOV	DI,BX		; PREPARE FOR MOVS

	MOV	CX,[BP+X+10]	; HOW MANY BYTES?
	SHR	CX,1						; CHECK WHETHER THIS CAN BE WORD MOV'ED OR NOT
	JC	DOBYTES						; NO, CANNOT USE WORD MOVE
	REP	MOVSW						; MOVE WORDS
	JMP	SHORT	DONEBYTES			; JUMP AROUND THE BYTE COPY

DOBYTES:
	MOV	CX,[BP+X+10]				; GET THE COUNT OF BYTES TO MOVE
	REP	MOVSB						; MOV THE MEMORY

DONEBYTES:
	POP		DI
	POP		SI
	POP	ES
	POP	DS
	POP	BP
	RET
_VGALINE1	ENDP


;
;  Transfer chunk to vga screen
;
;   usage : vgachunk(x,y,buf,xoff,yoff,width,height,linelen)
;				int x,y;  the position to place the block on the screen
;				char *buf; the chunk to display
;				int xoff,yoff; the x and y offset into the chunk
;				int width,height; the width and height of the chunk part to display
;				int linelen;  the length of a horizontal raster line in the chunk
;
_VGACHUNK	PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES
	PUSH	SI
	PUSH	DI

	LDS	SI,DWORD PTR [BP+X+4]	; WHERE DATA WILL COME FROM
	MOV	AX,[BP+X+10]	; GET THE OFFSET IN THE Y DIRECTION
	JZ	ADD_X_OFF		; IF THE Y OFFSET IS ZERO THEN JUST ADD IN THE X OFFSET
	MOV	DX,[BP+X+16]	; GET THE LINE LENGTH
	MUL	DX				; CALCULATE THE AMOUNT OF OFFSET IN THE Y DIRECTION
	ADD	SI,AX			; ADD IN THE Y OFFSET
ADD_X_OFF:
	ADD	SI,[BP+X+8]		; ADD THE OFFSET TO THE OFFSET OF THE ARRAY
;

	MOV	AX,[BP+X+2]		; GET THE Y VALUE
	MOV	BX,[BP+X]		; GET THE X VALUE
	CALL	PIXELADDR13	; CALCULATE THE ADDRESS OF THE PIXEL
	MOV	DI,BX			; PREPARE FOR MOVS

	MOV	CX,[BP+X+12]	; HOW MANY BYTES?
	SHR	CX,1			; CHECK WHETHER THIS CAN BE WORD MOV'ED OR NOT
	JC	CHUNKLOOPB		; NO, CANNOT USE WORD MOVE
	MOV	[BP+X+12],CX	; STORE THE NUMBER OF WORDS TO COPY

CHUNKLOOPW:
	PUSH	SI			; PUSH THE SOURCE INDEX
	PUSH	DI			; PUSH THE DESTINATION INDEX
	MOV	CX,[BP+X+12]	; GET THE COUNT OF BYTES TO MOVE
	REP	MOVSW			; MOVE WORDS

	POP	DI
	ADD DI,320			; ADD IN THE WIDTH OF THE SCREEN
	POP	SI
	ADD	SI,[BP+X+16]	; ADD IN THE OFFSET FOR THE NEXT LINE THE CHUNK TO COPY
	DEC WORD PTR [BP+X+14]		; DECREMENT THE NUMBER OF LINES TO COPY
	JNZ	CHUNKLOOPW		; CONTINUE TO BLAST OUT LINES UNTIL WE HAVE DONE THEM ALL
	JMP	SHORT	ENDCHUNK

CHUNKLOOPB:
	PUSH	SI			; PUSH THE SOURCE INDEX
	PUSH	DI			; PUSH THE DESTINATION INDEX
	MOV	CX,[BP+X+12]	; GET THE COUNT OF BYTES TO MOVE
	REP	MOVSB			; MOV THE MEMORY

	POP	DI
	ADD DI,320			; ADD IN THE WIDTH OF THE SCREEN
	POP	SI
	ADD	SI,[BP+X+16]	; ADD IN THE OFFSET FOR THE NEXT LINE THE CHUNK TO COPY
	DEC WORD PTR [BP+X+14]		; DECREMENT THE NUMBER OF LINES TO COPY
	JNZ	CHUNKLOOPB		; CONTINUE TO BLAST OUT LINES UNTIL WE HAVE DONE THEM ALL

ENDCHUNK:
	POP		DI
	POP		SI
	POP	ES
	POP	DS
	POP	BP
	RET
_VGACHUNK	ENDP

;  draw a point on vga screen
;
;   usage : vgapt(x,y,color)
;
_VGAPT	PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES
	PUSH	DI

;
;   READY TO PUT THE POINT
;
POKBANK:
	MOV	AX,[BP+X+2]	; GET THE Y VALUE
	MOV	BX,[BP+X]	; GET THE X VALUE
	CALL PIXELADDR13	; CALCULATE THE PIXEL ADDRESS
	MOV	DI,BX		; PREPARE FOR MOVS
	MOV	AL,[BP+X+4]	; GET COLOR TO PUT THERE

	STOSB			; PUT IT

	POP		DI
	POP	ES
	POP	DS
	POP	BP
	RET
_VGAPT	ENDP

_VGAMODE		PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES
	
	MOV		AX,[BP+X]		;GET SCREEN MODE TO SWITCH TO
	XOR		AH,AH			;ENTER VIDEO_IO ROUTINE (SET MODE=0)
	INT		10H				;VIDEO INTERUPT

	POP	ES
	POP	DS
	POP	BP
	RET
_VGAMODE	ENDP


_VGAOFF		PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES
	
	MOV		DX,03C4H		;ADDRESS OF THE SEQ CONTROLLER
	MOV		AL,01H			;INDEX OF THE CLOCKING MODE REGISTER
	OUT		DX,AL			;SET UP TO READ THE CLOCKING MODE REGISTER
	MOV		DX,03C5H		;ADDRESS TO READ FROM
	IN		AL,DX			;GET THE CLOCKING MODE REGISTER
	OR		AL,20H			;MASK OFF THE SCREEN ENABLE BIT	
	MOV		BL,AL			;KEEP THAT AROUND
	MOV		DX,03C4H		;ADDRESS OF THE SEQ CONTROLLER
	MOV		AL,01H			;INDEX OF THE CLOCKING REGISTER
	OUT		DX,AL			;SET UP TO WRITE BACK THE CLOCKING MODE REGISTER
	INC		DX				;SET TO ADDRESS TO WRITE TO
	MOV		AL,BL			;GET BACK THE PROPER VALUE
	OUT		DX,AL			;TURNS OFF THE VGA SCREEN

	POP	ES
	POP	DS
	POP	BP
	RET
_VGAOFF	ENDP

_VGAON		PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES
	
	MOV		DX,03C4H		;ADDRESS OF THE SEQ CONTROLLER
	MOV		AL,01H			;INDEX OF THE CLOCKING MODE REGISTER
	OUT		DX,AL			;SET UP TO READ THE CLOCKING MODE REGISTER
	INC		DX				;ADDRESS TO READ FROM
	IN		AL,DX			;GET THE CLOCKING MODE REGISTER
	AND		AL,0DFH			;TURN ON THE SCREEN ENABLE BIT	
	MOV		BL,AL			;KEEP THAT AROUND
	MOV		DX,03C4H		;ADDRESS OF THE SEQ CONTROLLER
	MOV		AL,01H			;INDEX OF THE CLOCKING REGISTER
	OUT		DX,AL			;SET UP TO WRITE BACK THE CLOCKING MODE REGISTER
	INC		DX				;SET TO ADDRESS TO WRITE TO
	MOV		AL,BL			;GET BACK THE PROPER VALUE
	OUT		DX,AL			;TURNS ON THE VGA SCREEN

	POP	ES
	POP	DS
	POP	BP
	RET
_VGAON	ENDP

;
;	showpalv(&palstore,pal_xoff,pal_yoff);
;	
_SHOWPALV		PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES
	PUSH	SI
	PUSH	DI


	MOV 	AX,[BP+X]		;GET OFFSET OF ARRAY
	MOV		DI,AX
	MOV		AX,[BP+X+2]		;GET SEGMENT OF STORAGE ARRAY
	MOV		ES,AX			

	MOV		AX,[BP+X+6]		;GET LINE TO START PALETTE ON
	MOV		DX,320			;GET THE LINE LENGTH
	MUL		DX				;GET THE OFFSET INTO THE SCREEN
	ADD		AX,[BP+X+4]		;ADD IN THE X OFFSET
	JNC		NO_ROLLOVER		;ADDITION DIDN'T CARRY
	INC		DX				;INCREMENT THE DX REGISTER ON A CARRY
NO_ROLLOVER:
	MOV		SI,AX			;KEEP TRACK OF THE OFFSET
	MOV		BX,SI			;IN TWO PLACES
	MOV		AX,320			;GET THE LINE LENGTH
	MOV		DX,8			;GET THE NUMBER OF LINES
	MUL		DX				;GET THE NUMBER OF BYTES TO COPY
	MOV		CX,AX			;MOVE INTO COUNTER
	MOV		AX,0A000H
	MOV		DS,AX			;GET THE SEGMENT FOR THE SOURCE
ZIP:
	REP		MOVSB			;COPY THAT SECTION OF SCREEN
	
	MOV		CH,0			;THE NUMBER OF LINES COPIED SO FAR
	MOV		CL,00			;THE NUMBER OF PIXELS
TOP1:
	MOV		SI,BX			;GET THE CORRECT OFFSET TO BE COPIED TO
	MOV		AX,0A000H
	MOV		ES,AX			;GET THE SEGMENT TO BE COPIED TO
TOP2:
	MOV		ES:[SI],CL		;COPY ACROSS THE SCREEN INCREMENTING VALUES
	INC		SI				;MOVE TO NEXT PIXEL
	INC		CL				;INCREMENT COUNTER
	JNE		TOP2			;IF COUNTER NOT EQUAL TO ZERO THEN COPY AGAIN
	
	ADD		BX,320			;MOVE DOWN TO NEXT LINE
	INC		CH				;INCREMENT THE LINE COUNTER
	CMP		CH,8			;CHECK IF ALL THE LINES ARE DONE
	JNE		TOP1			;IF LINE COUNT <8 THEN COPY ANOTHER LINE

	POP	DI
	POP	SI
	POP	ES
	POP	DS
	POP	BP
	RET
_SHOWPALV	ENDP

;
;	nopalv(&palstore,pal_xoff,pal_yoff);
;
_NOPALV		PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES
	PUSH	SI
	PUSH	DI

	MOV 	AX,[BP+X]		;GET OFFSET OF ARRAY
	MOV		SI,AX
	MOV		AX,[BP+X+2]		;GET SEGMENT OF STORAGE ARRAY
	MOV		DS,AX			

	MOV		AX,[BP+X+6]		;GET LINE TO COPY SCREEN BACK ONTO
	MOV		DX,320			;GET THE LINE LENGTH
	MUL		DX				;GET THE OFFSET INTO THE SCREEN
	ADD		AX,[BP+X+4]		;ADD IN THE X OFFSET
	JNC		NO_ROLL2		;ADDITION DIDN'T CARRY
	INC		DX				;INCREMENT THE DX REGISTER ON A CARRY
NO_ROLL2:
	MOV		DI,AX			;KEEP TRACK OF THE OFFSET
	MOV		AX,320			;GET THE LINE LENGTH
	MOV		DX,8			;GET THE NUMBER OF LINES
	MUL		DX				;GET THE NUMBER OF BYTES TO COPY
	MOV		CX,AX			;MOVE INTO COUNTER
	MOV		AX,0A000H
	MOV		ES,AX			;GET THE SEGMENT FOR THE SOURCE
ZOOM:
	REP		MOVSB			;COPY THAT SECTION OF SCREEN

	POP	DI
	POP	SI
	POP	ES
	POP	DS
	POP	BP
	RET
_NOPALV	ENDP

;
;  Invert A BOX ON THE SCREEN
;
;   usage : outlinev(x1,y1,x2,y2)
;
_OUTLINEV	PROC	FAR
	PUSH	BP
	MOV	BP,SP
	PUSH	DS
	PUSH	ES
	PUSH	SI
	PUSH	DI

	MOV	AX,[BP+X+2]	; GET FIRST Y VALUE
	CMP	AX,[BP+X+6]	; COMPARE WITH THE SECOND Y - VALUE
	JLE	CHECKX		; OK ORDER GOTO CHECKING THE X VALUES
	MOV	CX,AX		; SWAP THE TWO VALUES
	MOV	AX,[BP+X+6]	;
	MOV	[BP+X+2],AX	;
	MOV	AX,CX		;
	MOV	[BP+X+6],AX	;
CHECKX:
	MOV	AX,[BP+X]	; GET FIRST X VALUE
	CMP	AX,[BP+X+4]	; COMPARE WITH THE SECOND X - VALUE
	JLE	MAKELEN		; OK ORDER GOTO COMPUTING THE LENGTHS
	MOV	CX,AX		; SWAP THE TWO VALUES
	MOV	AX,[BP+X+4]	;
	MOV	[BP+X],AX	;
	MOV	AX,CX		;
	MOV	[BP+X+4],AX	;
MAKELEN:			; COMPUTE THE X AND Y WIDTHS FOR THE BOX TO BE INVERTED
	MOV	AX,[BP+X+4]	; GET THE LARGER OF THE TWO X VALUES
	SUB	AX,[BP+X]	; SUBTRACT THE SMALLER VALUE TO FIND THE LENGTH
	ADD	AX,1		;
	MOV	[BP+X+4],AX	; STORE IT IN THE OLD LOCATION FOR THE 2ND X VALUE
	MOV	AX,[BP+X+6]	; GET THE LARGER OF THE TWO Y VALUES
	SUB	AX,[BP+X+2]	; SUBTRACT THE SMALLER VALUE TO FIND THE LENGTH
	SUB	AX,1		; SUBTRACT TWO FOR THE TOP AND BOTTOM EDGES
	CMP	AX,0		; CHECK IF IT IS LESS THAN ZERO
	JG 	POSITIVE	; JUMP AROUND ZEROING THE ACC.
	MOV	AX,0
POSITIVE:
	MOV	[BP+X+6],AX	; STORE IT IN THE OLD LOCATION FOR THE 2ND Y VALUE
	MOV	AX,320		; COMPUTE THE VALUE TO ADD TO THE DI FOR COMPLETE WRAPAROUND
	SUB	AX,[BP+X+4]	;
	MOV	SI,AX		; KEEP TRACK OF IT
	
;	MOV	AX,0A000H	; DATA BUFFER
;	MOV	ES,AX
;
	MOV	AX,[BP+X+2]	; GET THE Y VALUE
	MOV	BX,[BP+X]	; GET THE X VALUE
	CALL	PIXELADDR13	; CALCULATE THE PIXEL ADDRESS
	MOV	DI,BX		; PREPARE FOR MOVS

	MOV	CX,[BP+X+4]	; HOW MANY BYTES?
BLASTA:
	MOV	AL,ES:[DI]	; GET THE VALUE TO INVERT
	NOT	AL		; INVERT THE VALUE THERE
	MOV	ES:[DI],AL	; REPLACE THE VALUE
	INC	DI		; INCREMENT TO NEXT POSITION
	LOOP 	BLASTA		; LOOP UNTIL ALL HAVE BEEN DONE

	ADD	DI,SI		; MOVE OVER TO THE BEGINNING OF THE NEXT LINE
	MOV	CX,[BP+X+6]	; COUNT VALUE FOR THE NEXT SERIES
	CMP	CX,0		; CHECK FOR NO LINES IN BETWEEN
	JLE	BLAST2A		; JUMP AROUND PUTTING THE LINES IN BETWEEN
BLAST2:
	MOV	AL,ES:[DI]	; GET THE VALUE TO INVERT
	NOT	AL			; INVERT IT
	MOV	ES:[DI],AL	; REPLACE THE INVERTED VALUE
	ADD	DI,[BP+X+4]	; GO TO THE LAST VALUE TO INVERT ON THAT LINE
	SUB	DI,1		;
	MOV	AL,ES:[DI]	; GET THE VALUE TO INVERT
	NOT	AL		; INVERT IT
	MOV	ES:[DI],AL	; REPLACE THE INVERTED VALUE
	ADD	DI,SI		; GET THE VALUE FOR THE BEGINNING OF THE NEXT LINE
	INC	DI		;
	LOOP	BLAST2		; DO THE NEXT LINE

BLAST2A:
	MOV	CX,[BP+X+4]	; PREPARE FOR LAST LINE
BLAST3:
	MOV	AL,ES:[DI]	; GET THE VALUE TO INVERT
	NOT	AL			; INVERT THE VALUE THERE
	MOV	ES:[DI],AL	; REPLACE THE VALUE
	INC	DI			; INCREMENT TO NEXT POSITION
	LOOP	BLAST3		; LOOP UNTIL ALL HAVE BEEN DONE

	POP		DI
	POP		SI
	POP	ES
	POP	DS
	POP	BP
	RET
_OUTLINEV	ENDP
;
;  Draw a 4x4 ball on the vga screen
;
;   usage : ball(x,y)
;
_BALL		PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES
	PUSH	DI

	MOV	AX,[BP+X+2] ; GET THE Y VALUE
	MOV	BX,[BP+X]	; GET THE X VALUE
	CALL	PIXELADDR13	; CALCULATE THE PIXEL ADDRESS
	MOV	DI,BX		; PREPARE FOR MOVS

	MOV	AL,ES:[DI]	; GET THE VALUE TO INVERT
	NOT	AL			; INVERT IT
	MOV	ES:[DI],AL	; REPLACE THE VALUE
	INC	DI			; MOVE OVER ONE BYTE
	MOV	AL,ES:[DI]	; GET THE VALUE TO INVERT
	NOT	AL			; INVERT IT
	MOV	ES:[DI],AL	; REPLACE THE VALUE

	ADD	DI,318		; MOVE TO THE NEXT LINE
	MOV	CX,4		; HOW MANY BYTES?
BLASTB:
	MOV	AL,ES:[DI]	; GET THE VALUE TO INVERT
	NOT	AL			; INVERT THE VALUE THERE
	MOV	ES:[DI],AL	; REPLACE THE VALUE
	INC	DI			; INCREMENT TO NEXT POSITION
	LOOP BLASTB		; LOOP UNTIL ALL HAVE BEEN DONE

	MOV	CX,4		; COUNT VALUE FOR THE NEXT SERIES
	ADD	DI,316		; MOVE OVER TO THE BEGINNING OF THE NEXT LINE
BLASTC:
	MOV	AL,ES:[DI]	; GET THE VALUE TO INVERT
	NOT	AL			; INVERT IT
	MOV	ES:[DI],AL	; REPLACE THE INVERTED VALUE
	INC DI			;
	LOOP	BLASTC	; DO THE NEXT LINE

	ADD	DI,317		; MOVE ONE BYTE OVER INTO THE NEXT LINE
	MOV	AL,ES:[DI]	; GET THE VALUE TO INVERT
	NOT	AL			; INVERT IT
	MOV	ES:[DI],AL	; REPLACE THE VALUE
	INC	DI			; MOVE OVER ONE BYTE
	MOV	AL,ES:[DI]	; GET THE VALUE TO INVERT
	NOT	AL			; INVERT IT
	MOV	ES:[DI],AL	; REPLACE THE VALUE

	POP		DI
	POP	ES
	POP	DS
	POP	BP
	RET
_BALL	ENDP

;
;  Draw a block on the vga screen
;
;   usage : vgablock(&block,x,y,xmax,ymax)
;
X_SIZE	DW	?		; X WIDTH OF THE BLOCK
X_WRAP	DW	?		; THE NUMBER OF BYTES TO WRAP AROUND THE SCREEN
Y_SIZE	DW	?		; THE Y HEIGHT OF THE BLOCK
_VGABLOCK	PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES
	PUSH	SI
	PUSH	DI

;	MOV	AX,0A000H	; DATA BUFFER
;	MOV	ES,AX
	
	MOV	AX,[BP+X+8]	; GET THE X SIZE
	MOV	X_SIZE,AX	; STORE THE X SIZE
	
	MOV	AX,320		; GET THE SCREEN SIZE
	SUB	AX,X_SIZE	; CALCULATE THE X_WRAP VALUE
	MOV	X_WRAP,AX	; STORE THE X_WRAP VALUE
	
	MOV	AX,[BP+X+10]; GET THE Y SIZE
	MOV	Y_SIZE,AX	; STORE THE Y SIZE
	MOV	AX,[BP+X+6]	; GET THE Y VALUE
	MOV	BX,[BP+X+4]	; GET THE X VALUE
	CALL	PIXELADDR13 ; CALCULATE THE PIXEL OFFSET
	MOV	DI,BX		; PREPARE FOR MOVS
	
	MOV	AX,[BP+X]	; GET THE OFFSET OF THE BLOCK
	MOV	SI,AX		; STORE THE OFFSET OF THE ARRAY
	MOV	AX,[BP+X+2]	; GET THE SEGMENT OF THE ARRAY
	MOV	DS,AX		; STORE THE SEGMENT
BLASTBLOCK:
	MOV	CX,X_SIZE	; GET THE NUMBER OF BYTES TO MOVE
	REP	MOVSB		; PUT A HORIZONTAL LINE OF THE BLOCK ON THE SCREEN
	
	ADD	DI,X_WRAP	; MOVE THE DESTINATION POINTER TO THE BEGINNING OF THE NEXT BLOCK
	DEC	Y_SIZE		; DECREMENT THE VERTICAL COUNTER
	JG	BLASTBLOCK	; IF THE COUNTER IS NOT ZERO THEN DO ANOTHER LINE
	
	POP		DI
	POP		SI
	POP	ES
	POP	DS
	POP	BP
	RET
_VGABLOCK	ENDP

;
;   Inverse a block on the vga screen
;
;   usage : vgablock(x0,y0,width,height)
;
_INVERSEV	PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES
	PUSH	DI

	MOV	BX,[BP+X+4]	; GET THE X SIZE
	MOV	X_SIZE,BX	; STORE THE X SIZE
	
	MOV	AX,320		; GET THE SCREEN SIZE
	SUB	AX,BX		; CALCULATE THE X_WRAP VALUE
	MOV	X_WRAP,AX	; STORE THE X_WRAP VALUE
	
	MOV	AX,[BP+X+6]	; GET THE Y SIZE
	MOV	Y_SIZE,AX	; STORE THE Y SIZE
;
	MOV	AX,[BP+X+2]; GET THE Y VALUE
	MOV	BX,[BP+X]	; GET THE X VALUE
	CALL	PIXELADDR13		; CALCULATE THE PIXEL ADDRESS (RETURNS WITH ES:VIDEO BUFF SEG, BX:OFFSET)
	MOV	DI,BX		; PREPARE FOR MOVS
	
INVERSEBLOCK:
	MOV	CX,X_SIZE	; GET THE NUMBER OF BYTES TO MOVE
INVERSELINE:
	MOV	AL,BYTE PTR ES:[DI]	; GET THE BYTE TO INVERSE
	NOT	AL			; INVERSE IT
	MOV	BYTE PTR ES:[DI],AL	; PUT THE BYTE BACK
	INC	DI
	LOOP INVERSELINE
	
	ADD	DI,X_WRAP	; MOVE THE DESTINATION POINTER TO THE BEGINNING OF THE NEXT BLOCK
	DEC	Y_SIZE		; DECREMENT THE VERTICAL COUNTER
	JG	INVERSEBLOCK	; IF THE COUNTER IS NOT ZERO THEN DO ANOTHER LINE
	
	POP		DI
	POP	ES
	POP	DS
	POP	BP
	RET
_INVERSEV	ENDP

;	CALLER 		MICROSOFT C
;
;					VOID(_LINE13(X1,Y1,X2,Y2,N);
;
;						INT X1,Y1,X2,Y2;	/* PIXEL COOR. */
;
;						INT N;			/* PIXEL VALUE */
;

ARGX1		EQU	WORD PTR [BP+6]	; STACK FRAME ADDRESSING
ARGY1		EQU	WORD PTR [BP+8]
ARGX2		EQU	WORD PTR [BP+10]
ARGY2		EQU WORD PTR [BP+12]
ARGN		EQU	BYTE PTR [BP+14]
VARINCR1	EQU	WORD PTR [BP-6]
VARINCR2	EQU WORD PTR [BP-8]
VARROUTINE	EQU WORD PTR [BP-10]

BYTESPERLINE	EQU	320

_LINE13	PROC	FAR
	PUSH	BP
	MOV		BP,SP
	SUB		SP,16H
	PUSH	DS
	PUSH	ES
	PUSH	SI
	PUSH	DI

; CHECK FOR VERTICAL LINE
	MOV		SI,BYTESPERLINE

	MOV		CX,ARGX2
	SUB		CX,ARGX1
	JZ		VERT_LINE13

; FORCE X1<X2
	JNS		L01

	NEG 	CX

	MOV		BX,ARGX2
	XCHG	BX,ARGX1
	MOV		ARGX2,BX

	MOV		BX,ARGY2
	XCHG	BX,ARGY1
	MOV		ARGY2,BX

; CALCULATE DY=ABS(Y2-Y1)
L01:
	MOV		BX,ARGY2
	SUB		BX,ARGY1
	JZ		HORIZ_LINE13

	JNS		L03

	NEG		BX
	NEG		SI
;SELECT APPROPRIATE ROUTINE FOR SLOPE OF LINE
L03:
	PUSH	SI
	MOV		VARROUTINE,OFFSET LOSLOPE_LINE13
	CMP		BX,CX
	JLE		L04
	MOV		VARROUTINE,OFFSET HISLOPE_LINE13
	XCHG	BX,CX

;CALCULATE INITIAL DECISION VARIABLE AND INCREMENTS
L04:
	SHL		BX,1
	MOV		VARINCR1,BX
	SUB		BX,CX
	MOV		SI,BX

	SUB		BX,CX
	MOV		VARINCR2,BX

;CALCULATE FIRST PIXEL ADDRESS
	PUSH	CX
	MOV		AX,ARGY1
	MOV		BX,ARGX1
	CALL	PIXELADDR13

	MOV		DI,BX

	POP		CX
	INC		CX

	POP		BX
	JMP		VARROUTINE

;ROUTINE FOR VERTICAL LINES
VERT_LINE13:
	MOV		AX,ARGY1
	MOV		BX,ARGY2
	MOV		CX,BX
	SUB		CX,AX
	JGE		L31

	NEG		CX
	MOV		AX,BX
L31:
	INC		CX
	MOV		BX,ARGX1
	PUSH	CX
	CALL	PIXELADDR13
	POP		CX
	MOV		DI,BX
	DEC		SI

	MOV		AL,ARGN
L32:
	STOSB
	ADD		DI,SI
	LOOP	L32
	JMP		LEXIT

;ROUTINE FOR HORIZONTAL LINES (SLOPE=0)
HORIZ_LINE13:
	PUSH	CX
	MOV		AX,ARGY1
	MOV		BX,ARGX1
	CALL	PIXELADDR13
	MOV		DI,BX

	POP		CX
	INC		CX

	MOV		AL,ARGN

	REP		STOSB
	JMP		LEXIT

;ROUTINE FOR DY<=DX (SLOPE<=1)
LOSLOPE_LINE13:
	MOV		AL,ARGN
L11:
	STOSB
	OR		SI,SI
	JNS		L12
	ADD		SI,VARINCR1
	LOOP	L11
	JMP		SHORT	LEXIT
L12:
	ADD		SI,VARINCR2
	ADD		DI,BX
	LOOP	L11
	JMP		SHORT LEXIT

;ROUTINE FOR DY>DX (SLOPE>1)
HISLOPE_LINE13:
	MOV		AL,ARGN
L21:
	STOSB
	ADD		DI,BX
L22:
	OR		SI,SI
	JNS		L23
	ADD		SI,VARINCR1
	DEC		DI
	LOOP	L21
	JMP		SHORT	LEXIT
L23:
	ADD		SI,VARINCR2
	LOOP	L21

LEXIT:
	POP		DI
	POP		SI
	POP		ES
	POP		DS
	MOV		SP,BP
	POP		BP
	RET
_LINE13		ENDP

_INVERT13	PROC	FAR
	PUSH	BP
	MOV		BP,SP
	SUB		SP,16H
	PUSH	DS
	PUSH	ES
	PUSH	SI
	PUSH	DI

; CHECK FOR VERTICAL LINE
	MOV		SI,BYTESPERLINE

	MOV		CX,ARGX2
	SUB		CX,ARGX1
	JZ		IVERT_LINE13

; FORCE X1<X2
	JNS		IL01

	NEG 	CX

	MOV		BX,ARGX2
	XCHG	BX,ARGX1
	MOV		ARGX2,BX

	MOV		BX,ARGY2
	XCHG	BX,ARGY1
	MOV		ARGY2,BX

; CALCULATE DY=ABS(Y2-Y1)
IL01:
	MOV		BX,ARGY2
	SUB		BX,ARGY1
	JZ		IHORIZ_LINE13

	JNS		IL03

	NEG		BX
	NEG		SI
;SELECT APPROPRIATE ROUTINE FOR SLOPE OF LINE
IL03:
	PUSH	SI
	MOV		VARROUTINE,OFFSET ILOSLOPE_LINE13
	CMP		BX,CX
	JLE		IL04
	MOV		VARROUTINE,OFFSET IHISLOPE_LINE13
	XCHG	BX,CX

;CALCULATE INITIAL DECISION VARIABLE AND INCREMENTS
IL04:
	SHL		BX,1
	MOV		VARINCR1,BX
	SUB		BX,CX
	MOV		SI,BX

	SUB		BX,CX
	MOV		VARINCR2,BX

;CALCULATE FIRST PIXEL ADDRESS
	PUSH	CX
	MOV		AX,ARGY1
	MOV		BX,ARGX1
	CALL	PIXELADDR13

	MOV		DI,BX

	POP		CX
	INC		CX

	POP		BX
	JMP		VARROUTINE

;ROUTINE FOR VERTICAL LINES
IVERT_LINE13:
	MOV		AX,ARGY1
	MOV		BX,ARGY2
	MOV		CX,BX
	SUB		CX,AX
	JGE		IL31

	NEG		CX
	MOV		AX,BX
IL31:
	INC		CX
	MOV		BX,ARGX1
	PUSH	CX
	CALL	PIXELADDR13
	POP		CX
	MOV		DI,BX
	DEC		SI

	MOV		AL,0FFH
IL32:
	XOR		ES:[DI],AL
	INC		DI
;	STOSB
	ADD		DI,SI
	LOOP	IL32
	JMP		ILEXIT

;ROUTINE FOR HORIZONTAL LINES (SLOPE=0)
IHORIZ_LINE13:
	PUSH	CX
	MOV		AX,ARGY1
	MOV		BX,ARGX1
	CALL	PIXELADDR13
	MOV		DI,BX

	POP		CX
	INC		CX
	MOV		AL,0ffh

IL51:
	XOR		ES:[DI],AL
	INC		DI
	LOOP	IL51
;REP	STOSB
	JMP		ILEXIT

;ROUTINE FOR DY<=DX (SLOPE<=1)
ILOSLOPE_LINE13:
	MOV		AL,0ffh
IL11:
	XOR		ES:[DI],AL
	INC		DI
;	STOSB
	OR		SI,SI
	JNS		IL12
	ADD		SI,VARINCR1
	LOOP	IL11
	JMP		SHORT	ILEXIT
IL12:
	ADD		SI,VARINCR2
	ADD		DI,BX
	LOOP	IL11
	JMP		SHORT ILEXIT

;ROUTINE FOR DY>DX (SLOPE>1)
IHISLOPE_LINE13:
	MOV		AL,0ffh
IL21:
	XOR		ES:[DI],AL
	INC		DI
;	STOSB
	ADD		DI,BX
IL22:
	OR		SI,SI
	JNS		IL23
	ADD		SI,VARINCR1
	DEC		DI
	LOOP	IL21
	JMP		SHORT	ILEXIT
IL23:
	ADD		SI,VARINCR2
	LOOP	IL21

ILEXIT:
	POP		DI
	POP		SI
	POP		ES
	POP		DS
	MOV		SP,BP
	POP		BP
	RET
_INVERT13		ENDP

;NAME:	_CIRCLE13
;	_CIRCLE13(XC,YC,A,B,N)
;
ARGXC	EQU WORD PTR [BP+6]
ARGYC	EQU WORD PTR [BP+8]
ARGA	EQU WORD PTR [BP+10]
ARGB	EQU WORD PTR [BP+12]
ARGN	EQU	BYTE PTR [BP+14]

ULADDR	EQU WORD PTR [BP-6]
URADDR	EQU WORD PTR [BP-8]
LLADDR	EQU WORD PTR [BP-10]
LRADDR	EQU WORD PTR [BP-12]
LMASK	EQU BYTE PTR [BP-14]
RMASK	EQU BYTE PTR [BP-16]

VARD		EQU WORD PTR [BP-20]
VARDX		EQU WORD PTR [BP-24]
VARDY		EQU WORD PTR [BP-28]
ASQUARED	EQU WORD PTR [BP-32]
BSQUARED	EQU WORD PTR [BP-36]
TWOASQUARED	EQU WORD PTR [BP-40]
TWOBSQUARED	EQU WORD PTR [BP-44]

BYTESPERLINE EQU	320

_CIRCLE13	PROC	FAR
	PUSH	BP
	MOV	BP,SP
	SUB	SP,50
	PUSH	DS
	PUSH	ES
	PUSH	SI
	PUSH	DI

;INITIAL CONSTANTS
	MOV AX,ARGA
	MUL	AX
	MOV ASQUARED,AX
	MOV	ASQUARED+2,DX
	SHL	AX,1
	RCL	DX,1
	MOV	TWOASQUARED,AX
	MOV	TWOASQUARED+2,DX
	MOV	AX,ARGB
	MUL	AX
	MOV BSQUARED,AX
	MOV BSQUARED+2,DX
	SHL	AX,1
	RCL DX,1
	MOV TWOBSQUARED,AX
	MOV TWOBSQUARED+2,DX

;PLOT PIXELS FROM (0,B) UNTIL DY/DX =-1
;INITIAL BUFFER ADDRESS AND BIT MASK
	MOV	AX,BYTESPERLINE
	MUL	ARGB
	MOV	SI,AX
	MOV	DI,AX
	MOV	AX,ARGYC
	MOV	BX,ARGXC
	CALL	PIXELADDR13

	ADD	SI,BX
	MOV	ULADDR,SI
	MOV URADDR,SI
	SUB	BX,DI
	MOV	LLADDR,BX
	MOV	LRADDR,BX

;INITIAL DECISION VARIABLES
	XOR	AX,AX
	MOV	VARDX,AX
	MOV	VARDX+2,AX

	MOV	AX,TWOASQUARED
	MOV DX,TWOASQUARED+2
	MOV CX,ARGB
	CALL LONGMULTIPLY
	MOV VARDY,AX
	MOV VARDY+2,DX

	MOV AX,ASQUARED
	MOV	DX,ASQUARED+2
	SAR DX,1
	RCR	AX,1
	SAR	DX,1
	RCR AX,1

	ADD AX,BSQUARED
	ADC	DX,BSQUARED+2
	MOV	VARD,AX
	MOV VARD+2,DX

	MOV	AX,ASQUARED
	MOV	DX,ASQUARED+2
	MOV CX,ARGB
	CALL LONGMULTIPLY
	SUB	VARD,AX
	SBB	VARD+2,DX
	
	;LOOP UNTIL DY/DX>=-1
	MOV	BX,ARGB
	XOR	CX,CX
	
C10:	
	MOV	AX,VARDX
	MOV	DX,VARDX+2
	SUB	AX,VARDY
	SBB	DX,VARDY+2
	JNS	C20
	
	CALL	SET4PIXELS
	MOV CX,1
	CMP	VARD+2,0
	JS	C11
	MOV	CH,1
	DEC	BX
	
	MOV AX,VARDY
	MOV	DX,VARDY+2
	SUB AX,TWOASQUARED
	SBB	DX,TWOASQUARED+2
	MOV VARDY,AX
	MOV	VARDY+2,DX

	SUB	VARD,AX
	SBB	VARD+2,DX
	
C11:
	MOV AX,VARDX
	MOV DX,VARDX+2
	ADD	AX,TWOBSQUARED
	ADC	DX,TWOBSQUARED+2
	MOV VARDX,AX
	MOV VARDX+2,DX
	ADD	AX,BSQUARED
	ADC	DX,BSQUARED+2
	ADD VARD,AX
	ADC	VARD+2,DX
	JMP	C10
	
;PLOT PIXELS FROM CURRENT (X,Y) UNTIL Y<0
	
C20:
	PUSH	BX
	PUSH	CX
	MOV	AX,ASQUARED
	MOV	DX,ASQUARED+2
	SUB	AX,BSQUARED
	SBB	DX,BSQUARED+2
	MOV BX,AX
	MOV CX,DX
	
	SAR DX,1
	RCR	AX,1
	ADD AX,BX
	ADC	DX,CX
	
	SUB AX,VARDX
	SBB	DX,VARDX+2
	SUB	AX,VARDY
	SBB	DX,VARDY+2
	
	SAR	DX,1
	RCR	AX,1
	
	ADD	VARD,AX
	ADC	VARD+2,DX
	
;LOOP UNTIL Y<0
	POP CX
	POP BX
C21:
	CALL SET4PIXELS
	MOV CX,100H
	
	CMP	VARD+2,0
	JNS	C22
	
	MOV CL,1
	MOV AX,VARDX
	MOV DX,VARDX+2
	ADD AX,TWOBSQUARED
	ADC	DX,TWOBSQUARED+2
	MOV	VARDX,AX
	MOV	VARDX+2,DX
	
	ADD	VARD,AX
	ADC	VARD+2,DX
	
C22:	
	MOV AX,VARDY
	MOV	DX,VARDY+2
	SUB	AX,TWOASQUARED
	SBB	DX,TWOASQUARED+2
	MOV	VARDY,AX
	MOV	VARDY+2,DX

	SUB	AX,ASQUARED
	SBB	DX,ASQUARED+2
	SUB	VARD,AX
	SBB	VARD+2,DX
	
	DEC	BX
	JNS	C21
	
;RESTORE DEFAULT GRAPHICS CONTROLLER REGISTERS
CEXIT:
	POP DI
	POP SI
	POP	ES
	POP	DS
	MOV SP,BP
	POP	BP
	RET
_CIRCLE13	ENDP

;NAME:	CIRCLE13
;	CIRCLE13(XC,YC,A,B,N)
;
ARGXC	EQU WORD PTR [BP+6]
ARGYC	EQU WORD PTR [BP+8]
ARGA	EQU WORD PTR [BP+10]
ARGB	EQU WORD PTR [BP+12]

ULADDR	EQU WORD PTR [BP-6]
URADDR	EQU WORD PTR [BP-8]
LLADDR	EQU WORD PTR [BP-10]
LRADDR	EQU WORD PTR [BP-12]
LMASK	EQU BYTE PTR [BP-14]
RMASK	EQU BYTE PTR [BP-16]


VARD		EQU WORD PTR [BP-20]
VARDX		EQU WORD PTR [BP-24]
VARDY		EQU WORD PTR [BP-28]
ASQUARED	EQU WORD PTR [BP-32]
BSQUARED	EQU WORD PTR [BP-36]
TWOASQUARED	EQU WORD PTR [BP-40]
TWOBSQUARED	EQU WORD PTR [BP-44]

RMWBITS		EQU	00H
BYTESPERLINE EQU	320

_INCIRC13	PROC	FAR
	PUSH	BP
	MOV	BP,SP
	SUB	SP,50
	PUSH	DS
	PUSH	ES
	PUSH	SI
	PUSH	DI


;INITIAL CONSTANTS
	MOV AX,ARGA
	MUL	AX
	MOV ASQUARED,AX
	MOV	ASQUARED+2,DX
	SHL	AX,1
	RCL	DX,1
	MOV	TWOASQUARED,AX
	MOV	TWOASQUARED+2,DX
	MOV	AX,ARGB
	MUL	AX
	MOV BSQUARED,AX
	MOV BSQUARED+2,DX
	SHL	AX,1
	RCL DX,1
	MOV TWOBSQUARED,AX
	MOV TWOBSQUARED+2,DX

;PLOT PIXELS FROM (0,B) UNTIL DY/DX =-1
;INITIAL BUFFER ADDRESS AND BIT MASK
	MOV	AX,BYTESPERLINE
	MUL	ARGB
	MOV	SI,AX
	MOV	DI,AX
	MOV	AX,ARGYC
	MOV	BX,ARGXC
	CALL	PIXELADDR13

	ADD	SI,BX
	MOV	ULADDR,SI
	MOV URADDR,SI
	SUB	BX,DI
	MOV	LLADDR,BX
	MOV	LRADDR,BX

;INITIAL DECISION VARIABLES
	XOR	AX,AX
	MOV	VARDX,AX
	MOV	VARDX+2,AX

	MOV	AX,TWOASQUARED
	MOV DX,TWOASQUARED+2
	MOV CX,ARGB
	CALL LONGMULTIPLY
	MOV VARDY,AX
	MOV VARDY+2,DX

	MOV AX,ASQUARED
	MOV	DX,ASQUARED+2
	SAR DX,1
	RCR	AX,1
	SAR	DX,1
	RCR AX,1

	ADD AX,BSQUARED
	ADC	DX,BSQUARED+2
	MOV	VARD,AX
	MOV VARD+2,DX

	MOV	AX,ASQUARED
	MOV	DX,ASQUARED+2
	MOV CX,ARGB
	CALL LONGMULTIPLY
	SUB	VARD,AX
	SBB	VARD+2,DX
	
	;LOOP UNTIL DY/DX>=-1
	MOV	BX,ARGB
	XOR	CX,CX
	
IC10:	
	MOV	AX,VARDX
	MOV	DX,VARDX+2
	SUB	AX,VARDY
	SBB	DX,VARDY+2
	JNS	IC20
	
	CALL	INVERT4PIXELS
	MOV CX,1
	CMP	VARD+2,0
	JS	IC11
	MOV	CH,1
	DEC	BX
	
	MOV AX,VARDY
	MOV	DX,VARDY+2
	SUB AX,TWOASQUARED
	SBB	DX,TWOASQUARED+2
	MOV VARDY,AX
	MOV	VARDY+2,DX

	SUB	VARD,AX
	SBB	VARD+2,DX
	
IC11:
	MOV AX,VARDX
	MOV DX,VARDX+2
	ADD	AX,TWOBSQUARED
	ADC	DX,TWOBSQUARED+2
	MOV VARDX,AX
	MOV VARDX+2,DX
	ADD	AX,BSQUARED
	ADC	DX,BSQUARED+2
	ADD VARD,AX
	ADC	VARD+2,DX
	JMP	IC10
	
;PLOT PIXELS FROM CURRENT (X,Y) UNTIL Y<0
	
IC20:
	PUSH	BX
	PUSH	CX
	MOV	AX,ASQUARED
	MOV	DX,ASQUARED+2
	SUB	AX,BSQUARED
	SBB	DX,BSQUARED+2
	MOV BX,AX
	MOV CX,DX
	
	SAR DX,1
	RCR	AX,1
	ADD AX,BX
	ADC	DX,CX
	
	SUB AX,VARDX
	SBB	DX,VARDX+2
	SUB	AX,VARDY
	SBB	DX,VARDY+2
	
	SAR	DX,1
	RCR	AX,1
	
	ADD	VARD,AX
	ADC	VARD+2,DX
	
;LOOP UNTIL Y<0
	POP CX
	POP BX
IC21:
	CALL INVERT4PIXELS
	MOV CX,100H
	
	CMP	VARD+2,0
	JNS	IC22
	
	MOV CL,1
	MOV AX,VARDX
	MOV DX,VARDX+2
	ADD AX,TWOBSQUARED
	ADC	DX,TWOBSQUARED+2
	MOV	VARDX,AX
	MOV	VARDX+2,DX
	
	ADD	VARD,AX
	ADC	VARD+2,DX
	
IC22:	
	MOV AX,VARDY
	MOV	DX,VARDY+2
	SUB	AX,TWOASQUARED
	SBB	DX,TWOASQUARED+2
	MOV	VARDY,AX
	MOV	VARDY+2,DX

	SUB	AX,ASQUARED
	SBB	DX,ASQUARED+2
	SUB	VARD,AX
	SBB	VARD+2,DX
	
	DEC	BX
	JNS	IC21
	
;RESTORE DEFAULT GRAPHICS CONTROLLER REGISTERS
ICEXIT:
	POP DI
	POP SI
	POP	ES
	POP	DS
	MOV SP,BP
	POP	BP
	RET

_INCIRC13	ENDP

SET4PIXELS	PROC	NEAR
	PUSH	AX
	PUSH	BX
	PUSH	DX
	MOV		AL,ARGN		; GET THE COLOR VALUE
	XOR	BX,BX
	TEST	CH,CH
	JZ	C30
	MOV	BX,BYTESPERLINE
	NEG	BX
C30:
	
;PIXELS AT (XC-X,YC+Y) AND XC-X,YC-Y)

	XOR	SI,SI
	TEST	CL,CL
	JZ	C31
	MOV	SI,-1
C31:

	MOV DI,SI
	ADD	SI,ULADDR
	ADD	SI,BX
	ADD	DI,LLADDR
	SUB	DI,BX
	MOV	ULADDR,SI
	MOV	LLADDR,DI
	MOV	ES:[SI],AL
	MOV	ES:[DI],AL
	
;PIXELS AT (XC+X,YC+Y) AND (XC+X,YC+Y)

	XOR	SI,SI
	TEST	CL,CL
	JZ	C32
	MOV	SI,1
C32:
	MOV	DI,SI
	
	ADD	SI,URADDR
	ADD SI,BX
	ADD	DI,LRADDR
	SUB	DI,BX
	
	MOV	URADDR,SI
	MOV	LRADDR,DI
	
	MOV	ES:[SI],AL
	MOV ES:[DI],AL
	
	POP	DX
	POP BX
	POP AX
	RET

SET4PIXELS	ENDP

INVERT4PIXELS	PROC	NEAR
	PUSH	AX
	PUSH	BX
	PUSH	DX
	XOR	BX,BX
	TEST	CH,CH
	JZ	IC30
	MOV	BX,BYTESPERLINE
	NEG	BX
IC30:
	
;PIXELS AT (XC-X,YC+Y) AND XC-X,YC-Y)

	XOR	SI,SI
	TEST	CL,CL
	JZ	IC31
	MOV	SI,-1
IC31:

	MOV DI,SI
	ADD	SI,ULADDR
	ADD	SI,BX
	ADD	DI,LLADDR
	SUB	DI,BX
	MOV	ULADDR,SI
	MOV	LLADDR,DI
	MOV	AL,ES:[SI]
	XOR AL,0FFH
	MOV	ES:[SI],AL
	MOV	AL,ES:[DI]
	XOR AL,0FFH
	MOV	ES:[DI],AL
	
;PIXELS AT (XC+X,YC+Y) AND (XC+X,YC+Y)

	XOR	SI,SI
	TEST	CL,CL
	JZ	IC32
	MOV	SI,1
IC32:
	MOV	DI,SI
	
	ADD	SI,URADDR
	ADD SI,BX
	ADD	DI,LRADDR
	SUB	DI,BX
	
	MOV	URADDR,SI
	MOV	LRADDR,DI
	
	MOV	AL,ES:[SI]
	XOR AL,0FFH
	MOV	ES:[SI],AL
	MOV	AL,ES:[DI]
	XOR AL,0FFH
	MOV	ES:[DI],AL
	
	POP	DX
	POP BX
	POP AX
	RET

INVERT4PIXELS	ENDP

LONGMULTIPLY	PROC	NEAR

	PUSH	AX
	MOV	AX,DX
	MUL	CX
	XCHG	AX,CX
	POP DX
	MUL DX
	ADD	DX,CX
	RET

LONGMULTIPLY	ENDP

;	ENDPS
	END
