;
;   Number Nine Revolution 512x8 
;   support routines for raster oriented graphics
;
;   Tim Krauskopf      July 1986
;
;   National Center for Supercomputing Applications, University of Illinois
;   153 Water Resources Building
;   605 E. Springfield Ave.
;   Champaign, IL  61820
;   (217)244-0072
;
;
	TITLE      NUMBER 9 GRAPHICS SUPPORT
	INCLUDE DOS.MAC
	SETX
	PSEG
	PUBLIC	PUTMAP9,NO9LINE,SHOWPAL9,NOPAL9,OUTLINE9,MAKECUR9;,NO9PT
;
SETBANK	MACRO
	LOCAL	NO706
	LOCAL	NO705	
	LOCAL	OKBANK		; A MACRO TO SET THE BANK FOR THE LINE OF THE NO9 MONITOR
						; BX MUST CONTAIN THE Y POSITION
	MOV	AX,BX		; y location on screen
	MOV	CL,7		; divide by 128
	SHR	AX,CL
	MOV	CL,AL		; make a copy
	CMP	AL,CS:BANK	; is it the same bank?
	JZ	OKBANK

	MOV	CS:BANK,AL	; bank will be this one
	MOV	DH,00H		; default, might be changed
	AND	AL,02H		; is high bit on?
	JZ	NO706

	MOV	DH,0FFH		;  setting for new bank
NO706:
	MOV	DL,00H		; default setting for 705
	MOV	AL,CL		; get back copy
	AND	AL,01H		; is low bit on?
	JZ	NO705

	MOV	DL,0FFH		; other portion of new bank
NO705:
	MOV	DI,0705H	; where bank reg is
	MOV	AX,DX
	STOSW			; sets both bytes, lo then hi
;
;   READY TO PUT THE LINE
;
OKBANK:
	ENDM			; END OF THE COMPUTE BANK MACRO
;
;  take three arrays of color table entries and transfer them to the
;  board's registers
;
;  usage:  putmap9(rmap,gmap,bmap);
;
PUTMAP9	PROC	FAR
	PUSH	BP
	MOV	BP,SP
	PUSH	DS
	PUSH	ES
	MOV	AX,[BP+X+2]
	MOV	DS,AX			; where to get maps (seg)
	MOV	SI,[BP+X]		; where to get red
	MOV	AX,0C000H		; control seg for #9
	MOV	ES,AX
	MOV	DI,0100H		; red map
	MOV	CX,256			; length of map
	REP	MOVSB			; mov red
;
	MOV	SI,[BP+X+4]
	MOV	DI,0200H		; green map
	MOV	CX,256
	REP	MOVSB
;
	MOV	SI,[BP+X+8]		; blue map
	MOV	DI,0300H	
	MOV	CX,256
	REP	MOVSB
;
	POP	ES
	POP	DS
	POP	BP
	RET

PUTMAP9	ENDP
;
;  Transfer line to #9 screen, one byte per pixel
;
;   usage : no9line(x,y,buf,xoff,nbytes)
;
NO9LINE	PROC	FAR
	PUSH	BP
	MOV	BP,SP
	PUSH	DS
	PUSH	ES
	MOV	AX,0C000H	; control regs
	MOV	ES,AX

	MOV	AX,[BP+X+6]	; ds of buffer
	MOV	DS,AX
	MOV	BX,[BP+X+2]	; y location on screen
	SETBANK			; CALL MACRO TO SET THE CORRECT MEMORY BANK FOR THE Y POSITION
	MOV	AX,0A000H	; data buffer
	MOV	ES,AX
	MOV	SI,[BP+X+4]	; where data will come from
	MOV	AX,[BP+X+8]	; GET THE X OFFSET INTO THE ARRAY
	CMP	AX,0		; CHECK FOR NEGATIVE OFFSET
	JGE	OKSIGN		; JUMP AROUND FIXING THE WINDOW
	NEG	AX			; TAKE THE OPPOSITE VALUE
	ADD AX,[BP+X]	; AND ADD IT TO THE POSITION ON THE SCREEN
	MOV	[BP+X],AX	; AND RE-STORE THE POSITION
	MOV	AX,[BP+X+8]	; GET THE NEGATIVE OFFSET AGAIN
	ADD	AX,[BP+X+10]	; REDUCE THE NUMBER OF BYTES TO COPY TO THE SCREEN
	MOV	[BP+X+10],AX	; AND STORE THE NUMBER OF BYTES AGAIN
