;-------------------------------------------------------------------------;
;                                  TIGA                                   ;
;        Copyright (c) 1987-1990  Texas Instruments Incorporated.         ;
;			   All Rights Reserved				  ;
;-------------------------------------------------------------------------;
;   TIGA - Graphics Manager Extension                                     ;
;-------------------------------------------------------------------------;
;                                                                         ;
; draw_oval function                                                      ;
;                                                                         ;
;   The draw_oval function draws the outline of an ellipse given the      ;
;   minimum enclosing rectangle in which the ellipse is inscribed.  The   ;
;   ellipse is in standard position, with its major and minor axes        ;
;   parallel to the coordinate axes.  The enclosing rectangle is defined  ;
;   in terms of its width w, height h, and the x-y coordinates at its     ;
;   top left corner, (x, y). (The convention for x-y coordinates is that  ;
;   x increases from left to right, and y increases from top to bottom.)  ;
;   The outline is one pixel thick, and is drawn in the current color1.   ;
;-------------------------------------------------------------------------;
; Usage:  draw_oval(w, h, x, y);                                          ;
;                                                                         ;
; Description of stack arguments:                                         ;
;   short w, h;    /* width and height of containing rectangle */         ;
;   short x, y;    /* top left corner of containing rectangle */          ;
;                                                                         ;
; Returned in register A8:  Void (undefined).                             ;
;                                                                         ;
; Registers altered:  A8                                                  ;
;-------------------------------------------------------------------------;
; Revision history:                                                       ;
;   6/15/87...Original version written.....................Jerry Van Aken ;
;   9/15/88...Added TIGA dm, globals and dstbm check.......Graham Short   ;
;-------------------------------------------------------------------------;
;
        .title    'draw oval'
        .file     'drawoval.asm'
;
;     GLOBAL INSERT FILE
;
       .include  gsptypes.inc
       .include  gspglobs.inc          
;
;     DECLARE GLOBAL FUNCTION NAMES
;
        .globl    _draw_oval
        .globl    _dm_draw_oval
;
;     DIRECT MODE ENTRY POINT
;
_dm_draw_oval:
        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      *-A14,A8,1          ;get pointer to data area
        SETF      16,0,0
        MOVE      *A8+,A0,0           ;pop 1st argument, w
        MOVE      *A8+,A1,0           ;pop 2nd argument, h
        MOVE      *A8,A2,1            ;pop 3rd & 4th arguments, y:x
        jruc      common_ep
;
;     C-PACKET ENTRY POINT
;
_draw_oval:
        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
* Pop four arguments from stack.
        MOVE      *-A14,A0,1          ;pop 1st argument, w
        MOVE      *-A14,A1,1          ;pop 2nd argument, h
        MOVE      *-A14,A2,1          ;pop 3rd argument, x
        MOVE      *-A14,A3,1          ;pop 4th argument, y
* Convert x and y from viewport coordinates to screen coordinates.
        SLL       16,A3                     ;
        MOVY      A3,A2                     ;concatenate x and y
;
;     TWO ENTRY POINTS JOIN 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
        JRNZ      DONE                      ; if zero, dstbm is set to screen
;
;     MAIN ALGORITHM
;
        MOVE      @_env+ENVIRONMENT_XYORIGIN,A3,1   ;viewport origin displacement
        ADDXY     A3,A2                     ;convert to screen coord's
* Determine whether ellipse is higher than it is wide, or vice versa.
        MOVK      1,A8                ;set (dxh,dyh) = (1,0)
        MOVK      1,A6                ;
        SLL       16,A6               ;set (dxv,dyv) = (0,1)
        CMP       A0,A1               ;compare width w and height h
        JRNN      HIGHER1             ;jump if w <= h
* Case w>h:  Exploit symmetry by swapping w and h, and x and y.
        RL        16,A2               ;swap x and y
        MOVE      A0,A3               ;
        MOVE      A1,A0               ;
        MOVE      A3,A1               ;swap w and h
        RL        16,A8               ;change (dxh,dyh) to (0,1)
        RL        16,A6               ;change (dxv,dyv) to (1,0)
* Four-way symmetry will be used to draw 4 points of the ellipse
* simultaneously.  Initial positions of 4 points (x1,y1), (x1,y2),
* (x2,y2) and (x2,y1) are x1=x+w-w/2, y1=y+h, x2=x1+w/2 and y2=y.
HIGHER1:
        MOVE      A0,A4               ;
        SRL       1,A4                ;calculate w/2
        MOVE      A1,A5               ;copy h
        SLL       16,A5               ;shift h into 16 MSBs
        MOVE      A0,A3               ;copy w
        SUBXY     A4,A3               ;calculate w-w/2
        ADDXY     A2,A3               ;(x1,y2) = (x+w-w/2,y)
        ADDXY     A2,A4               ;(x2,y2) = (x+w/2,y)
        ADDXY     A2,A5               ;
        MOVX      A4,A5               ;(x2,y1) = (x+w/2,y+h)
        MOVX      A3,A2               ;
        MOVY      A5,A2               ;(x1,y1) = (x+w-w/2,y+h)
