;
; Copyright (c) 1988 Commodore-Amiga, Inc.
;
; Executables based on this information may be used in software
; for Commodore Amiga computers.  All other rights reserved.
;
; This information is provided "as is"; no warranties are made.
; All use is at your own risk, and no liability or responsibility is assumed.
;
 		CODE
		NOLIST
		INCLUDE	"exec/types.i"
		INCLUDE	"graphics/rastport.i"
		INCLUDE	"custom.i"
		INCLUDE	"globals.i"
		LIST

		XREF	_LVOOwnBlitter,_LVODisownBlitter

		XDEF	Draw,Line,Clear


;============================================================================
; Draw( rp,x2,y2 )
;       a0 d0 d1
;
; Same as line but calls OwnBlitter before calling the line drawing routine.
;============================================================================
Draw		move.l	a6,-(sp)
		movea.l	GfxLib(a5),a6		need to own the blitter
		movem.l	d0/d1/a0,-(sp)		save line arguments
		jsr	_LVOOwnBlitter(a6)	get the blitter
		movem.l	(sp)+,d0/d1/a0		restore line args
		bsr.s	Line			draw the line
		jsr	_LVODisownBlitter(a6)	give blitter back to system
		movea.l	(sp)+,a6
		rts
		
;============================================================================
; NAME
;    Line ( rp,x2,y2 )
;	    a0 d0 d1
;
; Draws a line from the current position to x2,y2 in the given RastPort.
; Current color, linepat, mask and flags are observed from the rastport info.
; The blitter must be owned before calling this routine to draw lines.
;============================================================================
Line		movem.l	d2-d6/a2-a3,-(sp)
		movea.l	rp_BitMap(a0),a1	point to the bitmap struct
		movea.l	#_custom,a3		point to custom chips
		move.w	d0,d2			get start and end points
		move.w	d1,d3
		movem.w	rp_cp_x(a0),d0/d1	start positions
		movem.w	d2/d3,rp_cp_x(a0)	save new start position

		moveq.l	#$0f,d4			compute ASH3-ASH0
		and.w	d0,d4			for preshifting bltadat
		sub.w	d0,d2			convert X2 to deltaX
		sub.w	d1,d3			convert Y2 to deltaY
		mulu.w	bm_BytesPerRow(a1),d1	offset to correct bitmap row
		lsr.w	#3,d0			convert X1 to a byte offset
		add.w	d0,d1			now d1=offset into bitplanes

; compute the correct octant code for this line ( SUD,SUL,AUL ) and get the
; absolute value of max(deltaX, deltaY) into D2 for use as the line length.
		tst.w	d2
		bmi.s	40$			deltaX is negative

; when deltaX is positive, use the following octant generation decisions
		tst.w	d3		if deltaY is positive
		bmi.s	20$
		cmp.w	d3,d2			...then if deltaX > deltaY...
		blt.s	10$
		moveq.l	#OCT4,d5		...octant=4
		bra.s	GotOctant
10$		moveq.l	#OCT0,d5		...else octant=0...
		exg	d2,d3			...and switch the delta values
		bra.s	GotOctant

20$		neg.w	d3		else deltaY = -deltaY...
		cmp.w	d3,d2			...if deltaX > deltaY...
		blt.s	30$
		moveq.l	#OCT6,d5		...octant=6
		bra.s	GotOctant
30$		moveq.l	#OCT1,d5		...else octant=1...
		exg	d2,d3			...and switch the delta values
		bra.s	GotOctant

; but when deltaX is negative, use these octant generation decisions instead
40$		neg.w	d2		deltaX = -deltaX
		tst.w	d3		if deltaY is positive...
		bmi.s	60$
		cmp.w	d3,d2			...then if deltaX > deltaY
		blt.s	50$
		moveq.l	#OCT5,d5		...octant=5
		bra.s	GotOctant
50$		moveq.l	#OCT2,d5		...else octant=2...
		exg	d2,d3			...and switch the delta values
		bra.s	GotOctant

60$		neg.w	d3		else deltaY = -deltaY
		cmp.w	d3,d2			if deltaX > deltaY...
		blt.s	70$
		moveq.l	#OCT7,d5		...octant=7
		bra.s	GotOctant
70$		moveq.l	#OCT3,d5		...else octant = 6...
		exg	d2,d3			...and switch the delta values

; gets to here with the octant code in D5 and ABS(MAX(deltaX,deltaY)) in D2
GotOctant	addq.w	#1,d2			*** is this right ? ***
5$		add.w	d3,d3			D3 = 2Y
		move.w	d3,d0			calculate initial error term
		sub.w	d2,d0			D0=2Y-X
		bpl.s	10$			no need to set SIGN
		ori.w	#SIGN,d5		initial term is negative so...
;						we start one line further up

; this is a bit tricky, we need the start code in the top 4 bits of d5 and d4
; but they are currently in the low 4 bits of d4.  Instead of shifting them
; all the way up to position, we just rotate them around and or them in.
10$		ror.w	#4,d4			move start code to top bits
		or.w	d4,d5			need shift in both halves...
