        .width    132
;-------------------------------------------------------------------------;
;                                  TIGA                                   ;
;        Copyright (c) 1989-1990  Texas Instruments Incorporated.         ;
;			   All Rights Reserved				  ;
;-------------------------------------------------------------------------;
;   TIGA - Graphics Manager Extension                                     ;
;-------------------------------------------------------------------------;
; styled_oval and arcstyle functions                                      ;
;                                                                         ;
;     styled_oval:  This is a standard TIGA extended primitive that draws ;
;         a styled ellipse in standard position.                          ;
;                                                                         ;
;     arcstyle:  This function is called by the styled_ovalarc function,  ;
;         which is a standard TIGA extended primitive that draws a styled ;
;         arc from an ellipse in standard position.                       ;
;-------------------------------------------------------------------------;
; Revision History:                                                       ;
;   08/09/89...Original version written...................Jerry Van Aken  ;
;   03/26/90...Added direct-mode entry point..............W.S.Egr         ;
;-------------------------------------------------------------------------;
;
        .title    'styled oval'
        .file     'styloval.asm'
;
;
;     DEFINE GLOBAL SUBROUTINE NAMES
;
        .globl    _styled_oval, _dm_styled_oval, _arcstyle
;
;
;   INCLUDE FILES
;
        include   gspreg.inc
        include   gsptypes.inc        ;offsets into environment structure
        include   gspglobs.inc
;
;
;     DEFINE REGISTER VARIABLE NAMES
;
; Define symbolic names for GSP A-file registers.
A_MSBS  .set      A0                  ;32 MSBs of coefficient A
A_LSBS  .set      A1                  ;32 LSBs of coefficient A
C_MSBS  .set      A2                  ;32 MSBs of coefficient C
C_LSBS  .set      A3                  ;32 LSBs of coefficient C
D_MSBS  .set      A4                  ;32 MSBs of coefficient D
D_LSBS  .set      A5                  ;32 LSBs of coefficient D
E_MSBS  .set      A6                  ;32 MSBs of coefficient E
E_LSBS  .set      A7                  ;32 LSBs of coefficient E
F_MSBS  .set      A8                  ;32 MSBs of coefficient F
F_LSBS  .set      A9                  ;32 LSBs of coefficient F

K1_MSBS .set      A0                  ;32 MSBs of constant increment k1
K1_LSBS .set      A1                  ;32 LSBs of constant increment k1
K3_MSBS .set      A2                  ;32 MSBs of constant increment k3
K3_LSBS .set      A3                  ;32 LSBs of constant increment k3
U_MSBS  .set      A4                  ;32 MSBs of variable increment u
U_LSBS  .set      A5                  ;32 LSBs of variable increment u
V_MSBS  .set      A6                  ;32 MSBs of variable increment v
V_LSBS  .set      A7                  ;32 LSBs of variable increment v
DV_MSBS .set      A8                  ;32 MSBs of decision variable d
DV_LSBS .set      A9                  ;32 LSBs of decision variable d

Y1X1    .set      A0                  ;raw arc start coordinates (x1,y1)
Y2X2    .set      A2                  ;raw arc end coordinates (x2,y2)
YSXS    .set      A8                  ;actual arc start coord's (xs,ys)
YX      .set      A9                  ;temporary xy coordinates
TMP0    .set      A12                 ;temporary register 0
TMP1    .set      A13                 ;temporary register 1
HW      .set      A13                 ;concatenated rect height and width
ATMP    .set      A12                 ;temporary A-file register
DMODE   .set      A14                 ;drawing mode information

; Define symbolic names for GSP B-file registers.
ENDPT   .set      B0                  ;xy coordinates at arc end point
BTMP    .set      B1                  ;temporary B-file register
YTXL    .set      B1                  ;xy coord's, rect top left vertex
CURPT   .set      B2                  ;xy coord's at current point on arc
PIXCNT  .set      B7                  ;pixel count (inner loop counter)
OCTCNT  .set      B10                 ;octant count (outer loop counter)
DXYDIAG .set      B11                 ;x and y increments for diagonal move
DXYSQUA .set      B12                 ;x and y increments for square move
PATTERN .set      B13                 ;32-bit arc style pattern mask
OCTANT  .set      B14                 ;current octant number (range [1,8])


;-------------------------------------------------------------------------;
; styled_oval function                                                    ;
;                                                                         ;
;   Draw the styled outline of an ellipse, given the enclosing rectangle  ;
;   in which the ellipse is inscribed.  The outline of the ellipse is     ;
;   only one pixel in thickness, and is drawn using a 32-bit line-style   ;
;   pattern (or "oval-style" pattern, if you prefer).  The ellipse is in  ;
;   standard position, with its major and minor axes parallel to the      ;
;   coordinate axes.  The enclosing rectangle is defined by four          ;
;   arguments:                                                            ;
;       - The width w                                                     ;
;       - The height h                                                    ;
;       - The coordinates of the top left corner, (xleft, ytop)           ;
;   If either the width or height is 0, the oval is not drawn.            ;
;                                                                         ;
;   The line-style pattern is specified in argument style, a long integer ;
;   containing a 32-bit repeating line-style pattern.  Pattern bits are   ;
;   used in the order 0,1,...,31, where bit 0 is the LSB.  The pattern is ;
;   repeated modulo 32, as the ellipse is drawn.  A bit value of 1 in the ;
;   pattern specifies that color1 is to be used to draw the corresponding ;
;   pixel.  A bit value of 0 means either that the corresponding pixel is ;
;   to be drawn in color0 (if the LSB of mode = 1) or not drawn (if the   ;
;   LSB of mode = 0).  The ellipse is drawn in the clockwise direction on ;
;   the screen, beginning at the rightmost point of the ellipse if w < h, ;
;   or at the bottom of the ellipse if w >= h.                            ;
;                                                                         ;
;   Four drawing modes are supported:                                     ;
;       mode 0 -- Don't draw background pixels (leave gaps), and          ;
;                 load new line-style pattern from style argument.        ;
;       mode 1 -- Draw background pixels in color0, and load new          ;
;                 line-style pattern from style argument.                 ;
;       mode 2 -- Don't draw background pixels (leave gaps), and          ;
;                 re-use old line-style pattern (ignore style arg).       ;
;       mode 3 -- Draw background pixels in color0, and re-use old        ;
;                 line-style pattern (ignore style argument).             ;
;   Any mode bits to the left of the 2 LSBs are ignored by the function.  ;
;-------------------------------------------------------------------------;
; Usage:  styled_oval(w, h, xleft, ytop, style, mode);                    ;
;                                                                         ;
; Description of the arguments:                                           ;
;         short w, h;         /* width and height of encl. rectangle */   ;
;         short xleft, ytop;  /* xy at top left corner of rectangle */    ;
;         long  style;        /* line-style pattern (32-bit mask) */      ;
;         short mode;         /* drawing mode (range 0 to 3) */           ;
;                                                                         ;
; Returned in register A8:  void (undefined).                             ;
;                                                                         ;
; Registers altered:  A8                                                  ;
;-------------------------------------------------------------------------;
;
; GLOBAL SUBROUTINE ENTRY POINT (DIRECT-MODE)
;
_dm_styled_oval:
;
; Make sure that dstbm is pointing to the screen.
        MOVE      @(_env+ENVIRONMENT_DSTBM),A8,1 ;destination bit-map global
        JRNZ      ABORT_OVAL          ;if 0, dstbm points to screen
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A12,A13
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
;
; Pop arguments off program stack.
        SETF      16,0,0              ;use field 0 to get shorts
        MOVE      -*STK,A8,1          ;get pointer to data
        MOVE      *A8+,C_MSBS,0       ;get argument width w
        JRZ       EXIT_OVAL           ;done if width == 0
        MOVE      *A8+,A_MSBS,0       ;get argument height h
        JRZ       EXIT_OVAL           ;done if height == 0

        MOVE      *A8+,TMP0,1         ;get argument ytop::xleft
        MOVE      @(_env+ENVIRONMENT_XYORIGIN),TMP1,1 ;get yorg::xorg
        ADDXY     TMP1,TMP0           ;convert to screen coordinates
        MOVE      TMP0,YTXL           ;save xleft, ytop for later

        MOVE      *A8+,ATMP,1         ;get 32-bit arc style mask
        MOVE      ATMP,PATTERN        ;load pattern register

        MOVE      *A8+,DMODE,0        ;get drawing mode information
        MOVK      3,ATMP              ;
        AND       ATMP,DMODE          ;ignore all but 2 LSBs
        JRUC      COMMON_EP           ;jump to common entry point

