;;; -*- Mode: asm; indent-tabs-mode: t; tab-width: 8 -*-

;;drawing line from 2 cordinates
;;#  (X_pos, Y_pos)                                     #
;;#                     *                               #
;;#                         *                           #
;;#                             *                       #
;;#                                (X_end, Y_end)       #
;;NOTE THAT X_pos <= X_end, Y_pos <= Y_end. Max 45deg!

.proc line_down

        .include "line.inc"; Defines memory positions, ex X_pos

        ;;We need to clear this memory
        LDA #$00
        STA <V
        STA <dy_2
        STA $FD ; for pixel_draw

        ;; V = 2*(dx -dy)
        SEC
        LDA dx
        SBC dy
        STA >V
        Mult_16 >V, <V

        ;dy_2 = dy*2
        Mult_16 >dy_2, <dy_2 ;>dy_2 = dy (same address)

        ;; This is an Bresenham's line algorithm, se wikipedia bellow.
        ;;https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
        ;; We need to compute the Value D = 2*dy - dx,
        ;; but it may be or get negative.
        ;; IN the loop we may set D = D -V
        ;; Because math D needs to be at least >=V.
        ;; V_max = %00000001 11111111
        ;; We therefor need to add this offset to V 00000001 11111111
        ;; and to its branch logic later in the loop.

        ;;D = 2*dy - dx + 2*255
        Mov_16 >D, <D, >dy_2, <dy_2
        Add_16 >D, <D, #$ff, #$01, !
        Sub_16 >D, <D, dx, #$00

selfmod:
        ;; Self modifying code. Makes LDA and SBC instructions each take 1 cycle less.
        ;; You can remove this if you run the loop without # at dy_2 and V.
        ;;Note: The offsets like +2 etc is because there are instructions betwean the label and the
        ;address that needs to be modified
        ;; dy_2
        ;; Modifies LDA >dy_2
        LDA >dy_2
        STA case_2 +1
        ;; Modifies LDA <dy_2
        LDA <dy_2
        STA case_2 +7
        ;; V
        ;;Modidies SBC >V
        LDA >V
        STA case_1 +1
        ;; Modifies SBC <V
        LDA <V
        STA case_1 +7
end_selfmod:
        JSR pixel_draw ;;only used first pixel. after this relative position is abused
        ;; X = X_end - X_pos
        LDA X_end
        SEC
        SBC X_pos
        TAX
        ;LDX X_pos
        LDY #$00
for_x:
        ;; Paints A to address in |btp_mem_pos* + Y|
        ;; Y is pixel position in the chunk. Therefor it may be that Y = 0, 1, 2, 3, 4, ,5 ,6 ,7.
        LDA byte_to_paint ;A byte containing a single 1. Coresponds to X position in the chunk.
        ORA (>btp_mem_pos), Y
        STA (>btp_mem_pos), Y
increment_pixel_x:
        LSR byte_to_paint ; Rotates the pixel one bit to the left ON THE SCREEN.
        BCC increment_pixel_x_end; We need to move to the next chunk
move_8px_left:
        ;; Next chunk is 8 addresses away. Look in pixel_draw for more detail.
        ;; -8.
        ;; C = 1 therefore you se 07
        Add_16 >btp_mem_pos, <btp_mem_pos, #$07, #$00, !
        ;; Restores byte to paint
        LDA #%10000000
        STA byte_to_paint
increment_pixel_x_end:
        DEX
        BEQ end ;We keep track on when to stop line draw with the X registry.
        ;;If D <  %00000010 00000000:  case_2
        ;;else case 1.
        Lag_16 >D, <D, #$00, #$02, case_2
case_1:
        ;; D = D - V
        ;; Because Lag_16:
        ;;      C =1 so we can use !
        ;;      A = >D
        Sub_16_A >D, <D, #>V, #<V, !
increment_y_pos:
        INY ; Increment Y pos inside the buffer
        CPY #$08
        BNE for_x
move_8px_down: ; Z=1 --> C=1
        LDY #$00
        ;; Switch to chunk bellow
        ; C = 1
        ; So we subtract  #$3F, #$01 +C
        Add_16 >btp_mem_pos, <btp_mem_pos, #$3F, #$01, !; +320
        JMP for_x
increment_y_pos_end:
case_2:
        Add_16 >D, <D, #>dy_2, #<dy_2, ! ;D = D + 2*dy
        JMP for_x
end:
        RTS
.endproc