OKSIGN:
	ADD	SI,AX		; ADD THE OFFSET TO THE OFFSET OF THE ARRAY
;
	MOV	AX,[BP+X+2]	; get y value again
	MOV	CL,9
	SHL	AX,CL		; get 16 bit pointer for this bank
	ADD	AX,[BP+X]	; x value of where on screen added in
	MOV	DI,AX		; prepare for movs
	MOV	CX,[BP+X+10]	; how many bytes?
BLAST:
	REP	MOVSB

	POP	ES
	POP	DS
	POP	BP
	RET
BANK	DB	0FFH		; current bank number
NO9LINE	ENDP

;
;	showpal9(&palstore,pal_xoff,pal_yoff);
;
SHOWPAL9		PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES

	MOV	CX,16		; COUNT THE NUMBER OF LINES TO SAVE
	PUSH	CX		; AND SAVE THE COUNT
SHOWTOP:
	MOV	AX,0C000H	; control regs
	MOV	ES,AX
	MOV	BX,[BP+X+6]	; y location on screen
	INC	WORD PTR [BP+X+6]	; GET THE Y VALUE OF THE NEXT LINE
	SETBANK			; CALL MACRO TO SET THE CORRECT MEMORY BANK FOR THE Y POSITION
	MOV	AX,0A000H	; data buffer
	MOV	DS,AX
	MOV	AX,BX		; get y value again
	MOV	CL,9
	SHL	AX,CL		; get 16 bit pointer for this bank
	ADD	AX,[BP+X+4]	; ADD IN THE X OFFSET
	MOV	SI,AX		; prepare for movs
	MOV	DI,[BP+X]	; GET OFFSET OF ARRAY
	MOV	AX,[BP+X+2]	; GET SEGMENT OF STORAGE ARRAY
	MOV	ES,AX			
	MOV	CX,0		; how many bytes?
ZING:
	MOVSB			; SAVE THE OLD VALUE
	DEC	SI			; GO BACK TO PUT THE PALETTE IN MEMORY
	MOV	DS:BYTE PTR [SI],CL	; PUT THE PALETTE VALUE THERE
	INC	SI
	INC	CX			; INCREMENT THE LOOP COUNTER
	CMP	CH,1		; CHECK FOR THE END OF THE LINE
	JNE	ZING		; FINISH THE PALETTE  FOR THAT LINE

	POP	CX			; RECOVER THE COUNT OF LINES
	DEC	CX			; 
	PUSH	CX		; KEEP THE COUNT AROUND STILL
	MOV	[BP+X],DI	; SAVE MODIFIED OFFSET
	CMP	CX,0		; CHECK FOR THE COUNT BEING DONE
	JNE	SHOWTOP

	POP	CX		; GET RID OF EXTRANEOUS PUSH

	POP	ES
	POP	DS
	POP	BP
	RET
SHOWPAL9	ENDP
;
;	nopal9(&palstore,pal_xoff,pal_yoff);
;
NOPAL9		PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES

	MOV	CX,16		; THE NUMBER OF LINES TO REPLACE
	PUSH	CX		; SAVE THE NUMBER OF LINES
NOTOP:
	MOV	AX,0C000H	; control regs
	MOV	ES,AX
	MOV	BX,[BP+X+6]	; y location on screen
	INC	WORD PTR [BP+X+6]	; MAKE Y POSITION FOR NEXT LINE
	SETBANK			; CALL MACRO TO SET THE CORRECT MEMORY BANK FOR THE Y POSITION

	MOV	AX,0A000H	; data buffer
	MOV	ES,AX
	MOV	AX,[BP+X+2]	; ds of buffer
	MOV	DS,AX
	MOV	SI,[BP+X]	; where data will come from

	MOV	AX,BX		; get y value again
	MOV	CL,9
	SHL	AX,CL		; get 16 bit pointer for this bank
	ADD	AX,[BP+X+4]	; x value of where on screen added in
	MOV	DI,AX		; prepare for movs

	MOV	CX,256		; how many bytes?