;
; GLOBAL SUBROUTINE ENTRY POINT (C-PACKET)
;
_styled_oval:

;
; Make sure that dstbm is pointing to the screen.
        MOVE      @(_env+ENVIRONMENT_DSTBM),A8,1 ;destination bit-map global
        JRNZ      ABORT_OVAL          ;if 0, dstbm points to screen
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A12,A13
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
;
; Pop arguments off program stack.
        MOVE      -*STK,C_MSBS,1      ;get argument width w
        JRZ       EXIT_OVAL           ;done if width == 0
        MOVE      -*STK,A_MSBS,1      ;get argument height h
        JRZ       EXIT_OVAL           ;done if height == 0

        MOVE      -*STK,TMP0,1        ;get argument xleft
        MOVE      -*STK,TMP1,1        ;get argument ytop
        SLL       16,TMP1             ;left justify ytop
        MOVY      TMP1,TMP0           ;concatenate xleft, ytop
        MOVE      @(_env+ENVIRONMENT_XYORIGIN),TMP1,1 ;get yorg::xorg
        ADDXY     TMP1,TMP0           ;convert to screen coordinates
        MOVE      TMP0,YTXL           ;save xleft, ytop for later

        MOVE      *-STK,ATMP,1        ;get 32-bit arc style mask
        MOVE      ATMP,PATTERN        ;load pattern register

        MOVE      *-STK,DMODE,1       ;get drawing mode information
        MOVK      3,ATMP              ;
        AND       ATMP,DMODE          ;ignore all but 2 LSBs
;
; Use new line-style pattern, or continue to use old one?
COMMON_EP:
        BTST      1,DMODE             ;continue to use old pattern?
        JRZ       USENEW1             ;jump to use new pattern
        MOVE      @_env+ENVIRONMENT_STYLEMASK,PATTERN,1 ;use old
USENEW1:
;
; To draw full ellipse, specify number of octant crossings as 8.
        MOVK      8,OCTCNT            ;initial octant count = 8
        ADDK      8,DMODE             ;specify draw entire ellipse
;
; Concatenate width w and height h.
        MOVE      A_MSBS,HW           ;copy height h
        SLL       16,HW               ;left justify h
        MOVX      C_MSBS,HW           ;copy width w
;
; Calculate coefficients A = 4*h*h and C = 4*w*w.
        SETF      16,1,0              ;set up for 16-bit moves
        SETF      16,0,1              ;set up for 16-bit multiplier

        ADD       A_MSBS,A_MSBS       ;2*h
        MPYU      A_MSBS,A_MSBS       ;set coefficient A = 4*h*h

        ADD       C_MSBS,C_MSBS       ;2*w
        MPYU      C_MSBS,C_MSBS       ;set coefficient C = 4*w*w
;
;-----------------------------------------------------------------------
; Prepare to calculate ellipse equation coefficients A-F.
; If A-F overflow 32-bit word, scale down to fit into 32-bit word.  For
; overflow test, calculate 16*w*w*h or 16*w*h*h, whichever is larger.
        CMP       A_LSBS,C_LSBS       ;w < h?
        JRNN      W_GE_H              ;jump if w >= h
;
; Case w < h:  Start in octant 3 at coordinates (xleft+w, ytop+(h+1)/2).
        MOVK      3,OCTANT            ;starting octant number = 3

        MOVK      1,ATMP              ;
        SLL       16,ATMP             ;
        ADDXY     HW,ATMP             ;h+1 in 16 MSBs
        SRL       1,ATMP              ;(h+1)/2 in 16 MSBs
        MOVX      HW,ATMP             ;concatenate w, (h+1)/2
        MOVE      ATMP,CURPT          ;
        ADDXY     YTXL,CURPT          ;x0 = xleft+w, y0 = ytop+(h+1)/2
        MOVE      CURPT,ENDPT         ;set end point = start point
;
; Set coefficient D = 4*w*h*h, E = F = 0.
        MOVE      A_LSBS,D_MSBS       ;copy 4*h*h
        MPYU      HW,D_MSBS           ;D = 4*w*h*h
        CLR       E_MSBS              ;
        CLR       E_LSBS              ;E = 0
        CLR       F_MSBS              ;
        CLR       F_LSBS              ;F = 0
        BTST      16,HW               ;is rectangle height h odd?
        JRZ       READY               ;jump if h even
;
; Rectangle height h is odd.  Set E = 4*w*w and F = w*w.
        MOVE      C_LSBS,E_LSBS       ;E = 4*w*w
        MOVE      C_LSBS,F_LSBS       ;4*w*w
        SRL       2,F_LSBS            ;F = w*w
        JR        READY               ;ready to draw ellipse
