; 1st. February 1989 -- MFB
cseg	segment byte
	assume cs:cseg,ds:cseg,es:cseg

	org	100h

	asm	=	4	;dictionary entry flags
	const	=	10h
	immed	=	0
	head	=	0


	gradd	=	3ceh	;graphics address register
	grwrt	=	3cfh	;graphics write only register
	seqadd	=	3c4h	;sequence address select register
	seqdat	=	3c5h	;sequence data read/write register


start:
	call 	star
star:	pop	ax
	sub	ax,103h

	push	es
	push	ds
	push	cx	;4th pc
			;must change ds before we can store these
;	push	ax
	mov	cl,4
	shr	ax,cl	;ax contains new DS value
	mov	cx,ds
	add	cx,ax
	mov	ds,cx	;ds now ok for data access

;	pop	dx
;	and	dx,0fh	;dx contains new OFFSET value

	pop	cx	;original cx - do data access
	mov	cxsave,cx
	pop	cx	;original ds
	mov	dssave,cx
	pop	cx	;original es
	mov	essave,cx
	ret

fin:	mov	cx,cxsave
	mov	es,essave
	mov	ax,dssave
	mov	ds,ax
	lodsw
	jmp	ax		;now in INTRO.4TH

;	light pixel at x,y (no clipping)
;	   x,y (column/row) in CX,DX (as for BIOS Int 10 call)
;	all register contents on entry restored at exit
;
;	stack ==>  x y picval  ==> TOS
;

;=======
dpix:	
;=======
	call	start
	POP	DX		;picval
	MOV	(PICVAL),DX
	POP	DX		;y value
	POP	CX		;x value

	PUSH	SI		;display type is EGA
	PUSH	DI		;these two will need to be saved
	mov	ax,dx		;to line up with BIOS parameter standard
	call	dodot ; -6
	POP	DI
	POP	SI
;
	jmp	fin
;nmfb

SET_DOT:	;sets one point in CGA hires mode at the X co-ord in CX
		;and the Y co-ord in AX. All but AX & CX registers saved
;
	JMP	DPIX      ; set_dot not used any more
;

CGADOT:	

	PUSH	SI		;display type is CGA
	PUSH	DI		;these two will need to be saved

	sar	ax,1
	sar	dx,1
	MOV	SI,CX		;copy of CX
	AND	AX,0FEH		;strip odd/even bit
	SAL	AX,1
	SAL	AX,1
	SAL	AX,1
	MOV	dx,AX		;bx=ax*8
	SAL	AX,1
	SAL	AX,1		;AX=AX*32
	ADD	AX,dx		;ax=ax*40
	SAR	dx,1		;low bit int cf
	JNB	EVEN
	ADD	AX,2000H	;adjust for odd row
EVEN:	MOV	dx,SI
	SAR	dx,1
	SAR	dx,1	
	SAR	dx,1		;cx=cx/8
	ADD	AX,dx		;final address in AX
	XCHG	SI,AX
	AND	AL,7
	mov	cl,7
	sub	cl,al		;7 - (x MOD 8) is bit # in byte
	mov	al,1		;
	sal	al,cl		; al now contains bitmask
	MOV	cx,BX		;save contents of BX
;
	cmp	(picval),0
	jz	nodot
	MOV	BX,0b800h  ; VIDEO_BUFFER
	MOV	ES,BX		;set ES to point to video buffer segment
	MOV	BX,cx		;restore BX
DOT1:	OR	AL,BYTE PTR ES:[SI]
DOT2:	MOV	BYTE PTR ES:[SI],AL

;	MOV	AX,CS
;	MOV	ES,AX
;
nodot:	POP	DI
	POP	SI
	RET
;

dodot:	
	push	dx
	push	bx
	push	ds
	mov	bx,40h
	mov	ds,bx
	mov	bx,49h
	mov	dl,[bx]
	cmp	dl,6
	pop	ds
	pop	bx
	jnz	n6
	pop	dx
	call	cgadot
	ret
n6:	cmp	dl,10h
;	pop	dx
	jnz	n10
	 pop	dx
	jmp	ok10
n10:	 cmp	dl,4h
	 jnz	n4
	 pop	dx
	 call	cgadot
	 ret
n4:	pop	dx
	ret

