;-------------------------------------------------------------------------;
;                                  TIGA                                   ;
;        Copyright (c) 1987-1990  Texas Instruments Incorporated.         ;
;			   All Rights Reserved				  ;
;-------------------------------------------------------------------------;
;   TIGA - Graphics Manager Extension                                     ;
;-------------------------------------------------------------------------;
;                                                                         ;
; arc_draw function                                                       ;
;                                                                         ;
;   Draws an arc lying in one of the four quadrants of an ellipse.  (In   ;
;   the case of an arc that traverses multiple quadrants, this routine    ;
;   draws a portion of the arc lying in one of the quadrants.)  The       ;
;   arguments are passed in the form of a pointer to a structure          ;
;   (described below).                                                    ;
;                                                                         ;
;   This function is used in the implementation of the draw_ovalarc and   ;
;   draw_piearc functions.                                                ;
;-------------------------------------------------------------------------;
; Usage:  arc_draw(p);                                                    ;
;                                                                         ;
; Description of stack arguments:  32-bit pointer to structure below--    ;
;                                                                         ;
;   struct params {                                                       ;
;       short width, height;  /* dimensions of minimum enclosing          ;
;                                rectangle for ellipse from which         ;
;                                arc is taken */                          ;
;       short xnorm, ynorm;   /* coordinates normalized to 1st quadrant   ;
;                                of ellipse (to calculate v's and d's)*/  ;
;       short xcount, ycount;  /* counters for movement in x and y */     ;
;       short xcoord, ycoord;  /* starting arc coordinates */             ;
;       short deltax, deltay;  /* x and y increments */                   ;
;   } *p;                                                                 ;
;                                                                         ;
; Returned in register A8:  Void (undefined).                             ;
;                                                                         ;
; Registers altered:  A8                                                  ;
;-------------------------------------------------------------------------;
; Revision history:                                                       ;
;   2/12/87...Original version written...................Jerry Van Aken   ;
;   6/19/87...Fix STK pointer at return..................JV               ;
;   9/15/88...Convert to TIGA globals....................Graham Short     ;
;-------------------------------------------------------------------------;
;
        .title    'arc draw'
        .file     'arcdraw.asm'
;
;  INCLUDE GLOBAL DEFINITIONS
;
       .include   gsptypes.inc
       .include   gspglobs.inc
;
;     DECLARE GLOBAL FUNCTION NAME
;
        .globl    _arc_draw
;
;     ENTRY POINT
;
_arc_draw:
        SETF      16,1,0              ;
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13,A14
* Pop pointer to structure from stack.
        MOVE      *-A14,A14,1         ;Pop argument p
* Get first four variables from structure.
        MOVE      *A14+,A0,0          ;Get width w
        MOVE      *A14+,A1,0          ;Get height h
        MOVE      *A14+,A2,0          ;Get xnorm x
        MOVE      *A14+,A3,0          ;Get ynorm y
* Calculate k1, k2, and starting value for decision variable d.
        MOVE      A0,A5               ;Copy w
        SETF      16,1,1              ;(for fast 16-bit multiplies)
        MPYS      A5,A5               ;Calculate w*w
        MOVE      A5,A4               ;
        MOVE      A1,A5               ;Copy h
        MPYS      A5,A5               ;Calculate h*h
        MOVE      A2,A7               ;Copy x
        ADD       A7,A7               ;2*x
        SUB       A0,A7               ;2*x-w
        MOVE      A7,A10              ;Copy 2*x-w
        ADDK      1,A7                ;2*x+1-w
        MPYS      A1,A7               ;t1 = h*(2*x+1-w)
        MOVE      A3,A9               ;Copy y
        ADD       A9,A9               ;2*y
        SUB       A1,A9               ;2*y-h
        MOVE      A9,A12              ;Copy 2*y-h
        SUBK      2,A9                ;2*y-2-h
        MPYS      A0,A9               ;t2 = w*(2*y-2-h)
        MOVE      A9,A8               ;
        SETF      32,0,1              ;(32-bit multiplies)
        MPYS      A8,A8               ;t2*t2 to 64 bits
        MOVE      A7,A6               ;Copy t1
        MPYS      A6,A6               ;t1*t1 to 64 bits
        ADD       A9,A7               ;t1*t1+t2*t2
        ADDC      A8,A6               ;
        MOVE      A4,A8               ;Copy w*w
        MPYS      A5,A8               ;w*w*h*h to 64 bits
        SUB       A9,A7               ;d = t1*t1+t2*t2-w*w*h*h
        SUBB      A8,A6               ;to 64 bits of accuracy
        ADD       A10,A10             ;2*(2*x-w)
        MPYS      A5,A10              ;v2/2 = 2*h*h*(2*x-w)
        NEG       A12                 ;(-2*y+h)
        ADDK      1,A12               ;(-2*y+1+h)
        ADD       A12,A12             ;2*(-2*y+1+h)
        MPYS      A4,A12              ;v3/2 = 2*w*w*(-2*y+1+h)
        MOVE      A12,A8              ;Copy 2*w*w*(-2*y+1+h)
        MOVE      A13,A9              ;
        SUB       A11,A9              ;2*w*w*(-2*y+1+h)
        SUBB      A10,A8              ;- 2*h*h*(2*x-w)
        MOVE      A5,A3               ;Copy h*h
        ADD       A4,A3               ;w*w+h*h
        SLL       2,A4                ;k1 = 4*w*w
        SLL       2,A5                ;k2 = 4*h*h
        SUB       A5,A3               ;w*w - 3*h*h
        SUBB      A2,A2               ;(fill reg. with sign bit)
        ADD       A3,A9               ;v1 = 2*w*w*(-2*y+1+h)
        ADDC      A2,A8               ;-2*h*h*(2*x-w)+w*w-3*h*h
        ADD       A11,A11             ;v2 = 2*h*h*(2*x-w)
        ADDC      A10,A10             ;
        ADD       A13,A13             ;v3 = 2*w*w*(-2*y+1+h)
        ADDC      A12,A12             ;