;
; Case w >= h:  Start in octant 5 at coordinates (xleft+w/2, ytop+h).
W_GE_H:
        MOVK      5,OCTANT            ;starting octant number = 5

        CLR       ATMP                ;
        MOVX      HW,ATMP             ;copy w
        SRL       1,ATMP              ;
        MOVY      HW,ATMP             ;concatenate w/2, h
        MOVE      ATMP,CURPT          ;
        ADDXY     YTXL,CURPT          ;x0 = xleft+w/2, y0 = ytop+h
        MOVE      CURPT,ENDPT         ;end point = start point
;
; Set coefficient E = 4*w*w*h, D = F = 0.
        MOVE      C_LSBS,E_MSBS       ;copy 4*w*w
        RL        16,HW               ;swap h and w values in register
        MPYU      HW,E_MSBS           ;E = 4*w*w*h
        CLR       D_MSBS              ;
        CLR       D_LSBS              ;D = 0
        CLR       F_MSBS              ;
        CLR       F_LSBS              ;F = 0
        BTST      16,HW               ;is rectangle width w odd?
        JRZ       READY               ;jump if w even
;
; Rectangle width w is odd.  Set D = 4*h*h and F = h*h.
        MOVE      A_LSBS,D_LSBS       ;
        NEG       D_LSBS              ;D = -4*h*h
        NOT       D_MSBS              ;
        MOVE      A_LSBS,F_LSBS       ;4*h*h
        SRL       2,F_LSBS            ;F = h*h
;
; Call subroutine that actually draws styled elliptical arc.  The
; following arguments are passed as register arguments:  xs, ys, xe, ye,
; A, C, D, E, F, start_octant, octant_count, stylemask and transpflag.
READY:
        SETF      32,0,1              ;restore default field 1 size
        CALLR     STYLED_OVALARC      ;styled oval arc draw routine
;
*-----------------------------------------------------------------------
; Restore registers and return.
EXIT_OVAL:
        MOVE      PATTERN,@_env+ENVIRONMENT_STYLEMASK,1 ;save line style
        MMFM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        MMFM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A12,A13
ABORT_OVAL:
        MOVE      *SP(32),STK,1       ;restore program stack pointer
        RETS      2                   ;


;-------------------------------------------------------------------------;
; arcstyle function                                                       ;
;                                                                         ;
;   This globally-accessible routine is called by the styled_ovalarc      ;
;   function, which is a standard TIGA extended primitive.  The arcstyle  ;
;   routine below actually draws the styled arc, which is taken from an   ;
;   ellipse in standard position whose shape and position are described   ;
;   in terms of an enclosing rectangle.  The ellipse touches the          ;
;   rectangle at four points, each halfway along a side of the rectangle. ;
;   The dimensions of the ellipse are specified in terms of the width and ;
;   height of the enclosing rectangle, and the position in terms of the x ;
;   and y coordinates at the top left corner of the rectangle.  Argument  ;
;   dydx is a structure containing 16-bit width and height values, and    ;
;   argument daddr is a structure containing 16-bit x and y coordinate    ;
;   values at the top left corner.                                        ;
;                                                                         ;
;   The arc is specified in terms of its start and end points relative to ;
;   the center of the ellipse.  The arc is drawn in either a clockwise or ;
;   a counterclockwise direction from the start point to the end point.   ;
;   The direction is counterclockwise if bit 2 of the mode argument is 1, ;
;   and clockwise if it is 0.  The specified start and end points must    ;
;   lie no further than 1/2 pixel from the mathematical ellipse.          ;
;   Argument arc1 contains the 16-bit x and y coordinates at the arc      ;
;   start point, and argument end contains the arc end point coordinates. ;
;                                                                         ;
;   Also specified are the end points of rays drawn from the center of    ;
;   the ellipse through the arc start and end points.  Argument ray1      ;
;   contains the 16-bit x and y coordinates of the ray through the arc    ;
;   start point, and argument ray2 contains the coordinates of the ray    ;
;   through the arc end point.  These ray end points are used in          ;
;   determining in which octants the arc start and end points lie.        ;
;   Particularly in the case of smaller ellipses, the ray1 and ray2       ;
;   arguments yield more accurate octant determinations than would be     ;
;   available using the arc1 and arc2 arguments described above.          ;
;                                                                         ;
;   Argument style is a 32-bit repeating line-style pattern (or arc-style ;
;   pattern, if you prefer).  Pattern bits are used in the order          ;
;   0,1,...,31, where bit 0 is the LSB.  The pattern is repeated modulo   ;
;   32 as the arc is drawn.  A bit value of 1 in the pattern specifies    ;
;   that COLOR1 is to be used to draw the corresponding pixel.  A bit     ;
;   value of 0 in the pattern means that the corresponding pixel is       ;
;   either drawn in COLOR0 (if the LSB of mode = 0) or not drawn (i.e.,   ;
;   skipped over if LSB of mode = 1).  The four bits of the mode argument ;
;   are specified as follows:                                             ;
;       - bit 0:   0 ==> use COLOR0 to draw corresponding pixel (or skip  ;
;                        pixel if bit 1 of mode is 1)                     ;
;                  1 ==> use COLOR1 to draw corresponding pixel           ;
;       - bit 1:   0 ==> draw pixels corresponding to 0s in the pattern   ;
;                        using COLOR0                                     ;
;                  1 ==> skip over (do not draw) pixels corresponding to  ;
;                        0s in the pattern                                ;
;       - bit 2:   0 ==> draw arc in clockwise direction on screen        ;
;                  1 ==> draw arc in counterclockwise direction           ;
;       - bit 3:   0 ==> draw an arc that is only a portion of the        ;
;                        ellipse                                          ;
;                  1 ==> draw the entire ellipse                          ;
;   To draw the entire ellipse (see bit 3 above) the calling routine must ;
;   set arc2 = arc1 and ray2 = ray1.                                      ;
;-------------------------------------------------------------------------;
; Usage:  arcstyle(dfdx, daddr, arc1, arc2, ray1, ray2, style, mode)      ;
;                                                                         ;
; Stack parameters:                                                       ;
;         typedef struct { short x,y; } POINT2D;                          ;
;         POINT2D dydx;        /* width and height of rectangle */        ;
;         POINT2D daddr;       /* x and y at top left of rectangle */     ;
;         POINT2D arc1, arc2;  /* arc start and end coordinates */        ;
;         POINT2D ray1, ray2;  /* rays through arc start and end */       ;
;         long style;          /* 32-bit pattern of 1s and 0s */          ;
;         int mode;            /* specify drawing mode */                 ;
;                                                                         ;
; Return in A8:  void (undefined)                                         ;
;                                                                         ;
; Registers altered:  A8                                                  ;
;-------------------------------------------------------------------------;
;
;
; GLOBAL SUBROUTINE ENTRY POINT
;
_arcstyle:

