;-------------------------------------------------------------------------;
;                                  TIGA                                   ;
;        Copyright (c) 1986-1990  Texas Instruments Incorporated.         ;
;			   All Rights Reserved				  ;
;-------------------------------------------------------------------------;
;   TIGA - Graphics Manager Extension                                     ;
;-------------------------------------------------------------------------;
; draw_polyline function                                                  ;
;                                                                         ;
;   Draws multiple lines.  The points corresponding to each line are      ;
;   specified in the array of shorts pointlist.  Each line contains       ;
;   4 points in the point list corresponding to x1,y1,x2,and y2.          ;
;   Argument npts specifies the number of lines defined in the            ;
;   pointlist.  Successive lines are assumed to be connected.             ;
;                                                                         ;
;   The basic line-drawing algorithm is Bresenham's, but pre-clipping     ;
;   has been added to avoid computing non-visible pixels lying outside    ;
;   the window.  A line lying entirely outside the window is rejected     ;
;   trivially without drawing any portion of the line.  Horizontal and    ;
;   vertical lines are detected as special cases.  In the case in which   ;
;   both endpoints lie outside the window, but the line cannot be         ;
;   trivially rejected, the line is bisected and the line midpoint is     ;
;   tested to see if it lies inside window.  The bisection is repeated    ;
;   until either (1) a midpoint is found to lie within the window, or     ;
;   (2) the entire line can be trivially rejected.                        ;
;-------------------------------------------------------------------------;
; Usage:  draw_polyline(npts, pointlist);                                 ;
;                                                                         ;
; Description of stack arguments:                                         ;
;      long npts;  /* number of lines listed in linelist */               ;
;      short pointlist[];  /* each pair of elements specifies a point */  ;
;                                                                         ;
; Returned in register A8:  Void (undefined).                             ;
;                                                                         ;
; Registers altered:  A8                                                  ;
;-------------------------------------------------------------------------;
; Revision history:                                                       ;
;   10/10/86...Original version written..................Jerry Van Aken   ;
;    3/31/87...Fixed x overflow into LSB of y............JV               ;
;    8/07/87...Deleted reference to "SWAP" macro.........JV               ;
;   07/18/88...Restructured parameters...................W.S.Egr          ;
;   07/18/88...Added TIGA direct mode and dstbm check....W.S.Egr          ;
;   09/09/88...Access globals thru environment struct....W.S.Egr          ;
;   11/23/88...Save/Restore CONTROL, INTENB..............W.S.Egr          ;
;   07/21/89...Added 34020 support.......................A. Sharp         ;
;   08/21/89...Removed unneeded reg saves per JVA........A. Sharp         ;
;-------------------------------------------------------------------------;
;
        .title    'draw polyline'
        .file     'polyline.asm'
;
;   INCLUDE FILES
;
        .include   gsptypes.inc          ;offsets into environment structure
        .include   gspglobs.inc
        .include   gspreg.inc
        .include   oem.inc
;
;     DECLARE GLOBAL FUNCTION NAME
;
        .globl    _draw_polyline, _dm_draw_polyline
;
;    DIRECT-MODE ENTRY POINT
;
_dm_draw_polyline:
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13
        MMTM      SP,B0,B1,B2,B7,B8,B10,B11,B12,B13,B14
        move      STK,A13             ;A13 points to bottom of local frame
        move      -*A14,A11,1         ;will be address of pointlist
        setf      16,0,0
        move      *A11+,A10,0         ;1st word is # bytes
        srl       2,A10               ;Convert from bytes to # points
        jruc      common_ep
;
;    C-PACKET ENTRY POINT
;
_draw_polyline:
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13
        MMTM      SP,B0,B1,B2,B7,B8,B10,B11,B12,B13,B14
        move      STK,A13             ;A13 points to bottom of local frame
* Pop arguments from auxiliary stack.
        MOVE      *-A14,A10,1         ;Pop argument npts
        MOVE      *-A14,A11,1         ;Pop argument pointlist