ZOOM:
	REP	MOVSB

	POP	CX			; RECOVER THE COUNT OF LINES
	DEC	CX			; 
	PUSH	CX		; KEEP THE COUNT AROUND STILL
	MOV	[BP+X],SI	; SAVE MODFIED OFFSET
	CMP	CX,0		; CHECK FOR THE COUNT BEING DONE
	JNE 	NOTOP

	POP	CX			; GET RID OF EXTRANEOUS CX PUSH
	
	POP	ES
	POP	DS
	POP	BP
	RET
NOPAL9	ENDP
ifdef QAK
;
;	no9pt(x,y,color);
;
NO9PT		PROC	FAR
	PUSH	BP
	MOV		BP,SP
	PUSH	DS
	PUSH	ES
	MOV	AX,0C000H	; control regs
	MOV	ES,AX

	MOV	BX,[BP+X+2]	; GET LINE TO COPY SCREEN BACK ONTO
	SETBANK

	MOV	AX,0A000H	; data buffer
	MOV	ES,AX

	MOV	AX,[BP+X+2]	; get y value again
	MOV	CL,9
	SHL	AX,CL		; get 16 bit pointer for this bank
	ADD	AX,[BP+X]	; ADD IN THE X OFFSET

	MOV	DI,AX		; prepare for movs
	MOV	AL,[BP+X+4]	; GET THE VALUE TO PUT THERE

	STOSB			; PUT COLOR ON THE SCREEN

	POP	ES
	POP	DS
	POP	BP
	RET
NO9PT	ENDP
endif

Y_COUNT	DW	0		; THE NUMBER OF Y LINES TO INVERT
;
;  Invert A BOX ON THE SCREEN
;
;   usage : outline9(x1,y1,x2,y2)
;
OUTLINE9	PROC	FAR
	PUSH	BP
	MOV	BP,SP
	PUSH	DS
	PUSH	ES

;	INT	3			; PERFORM AN INTERUPT FOR DEBUGGER
	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
	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,0C000H	; control regs
	MOV	ES,AX
	MOV	BX,[BP+X+2]	; GET THE Y LOCATION FOR THE TOP LINE
	SETBANK			; CALL MACRO TO SET THE CORRECT MEMORY BANK FOR THE Y POSITION
	MOV	AX,0A000H	; SET THE DATA BUFFER
	MOV	ES,AX
	MOV	AX,[BP+X+2]	; GET THE Y POSITION FOR THE TOP LINE AGAIN
	MOV	CL,9
	SHL	AX,CL
	ADD	AX,[BP+X]	; ADD IN THE X OFFSET
	MOV	DI,AX		; STORE THE OFFSET
	MOV	CX,[BP+X+4]	; THE NUMBER OF BYTES TO INVERT
	INC	CX
BLASTA:
	MOV	AL,ES:[DI]	; GET THE BYTE TO INVERT
	NOT	AL		; INVERT THE BYTE
	MOV	ES:[DI],AL	; REPLACE THE BYTE
	INC	DI		; GO TO THE NEXT BYTE
	LOOP	BLASTA		; FINISH THE LINE OUT

	MOV	AX,0C000H	; control regs
	MOV	ES,AX
	ADD	BX,[BP+X+6]	; ADD IN THE Y SIZE TO GET TO THE LAST LINE
	ADD	BX,1		;
	SETBANK			; CALL MACRO TO SET THE CORRECT MEMORY BANK FOR THE Y POSITION
	MOV	AX,0A000H	; SET THE DATA BUFFER
	MOV	ES,AX
	MOV	AX,BX		; GET THE Y POSITION FOR THE TOP LINE AGAIN
	MOV	CL,9
	SHL	AX,CL
	ADD	AX,[BP+X]	; ADD IN THE X OFFSET
	MOV	DI,AX		; STORE THE OFFSET
	MOV	CX,[BP+X+4]	; THE NUMBER OF BYTES TO INVERT
	INC	CX