;
; Make sure that dstbm is pointing to the screen.
        MOVE      @(_env+ENVIRONMENT_DSTBM),A8,1 ;destination bit-map global
        JRNZ      ABORT_ARC           ;if 0, dstbm points to screen
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A12,A13
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
;
; Pop arguments off program stack.
        MOVE      -*STK,HW,1          ;get dydx = width, height
        MOVE      -*STK,ATMP,1        ;get daddr
        MOVE      @(_env+ENVIRONMENT_XYORIGIN),YSXS,1 ;get yorg::xorg
        ADDXY     YSXS,ATMP           ;convert to screen coordinates
        MOVE      ATMP,YTXL           ;set (xleft, ytop) = daddr
        MOVE      -*STK,YSXS,1        ;get arc1 = xs, ys
        MOVE      YSXS,CURPT          ;copy to current point
        ADDXY     YTXL,CURPT          ;translate to screen coord's
        ADDXY     YSXS,YSXS           ;calculate 2*xs, 2*ys
        SUBXY     HW,YSXS             ;x = 2*xs - w, y = 2*ys - h
        MOVE      -*STK,ATMP,1        ;get arc2 = xe, ye
        MOVE      ATMP,ENDPT          ;copy to arc end point
        ADDXY     YTXL,ENDPT          ;translate to screen coord's
        MOVE      -*STK,Y1X1,1        ;get ray1 = x1, y1
        MOVE      -*STK,Y2X2,1        ;get ray2 = x2, y2
        MOVE      -*STK,DMODE,1       ;get drawing mode information
;
; Get line-style pattern.
        MOVE      @(_env+ENVIRONMENT_STYLEMASK),PATTERN,1 ;use old
;
; Calculate constants w*w and h*h.
        SETF      16,1,0              ;set up for 16-bit moves
        SETF      16,1,1              ;set up for 16-bit multiplier

        MOVX      HW,C_LSBS           ;copy width w
        ZEXT      C_LSBS,0            ;isolate w
        MPYU      C_LSBS,C_LSBS       ;calculate w*w

        MOVY      HW,A_LSBS           ;copy height h
        SRL       16,A_LSBS           ;isolate h
        MPYU      A_LSBS,A_LSBS       ;calculate h*h
;
; Determine number of octant that contains arc starting point.
        MOVE      Y1X1,YX             ;raw arc start coordinates (x1,y1)
        BTST      2,DMODE             ;is arc direction counterclockwise?
        JRZ       CWDIR1              ;jump if clockwise

        CLR       YX                  ;else adjust for counterclockwise
        SUBXY     Y1X1,YX             ;raw arc start coord's (-x1,-y1)
CWDIR1:
        CALLR     GET_OCTANT          ;routine returns octant number
;
; Determine whether entire ellipse is to be drawn.
        MOVK      8,OCTCNT            ;initialize oct_count = 8
        BTST      3,DMODE             ;draw entire ellipse?
        JRNZ      GOT_COUNT           ;if so, jump
;
; Does arc start and end at same point?  If so, do not draw it.
        CMP       Y1X1,Y2X2           ;xs == xe && ys == ye ?
        JREQ      EXIT_ARC            ;if so, done
;
; Determine in which octant the arc end point lies.
        MOVE      OCTANT,OCTCNT       ;save start octant number
        MOVE      Y2X2,YX             ;raw arc end coordinates (x2,y2)
        BTST      2,DMODE             ;is arc direction counterclockwise?
        JRZ       CWDIR2              ;jump if clockwise

        CLR       YX                  ;else adjust for counterclockwise
        SUBXY     Y2X2,YX             ;raw arc end coord's (-x2,-y2)
CWDIR2:
        CALLR     GET_OCTANT          ;returns octant number
;
; Count number of octant boundary crossings from arc start to end.
        SUB       OCTANT,OCTCNT       ;oct_count = start_oct - end_oct
        JRZ       SAME_OCT            ;jump if start_oct = end_oct
        ADD       OCTCNT,OCTANT       ;restore start octant number
        BTST      2,DMODE             ;is arc direction counterclockwise?
        JRNZ      CCWDIR1             ;jump if counterclockwise

        NEG       OCTCNT              ;else oct_count = end_oct-start_oct
CCWDIR1:
        MOVE      OCTCNT,OCTCNT       ;test oct_count
        JRNN      GOT_COUNT           ;jump if oct_count > 0
        ADDK      8,OCTCNT            ;else make oct_count positive
        JR        GOT_COUNT           ;jump if oct_count != 0
;
; Arc starts and ends in same octant.  Should octant count be 0 or 8?
SAME_OCT:
        MOVY      Y2X2,D_LSBS         ;copy y2
        SRA       16,D_LSBS           ;isolate y2
        MPYS      Y1X1,D_LSBS         ;x1*y2

        MOVY      Y1X1,E_LSBS         ;copy y1
        SRA       16,E_LSBS           ;isolate y1
        MPYS      Y2X2,E_LSBS         ;y1*x2

        BTST      2,DMODE             ;is arc direction counterclockwise?
        JRNZ      CCWDIR2             ;jump if counterclockwise

        SUB       D_LSBS,E_LSBS       ;x2*y1 - y2*x1 (cross product)
        JRN       GOT_COUNT           ;jump if oct_count should be 0
        MOVK      8,OCTCNT            ;else change oct_count to 8
        JR        GOT_COUNT           ;
CCWDIR2:
        SUB       E_LSBS,D_LSBS       ;x1*y2 - y1*x2 (cross product)
        JRN       GOT_COUNT           ;jump if oct_count should be 0
        MOVK      8,OCTCNT            ;else change oct_count to 8
GOT_COUNT:
;
;-----------------------------------------------------------------------
; Prepare to calculate ellipse equation coefficients A-F:
;     x = 2*xs - w     y = 2*ys - h
;     A = 4*w*w        D = 4*h*h*x       F = h*h*x*x + w*w*y*y - w*w*h*h
;     C = 4*h*h        E = 4*w*w*y
;
        MOVE      YSXS,ATMP           ;copy x and y
        ADDXY     ATMP,ATMP           ;
        ADDXY     ATMP,ATMP           ;4*x and 4*y

        MOVE      A_LSBS,D_MSBS       ;copy h*h
        MPYS      ATMP,D_MSBS         ;D = 4*h*h*x

        MOVE      C_LSBS,E_MSBS       ;copy w*w
        RL        16,ATMP             ;rotate 4*y into 16 LSBs
        MPYS      ATMP,E_MSBS         ;E = 4*w*w*y