* If w > h, need to swap x and y halves of (x1,y1), (x1,y2), and etc.
        BTST      0,A8                ;if dxh = 0, then w > h
        JRNZ      HIGHER2             ;jump if dxh = 1 (and w <= h)
        RL        16,A2               ;swap x1 and y1
        RL        16,A3               ;swap x1 and y2
        RL        16,A4               ;swap x2 and y2
        RL        16,A5               ;swap x2 and y1
HIGHER2:
* Set up increments for horizontal, vertical and diagonal movements.
        MOVE      A6,A7               ;
        ADDXY     A8,A7               ;A7: dx = +1, dy = +1
        MOVE      A8,A9               ;
        SUBXY     A6,A9               ;A9: dx = +1, dy = -1
        CLR       A10                 ;
        SUBXY     A6,A10              ;A10: dx = 0, dy = -1
        MOVE      A10,A11             ;
        SUBXY     A8,A11              ;A11: dx = -1, dy = -1
        CLR       A12                 ;
        SUBXY     A8,A12              ;A12: dx = -1, dy = 0
        MOVE      A12,A13             ;
        ADDXY     A6,A13              ;A13: dx = -1, dy = +1
* Calculate w*w, k3 = 8*w*w, h*h and k4 = 8*h*h.
        MOVE      A0,B0               ;copy w to B file
        MOVE      A1,B2               ;copy h to B file
        SETF      16,1,1              ;set up for 16-bit multiplies
        MOVE      B0,B1               ;
        MPYU      B1,B1               ;calculate w*w
        MOVE      B1,B8               ;save copy of w*w
        SLL       3,B8                ;calculate k3 = 8*w*w
        MOVE      B2,B7               ;
        MPYU      B7,B7               ;calculate h*h
        MOVE      B7,B14              ;save copy of h*h
        SLL       3,B14               ;calculate k4 = 8*h*h
        SETF      32,0,1              ;restore field size to 32
* Calculate 4*w*w*h and 16*w*h*h to 64 bits as a precaution against
* possible arithmetic overflow.
        MOVE      B2,B10              ;copy h
        SLL       2,B10               ;calculate 4*h
        MPYU      B1,B10              ;calculate 4*w*w*h
        MOVE      B0,B12              ;copy w
        SLL       4,B12               ;calculate 16*w
        MPYU      B7,B12              ;calculate 16*w*h*h
* Will quantity 16*w*h*h overflow 32-bit register?
        LMO       B12,B12             ;measure amount of overflow
        JRZ       OKAY                ;jump if no overflow
* Need to ensure big ellipse cannot cause arithmetic overflow.
* Prescale all loop constants and variables by the same amount.
        SLL       B12,B10             ;prescale 4*w*w*h
        SRL       B12,B11             ;
        OR        B10,B11             ;
        SRL       B12,B1              ;prescale w*w
        SRL       B12,B8              ;prescale 8*w*w
        SRL       B12,B7              ;prescale h*h
        SRL       B12,B14             ;prescale 8*h*h
* Calculate initial values of loop constants k1, k2, k3 and k4.
OKAY:
        MOVE      B8,B12              ;copy k3 = 8*w*w
        SRL       1,B12               ;calculate k1 = 4*w*w
        MOVE      B14,B13             ;copy k4 = 8*h*h
        SRL       1,B13               ;calculate k2 = 4*h*h
* Calculate initial values of loop variables v1, v2, v3 and d2.
* Assume for the moment that w is odd.  If not, adjust values later.
        MOVE      B12,B2              ;copy 4*w*w
        SUB       B11,B2              ;v3 = 4*w*w-4*w*w*h
        MOVE      B12,B10             ;copy 4*w*w
        ADD       B13,B10             ;add 4*h*h
        SUB       B11,B10             ;d2 = 4*w*w+4*h*h-4*w*w*h
        MOVE      B12,B0              ;add 4*w*w
        SUB       B1,B0               ;subtract w*w
        SUB       B13,B0              ;subtract 4*h*h
        SUB       B7,B0               ;subtract h*h
        SRL       1,B11               ;2*w*w*h
        SUB       B11,B0              ;v1 = 3*w*w-2*w*w*h-5*h*h
        MOVE      B13,B1              ;v2 = 4*h*h
* The calculations above assumed w is odd.  Is w really even?
        BTST      0,A0                ;examine LSB of w
        JRNZ      LOOP                ;jump if w is odd after all
* Since w is in fact even, need to adjust values calculated above.
        ADD       B7,B0               ;add h*h
        ADD       B7,B0               ;v1 = 3*w*w-2*w*w*h+3*h*h
        CLR       B1                  ;v2 = 0
        SUB       B13,B10             ;subtract 4*h*h
        ADD       B7,B10              ;d2 = 4*w*w+h*h-4*w*w*h
* Case:  w is even.  Draw initial pixels of very skinny ellipse.
        JRLT      ENDWHILE            ;jump if d2 < 0
