;
; Arc3D line-drawing code
; By Andy McFadden
; Adapted from code by the FTA.
;
; Draws from (clpx0,clpy0) to (clpx1,clpy1) (output of a clipping routine).
;
penColor   equ   $70                      ;0 - 15
clpx0      equ   $72
clpy0      equ   $74
clpx1      equ   $76
clpy1      equ   $78

x0         equ   $80
y0         equ   $82
x1         equ   $84
y1         equ   $86
offset     equ   $88
deltax     equ   $8a
deltay     equ   $8c
diff       equ   $8e
even_c     equ   $90
odd_c      equ   $92

_DrawLine  ENTRY

DoDrawLine ANOP
           lda   <clpy1                   ;4 is y1 < y0?
           cmp   <clpy0                   ;4
           blt   in_order                 ;2/3 yes, so leave alone

;           lda   <clpy1                  ;we want y0 to be the largest,
           sta   y0                       ; so switch
           lda   <clpx1
           sta   x0
           lda   <clpy0
           sta   y1
           lda   <clpx0
           sta   x1
           bra   copy_done

in_order   ANOP
;           lda   <clpy1
           sta   y1
           lda   <clpx1
           sta   x1
           lda   <clpy0
           sta   y0
           lda   <clpx0
           sta   x0
; 39/41 cycles to here

; setup offset and deltas
copy_done  ANOP
           lda   y1
           asl   A
           asl   A
           adc   y1
           asl   A
           asl   A
           asl   A
           asl   A
           asl   A
           asl   A
           adc   x1
           sta   offset                   ;16+16=32

; penColor must be between 0 and 15
           lda   <penColor                ;setup pixel images
           sta   even_c                   ;0x000f
           xba          
           asl   A      
           asl   A      
           asl   A      
           asl   A      
           and   #$f000
           sta   odd_c                    ;0xf000

           lda   y0
           sec
           sbc   y1
           sta   deltay                   ;we know y0 is larger...
           beq   Horizontal               ;+2 do as special case

           lda   x1
           cmp   x0
           beq   Vertical                 ;+2 do as special case
;           bcc   Rev                      ;x1 is smaller; go other way
           bcs   Forw
           brl   Rev
Forw       ANOP
           sbc   x0
           sta   deltax

           cmp   deltay
           bcc   Forw_bigy_j
           brl   Forw_bigx
Forw_bigy_j brl  Forw_bigy

;
; Handle special cases (horizontal/vertical/point)
;

; handle vertical (deltax=0) lines
Vertical   ANOP
           lda   deltay
           tay                            ;count down

           lda   offset
           lsr   A
           tax
           bcc   vf_odd2
           clc
;           bra   vf_even2

; loop below
vf_even2   lda   $2000,x
           and   #$fff0
           ora   even_c
           sta   $2000,x

           txa
           adc   #160
           tax
           dey
           bpl   vf_even2
           bra   vf_done

vf_odd2    lda   $1fff,x
           and   #$0fff
           ora   odd_c
           sta   $1fff,x

           txa
           adc   #160
           tax
           dey
           bpl   vf_odd2
;           bra   vf_done

vf_done    brl   Exit

; handle horizontal (deltay=0) lines
Horizontal ANOP
           lda   x1
           cmp   x0
           bcc   h_rev                    ;x1 is smaller; go other way
           sbc   x0
           sta   deltax

; horizontal, moving forward
h_forw     ANOP
           lda   deltax
           tay                            ;count down

           lda   offset
           lsr   A
           tax
           bcc   hf_odd2
           clc
;           bra   hf_even2

; loop below
hf_even2   lda   $2000,x
           and   #$fff0
           ora   even_c
           sta   $2000,x

           dey
           bmi   hf_done

hf_odd2    lda   $1fff,x
           and   #$0fff
           ora   odd_c
           sta   $1fff,x

           dex
           dey
           bpl   hf_even2

hf_done    brl   Exit

; horizontal, reverse direction
h_rev      ANOP
           sec
           lda   x0
           sbc   x1
           sta   deltax

           lda   deltax
           tay                            ;count down

           lda   offset
           lsr   A
           tax
           bcc   hr_odd2
           clc
;           bra   hr_even2

; loop below
hr_even2   lda   $2000,x
           and   #$fff0
           ora   even_c
           sta   $2000,x

           dey
           bmi   hr_done
           inx

hr_odd2    lda   $1fff,x
           and   #$0fff
           ora   odd_c
           sta   $1fff,x

           dey
           bpl   hr_even2
