;-------------------------------------------------------------------------;
;                                  TIGA                                   ;
;        Copyright (c) 1987-1990  Texas Instruments Incorporated.         ;
;			   All Rights Reserved				  ;
;-------------------------------------------------------------------------;
;   TIGA - Graphics Manager Extension                                     ;
;-------------------------------------------------------------------------;
;                                                                         ;
; arc_pen 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       ;
;   arc is drawn using a rectangular drawing pen.  The arguments are      ;
;   passed in the form of a pointer to a structure (described below).     ;
;                                                                         ;
;   This function is used in the implementation of the pen_ovalarc,       ;
;   patnpen_ovalarc, pen_piearc and patnpen_piearc functions.             ;
;-------------------------------------------------------------------------;
; Usage:  arc_pen(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 */                   ;
;       short patn;  /* 1 = pattern fill, 0 = solid fill */               ;
;   } *p;                                                                 ;
;                                                                         ;
; Returned in register A8:  Void (undefined).                             ;
;                                                                         ;
; Registers altered:  A8                                                  ;
;-------------------------------------------------------------------------;
; Revision history:                                                       ;
;   2/24/87...Original version written...................Jerry Van Aken   ;
;   6/19/87...Modified pixel selection for fills.........JV               ;
;-------------------------------------------------------------------------;
;
        .title    'arc pen'
        .file     'arcpen.asm'
;
;     DECLARE GLOBAL FUNCTION NAME
;
        .globl    _arc_pen
;
;  INCLUDE GLOBAL DEFINITIONS
;
       .include   gsptypes.inc
       .include   gspglobs.inc
       .include   gspreg.inc
;
;     ENTRY POINT
;
_arc_pen:
        SETF      16,1,0              ;
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13,A14
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
* Pop pointer to structure from stack.
        MOVE      *-STK,A14,1         ;Pop argument pointer 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      A1,A5               ;Copy h
        SETF      16,0,1              ;(for fast 16-bit multiplies)
        MPYS      A5,A5               ;Calculate h*h
        MOVE      A5,A4               ;Save copy of h*h
        MOVE      A0,A5               ;Copy w
        MPYS      A5,A5               ;Calculate w*w
        MOVE      A2,A7               ;Copy x
        ADD       A7,A7               ;2*x
        SUB       A0,A7               ;2*x-w
        MOVE      A7,A8               ;Copy 2*x-w
        ADDK      1,A7                ;2*x+1-w
        MPYS      A1,A7               ;t1 = h*(2*x+1-w)
        MOVE      A3,A13              ;Copy y
        ADD       A13,A13             ;2*y
        SUB       A1,A13              ;2*y-h
        MOVE      A13,A10             ;Copy 2*y-h
        DEC       A13                 ;2*y-1-h
        MPYS      A0,A13              ;t2 = w*(2*y-2-h)
        MOVE      A13,A12             ;
        SETF      32,0,1              ;(32-bit multiplies)
        MPYS      A12,A12             ;t2*t2 to 64 bits
        MOVE      A7,A6               ;Copy t1
        MPYS      A6,A6               ;t1*t1 to 64 bits
        ADD       A13,A7              ;t1*t1+t2*t2
        ADDC      A12,A6              ;
        MOVE      A4,A12              ;Copy w*w
        MPYS      A5,A12              ;w*w*h*h to 64 bits
        SUB       A13,A7              ;d = t1*t1+t2*t2-w*w*h*h
        SUBB      A12,A6              ;to 64 bits of accuracy
        SLL       2,A8                ;
        MPYS      A4,A8               ;v1 = h*h*(8*x-4*w)
        NEG       A10                 ;
        SLL       2,A10               ;
        MPYS      A5,A10              ;v2 = w*w*(-8*y+4*h)
        SLL       3,A4                ;k1 = 8*h*h
        SLL       3,A5                ;k2 = 8*w*w
* 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      A4,A2               ;32*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      A5,A2               ;32*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             ;
        SRL       A2,A4               ;Prescale k1 = 8*h*h
        SRL       A2,A5               ;Prescale k2 = 8*w*w
