;       ------------------------------------------------------------
;          Optimized Implementation of Bresenham's line algorithm 
;         by Stephane JANTZEN (Stephane.Jantzen@scinfo.u-nancy.fr)
;
;                             Version 2 (01/31/96)
;       ------------------------------------------------------------
;
; This version replaces the previous one, which was a little bigger, and
; contained a bug for repeated lines. The little demo routine allow you to
; move the line with the arrows, just to see how fast it is redrawn. Just
; notice that redrawing time is principally spent clearing the screen.
;
; * parameters : 
;    - DE : coordinates of the 1st point
;    - HL : coordinates of the 2nd point
;
; * code size : 106 bytes
;
; The size could be smaller, but not without a significant loss of speed
; (using pushes and pops)
;
; Feel free to end all optimizations to the address above. I would especially
; like a solution to remove the "(way)" call, without losing speed of space.
; I would also be interested in a fast put_pixel routine.
;
; Many thanx to Pascal Bouron (bouron@Yoko.ENS-Cachan.fr) for his precious help


#include "ti-85.h"

        .org    $00
        .db     "Line Routine, version 2",0

Way     =$80E0

Start:                          ;test routine
        ld      A,$04
        out     ($05),A
        ld      DE,$2040
        ld      HL,$3050
        CALL_(Clear_LCD)
CallKey:
        ld      A,($8001)
        cp      K_NOKEY
        jr      Z,CallKey
        cp      Exit
        ret     Z
GoUp:
        cp      K_UP
        jr      NZ,GoDown
        inc     H
        jr      Trace
GoDown:
        cp      K_DOWN
        jr      NZ,GoLeft
        dec     H
        jr      Trace
GoLeft:
        cp      K_LEFT
        jr      NZ,GoRight
        dec     L
        jr      Trace
GoRight:
        cp      K_RIGHT
        jr      NZ,CallKey
        inc     L
Trace:
        CALL_(Clear_LCD)
        CALL_(Line)
        jr      CallKey
        ret

Clear_LCD:
        push    HL
        push    DE
        ROM_CALL(CLEARLCD)
        pop     DE
        pop     HL
        ret
Line:
        push    DE              ;can be removed
        push    HL              ;can be removed

        ld      A,D
        sub     H
        jr      NC,DXpositive    ;delta_x > 0
DXNegative:
        neg
DXPositive:
        ld      B,A              ;B <- |delta_x|
        ld      A,E
        sub     L
        jr      NC,DYpositive    ;delta_y > 0
DYNegative:
        neg
DYPositive:                
        sub     B               ;|delta_y|
        push    AF
        jr      C,DeltaX        ;|delta_x| > |delta_y|
DeltaY:
        ld      A,H             ;if |delta_x| < |delta_y| then
        ld      H,L             ;then values x and y are swapped
        ld      L,A             ;so the loop will always be performed on the
        ld      A,D             ;x value. A flag must be set to 
        ld      D,E             ;remind that data must be drawn (y,x) 
        ld      E,A             ;instead of (x,y)

        ;ld      A,$01           
        ;ld      (Flag),A        ;the Flag !!!
DeltaX:
        ld      A,D
        sub     H
        jr      NC,TestDY        ;x1 < x2 
TestDX:
        ex	DE,HL
TestDY:
        ld      A,E
        sub     L
        ld      A,$01
        jr      NC,StoreA
        neg                     ;y1 > y2 : in case2 the 'y' variable
StoreA:
        ld      (Way),A
InitLine:       
        ld      B,H
        ld      C,L
        ld      A,E
        sub     L
        jr      NC,EndInit
        ld      A,L
        ld      L,E
        ld      E,A
EndInit:
        ld      A,E      
        sub     L
        rla
        ld      L,A             ;value to add in case1 (d < 0)
        add     A,H
        sub     D
        ld      E,A             ;'d' variable is initialised
        add     A,H
        sub     D
        ld      H,A             ;value to add in case2 (d >= 0)
Loop:
        ld      A,B
        sub     D
        jr      NC,EndLine       ;the line is completely drawn.
        pop     AF
        ;ld      A,(Flag)
        bit     7,A
        push    AF
        push    AF
        push    BC
        jr      Z,DrawPoint
        ld      A,B
        ld      B,C
        ld      C,A
DrawPoint:     
        CALL_(PointOn)
        pop     BC
        pop     AF
TestD:
        bit     7,E
        jr      NZ,Case1
Case2:                          ;d >= 0 
        ld      A,E
        add     A,H
        ld      E,A
        ld      A,(Way)
        add     A,C
        ld      C,A
        jr      EndLoop
Case1:                          ;d < 0
        ld      A,E
        add     A,L
        ld      E,A
EndLoop:
        inc     B
        jr      Loop
EndLine:
        pop     AF              ;MUST NOT BE REMOVED
        pop     HL              ;can be removed
        pop     DE              ;can be removed
        ret

PointOn:
        push    DE              ;MUST NOT BE REMOVED
        push    HL              ;MUST NOT BE REMOVED
        ROM_CALL(FIND_PIXEL)
        ld      DE,$FC00
        add     HL,DE
        or      (HL)
        ld      (HL),A
        pop     HL              ;MUST NOT BE REMOVED
        pop     DE              ;MUST NOT BE REMOVED
        ret             

        .end