;           bra   hr_done

hr_done    brl   Exit


;
; Standard cases
;

; forward direction, deltay is bigger than deltax
Forw_bigy  ANOP
           lda   deltay
           tay                            ;count down
           lsr   A
           eor   #$ffff
           inc   A
           sta   diff

           lda   offset
           lsr   A
           tax
           bcc   fy_odd2
           clc
           bra   fy_even2

; loop below
fy_even1   sta   diff
fy_even2   lda   $2000,x
           and   #$fff0
           ora   even_c
           sta   $2000,x

           dey
           bmi   fy_done
           txa
           adc   #160
           tax
           lda   deltax
           adc   diff
           bmi   fy_even1
           sbc   deltay
fy_odd1    sta   diff
fy_odd2    lda   $1fff,x
           and   #$0fff
           ora   odd_c
           sta   $1fff,x

           dey
           bmi   fy_done
           txa
           adc   #160
           tax
           lda   deltax
           adc   diff
           bmi   fy_odd1
           sbc   deltay
           dex
           bra   fy_even1

fy_done    brl   Exit

; reverse direction
Rev        ANOP
           sec
           lda   x0
           sbc   x1
           sta   deltax
           cmp   deltay
           bcs   Rev_bigx

; reverse direction, deltay is bigger than deltax
Rev_bigy   ANOP
           lda   deltay
           tay                            ;count down
           inc   A
           lsr   A
           eor   #$ffff
           inc   A
           sta   diff

           lda   offset
           lsr   A
           tax
           bcc   ry_odd2
           clc
           bra   ry_even2

; loop below
ry_even1   sta   diff
ry_even2   lda   $2000,x
           and   #$fff0
           ora   even_c
           sta   $2000,x

           dey
           bmi   ry_done
           txa
           adc   #160
           tax
           lda   deltax
           adc   diff
           bmi   ry_even1
           sbc   deltay
           inx
ry_odd1    sta   diff
ry_odd2    lda   $1fff,x
           and   #$0fff
           ora   odd_c
           sta   $1fff,x

           dey
           bmi   ry_done
           txa
           adc   #160
           tax
           lda   deltax
           adc   diff
           bmi   ry_odd1
           sbc   deltay
           bra   ry_even1

ry_done    brl   Exit

; reverse direction, deltax is bigger than deltay
Rev_bigx   ANOP
           lda   deltax
           tay                            ;count down
           lsr   A
           eor   #$ffff
           inc   A
           sta   diff

           lda   offset
           lsr   A
           tax
           bcc   rx_odd2
           clc
           bra   rx_even2

; loop below
rx_even1   sta   diff
rx_even2   lda   $2000,x
           and   #$fff0
           ora   even_c
           sta   $2000,x

           dey
           bmi   rx_done
           inx
           lda   deltay
           adc   diff
           bmi   rx_odd1
           sbc   deltax
           sta   diff

           txa
           adc   #160
           tax
           bra   rx_odd2

rx_odd1    sta   diff
rx_odd2    lda   $1fff,x
           and   #$0fff
           ora   odd_c
           sta   $1fff,x

           dey
           bmi   rx_done
           lda   deltay
           adc   diff
           bmi   rx_even1
           sbc   deltax
           sta   diff
           txa
           adc   #160
           tax
           bra   rx_even2

rx_done    brl   Exit

; forward direction, deltax is bigger than deltay
Forw_bigx  ANOP
           lda   deltax
           tay                            ;count down
           lsr   A
           eor   #$ffff
           inc   A
           sta   diff

           lda   offset
           lsr   A
           tax
           bcc   fx_odd2
           clc
           bra   fx_even2

; loop below
fx_even1   sta   diff
fx_even2   lda   $2000,x
           and   #$fff0
           ora   even_c
           sta   $2000,x

           dey
           bmi   fx_done
           lda   deltay
           adc   diff
           bmi   fx_odd1
           sbc   deltax
           sta   diff

           txa
           adc   #160
           tax
           bra   fx_odd2

fx_odd1    sta   diff
fx_odd2    lda   $1fff,x
           and   #$0fff
           ora   odd_c
           sta   $1fff,x

           dey
           bmi   fx_done
           dex
           lda   deltay
           adc   diff
           bmi   fx_even1
           sbc   deltax
           sta   diff
           txa
           adc   #160
           tax
           bra   fx_even2

fx_done    brl   Exit


;
; common exit point
;
Exit       ANOP
           rtl