;---    MOVX      YSXS,F_MSBS         ;copy x  [same register]
        MOVY      YSXS,TMP1           ;copy y
        SEXT      F_MSBS,0            ;isolate x
        MPYS      F_MSBS,F_MSBS       ;x*x
        SRA       16,TMP1             ;right justify y
        MPYS      TMP1,TMP1           ;y*y

        SETF      32,0,1              ;set up for 32-bit multiplier

        MOVE      F_LSBS,F_MSBS       ;copy x*x
        MPYU      A_LSBS,F_MSBS       ;h*h*x*x
        SUB       A_LSBS,TMP1         ;y*y - h*h
        MOVE      TMP1,TMP0           ;
        MPYS      C_LSBS,TMP0         ;w*w*(y*y - h*h)
        ADD       TMP1,F_LSBS         ;
        ADDC      TMP0,F_MSBS         ;F = h*h*x*x + w*w*y*y - w*w*h*h

        SLL       2,A_LSBS            ;
        CLR       A_MSBS              ;A = 4*h*h

        SLL       2,C_LSBS            ;
        CLR       C_MSBS              ;C = 4*w*w
;
; Call subroutine that actually draws styled elliptical arc.  The
; following arguments are passed as register arguments:  xs, ys, xe, ye,
; A, C, D, E, F, stylemask and transpflag.
        CALLR     STYLED_OVALARC      ;styled arc draw routine
;
*-----------------------------------------------------------------------
; Restore registers and return.
EXIT_ARC:
        MOVE      PATTERN,@(_env+ENVIRONMENT_STYLEMASK),1 ;save pattern
        MMFM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        MMFM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A12,A13
        SETF      32,0,1              ;restore default field 1 size
ABORT_ARC:
        MOVE      *SP(32),STK,1       ;restore program stack pointer
        RETS      2                   ;


*-----------------------------------------------------------------------
*   Local subroutine:  GET_OCTANT
*-----------------------------------------------------------------------
*       Given endpoint coordinates x and y of ray through point on arc
*       relative to origin at center of ellipse, return the number of the
*       drawing octant containing the point on the arc.  Octant numbers
*       are in the range 1 to 8:
*             drawing octant 1:  0 < -df/dx < df/dy
*             drawing octant 2:  0 < df/dy < -df/dx
*             drawing octant 3:  0 < -df/dy < -df/dx
*             drawing octant 4:  0 < -df/dx < -df/dy
*             drawing octant 5:  0 < df/dx < -df/dy
*             drawing octant 6:  df/dx <= -df/dy < 0
*             drawing octant 7:  0 < df/dy < df/dx
*             drawing octant 8:  0 < df/dx < df/dy
*       Gradient vector components df/dx and df/dy are the partial
*       derivatives of the ellipse equation f(x,y)=0 w.r.t. x and y.
*-----------------------------------------------------------------------
;
;
; LOCAL SUBROUTINE ENTRY POINT
;
GET_OCTANT:

        MOVI      34216578h,OCTANT    ;load octant lookup table

        MOVX      YX,ATMP             ;copy x
        SEXT      ATMP,0              ;isolate x value
        JRNN      X_POS               ;jump if x >= 0

        ABS       ATMP                ;else make x positive
        SLL       16,OCTANT           ;else octant number is 1, 2, 3 or 4
X_POS:
        MOVE      A_LSBS,D_MSBS       ;copy h*h
        MPYU      ATMP,D_MSBS         ;|df/dx| = constant*h*h*|x|

        MOVY      YX,ATMP             ;copy y
        SRA       16,ATMP             ;isolate y value
        JRNN      Y_POS               ;jump if y >= 0

        ABS       ATMP                ;else make y positive
        SLL       8,OCTANT            ;else octant number is 3, 4, 5 or 6
Y_POS:
        MOVE      C_LSBS,E_MSBS       ;copy w*w
        MPYU      ATMP,E_MSBS         ;|df/dy| = constant*w*w*|y|

        SUB       E_LSBS,D_LSBS       ;
        SUBB      E_MSBS,D_MSBS       ;sign of |df/dx| - |df/dy|
        JRNN      X_GE_Y              ;jump if |df/dx| >= |df/dy|

        SLL       4,OCTANT            ;else octant number is 1, 4, 5 or 8
X_GE_Y:
        SRL       28,OCTANT           ;right justify octant number
        RETS      0                   ;return to calling routine


;-------------------------------------------------------------------------;
; Local subroutine:  STYLED_OVALARC                                       ;
;-------------------------------------------------------------------------;
;   Draw styled ellipse or elliptical arc using a 32-bit line-style       ;
;   pattern.  The DMODE (drawing mode) value determines whether           ;
;   background (COLOR0) pixels are rendered as opaque or transparent, and ;
;   whether the drawing direction is clockwise or counterclockwise:       ;
;       DMODE decoding:                                                   ;
;       - bit 0:  0 ==> background color is opaque                        ;
;                 1 ==> background color is transparent                   ;
;       - bit 2:  0 ==> arc is drawn in clockwise direction               ;
;                 1 ==> arc is drawn in counterclockwise direction        ;
;   The ellipse is assumed to be in standard position so that in the      ;
;   equation for the ellipse,                                             ;
;           f(x,y) = Axx + Bxy + Cyy + Dx + Ey + F = 0                    ;
;   coefficient B is always 0, and therefore need not be specified.       ;
;   The CURPT value is the concatenated xy coordinates of the current     ;
;   point on the arc, while ENDPT contains the coordinates of the arc end ;
;   point.  Arguments A, C, D, E and F are the coefficients of the        ;
;   ellipse equation, and are assumed to have been calculated with the    ;
;   origin translated to the arc starting coordinates.  Argument          ;
;   OCTANT is initially the drawing octant containing the arc starting    ;
;   point, and is in the range 1 to 8.  Argument OCTCNT is the number of  ;
;   octant boundaries that must be crossed in tracking the arc from the   ;
;   start point to the end point.  Argument style is a 32-bit repeating   ;
;   arc-style pattern.  Pattern bits are used in the order 0,1,...,31,    ;
;   where 0 is the rightmost bit (the LSB).  The pattern is repeated      ;
;   modulo 32 as the arc is drawn.  A bit value of 1 in the pattern       ;
;   specified that COLOR1 is to be used to draw the corresponding pixel.  ;
;   A value of 0 in one of the line-style pattern bits means that the     ;
;   corresponding pixel is either drawn in COLOR0 (if LSB of mode = 0) or ;
;   not drawn (i.e., skipped over if LSB of mode = 1).                    ;
;-------------------------------------------------------------------------;
;
;
;    LOCAL SUBROUTINE ENTRY POINT
;
STYLED_OVALARC:

        MOVI      [-1,-1],DXYSQUA     ;init dxsquare = dysquare = -1
        CLR       DXYDIAG             ;
        SUBXY     DXYSQUA,DXYDIAG     ;init dxdiag = dydiag = 1
