    ; from CBM Draw.asm
    ; modified for speed by Jean-Michel Forgeas, June 89
    ;       from 2000 to 2430 vectors/second
    ;       in a 704x280, 1 bit-plane BitMap

        CODE    text

        INCLUDE "exec/types.i"
        INCLUDE "graphics/rastport.i"
        INCLUDE "custom.i"

        XDEF    _XPolyLines,_XClear     ; assembler interface


;============================================================================
; NAME
;
;    XPolyLines ( rp, startad, vectors )      startad: X1, Y1, X2, Y2, CL
;                 a0    a4       d7.w                  d0  d1  d2  d3  d4
;
; The blitter must be owned before calling this routine to draw lines.
;============================================================================

_XPolyLines
        movem.l d0-d7/a2-a4,-(sp)
        movea.l rp_BitMap(a0),a1        point to the bitmap struct
        movea.l #_custom,a3             point to custom chips

        lea.l   bm_Planes(a1),a5        point to array of plane ptrs
        movea.l (a5),a5                 get bitplane address

        bra     EndNextVector

NextVector:
        movem.w (a4),d0-d4
        adda.l  #10,a4
;        move.w  (a4)+,d0                  X1 value
;        move.w  (a4)+,d1                  Y1 value
;        move.w  (a4)+,d2                  X2 value
;        move.w  (a4)+,d3                  Y2 value
;        move.w  (a4)+,d4                  color value  (not used but let increment)

        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)
        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

        movea.l a5,a2                   get bitplane address
        adda.w  d1,a2                   start address of line

        move.b  #$ca,d4                 NAC+AB we are drawing the line
        moveq.l #-1,d3                  first and last masks = $FFFF
        move.l  d3,bltafwm(a3)          this stores to both
        move.w  d3,bltbdat(a3)          set up line pattern = $FFFF
        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

EndNextVector:
        dbra    d7,NextVector           next vector now.

        movem.l (sp)+,d0-d7/a2-a4       restore regs
        rts                             all done

;============================================================================
; XClear( 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!!!!!!!!!!!!
;============================================================================

_XClear
        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