BACK:
        DRAV      A10,A2              ;draw (x1,y1), step vertical
        DRAV      A6,A4               ;draw (x2,y2), step vertical
        ADDXY     A10,A5              ;update (x2,y1), step vert.
        ADDXY     A6,A3               ;update (x1,y2), step vert.
        SUBK      2,A1                ;count -= 2
        JRLE      LASTDOT             ;jump if count <= 0
        ADD       B12,B0              ;v1 += k1
        ADD       B8,B2               ;v3 += k3
        ADD       B2,B10              ;d2 += v3
        JRGT      BACK                ;jump while d2 > 0
ENDWHILE:
* Case:  w is even.  Draw two pixels at top and bottom of ellipse.
        DRAV      A8,A2               ;draw (x1,y1), step horizontl
        ADDXY     A8,A3               ;(x1,y2) step horizontal
        DRAV      A12,A4              ;draw (x2,y2), step horizontl
        ADDXY     A12,A5              ;(x2,y1) step horizontal
        CMP       B0,B10              ;is d2 >= v1 ?
        JRLT      NOTDIAG             ;jump if d2 < v1
        ADDXY     A10,A2              ;(x1,y1) step vertical
        ADDXY     A6,A3               ;(x1,y2) step vertical
        ADDXY     A6,A4               ;(x2,y2) step vertical
        ADDXY     A10,A5              ;(x2,y1) step vertical
        SUBK      2,A1                ;count -= 2
        JRLE      LAST2DOTS           ;jump if count <= 0
        ADD       B12,B0              ;v1 += k1
        ADD       B8,B2               ;v3 += k3
        ADD       B2,B10              ;d2 += v3
NOTDIAG:
        SUB       B13,B0              ;v1 -= k2
        ADD       B14,B1              ;v2 += k4
        ADD       B1,B10              ;d2 += v2

* Main Loop:  Draws remainder of ellipse for all cases.
LOOP:
        CMP       B0,B10              ;is d2 < v1 ?
        JRGE      NOTHORIZ            ;jump if d2 >= v1
HORIZ:
        DRAV      A8,A2               ;draw (x1,y1), step horizontl
        DRAV      A8,A3               ;draw (x1,y2), step horizontl
        DRAV      A12,A4              ;draw (x2,y2), step horizontl
        DRAV      A12,A5              ;draw (x2,y1), step horizontl
        SUB       B13,B0              ;v1 -= k2
        ADD       B14,B1              ;v2 += k4
        ADD       B1,B10              ;d2 += v2
        CMP       B0,B10              ;is d2 < v1 ?
        JRLT      HORIZ               ;jump if d2 < v1
NOTHORIZ:
        MOVE      B10,B10             ;is d2 < 0 ?
        JRGE      VERT                ;jump if d2 >= 0
DIAG:
        DRAV      A9,A2               ;draw (x1,y1), step diagonal
        DRAV      A7,A3               ;draw (x1,y2), step diagonal
        DRAV      A13,A4              ;draw (x2,y2), step diagonal
        DRAV      A11,A5              ;draw (x2,y1), step diagonal
        SUBK      2,A1                ;count -= 2
        JRLE      LAST2DOTS           ;jump if count <= 0
        ADD       B12,B0              ;
        SUB       B13,B0              ;v1 += k1 - k2
        ADD       B14,B1              ;v2 += k4
        ADD       B8,B2               ;v3 += k3
        ADD       B1,B10              ;
        ADD       B2,B10              ;d2 += v2 + v3
        CMP       B0,B10              ;is d2 >= v1 ?
        JRLT      HORIZ               ;jump if d2 < v1
        MOVE      B10,B10             ;is d2 >= 0 ?
        JRLT      DIAG                ;jump if d2 < 0
VERT:
        DRAV      A10,A2              ;draw (x1,y1), step vertical
        DRAV      A6,A3               ;draw (x1,y2), step vertical
        DRAV      A6,A4               ;draw (x2,y2), step vertical
        DRAV      A10,A5              ;draw (x2,y1), step vertical
        SUBK      2,A1                ;count -= 2
        JRLE      LAST2DOTS           ;jump if count <= 0
        ADD       B12,B0              ;v1 += k1
        ADD       B8,B2               ;v3 += k3
        ADD       B2,B10              ;d2 += v3
        JRLT      DIAG                ;jump if d2 < 0
        JRUC      VERT                ;
* Draw final pixel of ellipse of even height and zero width.
LASTDOT:
        JRNZ      DONE                ;jump if h is odd
        DRAV      A10,A2              ;draw pixel at (x1,y1)
        JRUC      DONE                ;
* Draw two final pixels of ellipse of even height.
LAST2DOTS:
        JRNZ      DONE                ;jump if h is odd
        DRAV      A10,A2              ;draw pixel at (x1,y1)
        DRAV      A6,A4               ;draw pixel at (x2,y2)
* Restore A- and B-file registers; then return
DONE:
        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
        RETS      2                   ;return
        .end