;
;    2 ENTRY POINTS JOIN UP HERE
;
common_ep:
;
;    Check for destination bitmap pointing to the screen.  If not, abort for
;    now.  Linear drawing capability will be added at a later time.
;
        move      @(_env+ENVIRONMENT_DSTBM),A8,1    ;destination bit-map global variable
        jrnz      EXIT                ;if zero, dstbm is set to screen
* Load constants for later.
        MOVK      01h,A6              ;Increment for x half of reg.
        MOVI      010000h,A7          ;Increment for y half of reg.
        MOVE      @(_env+ENVIRONMENT_XYORIGIN),A12,1    ;For XY coord. conversion
        MOVI      010001h,B8          ;y::x = +1::+1
        DEC       A10                 ;convert #points into #lines      
* Save CONTROL and INTENB register contents.  Restore on exit.                
        setf      16,0,0
        move      @CONTROL,A8,0
        move      A8,*A13,0           ;Save in local frame
        move      @INTENB,A8,0
        move      A8,*A13(16),0       ;Save in local frame
* Set W=3 clipping mode. 
        MOVI      CONTROL+6,A9        ;Get pointer to W field
        setf      2,0,0
        movk      3,A8
        move      A8,*A9,0            ;Set W=3 clipping mode
* Clear WVE bit in INTENB register.                        
        setf      1,0,0
        clr       A8                  ;Clear A8  
        move      A8,@INTENB+11,0     ;Clear WVE bit
*-----------------------------------------------------------------------
* Get next line from list (read coordinates for two end points).
TOPLOOP:
        SETF      1,0,0               ;
        MOVE      A6,*A9,0            ;Set window mode W = 3
        SETF      16,0,0              ;
TOPLOOP2:
        MOVE      *A11+,A0,1          ;Get XY address ys::xs
        ADDXY     A12,A0              ;Convert to screen coord's
        MOVE      *A11,A1,1           ;Get XY address ye::xe
        ADDXY     A12,A1              ;Convert to screen coord's
* Use CPW instruction to see if entire line can be "trivially rejected."
        CPW       A0,A2               ;Get outcode1 for (xs,ys)
        CPW       A1,A3               ;Get outcode2 for (xe,ye)
        AND       A2,A3               ;Bitwise AND the two outcodes
        JRZ       NOTRIVIAL           ;Jump if not trivial reject
        DSJS      A10,TOPLOOP2        ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

*-----------------------------------------------------------------------
* Unable to trivially reject entire line at this point in function.
* Determine whether line is vertical, horizontal, or otherwise.
NOTRIVIAL:
        MOVE      A1,A4               ;a = xe-xs, b = ye-ys
        SUBXY     A0,A4               ;
        JRP       NOTVORH             ;Jump if line not vert/horiz
* Line is known to be vertical or horizontal.  Determine whether the
* line points in the +x or +y direction, or in the -x or -y direction.
        JRV       NEGDIR              ;Jump if -x direction
        JRC       NEGDIR              ;Jump if -y direction
* Line points in +x or +y direction.
        MOVE      A0,DADDR            ;Use (xs,ys) as start point
        MOVE      A4,DYDX             ;Set DY::DX = 0::a or b::0
        JRUC      VORHLINE            ;
* Line points in -x or -y direction.
NEGDIR:
        MOVE      A1,DADDR            ;Use (xe,ye) as start point
        CLR       A5                  ;Get absolute value of b
        SUBXY     A4,A5               ;
        MOVE      A5,DYDX             ;DY::DX = 0::|a| or |b|::0
VORHLINE:
        ADD       B8,DYDX             ;DY += 1, DX += 1
        FILL      XY                  ;Draw horiz. or vert. line
        DSJ       A10,TOPLOOP2        ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

*-----------------------------------------------------------------------
* Line is neither vertical or horizontal.  Determine whether either the
* specified start point (xs,ys) or end point lies inside window.
NOTVORH:
        SETF      1,0,0               ;
        MOVE      A7,*A9,0            ;Set window mode W = 2
        SETF      16,0,0              ;
        MOVE      A0,DADDR            ;Load starting XY address
        CPW       A0,A2               ;Is start point in window?
        JRNV      STARTIN             ;Jump if start point inside

        .if     GSP_34010 ; Code used if the processor is a 34010