ok10:	PUSH	SI		;display type is EGA
	PUSH	DI		;these two will need to be saved
	push	cx
	push	dx
				; x,y in cx,dx
	call	setbyte ; -15
	call	setbit ; -15

	jmp	comn



;	stack ==>  x y picval  ==> TOS
;=======
d4pix:
;=======
	call	start
	POP	DX
	MOV	(PICVAL),DX
	POP	DX
	POP	CX
	CALL	EGABYTE ; -8

	jmp	fin

egabyte:	
	PUSH	SI		;display type is EGA
	PUSH	DI		;these two will need to be saved
	push	cx
	push	dx
	mov	ax,dx		;to line up with BIOS parameter standard
				; x,y in cx,dx
	call	setbyte
	pushf
	and	al,0fh
	mov	al,0f0h
	jz	lozero
	mov	al,0fh
lozero:	popf
	call	setbit
;mmfb
comn:	
	MOV	AX,0A000H
	MOV	ES,AX		;set EGA hires video buffer
	MOV	AL,BYTE PTR ES:[SI] 	;Read at address A000:offset
				;This latches all 4 bit planes.
				;(The byte "read" is ignored.)
	MOV	AL,0
	MOV	BYTE PTR ES:[SI],AL	;Write at address A000:offset
				;This sets the bit-masked bits to '0'
				;and stores the latched bytes to the
				;bit planes
; 
	MOV     DX,seqadd   ;Sequencer/Map Mode port address
	MOV	AL,2
	OUT	DX,AL		;Select "Map Mask" register 2
	MOV	DX,seqdat
;	SUB	AX,AX		;make nul value
;	OR	BYTE PTR form,0 
;	JNS	MAKEDOT
	MOV	AX,(picval)
;MAKEDOT:			;zero if erase mode, otherwise picval
	OUT	DX,AL
	MOV	AX,0A000H
	MOV	ES,AX		;set EGA hires video buffer
	MOV	AL,BYTE PTR ES:[SI]	; Latch the bit plane data.
	MOV	AL,11111111b
	MOV	BYTE PTR ES:[SI],AL	; Set bits to '1' in 
;					appropriate planes.
	call	rstega

	pop	dx
	pop	cx
	POP	DI
	POP	SI
;nmfb
;	MOV	AX,CS
;	MOV	ES,AX
	ret
;
setbyte:
;;	MOV	DI,AX		;copy of AX
	MOV	SI,CX		;and CX
	mov	cl,3
	sal	ax,cl		;cl=3
	mov	dx,ax		;dx = ax * 8
	dec	cl		;cl becomes 2
	sal	ax,cl
	add	ax,dx
	SAL	AX,1		;ax * 80
	mov	dx,si		; x value into dx
	inc	cl		;cl becomes 3
	sar	dx,cl		; dx = dx/8 to find byte addr
	add	ax,dx		;final address
	XCHG	SI,AX		;place addr into SI 
				;  restore x value to AX

	AND	AX,7		;x mod 8
	mov	cl,7
	sub	cl,al		;7 - (x MOD 8) is bit # in byte
	mov	al,1		;
	sal	al,cl		; al now contains bitmask
	ret

setbit:	MOV	DX,gradd 	;3CEh Graphics Controller port address
	MOV	AH,AL
	MOV	AL,8
	OUT	DX,AL		; select register 8
	MOV	DX,grwrt 	;3CFh
	MOV	AL,AH
	OUT	DX,AL		; load the bit mask into reg 8
	ret

rstega:	MOV	DX,seqadd
	MOV	AL,2		; Again, select ...
	OUT	DX,AL		; ... Sequencer/Map Mask register 2.
	MOV	DX,seqdat
	MOV	AL,1111b	; Default map mask
	OUT	DX,AL		; Enable all 4 bit planes
	MOV	DX,gradd
	MOV	AL,8		; Again, select ...
	OUT	DX,AL		; ... Graphics Controller register 8
	MOV	DX,grwrt
	MOV	AL,11111111b	; Default bit mask
	OUT	DX,AL		; Restore default bit mask
	ret

;
;  ****** NOTE ***** now redefined in UCC1.BLD as DBOX (was egabox)
;                   principally to allow parameters to be
;                   specified as X1 X2 Y1 Y2 picval
;

;=======
 dbox:			    ;draw a filled box
;=======
	call	start
	pop	(picval)