* Set up xy addresses, increments and counters.
AD03:
        MOVE      *A14+,A13,0                 ;Get xcount
        ABS       A13                         ;
        MOVE      A13,B0                      ;cx = xcount
        MOVE      *A14+,A2,0                  ;Get ycount
        ABS       A2                          ;
        MOVE      A2,B1                       ;cy = ycount
        MOVE      *A14+,A0,1                  ;Get (xcoord,ycoord) = (x,y)
        MOVE      @_env+ENVIRONMENT_XYORIGIN,A1,1     ;(Viewport origin disp's)
        ADDXY     A1,A0                       ;Convert to screen coord's
        MOVE      *A14+,A1,0                  ;Get deltax (= dxA)
        ZEXT      A1,0                        ;(Set y half to zero)
        MOVE      @_env+ENVIRONMENT_PENSIZE,B10,1     ;Get pen height
        SRL       16,B10
        MOVE      *A14+,A3,0                  ;Get deltay (= dy)
        JRNN      AD04                        ;Jump if dy == +1
        MOVE      B10,A6                      ;Copy pen height
        SUBK      1,A6                        ;
        SLL       16,A6                       ;
        ADDXY     A6,A0                       ;y += penhigh - 1
AD04:
        SLL       16,A3                       ;Move deltay to y half of A3
        MOVE      *A14,A6,0                   ;Get patn (=1 if pattern)
        JRZ       AD05                        ;Jump if patn=0 (solid fill)
        move      @_pattern+PATTERN_HSRV,A6,1    ;Load address of pattern func  
AD05:
        MOVE      @_env+ENVIRONMENT_PENSIZE,B7,1      ;Get pen width (= wfill)
        SLL       16,B7
        SRL       16,B7
        ORI       010000h,B7                  ;DYDX = (wfill, +1)
        MOVE      B10,A14                     ;save copy of penhigh
* Make initial inner arc variables same as initial outer arc variables.
        MOVE      A7,A8                       ;dB = dA (B=inner, A=outer)
        MOVE      A9,A10                      ;v1B = v1A
        MOVE      A11,A12                     ;v2B = v2A

* Determine which of two cases the arc represents.  Draw the arc.
        CMP       B10,B1              ;Is cy >= penhigh ?
        JRN       AD11                ;Jump if cy < penhigh
* Case 1:  y extent of arc is greater than or equal to penhigh.
        MOVE      B10,B1              ;cy = penhigh
        CALLR     TOP_LOOP            ;Draw top of arc
        MOVE      B1,B1               ;Is cy > 0 ?
        JRLE      AD08                ;Jump if cy == 0
        MOVE      A6,A6               ;Is patn == 0 ? (solid fill)
        JRNZ      AD07                ;Jump if pattern fill
AD06:
        MOVE      A0,B2               ;Load destination address
        FILL      XY                  ;Solid fill horizontal line
        ADDXY     A3,A0               ;y += dy
        DSJS      B1,AD06             ;Loop while --cy > 0
        JRUC      AD08                ;
AD07:
        MOVE      A0,B2               ;Load destination address
        CALL      A6                  ;Call _patn_line subroutine
        ADDXY     A3,A0               ;y += dy
        DSJS      B1,AD07             ;Loop while --cy > 0
AD08:
        MOVE      A2,B1               ;Copy ycount
        MOVE      A14,B10             ;Copy penhigh
        SUB       B10,B1              ;cy = ycount - penhigh
        MOVK      1,A2                ;
        ADDXY     A1,A2               ;dxB = dxA + 1
        MOVE      B0,B0               ;Is cx > 0 ?
        JRLE      AD10                ;Jump if cx <= 0
        CALLR     MIDDLE_LOOP         ;Draw middle of arc
        MOVE      B0,B0               ;cx > 0 ?
        JRLE      AD10                ;Jump if cx == 0
        ADD       B0,B7               ;wfill += cx
AD09:
        ADDXY     A1,A0               ;x += dxA
        DSJS      B0,AD09             ;Loop while --cx > 0
AD10:
        MOVE      @_env+ENVIRONMENT_PENSIZE,B10,1     ;Get width of pen
        SLL       16,B10
        SRL       16,B10
        MOVX      B7,B0                       ;Copy wfill
        SUB       B10,B0                      ;cx = wfill - penwide
        MOVE      A14,B10                     ;Get height of pen
        ADD       B10,B1                      ;cy += penhigh
        CALLR     BOTTOM_LOOP                 ;Draw bottom of arc
        JRUC      DONE                        ;Arc is finished!
* Case 2:  y extent of arc is less than penhigh.
AD11:
        MOVE      B1,B1               ;Is cy == 0 ?
        JRNZ      AD15                ;Jump if cy > 0
        MOVE      B10,B1              ;cy = penhigh
        ADDXY     B0,B7               ;wfill = cx + penwide
        BTST      15,A1               ;Is dxA == -1 ?
        JRZ       AD12                ;Jump if dxA == +1
        MOVE      B0,A1               ;On left side of ellipse
        SUBXY     A1,A0               ;x -= cx (at left of fill)
AD12:
        MOVE      A6,A6               ;Is patn == 0 ? (solid fill)
        JRNZ      AD14                ;Jump if pattern fill
AD13:
        MOVE      A0,B2               ;Load destination address
        FILL      XY                  ;Solid fill horizontal line
        ADDXY     A3,A0               ;y += dy
        DSJS      B1,AD13             ;Loop while --cy > 0
        JRUC      DONE                ;Arc is finished!
AD14:
        MOVE      A0,B2               ;Load destination address
        CALL      A6                  ;Call _patn_line subroutine
        ADDXY     A3,A0               ;y += dy
        DSJS      B1,AD14             ;Loop while --cy > 0
        JRUC      DONE                ;Arc is finished!
AD15:
        CALLR     TOP_LOOP            ;Draw top of arc
        MOVE      B0,B0               ;cx > 0 ?
        JRLE      AD17                ;Jump if cx == 0
        ADDXY     B0,B7               ;wfill += cx
AD16:
        ADDXY     A1,A0               ;x += dxA
        DSJS      B0,AD16             ;Loop while --cx > 0
AD17:
        MOVE      A14,B10             ;Get height of pen
        ADD       B10,B1              ;
        MOVE      A2,B10              ;
        SUB       B10,B1              ;cy += penhigh - ycount
        JRLE      AD20                ;Jump if cy == 0
        MOVE      A6,A6               ;Is patn == 0 ? (solid fill)
        JRNZ      AD19                ;Jump if pattern fill
AD18:
        MOVE      A0,B2               ;Load destination address
        FILL      XY                  ;Solid fill horizontal line
        ADDXY     A3,A0               ;y += dy
        DSJS      B1,AD18             ;Loop while --cy > 0
        JRUC      AD20                ;
AD19:
        MOVE      A0,B2               ;Load destination address
        CALL      A6                  ;Call _patn_line subroutine
        ADDXY     A3,A0               ;y += dy
        DSJS      B1,AD19             ;Loop while --cy > 0
AD20:
        MOVE      A13,B0              ;cx = xcount
        MOVE      A2,B1               ;cy = ycount
        MOVK      1,A2                ;
        ADDXY     A1,A2               ;dxB = dxA + 1
        CALLR     BOTTOM_LOOP         ;Draw bottom of arc
* Restore registers and return to calling routine.
DONE:
        MMFM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        MMFM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13,A14
        RETS      2                   ;Return

*-----------------------------------------------------------------------
* 1st region of arc:  Horizontal fill lines in this region are bounded
* on one end by the outer edge of the arc, and on the other end by an
* imaginary vertical line through the center of the ellipse.
*

TOP_LOOP:

        MOVE      A7,A7               ;Is dA < 0 ?
        JRNN      TL02                ;Jump if dA >= 0
* Search horizontally for end of outer arc on current scan line.
TL01:
        DEC       B0                  ;--cx
        JRN       TL06                ;Jump if cx < 0
        ADDXY     A1,A0               ;x += dxA
        ADDK      1,B7                ;++wfill
        ADD       A4,A9               ;v1A += k1
        ADD       A9,A7               ;dA += v1A
        JRN       TL01                ;Loop while dA < 0
* Fill more scan lines?  (Stop when y count reaches zero.)
TL02:
        DEC       B1                  ;Is --cy >= 0 ?
        JRN       TL07                ;Jump if cy < 0
        MOVE      A0,B2               ;Load destination address
        MOVE      A6,A6               ;Solid or pattern fill?
        JRZ       TL03                ;Jump if solid fill
        CALL      A6                  ;Pattern fill scan line
        JRUC      TL04                ;
TL03:
        FILL      XY                  ;Solid fill scan line
TL04:
* Move vertically to next scan line.
        ADDXY     A3,A0               ;y += dy (advance in y)
        ADD       A5,A11              ;v2A += k2
        ADD       A11,A7              ;dA += v2A
        JRN       TL01                ;If dA < 0, search horizontal
        JRUC      TL02                ;Else step vertical again
* Take care of end conditions.
TL06:
        CLR       B0                  ;cx = 0
        RETS      0                   ;Return
TL07:
        CLR       B1                  ;cy = 0
        RETS      0                   ;Return

*-----------------------------------------------------------------------
* 2nd region of arc:  Horizontal fill lines in this region are bounded
* on one end by the outer edge of the arc, and on the other end by the
* inner edge of the arc.
*
MIDDLE_LOOP:
        MOVE      A7,A7               ;Is dA < 0 ?
        JRNN      ML01                ;Jump if dA >= 0
* Search horizontally for edge of outer arc on current scan line.
ML00:
        DEC       B0                  ;--cx
        JRN       ML09                ;Jump if cx < 0
        ADDXY     A1,A0               ;x += dxA
        INC       B7                  ;++wfill
        ADD       A4,A9               ;v1A += k1
        ADD       A9,A7               ;dA += v1A
        JRN       ML00                ;Loop while dA < 0
* Fill more scan lines?  (Stop when y count reaches zero.)
ML01:
        DEC       B1                  ;Is --cy >= 0 ?
        JRN       ML10                ;Jump if cy < 0

* Search for edge of inner arc on current scan line.
ML02:
        MOVE      A8,A8               ;Is dB < 0 ?
        JRNN      ML03                ;Jump if dB >= 0
ML02A:
        ADDXY     A2,A0               ;x += dxB
        DEC       B7                  ;--wfill
        ADD       A4,A10              ;v1B += k1
        ADD       A10,A8              ;dB += v1B
        JRN       ML02A               ;
ML03:

* Fill current scan line, then move up or down to next scan line.
        MOVE      A0,B2               ;Load destination address
        MOVE      A6,A6               ;Solid or pattern fill?
        JRZ       ML05                ;Jump if solid fill
        CALL      A6                  ;Pattern fill scan line
        JRUC      ML06                ;
ML05:
        FILL      XY                  ;Solid fill scan line
ML06:
* Move vertically to next scan line.
        ADDXY     A3,A0               ;y += dy (advance in y)
        ADD       A5,A12              ;v2B += k2
        ADD       A12,A8              ;dB += v2B
        ADD       A5,A11              ;v2A += k2
        ADD       A11,A7              ;dA += v2A
        JRN       ML00                ;To top of loop if dA < 0
        JRUC      ML01                ;Else ready for fill again
* Take care of end conditions.
ML09:
        CLR       B0                  ;cx = 0
        RETS      0                   ;Return
ML10:
        CLR       B1                  ;cy = 0
        RETS      0                   ;Return

*-----------------------------------------------------------------------
* 3rd region of arc:  Horizontal fill lines in this region are bounded
* on one end by the inner edge of the arc, and on the other end by the
* right or left side of the ellipse.
*

BOTTOM_LOOP:

        DEC       B1                  ;Is --cy >= 0 ?
        JRN       BL08                ;Jump if cy < 0
* Search for end of inner arc on previous scan line.
BL01:
        MOVE      A8,A8               ;Is dB < 0 ?
        JRNN      BL02                ;Jump if dB >= 0
BL01A:
        DEC       B0                  ;--cx
        JRN       BL05                ;Jump if cx < 0
        ADDXY     A2,A0               ;x += dxB
        SUBK      1,B7                ;--wfill
        ADD       A4,A10              ;v1B += k1
        ADD       A10,A8              ;dB += v1B
        JRN       BL01A               ;Do search loop while dB < 0
* Move inner arc pointer to current scan line.
BL02:
* Move vertically to next scan line.
        ADD       A5,A12              ;v2B += k2
        ADD       A12,A8              ;dB += v2B
* Fill current scan line with either pattern or solid color.
        MOVE      A0,B2               ;Load destination address
        MOVE      A6,A6               ;Solid or pattern fill?
        JRZ       BL04                ;Jump if solid fill
        CALL      A6                  ;Pattern fill scan line
        ADDXY     A3,A0               ;y += dy (advance in y)
        JRUC      BOTTOM_LOOP         ;Loop again
BL04:
        FILL      XY                  ;Solid fill scan line
        ADDXY     A3,A0               ;y += dy (advance in y)
        JRUC      BOTTOM_LOOP         ;Loop again
* Take care of end conditions.
* Fill remaining scan lines; stop when y count reaches zero.
BL05:
        ADDK      1,B1                ;++cy
        MOVE      A6,A6               ;Solid or pattern fill?
        JRNZ      BL07                ;Jump if pattern fill
BL06:
        MOVE      A0,B2               ;Load destination address
        FILL      XY                  ;Solid fill scan line
        ADDXY     A3,A0               ;y += dy (advance in y)
        DSJS      B1,BL06             ;Loop while --cy > 0
        RETS      0                   ;Return
BL07:
        MOVE      A0,B2               ;Load destination address
        CALL      A6                  ;Pattern fill scan line
        ADDXY     A3,A0               ;y += dy (advance in y)
        DSJS      B1,BL07             ;Loop while --cy > 0
BL08:
        RETS      0                   ;Return
        .end