* Specified start point lies outside window.  Is end point inside?
        CPW       A1,A2               ;Is end point in window?
        JRV       ENDOUT              ;Jump if end point outside
* End point (xe,ye) lies in window.  Replace start point with end point.
        MOVE      A1,DADDR            ;Load starting XY address
        SUBXY     A1,A0               ;b::a = ye::xe - ys::xs
        MOVE      A0,B0               ;copy b::a
        JRUC      STARTIN2            ;
* Either specified start point or end point lies inside window.
* Determine which quadrant line is in.  Calculate values a = xe - xs
* and b = ye - ys.  Signs of a and b specify orientation of line.
STARTIN:
        SUBXY     A0,A1               ;b::a = ye::xe - ys::xs
        MOVE      A1,B0               ;copy b::a
STARTIN2:
        MOVI      -1,B11              ;
        MOVK      1,B10               ;
        CLR       B7                  ;
        SUBXY     B0,B7               ;B7 now contains (-a,-b)
        JRNC      L1                  ;jump if b < 0
; Deal with case b >= 0.
        SRL       15,B11              ;change -1::-1 to +1::-1
        MOVY      B0,B7               ;Take absolute value of b
L1:
        JRNV      L2                  ;jump if a < 0
* Deal with case a >= 0.
        MOVX      B10,B11             ;change dx_diag to +1
        MOVX      B0,B7               ;Take absolute value of a
L2:
* Compare magnitudes of a and b.
        CLR       B12                 ;dx_nondiag = dy_nondiag = 0
        MOVE      B7,B0               ;copy a and b
        SRL       16,B0               ;move b into 16 LSBs
        CMPXY     B0,B7               ;compare a and b
        JRV       L3                  ;jump if a < b
* Case:  a >= b.
        MOVX      B11,B12             ;dx_nondiag = dx_diag, dy_nondiag = 0
        JRUC      L4                  ;(unconditional jump)
* Case:  a < b.
L3:
        MOVY      B11,B12             ;dx_nondiag = 0, dy_nondiag = dy_diag
        MOVX      B7,B0               ;copy b into B0
        RL        16,B7               ;swap a and b halves of register
* Calculate initial values of decision variable d and loop counter.
L4:
        ADD       B0,B0               ;put 2*b in B0
        MOVX      B7,B10              ;put a in B10
        SUB       B10,B0              ;initial d = 2*b-a in B0
        ADDK      1,B10               ;loop count = a+1 in B10
* Determine whether line points up or down.
        MOVE      B11,B11             ;Does line point up or down?
        JRLT      NEGYDIR             ;Jump if line points -y dir.
* Line points in +y direction.
        MOVI      -1,B13
        LINE      0                   ;Draw the line
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done

* Line points in -y direction.
NEGYDIR:
        MOVI -1,B13
        LINE      1                   ;Draw the line
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done
        .endif
        .if     GSP_34020 ;  Code used if the processor is a 34020
* Specified start point lies outside window.  Is end point inside?
        CPW       A1,A2               ;Is end point in window?
        JRV       ENDOUT              ;Jump if end point outside
* End point (xe,ye) lies in window.  Replace start point with end point.
        MOVE      A1,DADDR            ;Load starting XY address
        MOVE      A0,B7               ;set endpoint
        JRUC      STARTIN2            ;
* Either specified start point or end point lies inside window.
* Determine which quadrant line is in.  Calculate values a = xe - xs
* and b = ye - ys.  Signs of a and b specify orientation of line.
STARTIN:
        MOVE      A1,B7               ;set endpoint
STARTIN2:
        MOVI      -1,B13
        LINIT
        JRV       DRAW                ;clipping required use LINE
        CVDXYL    B2                  ;convert to linear address
        MOVE      B11,B11             ;does line point up or down?
        JRLT      FDOWN
        FLINE      0                   ;draw Bresenham line
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;
FDOWN:
        FLINE      1                   ;draw Bresenham line
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;
DRAW:
        MOVE      B11,B11             ;does line point up or down?
        JRLT      DOWN
        LINE      0                   ;draw Bresenham line
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;
DOWN:
        LINE      1                   ;draw Bresenham line
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;
        .endif