;						to shift line pattern too
		ori.w	#USEA!USEC!USED,d4	move in codes for DMA channels

; OK, let's start stuffing registers that won't change between successive blits
; so we can speed up the innner loop that draws a line in each bit plane. Make
; sure that the blitter is not busy from a previous line draw routine before
; we start storing to the registers.
		move.w	#BBUSY,d6
20$		and.w	dmaconr(a3),d6		wait for the blitter to finish
		bne.s	20$			still busy

		move.w	#SETBIT!BLTPRI,dmacon(a3)  give blit high priority
		move.w	d3,bltbmod(a3)		bltbmod=2Y
		move.w	d0,d3
		sub.w	d2,d3			compute 2Y-2X
		move.w	d3,bltamod(a3)		bltamod=2Y-2X
		move.w	bm_BytesPerRow(a1),bltcmod(a3)
		move.w	bm_BytesPerRow(a1),bltdmod(a3)
		moveq.l	#-1,d3			first and last masks = $FFFF
		move.l	d3,bltafwm(a3)		this stores to both
		move.w	rp_LinePtrn(a0),bltbdat(a3) set up line pattern
		asl.w	#6,d2			convert line length to bltsize
		addq.w	#2,d2			width=2 for all line drawing
		move.w	d5,bltcon1(a3)		set up bltcon1

; stash things that need frequent reference during the plane drawing loop
		move.b	rp_FgPen(a0),d5		get pen color
		and.b	rp_Mask(a0),d5		and observe mask
		clr.w	d3
		move.b	bm_Depth(a1),d3		get a plane counter
		lea.l	bm_Planes(a1),a1	point to array of plane ptrs
		bra.s	LoopEntry

; this is the loop that draws lines in each of the required bitplanes.
; Registers are set up as follows:-
;	D0 = 2Y-X
;	D1 = Offset in bitplane to first word of the line
;	D2 = BlitSize to start the blitter with
;	D3 = plane counter
;	D4 = bltcon0
;	D5 = pencolor
;	A1 = pointer to bitplane pointers
;	A3 = pointer to custom chips
; Notice that during the loop, the blitter can be busy drawing the last line
; segment while the CPU is setting up for the next load of stores.
PlaneLoop	movea.l	(a1)+,a2		get next bitplane address
		adda.w	d1,a2			start address of line
		move.b	#$0a,d4			assume erasing (minterm = NAC)
		lsr.w	#1,d5			shift next bit into carry
		bcc.s	5$			it's 0 so erase this bit
		move.b	#$ca,d4			NAC+AB we are drawing the line

5$		move.w	#BBUSY,d6
10$		and.w	dmaconr(a3),d6		wait for the blitter to finish
		bne.s	10$			still busy

		move.w	#$8000,bltadat(a3)	put in the line bit
		move.l	a2,bltcpth(a3)		fill in line start address...
		move.l	a2,bltdpth(a3)		...of this line
		move.w	d0,bltaptl(a3)		2Y-X, needs reloading each use
		move.w	d4,bltcon0(a3)		store the minterm and stuff
		move.w	d2,bltsize(a3)		ZOOOOM! start the line draw
LoopEntry	dbra	d3,PlaneLoop		and do the next plane

		movem.l	(sp)+,d2-d6/a2-a3	restore regs
		rts				all done

;============================================================================
; Clear( rp )
;        a0
;
; Clears ALL bitmap memory in the given rastport.  Must call OwnBlitter()
; before calling this routine (or nasty things will happen fer sure).
; This routine assumes all bitplanes are contiguous in memory!!!!!!!!!!!!
;============================================================================
Clear		movea.l	#_custom,a1		point to custom chips
		movea.l	rp_BitMap(a0),a0	get the bitmap ptr
		moveq.l	#0,d0
		moveq.l	#0,d1
		move.w	bm_Rows(a0),d0		calculate blitsize
		move.b	bm_Depth(a0),d1
		mulu.w	d1,d0			d0 = #lines to clear
		lsl.l	#6,d0			move to correct bits
		move.w	bm_BytesPerRow(a0),d1	get width in words
		lsr.w	#1,d1
		or.w	d1,d0			d0 = bltsize reg

		move.w	#BBUSY,d1
10$		and.w	dmaconr(a1),d1		wait for blitter to finish
		bne.s	10$			the last operation

		move.w	#SETBIT!BLTPRI,dmacon(a1)	blitter nasty
		clr.l	bltamod(a1)		bltamod & bltbmod = 0
		clr.l	bltcmod(a1)		bltcmod & bltdmod = 0
		clr.w	bltcon1(a1)		no shift or anything special
		move.w	#$01f0,bltcon0(a1)	only using destination
		move.l	bm_Planes(a0),bltdpth(a1)	where we are storing to
		clr.w	bltadat(a1)		what we are storing (0's)
		move.w	d0,bltsize(a1)		start the blit
		rts				done

		END
