; plot.asm - fast line drawing routines using the blitter.
;
; line drawing functions (lines must be pre-clipped)
;
;	line(BitMap,x1,y1,x2,y2);				- draw a single line
;	polyline(BitMap,line_array,count,mod);	- draw series of connected lines
;	polygon(BitMap,line_array,count,mod);	- as above, 1st point = last
;	colorline(BitMap,x1,y1,x2,y2,color);	- as line but colored
;	setpixel(BitMap,x1,y1,color);
;	area(BitMap,tmpras,line_array,count,mod,color1,color2,percent);
;				as polygon with fill & vertex
;	clearplanes(BitMap,plane);				- zero-out plane #n

DMACONR		equ		2

BLTAPT		equ		$50
BLTAPTL		equ		$52
BLTBPT		equ		$4C
BLTCPT		equ		$48
BLTDPT		equ		$54
BLTCON0		equ		$40
BLTCON1		equ		$42
BLTAFWM		equ		$44
BLTALWM		equ		$46
BLTSIZE		equ		$58
BLTAMOD		equ		$64
BLTBMOD		equ		$62
BLTCMOD		equ		$60
BLTDMOD		equ		$66
BLTADAT		equ		$74
BLTBDAT		equ		$72

DisownBlitter	equ	$FFFFFE32
OwnBlitter		equ	$FFFFFE38
WaitBlit		equ	$FFFFFF1C

BMWidth			equ	0		; bit map width
BMRows			equ	2		; bit map height
BMFlags			equ	4		; bit map flags
BMDepth			equ	5		; bit map depth
BMPlanes		equ	8		; bit map planes

		public	_line,_clearplane
		public	_GfxBase

_line
		movem.l	d2-d7/a2-a3/a6,-(sp)
		move.l	#$dff000,a0			; address of custom regs

		move.l	_GfxBase,a6
		jsr		OwnBlitter(a6)		; get blitter

		move.l	10*4(sp),a1			; address of bitmap
		movem.l	11*4(sp),d0-d3		; coordinates of line draw
		bsr.s	drawline

		jsr		DisownBlitter(a6)
		movem.l	(sp)+,d2-d7/a2-a3/a6
		rts

; drawline - a1 = bitmap structure, d0-d3 = coordinates

drawline
		moveq	#$f,d4			; mask
		and.w	d2,d4			; d4 = bottom 4 bits of x coordinate

		sub.w	d3,d1			; d1 = dy
		mulu.w	BMWidth(a1),d3	; d3 = screen offset (words) = d3 * 40
		sub.w	d2,d0			; d0 = dx
		blt.s	draw50			; if dx is negative goto draw4c
		tst.w	d1				; if dy is negative goto draw3c
		blt.s	draw40
draw30	cmp.w	d0,d1			; dx > dy goto draw36
		bge.s	draw35
		moveq	#$11,d7
		bra.s	draw70
draw35	moveq	#$1,d7
		exg		d1,d0
		bra.s	draw70

draw40	neg.w	d1
		cmp.w	d0,d1
		bge.s	draw45
		moveq	#$19,d7
		bra.s	draw70
draw45	moveq	#$5,d7
		exg		d1,d0
		bra.s	draw70

draw50	neg.w	d0
		tst.w	d1
		blt.s	draw60
		cmp.w	d0,d1
		bge.s	draw55
		moveq	#$15,d7
		bra.s	draw70
draw55	moveq	#$9,d7
		exg		d1,d0
		bra.s	draw70

draw60	neg.w	d1
		cmp.w	d0,d1
		bge.s	draw65
		moveq	#$1d,d7
		bra.s	draw70
draw65	moveq	#$d,d7
		exg		d1,d0

draw70	move.w	d0,d5			; length of line
		add.w	d1,d1			; d1 <= 2y
		asr.w	#3,d2			; d2 = y1 / 8
		ext.l	d2
		add.l	d2,d3			; d3 = map(x1,y1)
		move.w	d1,d2			; d2 = 2y
		sub.w	d0,d2			; d2 = 2y - x
		bge.s	draw80			; if (2dy - dx) > 0 then draw80
		ori.w	#$40,d7			; do something mysterious to octant
draw80	btst	#6,DMACONR(a0)	; wait for blitter free
		btst	#6,DMACONR(a0)
		beq.s	draw85
		jsr		WaitBlit(a6)