*-----------------------------------------------------------------------
* Next section draws line that neither starts nor ends in window.
*-----------------------------------------------------------------------
* Both start and end points lie outside window, but line cannot yet be
* trivially rejected.  Use subdivision to bisect line iteratively until
* either (1) a point on the line is found to lie within the clipping
* window, or (2) the entire line can be trivially rejected.
ENDOUT:
        MOVE      A4,A4               ;Test sign of b = ye - ys
        JRP       BPOS                ;Jump if b > 0
* Line is in quadrant 2 or 3:  ye < ys.  Swap start and end points.
        XOR       A0,A1               ;
        XOR       A1,A0               ;Swap ye::xe and ys::xs
        XOR       A0,A1               ;
* Line is in quadrant 0 or 1:  ye > ys.
BPOS:
        CLR       B12                 ;
        MOVE      A1,A4               ;b::a = ye::xe - ys::xs
        SUBXY     A0,A4               ;
        JRV       ANEG                ;Jump if a < 0
* a is positive:  Line is in octant 0 or 1.
        MOVE      B8,B11              ;Specify diagonal increment
        JRUC      GETOCT              ;
* a is negative:  Line is in octant 2 or 3.
ANEG:
        MOVI      01FFFFh,B11         ;Specify diagonal increment
        CLR       A5                  ;Get absolute value of a
        SUBXY     A4,A5               ;
        MOVX      A5,A4               ;
GETOCT:
        MOVE      A4,DYDX             ;Set DY::DX = b::a
        MOVE      DYDX,B10            ;Compare magnitudes of a, b
        RL        16,B10              ;
        CMPXY     DYDX,B10            ;
        JRC       BGTA                ;Jump if b > a
* |a| > b.  Line is in octant 0 or 3.
        SRL       16,B10              ;Isolate a
        MOVY      DYDX,B13            ;Isolate b
        SRL       16,B13              ;
        MOVE      B10,B14             ;Calculate 2*a
        ADD       B14,B14             ;
        MOVX      B11,B12             ;Non-diagonal increment
        BTST      15,B11              ;Test sign of a
        JRZ       OCTBIS0             ;Octant 0 if a > 0
        JRUC      OCTBIS3             ;Octant 3 if a < 0
* |a| < b.  Line is in octant 1 or 2.
BGTA:
        RL        16,DYDX             ;Swap a and b values
        MOVY      B12,B10             ;Isolate a (used to be b)
        MOVY      DYDX,B13            ;Isolate b (used to be a)
        SRL       16,B13              ;
        MOVE      B10,B14             ;Calculate 2*a
        ADD       B14,B14             ;
        MOVY      B11,B12             ;Non-diagonal increment
        BTST      15,B11              ;Test sign of a
        JRZ       OCTBIS1             ;Octant 1 if a > 0
        JRUC      OCTBIS2             ;Octant 2 if a < 0

*-----------------------------------------------------------------------
* Start and end points both lie outside window--Octant 0 case
OCTBIS0:
        MOVE      B10,B0              ;d1 = -a initially
        NEG       B0                  ;
        MOVE      B0,B1               ;d2 = -a initially
        MOVE      B0,B2               ;d3 = -a initially
        MOVE      B14,A5              ;Loop count = log2(2*a)
* Calculate sum of y1 and y2 in 16 MSBs of register A2.
BISECT0:
        MOVE      A0,A2               ;
        ADDXY     A1,A2               ;Add y1 and y2
        MOVE      A0,A8               ;
        SRA       1,A2                ;y3 = (y1 + y2) >> 1
        BTST      15,A2               ;test LSB of (y1+y2)
        JRZ       YSUMEVEN0           ;jump if (y1+y2) is even
* Adjust decision variable d3 if sum of y1 and y2 is odd.
        ADD       B10,B2              ;d3 += a
* Calculate sum of x1 and x2 in 16 LSBs of register A8.
YSUMEVEN0:
        ADD       A1,A8               ;Add x1 and x2
        SEXT      A8,0                ;
        SRA       1,A8                ;x3 = (x1 + x2) >> 1
        JRNC      XSUMEVEN0           ;Jump if (x1 + x2) is even