;
; If starting octant = 3, 4, 5 or 6, change sign of coefficient D.
        INC       OCTANT              ;n = octant + 1
        BTST      2,OCTANT            ;
        JRZ       D_OKAY              ;jump if octant 1, 2, 7 or 8

        NEG       D_LSBS              ;
        NEGB      D_MSBS              ;D = -D
        MOVX      DXYSQUA,DXYDIAG     ;dxdiag = -1
D_OKAY:
;
; If starting octant = 5, 6, 7 or 8, change sign of coefficient E.
        SUBK      2,OCTANT            ;n = octant - 1
        BTST      2,OCTANT            ;
        JRZ       E_OKAY              ;jump if octant 1, 2, 3 or 4

        NEG       E_LSBS              ;
        NEGB      E_MSBS              ;E = -E
        MOVY      DXYSQUA,DXYDIAG     ;dydiag = -1
E_OKAY:
;
; If starting octant = 2, 3, 6 or 7, swap A with C, and D with E.
        CLR       DXYSQUA             ;dysquare = 0
        MOVX      DXYDIAG,DXYSQUA     ;dxsquare = dxdiag
        INC       OCTANT              ;n = octant (range [1,8])
        BTST      1,OCTANT            ;
        JRZ       NO_SWAP             ;jump if octant 1, 4, 5 or 8

        MOVE      A_LSBS,ATMP         ;swap coefficients A and C
        MOVE      C_LSBS,A_LSBS       ;
        MOVE      ATMP,C_LSBS         ;
        MOVE      A_MSBS,ATMP         ;
        MOVE      C_MSBS,A_MSBS       ;
        MOVE      ATMP,C_MSBS         ;

        MOVE      D_LSBS,ATMP         ;swap coefficients D and E
        MOVE      E_LSBS,D_LSBS       ;
        MOVE      ATMP,E_LSBS         ;
        MOVE      D_MSBS,ATMP         ;
        MOVE      E_MSBS,D_MSBS       ;
        MOVE      ATMP,E_MSBS         ;

        CLR       DXYSQUA             ;dxsquare = 0
        MOVY      DXYDIAG,DXYSQUA     ;dysquare = dydiag
NO_SWAP:
;
; Calculate initial values of loop parameters d, u, v, k1 and k3.
;--     MOVE      D_LSBS,U_LSBS       ;[same register]
;--     MOVE      D_MSBS,U_MSBS       ;D

        ADD       A_LSBS,U_LSBS       ;
        ADDC      A_MSBS,U_MSBS       ;A + D

        ADD       U_LSBS,U_LSBS       ;
        ADDC      U_MSBS,U_MSBS       ;
        ADD       U_LSBS,U_LSBS       ;
        ADDC      U_MSBS,U_MSBS       ;u = 4*(A + D)

;--     MOVE      F_LSBS,DV_LSBS      ;[same register]
;--     MOVE      F_MSBS,DV_MSBS      ;F

        ADD       DV_LSBS,DV_LSBS     ;
        ADDC      DV_MSBS,DV_MSBS     ;2*F

        ADD       E_LSBS,DV_LSBS      ;
        ADDC      E_MSBS,DV_MSBS      ;2*F + E

        ADD       DV_LSBS,DV_LSBS     ;
        ADDC      DV_MSBS,DV_MSBS     ;4*F + 2*E

        ADD       U_LSBS,DV_LSBS      ;
        ADDC      U_MSBS,DV_MSBS      ;4*(A + D + F) + 2*E

        ADD       C_LSBS,DV_LSBS      ;
        ADDC      C_MSBS,DV_MSBS      ;d = 4*(A + D + F) + C + 2*E

;--     MOVE      E_LSBS,V_LSBS       ;[same register]
;--     MOVE      E_MSBS,V_MSBS       ;E

        ADD       V_LSBS,V_LSBS       ;
        ADDC      V_MSBS,V_MSBS       ;
        ADD       V_LSBS,V_LSBS       ;
        ADDC      V_MSBS,V_MSBS       ;4*E

        ADD       U_LSBS,V_LSBS       ;
        ADDC      U_MSBS,V_MSBS       ;v = 4*(A + D + E)

;--     MOVE      A_LSBS,K1_LSBS      ;[same register]
;--     MOVE      A_MSBS,K1_MSBS      ;A

        MOVE      K1_LSBS,ATMP        ;
        SLL       3,K1_LSBS           ;
        SRL       29,ATMP             ;
        SLL       3,K1_MSBS           ;
        OR        ATMP,K1_MSBS        ;k1 = 8*A

;--     MOVE      C_LSBS,K3_LSBS      ;[same register]
;--     MOVE      C_MSBS,K3_MSBS      ;C

        MOVE      K3_LSBS,ATMP        ;
        SLL       3,K3_LSBS           ;
        SRL       29,ATMP             ;
        SLL       3,K3_MSBS           ;
        OR        ATMP,K3_MSBS        ;8*C

        ADD       K1_LSBS,K3_LSBS     ;
        ADDC      K1_MSBS,K3_MSBS     ;k3 = 8*A + 8*C
;
; If arc drawing direction is clockwise, complement octant number.
        BTST      2,DMODE             ;arc direction = clockwise ?
        JRNZ      ISCCW               ;jump if counterclockwise
        NOT       OCTANT              ;octant = ~octant
ISCCW:
;
; If octant number is odd and direction is CCW, or if octant number is
; even and direction is CW, reverse signs of d, u, v, k1 and k3.
        BTST      0,OCTANT            ;is octant number odd?
        JRZ       INIT_LOOP           ;jump if octant number is even

        NEG       DV_LSBS             ;
        NEGB      DV_MSBS             ;d = -d
        NEG       U_LSBS              ;
        NEGB      U_MSBS              ;u = -u
        NEG       V_LSBS              ;
        NEGB      V_MSBS              ;v = -v
        NEG       K1_LSBS             ;
        NEGB      K1_MSBS             ;k1 = -k1
        NEG       K3_LSBS             ;
        NEGB      K3_MSBS             ;k3 = -k3