BLASTB:
	MOV	AL,ES:[DI]	; GET THE BYTE TO INVERT
	NOT	AL			; INVERT THE BYTE
	MOV	ES:[DI],AL	; REPLACE THE BYTE
	INC	DI			; GO TO THE NEXT BYTE
	LOOP	BLASTB	; FINISH THE LINE OUT

	MOV	CX,[BP+X+6]	; GET THE NUMBER OF LINES IN THE MIDDLE
	MOV	Y_COUNT,CX	; STORE IT IN THE PROPER PLACE
OUTTOP:
	MOV	AX,0C000H	; control regs
	MOV	ES,AX
	INC	WORD PTR [BP+X+2]	; INCREMENT THE LINE TO INVERT
	MOV	BX,[BP+X+2]	; GET THE LINE TO MODIFY
	SETBANK			; CALL MACRO TO SET THE CORRECT MEMORY BANK FOR THE Y POSITION
	MOV	AX,0A000H	; SET THE DATA BUFFER
	MOV	ES,AX
	MOV	AX,[BP+X+2]	; GET THE Y POSITION FOR THE TOP LINE AGAIN
	MOV	CL,9
	SHL	AX,CL
	ADD	AX,[BP+X]	; ADD IN THE X OFFSET
	MOV	DI,AX		; STORE THE OFFSET
	MOV	AL,ES:[DI]	; GET THE BYTE TO INVERT
	NOT	AL			; INVERT THE BYTE
	MOV	ES:[DI],AL	; REPLACE THE BYTE
	ADD	DI,[BP+X+4]	; GET TO THE END OF THE LINE		
	MOV	AL,ES:[DI]	; GET THE BYTE TO INVERT
	NOT	AL			; INVERT THE BYTE
	MOV	ES:[DI],AL	; REPLACE THE BYTE
	DEC	Y_COUNT		; DECREMENT THE COUNT
	CMP	Y_COUNT,0	; CHECK FOR THE END OF THE BOX
	JG	OUTTOP		; JUMP BACK TO THE BEGINNING

	POP	ES
	POP	DS
	POP	BP
	RET
OUTLINE9	ENDP

X_SIZE	EQU	16		; X WIDTH OF THE CURSOR
Y_SIZE	EQU	32		; TWICE THE Y HEIGHT OF THE CURSOR
X_HOT	EQU	7		; HORIZONTAL HOT SPOT FOR THE CURSOR
Y_HOT	EQU	7		; VERTICAL HOT SPOT FOR THE CURSOR
X_START	DW	?		; THE X POSITION TO START THE ARRAY ON
;
;	EACH BIT PLACE IN THE CURSOR ARRAY STANDS FOR A BYTE ON THE SCREEN
;	IF THE BIT IS ON, THEN THAT BYTE ON THE SCREEN WILL BE INVERTED
;	IF NOT, THEN THE BYTE WILL BE UNTOUCHED.
;	THE NUMBER OF WORDS FOR THE CURSOR ARRAY, AND THE NUMBER OF BITS
;	IN EACH IS CONTROLLED BY THE X_SIZE AND Y_SIZE VARIABLES.
CURSOR	LABEL	WORD		; LABEL FOR THE BEGINNING OF THE CURSOR ARRAY
		DW	0000000000000000B
		DW	0000000000000000B
		DW	0000000110000000B
		DW	0000000110000000B
		DW	0000000110000000B
		DW	0000000110000000B
		DW	0000000110000000B
		DW	0011111111111100B
		DW	0011111111111100B
		DW	0000000110000000B
		DW	0000000110000000B
		DW	0000000110000000B
		DW	0000000110000000B
		DW	0000000110000000B
		DW	0000000000000000B
		DW	0000000000000000B
