
        CODE
        NOLIST
        INCLUDE "exec/types.i"
        INCLUDE "graphics/rastport.i"
        INCLUDE "custom.i"
        LIST

        XREF    _GfxBase
        XREF    _LVOOwnBlitter,_LVODisownBlitter

        XDEF    _Line,_Clear     ; assembler interface


;============================================================================
; NAME
;    Line ( rp,x1,y1,x2,y2 )
;           a0 d0 d1 d2 d3
;
; 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 d1-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)+,d1-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