* Adjust decision variable d3 if sum of x1 and x2 is odd.
        ADD       B13,B2              ;d3 += b
        ADDK      1,A8                ;++x3 (round upwards)
XSUMEVEN0:
* Nudge (x3,y3) closer to line, if possible.
        MOVE      B2,B2               ;Check sign of d3
        JRLT      D3NEG0              ;Jump if d3 < 0
        SUB       B14,B2              ;d3 -= 2*a
        ADD       A7,A2               ;++y3 (nudge in +y direction)
D3NEG0:
        MOVX      A8,A2               ;concatenate y3::x3
* Check whether pixel at (x3,y3) lies inside window.
        CPW       A2,A3               ;Get outcode3 for x3,y3
        JRNV      INWDW0OR3           ;Jump if x3,y3 lies in window
* Pixel at (x3,y3) lies outside window.
        CPW       A0,A4               ;Get outcode1 for x1,y1
        AND       A3,A4               ;AND outcode3 with outcode1
        JRZ       P3P1SEG0            ;Jump if new line is P3 to P1
* Segment from (x3,y3) to (x1,y1) can be rejected.
        CPW       A1,A4               ;Get outcode for x2,y2
        AND       A3,A4               ;AND outcode3 with outcode2
        JRZ       P3P2SEG0            ;Jump if new line is P3 to P2
* Trivially reject entire line.  Do not draw anything.
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

* Segment from (x3,y3) to (x2,y2) can be rejected.
P3P2SEG0:
        MOVE      A2,A0               ;y3::x3 replaces y1:x1
        MOVE      B2,B0               ;d3 replaces d1
        ADD       B1,B2               ;d3 = (d1 + d2) >> 1
        SRA       1,B2                ;
        SRL       1,A5                ;Decrement loop count
        JRNZ      BISECT0             ;If count > 0, keep bisecting
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

* Segment from (x3,y3) to (x1,y1) can be rejected.
P3P1SEG0:
        MOVE      A2,A1               ;y3::x3 replaces y2:x2
        MOVE      B2,B1               ;d3 replaces d2
        ADD       B0,B2               ;d3 = (d1 + d2) >> 1
        SRA       1,B2                ;
        SRL       1,A5                ;Decrement loop count
        JRNZ      BISECT0             ;If count > 0, keep bisecting
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

*-----------------------------------------------------------------------
* Start and end points both lie outside window--Octant 1 case
* Begin by swapping values a and b.
OCTBIS1:
        MOVE      B10,B0              ;d1 = a initially
        MOVE      B0,B1               ;d2 = a initially
        MOVE      B0,B2               ;d3 = a initially
        MOVE      B14,A5              ;Loop count = log2(2*a)
* Calculate sum of y1 and y2 in 16 MSBs of register A2.
BISECT1:
        MOVE      A0,A2               ;
        ADDXY     A1,A2               ;Add y1 and y2
        MOVE      A0,A8               ;
        SRA       1,A2                ;y3 = (y1 + y2) >> 1
        BTST      15,A2               ;test LSB of (y1+y2)
        JRZ       YSUMEVEN1           ;jump if (y1+y2) is even
* Adjust decision variable d3 if sum of y1 and y2 is odd.
        SUB       B13,B2              ;d3 -= b
* Calculate sum of x1 and x2 in 16 LSBs of register A8.
YSUMEVEN1:
        ADD       A1,A8               ;Add x1 and x2
        SEXT      A8,0                ;
        SRA       1,A8                ;x3 = (x1 + x2) >> 1
        JRNC      XSUMEVEN1           ;Jump if (x1 + x2) is even
* Adjust decision variable d3 if sum of x1 and x2 is odd.
        SUB       B10,B2              ;d3 -= a
        ADDK      1,A8                ;++x3 (round upwards)
XSUMEVEN1:
* Nudge (x3,y3) closer to line, if possible.
        MOVE      B2,B2               ;Check sign of d3
        JRGE      D3POS1              ;Jump if d3 >= 0
        ADD       B14,B2              ;d3 += 2*a
        SUBK      1,A8                ;--x3 (nudge in -x direction)