;
; Initialize remaining loop parameters.
INIT_LOOP:
        RL        1,PATTERN           ;compensate for initial shift
        MOVI      -1,PIXCNT           ;init to max possible count value
        MOVE      OCTCNT,OCTCNT       ;oct_count == 0 ? (last octant?)
        JRZ       LAST_OCTANT         ;jump if oct_count == 0
;
*------------------------------------------------------------------------
; Each iteration of outer loop below draws one octant of conic curve.
NEXT_OCTANT:
        BTST      0,OCTANT            ;is octant number even or odd ?
        JRZ       OCTEVEN             ;jump if octant number is even

        MOVE      U_MSBS,U_MSBS       ;is u >= 0 ? (still in odd octant?)
        JRNN      NEXT_PIXEL          ;jump if u >= 0 (still in odd)
        JR        ENTER_EVEN          ;u < 0: enter even octant
OCTEVEN:
        MOVE      V_MSBS,V_MSBS       ;is v < 0 ? (still within octant?)
        JRNN      ENTER_ODD           ;jump if v >= 0 (enter odd octant)
;
*------------------------------------------------------------------------
; Each iteration of inner loop below draws one pixel in current octant.
NEXT_PIXEL:
        RL        31,PATTERN          ;rotate pattern right by 1
        JRC       PLOT                ;jump if pattern bit = 1

        BTST      0,DMODE             ;are background pixels opaque?
        JRZ       SKIP                ;jump if they are transparent

        PIXT      COLOR0,*CURPT.XY    ;else draw color-0 pixel
        JR        SKIP                ;
PLOT:
        PIXT      COLOR1,*CURPT.XY    ;else draw color-1 pixel
SKIP:
;
; Make diagonal or square move, dep. on sign of decision var. d.
        MOVE      DV_MSBS,DV_MSBS     ;is d < 0?
        JRGE      DIAG_MOVE           ;jump if d >= 0
;
; Make square (horizontal or vertical) move to next pixel in arc.
        ADDXY     DXYSQUA,CURPT       ;make square move
        ADD       K1_LSBS,U_LSBS      ;
        ADDC      K1_MSBS,U_MSBS      ;u += k1
        JRN       UNEG1               ;jump if u < 0 (exit odd octant)
BACK1:
        ADD       U_LSBS,DV_LSBS      ;
        ADDC      U_MSBS,DV_MSBS      ;d += u
        ADD       K1_LSBS,V_LSBS      ;
        ADDC      K1_MSBS,V_MSBS      ;v += k1
        JRNN      VPOS1               ;jump if v >= 0 (exit even octant)
BACK2:
        DSJ       PIXCNT,NEXT_PIXEL   ;loop while pix_count != 0
        JR        DONE                ;done when pix_count is zero
;
; Break on u < 0.  If current octant is odd, enter new (even) octant.
UNEG1:
        BTST      0,OCTANT            ;verify that current octant is odd
        JRZ       BACK1               ;jump back if octant is even

        ADD       U_LSBS,DV_LSBS      ;
        ADDC      U_MSBS,DV_MSBS      ;d += u
        ADD       K1_LSBS,V_LSBS      ;
        ADDC      K1_MSBS,V_MSBS      ;v += k1
        DSJ       PIXCNT,ENTER_EVEN   ;enter even octant
        JR        DONE                ;done if pix_count is zero
;
; Break on v >= 0.  If current octant is even, enter new (odd) octant.
VPOS1:
        BTST      0,OCTANT            ;verify that current octant is even
        JRNZ      BACK2               ;jump back if octant is odd

        DSJ       PIXCNT,ENTER_ODD    ;enter odd octant
        JR        DONE                ;done if pix_count is zero
;
; Make diagonal move to next pixel in arc.
DIAG_MOVE:
        ADDXY     DXYDIAG,CURPT       ;make diagonal move
        ADD       K3_LSBS,V_LSBS      ;
        ADDC      K3_MSBS,V_MSBS      ;v += k3
        JRNN      VPOS2               ;jump if v >= 0 (exit even octant)
BACK3:
        ADD       V_LSBS,DV_LSBS      ;
        ADDC      V_MSBS,DV_MSBS      ;d += v
        ADD       K1_LSBS,U_LSBS      ;
        ADDC      K1_MSBS,U_MSBS      ;u += k1
        JRN       UNEG2               ;jump if u < 0 (exit odd octant)
BACK4:
        DSJ       PIXCNT,NEXT_PIXEL   ;loop while pix_count != 0
        JR        DONE                ;done when pix_count is zero
;
; Break on v >= 0.  If current octant is even, enter new (odd) octant.
VPOS2:
        BTST      0,OCTANT            ;verify that current octant is even
        JRNZ      BACK3               ;jump back if octant is odd

        ADD       V_LSBS,DV_LSBS      ;
        ADDC      V_MSBS,DV_MSBS      ;d += v
        ADD       K1_LSBS,U_LSBS      ;
        ADDC      K1_MSBS,U_MSBS      ;u += k1
        DSJ       PIXCNT,ENTER_ODD    ;enter odd octant
        JR        DONE                ;done if pix_count is zero
;
; Break on u < 0.  If current octant is odd, enter new (even) octant.
UNEG2:
        BTST      0,OCTANT            ;verify that current octant is odd
        JRZ       BACK4               ;jump back if octant is even

        DSJ       PIXCNT,ENTER_EVEN   ;enter even octant
        JR        DONE                ;done if pix_count is zero