* Is ellipse's width or height more likely to cause arithmetic overflow?
        CMP       A0,A1               ;Is w <= h ?
        JRLT      AD01                ;Jump if w > h
* Case w <= h:  Will quantity 16*w*h*h overflow 32-bit register?
        MOVE      A0,A2               ;Copy w
        SLL       2,A2                ;4*w
        MPYS      A5,A2               ;16*w*h*h to 64 bits
        LMO       A2,A2               ;Measure amount of overflow
        JRZ       AD03                ;Jump if no overflow
        JRUC      AD02                ;Need to prescale variables
* Case w > h:  Will quantity 16*h*w*w overflow 32-bit register?
AD01:
        MOVE      A1,A2               ;Copy h
        SLL       2,A2                ;4*h
        MPYS      A4,A2               ;16*h*w*w to 64 bits
        LMO       A2,A2               ;Measure amount of overflow
        JRZ       AD03                ;Jump if no overflow
* Need to prescale all loop constants and variables by same amount.
AD02:
        SLL       A2,A6               ;Prescale d
        SRL       A2,A7               ;
        OR        A6,A7               ;
        SLL       A2,A8               ;Prescale v1
        SRL       A2,A9               ;
        OR        A8,A9               ;
        SLL       A2,A10              ;Prescale v2
        SRL       A2,A11              ;
        OR        A10,A11             ;
        SLL       A2,A12              ;Prescale v3
        SRL       A2,A13              ;
        OR        A12,A13             ;
        SRL       A2,A4               ;Prescale k1 = 4*w*w
        SRL       A2,A5               ;Prescale k2 = 4*h*h
* Set up xy addresses, increments and counters.
AD03:
        MOVE      A4,A10                    ;
        ADD       A10,A10                   ;k3 = 2*k1 = 8*w*w
        MOVE      A5,A12                    ;
        ADD       A12,A12                   ;k4 = 2*k2 = 8*h*h
        MOVE      *A14+,A6,0                ;Get xcount
        ABS       A6                        ;xcount = |xs-xe|
        MOVE      *A14+,A8,0                ;Get ycount
        ABS       A8                        ;ycount = |ys-ye|
        MOVE      *A14+,A0,1                ;Get (xcoord,ycoord)
        MOVE      @_env+ENVIRONMENT_XYORIGIN,A1,1   ;(Viewport origin disp's)
        ADDXY     A1,A0                     ;Convert to screen coord's
        MOVE      *A14+,A2,1                ;Get (deltax,deltay)
        CLR       A1                        ;
        MOVX      A2,A1                     ;Calculate(deltax,0)
        CLR       A3                        ;
        MOVY      A2,A3                     ;Calculate(0,deltay)
* Begin main loop.  Draw one pixel of arc per iteration.
LOOP:
        CMP       A9,A7               ;Is d < v1 ?
        JRGE      AD04                ;Jump if d >= v1
*------ Horizontal Move ------
        DEC       A6                  ;--xcount
        JRLT      AD06                ;Jump if xcount < 0
        DRAV      A1,A0               ;Draw pixel, horizontal move
        SUB       A5,A9               ;v1 -= k2
        ADD       A12,A11             ;v2 += k4
        ADD       A11,A7              ;d += v2
        JRUC      LOOP                ;
AD04:
        MOVE      A9,A9               ;test for very flat ellipse
        JRGT      AD09                ;jump if v1 > 0 (flat indeed)
        DEC       A8                  ;--ycount
        JRLT      AD09                ;Jump if ycount < 0
        MOVE      A7,A7               ;Is d < 0 ?
        JRGE      AD05                ;Jump if d >= 0
*------ Diagonal Move ------
        DEC       A6                  ;--xcount
        JRLT      AD07                ;Jump if xcount < 0
        DRAV      A2,A0               ;Draw pixel, diagonal move
        ADD       A4,A9               ;v1 += k1 - k2
        SUB       A5,A9               ;
        ADD       A12,A11             ;v2 += k4
        ADD       A10,A13             ;v3 += k3
        ADD       A11,A7              ;d += v2 + v3
        ADD       A13,A7              ;
        JRUC      LOOP                ;
AD05:
*------ Vertical Move ------
        DRAV      A3,A0               ;Drawpixel, vertical move
        ADD       A4,A9               ;v1 += k1
        ADD       A10,A13             ;v3 += k3
        ADD       A13,A7              ;d += v3
        JRUC      LOOP                ;
* End of main loop.  Handle special end-of-arc conditions below.
AD06:
        DEC       A8                  ;--ycount
        JRLT      AD09
AD07:
        INC       A8                  ;++ycount (DSJS compensation)
AD08:
        DRAV      A3,A0               ;Draw pixel, vertical move
        DSJS      A8,AD08             ;Loop if --ycount > 0
        JRUC      DONE                ;
* Handle special case of height h = 0 (a very flat ellipse).
AD09:
        INC       A6                  ;++xcount
        JRLE      DONE                ;done if xcount <= 0
AD10:
        DRAV      A1,A0               ;Draw pixel, horizontal move
        DSJ       A6,AD10             ;Loop while xcount != 0
* Restore registers and return to calling routine.
DONE:
        MMFM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13,A14
        SUBK      32,A14              ;Fix STK pointer
        RETS      2                   ;Return
        .end