D3POS1:
        MOVX      A8,A2               ;concatenate y3::x3
* Check whether pixel at (x3,y3) lies inside window.
        CPW       A2,A3               ;Get outcode3 for x3,y3
        JRNV      INWDW1OR2           ;Jump if x3,y3 lies in window
* Pixel at (x3,y3) lies outside window.
        CPW       A0,A4               ;Get outcode1 for x1,y1
        AND       A3,A4               ;AND outcode3 with outcode1
        JRZ       P3P1SEG1            ;Jump if new line is P3 to P1
* Segment from (x3,y3) to (x1,y1) can be rejected.
        CPW       A1,A4               ;Get outcode for x2,y2
        AND       A3,A4               ;AND outcode3 with outcode2
        JRZ       P3P2SEG1            ;Jump if new line is P3 to P2
* Trivially reject entire line.  Do not draw anything.
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

* Segment from (x3,y3) to (x2,y2) can be rejected.
P3P2SEG1:
        MOVE      A2,A0               ;y3::x3 replaces y1:x1
        MOVE      B2,B0               ;d3 replaces d1
        ADD       B1,B2               ;d3 = (d1 + d2) >> 1
        SRA       1,B2                ;
        SRL       1,A5                ;Decrement loop count
        JRNZ      BISECT1             ;If count > 0, keep bisecting
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

* Segment from (x3,y3) to (x1,y1) can be rejected.
P3P1SEG1:
        MOVE      A2,A1               ;y3::x3 replaces y2:x2
        MOVE      B2,B1               ;d3 replaces d2
        ADD       B0,B2               ;d3 = (d1 + d2) >> 1
        SRA       1,B2                ;
        SRL       1,A5                ;Decrement loop count
        JRNZ      BISECT1             ;If count > 0, keep bisecting
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

*-----------------------------------------------------------------------
* Start and end points both lie outside window--Octant 2 case
* Begin by swapping values a and b.
OCTBIS2:
        MOVE      B10,B0              ;d1 = a initially
        MOVE      B0,B1               ;d2 = a initially
        MOVE      B0,B2               ;d3 = a initially
        MOVE      B14,A5              ;Loop count = log2(2*a)
* Calculate sum of y1 and y2 in 16 MSBs of register A2.
BISECT2:
        MOVE      A0,A2               ;
        ADDXY     A1,A2               ;Add y1 and y2
        MOVE      A0,A8               ;
        SRA       1,A2                ;y3 = (y1 + y2) >> 1
        BTST      15,A2               ;test LSB of (y1+y2)
        JRZ       YSUMEVEN2           ;jump if (y1+y2) is even
* Adjust decision variable d3 if sum of y1 and y2 is odd.
        SUB       B13,B2              ;d3 -= b
* Calculate sum of x1 and x2 in 16 LSBs of register A8.
YSUMEVEN2:
        ADD       A1,A8               ;Add x1 and x2
        SEXT      A8,0                ;
        SRA       1,A8                ;x3 = (x1 + x2) >> 1
        JRNC      XSUMEVEN2           ;Jump if (x1 + x2) is even
* Adjust decision variable d3 if sum of x1 and x2 is odd.
        SUB       B10,B2              ;d3 -= a
XSUMEVEN2:
* Nudge (x3,y3) closer to line, if possible.
        MOVE      B2,B2               ;Check sign of d3
        JRGE      D3POS2              ;Jump if d3 >= 0
        ADD       B14,B2              ;d3 += 2*a
        ADDK      1,A8                ;++x3 (nudge in +x direction)
D3POS2:
        MOVX      A8,A2               ;concatenate y3::x3
* Check whether pixel at (x3,y3) lies inside window.
        CPW       A2,A3               ;Get outcode3 for x3,y3
        JRNV      INWDW1OR2           ;Jump if x3,y3 lies in window
* Pixel at (x3,y3) lies outside window.
        CPW       A0,A4               ;Get outcode1 for x1,y1
        AND       A3,A4               ;AND outcode3 with outcode1
        JRZ       P3P1SEG2            ;Jump if new line is P3 to P1