;
; End of inner loop.
*------------------------------------------------------------------------
; Cross diagonal octant boundary into odd-numbered octant.
; Update loop parameters d, u, v, k1, k3, dxsquare and dysquare.
ENTER_ODD:
        DEC       OCTANT              ;decrement to odd octant number

        NEG       DV_LSBS             ;
        NEGB      DV_MSBS             ;-d

        ADD       U_LSBS,DV_LSBS      ;
        ADDC      U_MSBS,DV_MSBS      ;-d + u

        ADD       DV_LSBS,DV_LSBS     ;
        ADDC      DV_MSBS,DV_MSBS     ;2*(-d + u)

        SUB       V_LSBS,DV_LSBS      ;
        SUBB      V_MSBS,DV_MSBS      ;2*(-d + u) - v

        ADD       K1_LSBS,DV_LSBS     ;
        ADDC      K1_MSBS,DV_MSBS     ;2*(-d + u) - v + k1

        SUB       K3_LSBS,DV_LSBS     ;
        SUBB      K3_MSBS,DV_MSBS     ;2*(-d + u) - v + k1 - k3

        ADD       DV_LSBS,DV_LSBS     ;
        ADDC      DV_MSBS,DV_MSBS     ;
        ADD       DV_LSBS,DV_LSBS     ;
        ADDC      DV_MSBS,DV_MSBS     ;8*(-d + u) + 4*(-v + k1 - k3)

        ADD       K3_LSBS,DV_LSBS     ;
        ADDC      K3_MSBS,DV_MSBS     ;8*(-d + u) + 4*(-v + k1 - k3) + k3

        MOVE      DV_MSBS,ATMP        ;shift 64-bit value 3 bits to right
        SLL       29,ATMP             ;
        SRL       3,DV_LSBS           ;
        OR        ATMP,DV_LSBS        ;
        SRA       3,DV_MSBS           ;d' = -d + u - v/2 + k1/2 - 3*k3/8

        SUB       V_LSBS,U_LSBS       ;
        SUBB      V_MSBS,U_MSBS       ;u - v
        ADD       U_LSBS,U_LSBS       ;
        ADDC      U_MSBS,U_MSBS       ;2*(u-v)
        ADD       K1_LSBS,U_LSBS      ;
        ADDC      K1_MSBS,U_MSBS      ;2*(u-v) + k1
        SUB       K3_LSBS,U_LSBS      ;
        SUBB      K3_MSBS,U_MSBS      ;2*(u-v) + k1 - k3
        SRL       1,U_LSBS            ;shift 64-bit value 1 bit to right
        SRA       1,U_MSBS            ;
        ADDC      U_LSBS,U_LSBS       ;
        RL        31,U_LSBS           ;u' = u - v + k1/2 - k3/2

        NEG       V_LSBS              ;
        NEGB      V_MSBS              ;-v
        ADD       K1_LSBS,V_LSBS      ;
        ADDC      K1_MSBS,V_MSBS      ;-v + k1
        ADD       V_LSBS,V_LSBS       ;
        ADDC      V_MSBS,V_MSBS       ;2*(-v + k1)
        SUB       K3_LSBS,V_LSBS      ;
        SUBB      K3_MSBS,V_MSBS      ;2*(-v + k1) - k3
        SRL       1,V_LSBS            ;shift 64-bit value 1 bit to right
        SRA       1,V_MSBS            ;
        ADDC      V_LSBS,V_LSBS       ;
        RL        31,V_LSBS           ;v' = -v + k1 - k3/2

        SUB       K3_LSBS,K1_LSBS     ;
        SUBB      K3_MSBS,K1_MSBS     ;k1' = k1 - k3

        NEG       K3_LSBS             ;
        NEGB      K3_MSBS             ;k3' = -k3

        RL        16,DXYSQUA          ;dxsquare' = dysquare
        CLR       BTMP                ;
        SUBXY     DXYSQUA,BTMP        ;
        BTST      2,DMODE             ;clockwise arc?
        JRNZ      CCW1                ;jump if counterclockwise

        MOVX      BTMP,DXYSQUA        ;dxsquare' = -dysquare
        DSJ       OCTCNT,NEXT_OCTANT  ;ready to draw next pixel
        JR        LAST_OCTANT         ;enter final octant if oct_count=0
CCW1:
        MOVY      BTMP,DXYSQUA        ;dysquare' = -dxsquare

        DSJ       OCTCNT,NEXT_OCTANT  ;ready to draw next pixel
        JR        LAST_OCTANT         ;enter final octant if oct_count=0
;
*------------------------------------------------------------------------
; Cross square octant boundary into even-numbered octant.
; Update loop parameters d, u, v, k1, k3, dxdiag and dydiag.
ENTER_EVEN:
        DEC       OCTANT              ;decrement to even octant number

        SUB       U_LSBS,V_LSBS       ;
        SUBB      U_MSBS,V_MSBS       ;-u + v

        NEG       DV_LSBS             ;
        NEGB      DV_MSBS             ;-d
        ADD       V_LSBS,DV_LSBS      ;
        ADDC      V_MSBS,DV_MSBS      ;d' = -d - u + v

        SUB       U_LSBS,V_LSBS       ;
        SUBB      U_MSBS,V_MSBS       ;v' = -2*u + v

        NEG       U_LSBS              ;
        NEGB      U_MSBS              ;u' = -u

        NEG       K1_LSBS             ;
        NEGB      K1_MSBS             ;k1' = -k1

        NEG       K3_LSBS             ;
        NEGB      K3_MSBS             ;k3' = -k3

        RL        16,DXYDIAG          ;dxdiag' = dydiag
        CLR       BTMP                ;
        SUBXY     DXYDIAG,BTMP        ;
        BTST      2,DMODE             ;clockwise arc?
        JRNZ      CCW2                ;jump if counterclockwise

        MOVX      BTMP,DXYDIAG        ;dxdiag' = -dydiag
        DSJ       OCTCNT,NEXT_OCTANT  ;ready to draw next pixel
        JR        LAST_OCTANT         ;enter final octant if oct_count=0
CCW2:
        MOVY      BTMP,DXYDIAG        ;dydiag' = -dxdiag

        DSJ       OCTCNT,NEXT_OCTANT  ;ready to draw next pixel
;
*------------------------------------------------------------------------
; Final octant.  Count number of pixels left to be drawn to end of arc.
LAST_OCTANT:
        MOVE      ENDPT,PIXCNT        ;copy arc end coordinates (xe,ye)
        SUBXY     CURPT,PIXCNT        ;subtract current coordinates (x,y)
        MOVE      OCTANT,TMP0         ;
        BTST      2,DMODE             ;is arc direction clockwise?
        JRNZ      NOTCW               ;jump if counterclockwise
        NOT       TMP0                ;un-complement octant number
NOTCW:
        BTST      1,TMP0              ;last octant = 2, 3, 6 or 7 ?
        JRZ       OCT1458             ;jump if octant = 1, 4, 5 or 8

        SRA       16,PIXCNT           ;else set pix_count = ye - y
OCT1458:
        SEXT      PIXCNT,0            ;pix_count = xe - x
        ABS       PIXCNT              ;pix_count = |pix_count|
        JRNZ      NEXT_OCTANT         ;ready to draw next pixel
;
; End of outer loop.
*-----------------------------------------------------------------------
; Return.
DONE:
        RETS      0                   ;
        .end