;
;
;	Routine to make a cursor on the screen
;	makecur9(x,y);
;
MAKECUR9	PROC	FAR
	PUSH	BP
	MOV	BP,SP
	PUSH	DS
	PUSH	ES

	MOV	AX,[BP+X+2]	; GET THE Y VALUE TO MODIFY FOR THE HOT SPOT
	SUB	AX,Y_HOT	; SUBTRACT THE HOT SPOT VALUE
	MOV	[BP+X+2],AX	; REPLACE THE Y VALUE

	MOV	AX,[BP+X]	; GET THE X VALUE TO MODIFY FOR THE HOT SPOT
	SUB	AX,X_HOT	; SUBTRACT THE HOT SPOT VALUE
	MOV	[BP+X],AX	; REPLACE THE X VALUE

	MOV	X_START,0	; INITIALIZE THE X_START TO BE IN THE 0 POSITION
	MOV	SI,0		; INITIALIZE THE Y COUNTER
CURTOP:
	MOV	AX,0C000H	; control regs
	MOV	ES,AX
	MOV	BX,[BP+X+2]	; GET LINE TO COPY SCREEN BACK ONTO
	CMP	BX,0		; CHECK FOR NEGATIVE COORDINATES
	JL	CUREND		; IF NEGATIVE COORDINATES THEN JUMP TO END OF LOOP
	SETBANK

	MOV	AX,0A000H	; data buffer
	MOV	ES,AX

	MOV	DX,X_START	; INITIALIZE THE X COUNTER
	MOV	BX,CURSOR[SI]	; GET THE CURRENT CURSOR INFORMATION
	MOV	CX,X_START	; GET THE INITIAL NUMBER OF BITS TO SHIFT THE ARRAY
	SHL	BX,CL		; SHIFT THE ARRAY THAT MANY BYTES
TRYAGAIN:
	MOV	AX,[BP+X]	; GET THE X POSITION
	CMP	AX,0		; CHECK FOR NEGATIVE POSITION
	JGE	OKFINE		; NOT A NEGATIVE VALUE
	INC	WORD PTR [BP+X]	; INCREMENT THE X POSITION
	INC	DX			; AND THE POSITION IN THE ARRAY
	INC	WORD PTR X_START	; INCREMENT THE POSITION TO START IN THE ARRAY FOR NEXT LOOP THRU
	SHL	BX,1		; GET RID OF A BIT OF THE CURSOR INFORMATION
	JMP	TRYAGAIN	; JUMP BACK TO TRY FOR ANOTHER X POSITION
OKFINE:
	MOV	AX,[BP+X+2]	; get y value again
	MOV	CL,9
	SHL	AX,CL		; get 16 bit pointer for this bank
	ADD	AX,[BP+X]	; ADD IN THE X OFFSET
	MOV	DI,AX		; prepare for movs

LOOPTOP:
	SHL	BX,1		; GET THE BIT FOR THIS CURSOR POSITION
	JNC	LOOPBOT		; IF IT NOT SET THEN JUMP TO BOTTOM OF LOOP
	MOV	AL,ES:[DI]	; GET THE BYTE TO INVERT
	NOT	AL			; INVERT THE BYTE
	MOV	ES:[DI],AL	; REPLACE THE INVERTED BYTE
LOOPBOT:
	INC	DI			; INCREMENT FOR NEXT BYTE ON THE SCREEN
	INC	DX			; INCREMENT THE POSITION IN THE ARRAY
	CMP	DX,X_SIZE	; CHECK TO SEE IF THE END OF THE LINE HAS BEEN FOUND
	JNE	LOOPTOP		; IF NOT END THEN JUMP TO BEGINNING OF THE LOOP

CUREND:
	INC	WORD PTR [BP+X+2]	; INCREMENT Y VALUE FOR THE NEXT LINE
	INC	SI			; INCREMENT THE Y POSITION IN THE ARRAY
	INC	SI
	CMP	SI,Y_SIZE	; CHECK TO SEE IF THE BOOTOM OF THE ARRAY HAS BEEN REACHED
	JE	KLUDGE		; JUMP AROUND JUMP BACK IF AT END
	JMP	CURTOP		; IF NOT THEN JUMP TO BEGINNING OF A NEW LINE
KLUDGE:

	POP	ES
	POP	DS
	POP	BP
	RET
MAKECUR9	ENDP

	ENDPS
	END