* Segment from (x3,y3) to (x1,y1) can be rejected.
        CPW       A1,A4               ;Get outcode for x2,y2
        AND       A3,A4               ;AND outcode3 with outcode2
        JRZ       P3P2SEG2            ;Jump if new line is P3 to P2
* Trivially reject entire line.  Do not draw anything.
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

* Segment from (x3,y3) to (x2,y2) can be rejected.
P3P2SEG2:
        MOVE      A2,A0               ;y3::x3 replaces y1:x1
        MOVE      B2,B0               ;d3 replaces d1
        ADD       B1,B2               ;d3 = (d1 + d2) >> 1
        SRA       1,B2                ;
        SRL       1,A5                ;Decrement loop count
        JRNZ      BISECT2             ;If count > 0, keep bisecting
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

* Segment from (x3,y3) to (x1,y1) can be rejected.
P3P1SEG2:
        MOVE      A2,A1               ;y3::x3 replaces y2:x2
        MOVE      B2,B1               ;d3 replaces d2
        ADD       B0,B2               ;d3 = (d1 + d2) >> 1
        SRA       1,B2                ;
        SRL       1,A5                ;Decrement loop count
        JRNZ      BISECT2             ;If count > 0, keep bisecting
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

*-----------------------------------------------------------------------
* Start and end points both lie outside window--Octant 3 case
* Begin by swapping values a and b.
OCTBIS3:
        MOVE      B10,B0              ;d1 = -a initially
        NEG       B0                  ;
        MOVE      B0,B1               ;d2 = -a initially
        MOVE      B0,B2               ;d3 = -a initially
        MOVE      B14,A5              ;Loop count = log2(2*a)
* Calculate sum of y1 and y2 in 16 MSBs of register A2.
BISECT3:
        MOVE      A0,A2               ;
        ADDXY     A1,A2               ;Add y1 and y2
        MOVE      A0,A8               ;
        SRA       1,A2                ;y3 = (y1 + y2) >> 1
        BTST      15,A2               ;test LSB of (y1+y2)
        JRZ       YSUMEVEN3           ;jump if (y1+y2) is even
* Adjust decision variable d3 if sum of y1 and y2 is odd.
        ADD       B10,B2              ;d3 += a
* Calculate sum of x1 and x2 in 16 LSBs of register A8.
YSUMEVEN3:
        ADD       A1,A8               ;Add x1 and x2
        SEXT      A8,0                ;
        SRA       1,A8                ;x3 = (x1 + x2) >> 1
        JRNC      XSUMEVEN3           ;Jump if (x1 + x2) is even
* Adjust decision variable d3 if sum of x1 and x2 is odd.
        ADD       B13,B2              ;d3 += b
XSUMEVEN3:
* Nudge (x3,y3) closer to line, if possible.
        MOVE      B2,B2               ;Check sign of d3
        JRLT      D3NEG3              ;Jump if d3 < 0
        SUB       B14,B2              ;d3 -= 2*a
        ADDXY     A7,A2               ;++y3 (nudge in +y direction)
D3NEG3:
        MOVX      A8,A2               ;concatenate y3::x3
* Check whether pixel at (x3,y3) lies inside window.
        CPW       A2,A3               ;Get outcode3 for x3,y3
        JRNV      INWDW0OR3           ;Jump if x3,y3 lies in window
* Pixel at (x3,y3) lies outside window.
        CPW       A0,A4               ;Get outcode1 for x1,y1
        AND       A3,A4               ;AND outcode3 with outcode1
        JRZ       P3P1SEG3            ;Jump if new line is P3 to P1
* Segment from (x3,y3) to (x1,y1) can be rejected.
        CPW       A1,A4               ;Get outcode for x2,y2
        AND       A3,A4               ;AND outcode3 with outcode2
        JRZ       P3P2SEG3            ;Jump if new line is P3 to P2
* Trivially reject entire line.  Do not draw anything.
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