;	stack ==>  X1 Y1 X2 Y2  picval ==> TOS

	pop	ax	;y2 
	pop	bx	;x2 
	pop	dx	;y1 
	sub	ax,dx	;y2 
	jz	nogo1
	xchg	ax,bx	;ax=x2 bx=ycount
	pop	cx	;cx = x1 
	sub	ax,cx	;x2 - x1

	sar	ax,1
	sar	ax,1	;divide by 4
	jz	nogo2
	MOV	(xcount),AX	;XCOUNT
;	pop	(picval)

	push	cx	;                cx is X start value 
			;		    push for later restoring
			;		 dx is Y start value
dotlp:	push	ax
	PUSH	BX
	call	egabyte ; +7	;assembly graphics write CX,DX IS X,Y
	POP	BX
	pop	ax

	add	cx,4	;8 next x value
	DEC	ax	;xcount
	jnz	dotlp

	mov	ax,(xcount) 	;restore xcount
	pop	cx			;restore xstart
	push	cx	;save again
	inc	dx	;next y value
	DEC	BX	;ycount
	jnz	dotlp

	pop	cx	;not wanted any more
	jmp	nogo2

nogo1:	pop	ax

nogo2:	jmp	fin

;
;	Bresenhan's line drawing algorithm
;

;======
dline:				;draw a line from last plotted point
;======
	call	start
	POP	DX		;picval
	MOV	(PICVAL),DX
	POP	DX		;y value
	POP	CX		;x value

	PUSH	SI		;display type is EGA
	PUSH	DI		;these two will need to be saved
	call	doline ; -7

	POP	DI
	POP	SI

	jmp	fin
Doline:	

;	mov	dx,ax		;x value
;	mov	cx,cx		;y value

	mov	(y2),dx
	mov	(x2),cx

;	POP	Y2
;	POP	X2

	MOV	AX,WORD PTR (LASTPOINT)
	MOV	(X1),AX
	MOV	AX,WORD PTR (LASTPOINT+2)
	MOV	(Y1),AX
	MOV	AX,(Y2)
	MOV	WORD PTR (LASTPOINT+2),AX
	MOV	AX,(X2)
	MOV	WORD PTR (LASTPOINT),AX
	CALL	LINE ; -5
	ret
;

LINE:	MOV	AX,(Y2)
	SUB	AX,(Y1)
	MOV	SI,1
	JGE	STOREY
	MOV	SI,-1
	NEG	AX
STOREY:
	MOV	(DELTAY),AX
;
	MOV	AX,(X2)
	SUB	AX,(X1)
	MOV	DI,1
	JGE	STOREX
	MOV	DI,-1
	NEG	AX
STOREX:
	MOV	(DELTAX),AX
;
	CMP	AX,(DELTAY)
	JL	CSTEEP
	CALL	EASY
;	ret
;

CSTEEP:	CALL	STEEP  
FINISH:	RET
;

EASY:	MOV	AX,(DELTAX)
	SHR	AX,1
	MOV	(HALFX),AX
	MOV	CX,(X1)
	MOV	AX,(Y1)
	SUB	BX,BX
	MOV	DX,(DELTAX)
	MOV	(COUNT),DX
NEWDOT:	
	PUSH	AX		;y value
	PUSH	CX		;x value

;	mov	ax,dx		;to line up with BIOS parameter standard
	CALL	dodot ; 

	POP	CX
	POP	AX

	ADD	CX,DI
	ADD	BX,(DELTAY)
	CMP	BX,(HALFX)
	JLE	DCOUNT
	SUB	BX,(DELTAX)
	ADD	AX,SI
DCOUNT:	DEC	(COUNT)
	JGE	NEWDOT
	RET
;

STEEP:	MOV	AX,(DELTAY)
	SHR	AX,1
	MOV	(HALFY),AX
	MOV	CX,(X1)
	MOV	AX,(Y1)
	SUB	BX,BX
	MOV	DX,(DELTAY)
	MOV	(COUNT),DX
NEWDOT2:
	PUSH	AX	;y1
	PUSH	CX	;x1
;	mov	ax,dx		;to line up with BIOS parameter standard
	CALL	dodot ; 
	POP	CX
	POP	AX
	ADD	AX,SI
	ADD	BX,(DELTAX)
	CMP	BX,(HALFY)
	JLE	DCOUNT2
	SUB	BX,(DELTAY)
	ADD	CX,DI