draw85	movea.w	d2,a3			; a3 = (2y - x)
		move.w	d1,BLTBMOD(a0)	; BLTBMOD = (2y)
		move.w	d2,d1			; d1 = 2y-x
		sub.w	d0,d1			; d1 = 2y-2x
		move.w	d1,BLTAMOD(a0)	; BLTAMOD = (2y-2x)
		moveq	#-1,d1
		move.l	d1,BLTAFWM(a0)	; set first & last mask to $ffff
		move.w	#$ffff,BLTBDAT(a0)	; ffff = set pixels
		move.w	#$8000,BLTADAT(a0) ; line start

		move.l	BMPlanes(a1),d2	; address of screen
		add.l	d3,d2

		move.l	d4,d3			; save low 4 bits of x
		swap	d3				; put in high half
		asr.l	#4,d3			; >>4 (equivalent << 12)
		ori.w	#$b00,d3		; blitter code
		ori.w	#$ca,d3			; $fa = normal (line pat) $4a = exclusive-or miniterm

		move.w	BMWidth(a1),BLTCMOD(a0)	; set modulus
		move.w	BMWidth(a1),BLTDMOD(a0)
		move.w	d3,BLTCON0(a0)	; shift value and miniterm
		move.w	d7,BLTCON1(a0)	; quadrant and control bits
		move.w	a3,BLTAPTL(a0)	; BLTAPTL = (2y - x)
		move.l	d2,BLTCPT(a0)	; BLTCPT = address
		move.l	d2,BLTDPT(a0)	; BLTDPT = address

		addq	#1,d5
		lsl.w	#6,d5
		ori.w	#2,d5
		move.w	d5,BLTSIZE(a0)
		
		rts

;	clearplane(BitPlane,num) -- zero out first bitplane of a bitmap

_clearplane
		movem.l	d2/a6,-(sp)				; save 2 regs
		move.l	12(sp),a1				; address of BitMap

		move.l	_GfxBase,a6
		jsr		OwnBlitter(a6)			; get blitter

		move.l	#$dff000,a0				; custom regs

		btst	#6,DMACONR(a0)			; wait for blitter free
		btst	#6,DMACONR(a0)
		beq.s	clear10
		jsr		WaitBlit(a6)

clear10	move.w	#$0100,BLTCON0(a0)		; use D only, miniterm = 0
		move.w	#$0000,BLTCON1(a0)		; no options
		move.w	#0,BLTDMOD(a0)			; no modulus
		move.w	BMRows(a1),d0			; d0 = scanlines to process (=V)
		move.w	BMWidth(a1),d1			; d1 = width (words) of bitmap (=H)
		move.l	16(sp),d2				; plane #2
		add.l	d2,d2					; *2
		add.l	d2,d2					; *4
		add.l	d2,a1					; get plane # n
		move.l	BMPlanes(a1),BLTDPT(a0)	; destination = address of screen
		lsl.w	#6,d0					; v * 64
		lsr.w	#1,d1					; word count
		and.w	#63,d1					; h mod 63
		add.w	d1,d0
		move.w	d0,BLTSIZE(a0)			; set size and DO IT!

		jsr		DisownBlitter(a6)		; okay, your turn

		movem.l	(sp)+,d2/a6				; restore 2 regs
		rts

;		compact(buffer,x1,y1,x2,y2)
;
;		x2[11.4],(x2[3.0]x1[11.8]),x1[7.0],y2,y1
;
;		8(sp)  - x1
;		10(sp) - y1
;		12(sp) - x2
;		14(sp) - y2

		xdef	_compact
_compact
		move.l	4(sp),a0

		move.w	12(sp),d1		; high 8 bits x2
		move.w	d1,d0
		lsr.w	#4,d1
		move.b	d1,(a0)+

		lsl.w	#4,d0			; low 4 bits x2
		move.b	8(sp),d1 
		and.b	#$0f,d1			; high 4 bits x1
		add.b	d0,d1
		move.b	d1,(a0)+

		move.b	9(sp),(a0)+		; finally low 8 bits x1

		move.b	15(sp),(a0)+	; y2
		move.b	11(sp),(a0)+	; y1

		rts

;		expand(stream,pts)
;
;		x2[11.4],(x2[3.0]x1[11.8]),x1[7.0],y2,y1

		xdef	_expand
_expand
		move.l	4(sp),a0
		move.l	8(sp),a1

		move.b	(a0)+,d0
		ext.w	d0
		lsl.w	#4,d0
		
		move.b	(a0),d1
		lsr.b	#4,d1
		and.b	#$0f,d1
		add.b	d1,d0
		move.w	d0,4(a1)		; x2

		move.b	(a0)+,d0
		lsl.b	#4,d0
		ext.w	d0
		lsl.w	#4,d0
		move.b	(a0)+,d0
		move.w	d0,(a1)			; x1

		moveq	#0,d0
		move.b	(a0)+,d0
		move.w	d0,6(a1)		; y2

		move.b	(a0)+,d0
		move.w	d0,2(a1)		; y1

		rts

		end