* Segment from (x3,y3) to (x2,y2) can be rejected.
P3P2SEG3:
        MOVE      A2,A0               ;y3::x3 replaces y1:x1
        MOVE      B2,B0               ;d3 replaces d1
        ADD       B1,B2               ;d3 = (d1 + d2) >> 1
        SRA       1,B2                ;
        SRL       1,A5                ;Decrement loop count
        JRNZ      BISECT3             ;If count > 0, keep bisecting
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

* Segment from (x3,y3) to (x1,y1) can be rejected.
P3P1SEG3:
        MOVE      A2,A1               ;y3::x3 replaces y2:x2
        MOVE      B2,B1               ;d3 replaces d2
        ADD       B0,B2               ;d3 = (d1 + d2) >> 1
        SRA       1,B2                ;
        SRL       1,A5                ;Decrement loop count
        JRNZ      BISECT3             ;If count > 0, keep bisecting
        DSJ       A10,TOPLOOP         ;Loop if there are more lines
        JRUC      DONE                ;Otherwise, all done!

*-----------------------------------------------------------------------
* Segment midpoint (x3,y3) is known to lie within window.  Calculate
* starting value of decision variables for two "inside out" lines.
* Line is in octant 0 or 3.
INWDW0OR3:
        ADD       B13,B13             ;Constant 2*b
        MOVE      B13,B0              ;Set dA = d3 + 2*b
        ADD       B2,B0               ;
        MOVE      B13,B1              ;Set dB = -d3 + 2*b - 2*a
        SUB       B14,B1              ;
        SUB       B2,B1               ;
        JRUC      DRWLN               ;
* Line is in octant 1 or 2.
INWDW1OR2:
        ADD       B13,B13             ;Constant 2*b
        MOVE      B13,B0              ;Set dA = d3 + 2*b - 2*a
        SUB       B14,B0              ;
        ADD       B2,B0               ;
        MOVE      B13,B1              ;Set dB = -d3 + 2*b
        SUB       B2,B1               ;
* Since start and end points are both outside window, draw line from the
* inside out, starting at point (x3,y3), which is known to be in window.
DRWLN:
        MOVE      A2,B2               ;Set y::x = y3::x3
* Step over first pixel (at (x3,y3)) so it won't be drawn twice.
        MOVE      B0,B0               ;Get sign of dA
        JRGE      DSTEP               ;Jump if dA > 0
        ADDXY     B12,B2              ;Take non-diagonal step
        ADD       B13,B0              ;dA += 2*b
        JRUC      SPLITLN             ;
DSTEP:
        ADDXY     B11,B2              ;Take diagonal step
        ADD       B13,B0              ;dA += 2*b - 2*a
        SUB       B14,B0              ;
* First, draw line from (x,y) to (x2,y2) using decision variable dA.
SPLITLN:
        MOVE      B13,A8
        MOVI      -1,B13
        LINE      0                   ;draw Bresenham line
        MOVE      A8,B13
* Now draw line from (x3,y3) to (x1,y1) using decision variable dB.
        MOVE      A2,B2               ;Start at point (x3,y3)
        CLR       B0                  ;Reverse signs of dyd::dxd
        SUBXY     B11,B0              ;
        MOVE      B0,B11              ;
        CLR       B0                  ;Reverse signs of dyr:dxr
        SUBXY     B12,B0              ;
        MOVE      B0,B12              ;
        MOVE      B1,B0               ;Load decision variable dB
        MOVE      B13,A8
        MOVI -1,B13
        LINE      1                   ;Draw the line
        MOVE      A8,B13
        DSJ       A10,TOPLOOP         ;Loop if there are more lines

* All done!  Restore previous contents of registers and return.
DONE:
* Clear WVP pending bit in INTPEND
        setf      1,0,0
        clr       A8
        move      A8,@INTPEND+11,0
* Restore contents of CONTROL and INTENB registers
        setf      16,0,0
        move      *A13,A8,0
        move      A8,@CONTROL,0
        move      *A13(16),A8,0
        move      A8,@INTENB,0  
EXIT:
        MMFM      SP,B0,B1,B2,B7,B8,B10,B11,B12,B13,B14
        MMFM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13
        MOVE      *SP(32),A14,1       ;restore program stack pointer
        RETS      2                   ;Return
        .end