DCOUNT2:
	DEC	(COUNT)
	JGE	NEWDOT2
	RET	

; ***********************
;
; This routine is based on the article page 65 of Dr. Dobbs Journal
; July 1983 - Anatomy of a Digital Vector and Curve Generator - by 
; Richard Shiffman.
;
; ***********************

;======
circle:
;======
	call	start
	pop	(PICVAL)
	mov	cl,5		; get more significant digits
	pop	dx		; by shifting left by ???
	sal	dx,cl		; 5 chosen arbitrarily
	mov	(rad),dx
	pop	(yc)
	pop	(xc)
	PUSH	SI		;display type is EGA
	PUSH	DI		;these two will need to be saved

	mov	ax,(rad)	;original y = radius
	mov	bx,0		;original x zero

	mov	cx,800		;loop count
	push	cx
cirlp:	mov	cl,7		; divisor for incrementing
	push	ax		; round circle (arbitrarily chosen
				;   but must match 800 loop count
	sar	ax,cl		;divide y
	sub	bx,ax		;updated x
	pop	ax

	push	bx
	sar	bx,cl		;divide x
	add	ax,bx		;updated y
	pop	bx
	
	mov	cx,bx
	mov	dx,ax

	push	ax
	push	bx
	mov	ax,cx
	mov	cl,5	; undo significant digit shift left
	sar	ax,cl	; for BOTH x and y values
	sar	dx,cl
	mov	cx,ax

	push	dx	; correction
	mov	ax,cx   ;   for
	mov	bx,7    ;     aspect
	imul	bx      ;        ratio
	mov	bx,6    ;
	idiv	bx      ;
	mov	cx,ax   ;
	pop	dx      ;

	add	cx,(xc)  ; add x value for centre
	js	skp	      ; must still use signed numbers
	cmp	cx,640 	      ; clip at edges of screen
	jnc	skp

;	push	dx	; aspect ratio correction
;	mov	ax,cx	; moved to before Xc added
;	mov	bx,7    ;
;	mul	bx      ; see file SMITH for
;	mov	bx,6    ; method of aspect correction
;	div	bx      ; for Xc and Yc
;	mov	cx,ax   ;
;	pop	dx      ;

	add	dx,(yc)  ; add y value for centre
	js	skp	      ; must use signed numbers
	cmp	dx,15eh	      ; clip at bottom of screen
	jnc	skp
	mov	ax,dx
	call	dodot ; 
skp:	pop	bx
	pop	ax

	pop	cx
	dec	cx	; loop count
	push	cx
	jnz	cirlp	; round again
	pop	cx

	POP	DI
	POP	SI

	jmp	fin

;	org	((512) + ($-start)) - (($-start) mod 256)

;******************************************************
PICVAL	DW	2	;colour value for pixel to be lit
cxsave	dw	1
dssave	dw	0
essave	dw	0
FORM	DB	080h
;;BITMASK	DB	128,64,32,16,8,4,2,1 (not used now)

lastpoint dw	4 dup (?)
DELTAX	DW	0
DELTAY	DW	0
HALFY	DW	0
HALFX	DW	0
COUNT	DW	0
X2	DW	0
Y2	DW	0
X1	DW	0
Y1	DW	0
xcount	dw	0
xc	dw	0
yc	dw	0
rad	dw	0
;
;******************************************************
;
	db	'binload endproc '

;	db	af - ae
;ae	db	'EGAPARM'
;af	db	immed
;	dw	egaparm


	db	ad - ac
ac	db	'CIRCLE'
ad	db	immed
	dw	circle

	db	ab - aa
aa	db	'DOLINE'
ab	db	immed
	dw	doline

	db	z - y
y	db	'DLINE'
z	db	immed
	dw	dline

	db	x - w
w	db	'DBOX'
x	db	immed
	dw	dbox

	db	v - u
u	db	'EGABYTE'
v	db	immed
	dw	egabyte

	db	t - s
s	db	'D4PIX'
t	db	immed
	dw	d4pix

;	db	r - q
;q	db	'SETDOT'
;r	db	immed
;	dw	set_dot

	db	p - o
o	db	'DPIX'
p	db	immed
	dw	dpix

	db	'endfile '

cseg	ends
	end	start

