;-------------------------------------------------------------------------;
;                                  TIGA                                   ;
;        Copyright (c) 1987-1990  Texas Instruments Incorporated.         ;
;			   All Rights Reserved				  ;
;-------------------------------------------------------------------------;
;   TIGA - Graphics Manager Extension                                     ;
;-------------------------------------------------------------------------;
;                                                                         ;
; frame_oval and patnframe_oval functions                                 ;
;                                                                         ;
;   Draw an oval shaped frame.  The frame consists of a filled region     ;
;   between two concentric ellipses.  The outer oval is described by      ;
;   the minimum enclosing rectangle in which it can be circumscribed.     ;
;   The rectangle is specified in terms of its width, height, and the     ;
;   coordinates at its top left corner.  The thickness of the frame in    ;
;   the x and y dimensions is given by two additional arguments, which    ;
;   specify the horizontal and vertical distances between the outer and   ;
;   inner ellipses.                                                       ;
;                                                                         ;
;   In the case of the frame_oval function, the elliptical frame is       ;
;   filled with solid color 1.  In the case of the patnframe_oval         ;
;   function, the elliptical frame is filled with the currently selected  ;
;   pattern in colors 0 and 1.                                            ;
;-------------------------------------------------------------------------;
; Usage:  frame_oval(w, h, xleft, ytop, dx, dy);                          ;
;                                                                         ;
; Description of stack arguments:                                         ;
;   int w, h;         /* width and height of enclosing rectangle */       ;
;   int xleft, ytop;  /* coordinates at top left of encl. rect. */        ;
;   int dx, dy;       /* horizontal and vertical thicknesses of frame */  ;
;                                                                         ;
; Returned in register A8:  Void (undefined).                             ;
;                                                                         ;
; Registers altered:  A8                                                  ;
;-------------------------------------------------------------------------;
; Revision history:                                                       ;
;   3/16/87...Original version written...................Jerry Van Aken   ;
;   9/16/88...Changed to TIGA direct mode, globals.......Graham Short     ;
;-------------------------------------------------------------------------;
;
        .title    'elliptical frame'
        .file     'framoval.asm'
;
;  INCLUDE GLOBAL DEFINITIONS
;
       .include   gsptypes.inc
       .include   gspglobs.inc          
;
;     DECLARE GLOBAL FUNCTION NAME
;
        .globl    _frame_oval, _dm_frame_oval
        .globl    _patnframe_oval, _dm_patnframe_oval
;
;     C-PACKET ENTRY POINTS
;
_frame_oval:
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13
        CLR       B0                  ;set flag for solid fill
        JRUC      CP_EP
;
_patnframe_oval:
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13
        move      @_pattern+PATTERN_HSRV,B0,1   ;subroutine for pattern fill
CP_EP:
* Pop six 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, xleft
        MOVE      *-A14,A3,1          ;pop 4th argument, ytop
        MOVE      *-A14,A4,1          ;pop 5th argument, dx
        MOVE      *-A14,A5,1          ;pop 6th argument, dy
        jruc      common_ep
;
;     DIRECT MODE ENTRY POINTS
;
_dm_frame_oval:
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13
        CLR       B0                  ;set flag for solid fill
        JRUC      DM_EP
;
_dm_patnframe_oval:
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13
        move      @_pattern+PATTERN_HSRV,B0,1   ;subroutine for pattern fill
DM_EP:
* Get six arguments from data area
        MOVE      *-A14,A8,1          ;get pointer to data area
        SETF      16,1,0              ;
        MOVE      *A8+,A0,0           ;get 1st argument, w
        MOVE      *A8+,A1,0           ;get 2nd argument, h
        MOVE      *A8+,A2,0           ;get 3rd argument, xleft
        MOVE      *A8+,A3,0           ;get 4th argument, ytop
        MOVE      *A8+,A4,0           ;get 5th argument, dx
        MOVE      *A8 ,A5,0           ;get 6th argument, dy
;
;     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      SFDONE                    ; if zero, dstbm is set to screen
;
;     MAIN ALGORITHM
;
        MOVE      A14,*-SP,1          ;save STK pointer
* Calculate width wB and height hB of inner ellipse.
        SETF      16,1,0              ;
        ADD       A4,A4               ;2*dx
        ZEXT      A4,0                ;
        ADD       A5,A5               ;2*dy
        ZEXT      A5,0                ;
        MOVE      A5,B1               ;initialize 1st loop counter

        MOVE      A1,A8               ;
        SUB       A5,A8               ;hB = hA - 2*dy
        JRGT      F01                 ;jump if hB > 0
        MOVE      A1,B1               ;1st loop counter = height
F01:
        MOVE      A0,A6               ;
        SUB       A4,A6               ;wB = wA - 2*dx
        JRGT      F02                 ;jump if wB > 0
        MOVE      A1,B1               ;1st loop counter = height
        SRL       1,A8                ;
        SUBB      A8,A8               ;set hB<=0 as 'no hole' flag
F02:
* Calculate starting x1, x2, y1 and y2 values.
        ADD       A2,A2                       ;
        ADD       A0,A2                       ;
        SRL       1,A2                        ;initial x1 = xleft + w/2
        CLR       A4                          ;
        ADDC      A2,A4                       ;initial x2 = xleft + (w+1)/2
        SLL       16,A3                       ;concatenate y1, x1
        MOVY      A3,A2                       ;where y1 = ytop
        MOVE      A1,A3                       ;
        SUBK      1,A3                        ;
        SLL       16,A3                       ;concatenate y1, x1
        ADDXY     A2,A3                       ;where y1 = ytop + h - 1
        MOVE      @_env+ENVIRONMENT_XYORIGIN,A5,1     ;viewport origin displacement
        ADDXY     A5,A2                       ;screen relative coordinates
        ADDXY     A5,A3                       ;
        ADDXY     A5,A4                       ;
* Calculate initial values of ellipse algorithm control parameters.
        CALLR     OVAL_PARAMS         ;
* Initialize x and y movement increments.
        MOVK      1,A14               ;x increment = 0::1
        MOVI      010000h,A1          ;y increment = 1::0
        MOVE      A1,B7               ;initial fill width wfill = 0
        BTST      0,A0                ;is ellipse width odd ?
        JRZ       F03                 ;jump if width is even
        ADDK      1,B7                ;set wfill = 1 instead
F03:
* Decide whether to do solid fill or pattern fill.
        MOVE      B0,B0               ;
        JRNZ      PATNFILL            ;jump if pattern fill

*-----------------------------------------------------------------------
*                       SOLID FILLED OVAL FRAME
*-----------------------------------------------------------------------
* Main Loop #1:  Draw portion of solid-filled ellipse above/below hole.
*
        MOVE      A13,A13             ;check sign of dA
        JRNN      SF2                 ;jump if dA >= 0
* Step in horizontal direction
SF1:
        SUBXY     A14,A2              ;--x1
        SUBXY     A14,A3              ;
        ADDK      2,B7                ;wfill += 2
        ADD       A5,A9               ;v1A += k1A
        ADD       A9,A13              ;dA += v1A
        JRN       SF1                 ;loop while dA < 0
SF2:
* Decrement count; if negative, break out of loop.
        SUBK      2,B1                ;ycount -= 2
        JRN       SF3                 ;if ycount < 0, exit loop
* Fill two horizontal lines in top and bottom halves of ellipse.
        MOVE      A2,B2               ;DADDR = y1::x1
        FILL      XY                  ;fill line in top of oval
        MOVE      A3,B2               ;DADDR = y2::x1
        FILL      XY                  ;fill line in bottom half
* Move vertically to next fill line.
        ADDXY     A1,A2               ;++y1
        SUBXY     A1,A3               ;--y2
        ADD       A7,A11              ;v2A += k2A
        ADD       A11,A13             ;dA += v2A
        JRN       SF1                 ;jump if dA < 0
        JRUC      SF2                 ;
SF3:
*--- End of 1st loop ---
* If doughnut has no hole, finish ellipse fill and return.
        MOVE      A8,A1               ;move hB
        JRGT      SF4                 ;jump if hB > 0
        BTST      0,A1                ;is height odd ?
        JRZ       SFDONE              ;jump if height is even
        MOVE      A2,B2               ;DADDR = y1::x1
        FILL      XY                  ;fill strip thru center
        JRUC      SFDONE              ;done
SF4:
* Otherwise, prepare to fill around hole in doughnut.
        MOVE      A6,A0               ;move wB
        MOVX      A4,A3               ;move x2
        MOVE      A9,A8               ;move v1A
        MOVE      A7,A6               ;move k2A
        MOVE      A5,A4               ;move k1A
        MOVE      A11,B10             ;move v2A
        MOVE      A13,B12             ;move dA
* Calculate initial values of ellipse algorithm control parameters.
        CALLR     OVAL_PARAMS         ;
* Get ready to enter 2nd loop to fill around hole.
        MOVE      A1,B1               ;initial ycount = hB
        MOVE      B10,A10             ;move v2A
        MOVE      B12,A12             ;move dA
        SRL       1,B7                ;
        ADDI      08000h,B7           ;wfill >>= 1
        MOVK      1,A14               ;x increment = 0::1
        MOVI      010000h,A1          ;y increment = 1::0
*-----------------------------------------------------------------------
* Main Loop #2:  Draw portion of solid-filled ellipse beside hole.
*
        MOVE      A13,A13             ;check sign of dB
        JRNN      SF6                 ;jump if dB >= 0
* Step in horizontal direction
SF5:
        ADDXY     A14,A3              ;++x2
        SUBK      1,B7                ;--wfill
        ADD       A5,A9               ;v1B += k1B
        ADD       A9,A13              ;dB += v1B
        JRN       SF5                 ;
SF6:
* Decrement count; if negative, break out of loop.
        SUBK      2,B1                ;ycount -= 2
        JRN       SF9                 ;if ycount < 0, exit loop
* Fill two horizontal lines in top and bottom halves of ellipse.
        MOVE      A2,B2               ;DADDR = y1::x1
        FILL      XY                  ;fill line in top left
        MOVE      A2,A0               ;
        MOVY      A3,A0               ;
        MOVE      A0,B2               ;DADDR = y2::x1
        FILL      XY                  ;fill line in bottom left
        MOVE      A2,A0               ;
        MOVX      A3,A0               ;
        MOVE      A0,B2               ;DADDR = y1::x2
        FILL      XY                  ;fill line in top right
        MOVE      A3,B2               ;DADDR = y2::x2
        FILL      XY                  ;fill line in bottom right
* Move vertically to next fill line.
        ADDXY     A1,A2               ;++y1
        SUBXY     A1,A3               ;--y2
        ADD       A6,A10              ;v2A += k2A
        ADD       A10,A12             ;dA += v2A

        JRNN      SF8                 ;jump if dA >= 0
* Step in horizontal direction
SF7:
        SUBXY     A14,A2              ;--x1
        ADDK      1,B7                ;++wfill
        ADD       A4,A8               ;v1A += k1A
        ADD       A8,A12              ;dA += v1A
        JRN       SF7                 ;loop while dA < 0
SF8:
        ADD       A7,A11              ;v2B += k2B
        ADD       A11,A13             ;dB += v2B
        JRN       SF5                 ;loop again (dB < 0)
        JRUC      SF6                 ;(dB >= 0)
SF9:
*--- End of 2nd loop ---
        BTST      0,B1                ;is ycount odd ?
        JRZ       SFDONE              ;done if ycount is even
        MOVE      A2,B2               ;DADDR = y1::x1
        FILL      XY                  ;fill left middle of frame
        MOVE      A3,B2               ;DADDR = y2::x2
        FILL      XY                  ;fill right middle of frame

*-----------------------------------------------------------------------
* Restore registers and return.
SFDONE:
        MMFM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13,A14
        MMFM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        RETS      2                   ;return

*-----------------------------------------------------------------------
*                      PATTERN FILLED OVAL FRAME
*-----------------------------------------------------------------------
* Main Loop #1:  Draw portion of pattern-filled ellipse above/below hole
*
PATNFILL:
        MOVE      A13,A13             ;check sign of dA
        JRNN      PF2                 ;jump if dA >= 0
* Step in horizontal direction
PF1:
        SUBXY     A14,A2              ;--x1
        SUBXY     A14,A3              ;
        ADDK      2,B7                ;wfill += 2
        ADD       A5,A9               ;v1A += k1A
        ADD       A9,A13              ;dA += v1A
        JRN       PF1                 ;loop while dA < 0
PF2:
* Decrement count; if negative, break out of loop.
        SUBK      2,B1                ;ycount -= 2
        JRN       PF3                 ;if ycount < 0, exit loop
* Fill two horizontal lines in top and bottom halves of ellipse.
        MOVE      A2,B2               ;DADDR = y1::x1
        CALL      B0                  ;fill line in top of oval
        MOVE      A3,B2               ;DADDR = y2::x1
        CALL      B0                  ;fill line in bottom half
* Move vertically to next fill line.
        ADDXY     A1,A2               ;++y1
        SUBXY     A1,A3               ;--y2
        ADD       A7,A11              ;v2A += k2A
        ADD       A11,A13             ;dA += v2A
        JRN       PF1                 ;jump if dA < 0
        JRUC      PF2                 ;
PF3:
*--- End of 1st loop ---
* If doughnut has no hole, finish ellipse fill and return.
        MOVE      A8,A1               ;move hB
        JRGT      PF4                 ;jump if hB > 0
        BTST      0,A1                ;is height odd ?
        JRZ       PFDONE              ;jump if height is even
        MOVE      A2,B2               ;DADDR = y1::x1
        CALL      B0                  ;fill strip thru center
        JRUC      PFDONE              ;done
PF4:
* Otherwise, prepare to fill around hole in doughnut.
        MOVE      A6,A0               ;move wB
        MOVX      A4,A3               ;move x2
        MOVE      A9,A8               ;move v1A
        MOVE      A7,A6               ;move k2A
        MOVE      A5,A4               ;move k1A
        MOVE      A11,B10             ;move v2A
        MOVE      A13,B12             ;move dA
* Calculate initial values of ellipse algorithm control parameters.
        CALLR     OVAL_PARAMS         ;
* Get ready to enter 2nd loop to fill around hole.
        MOVE      A1,B1               ;initial ycount = hB
        MOVE      B10,A10             ;move v2A
        MOVE      B12,A12             ;move dA
        SRL       1,B7                ;
        ADDI      08000h,B7           ;wfill >>= 1
        MOVK      1,A14               ;x increment = 0::1
        MOVI      010000h,A1          ;y increment = 1::0
*-----------------------------------------------------------------------
* Main Loop #2:  Draw portion of pattern-filled ellipse beside hole.
*
        MOVE      A13,A13             ;check sign of dB
        JRNN      PF6                 ;jump if dB >= 0
* Step in horizontal direction
PF5:
        ADDXY     A14,A3              ;++x2
        SUBK      1,B7                ;--wfill
        ADD       A5,A9               ;v1B += k1B
        ADD       A9,A13              ;dB += v1B
        JRN       PF5                 ;
PF6:
* Decrement count; if negative, break out of loop.
        SUBK      2,B1                ;ycount -= 2
        JRN       PF9                 ;if ycount < 0, exit loop
* Fill two horizontal lines in top and bottom halves of ellipse.
        MOVE      A2,B2               ;DADDR = y1::x1
        CALL      B0                  ;fill line in top left
        MOVE      A2,A0               ;
        MOVY      A3,A0               ;
        MOVE      A0,B2               ;DADDR = y2::x1
        CALL      B0                  ;fill line in bottom left
        MOVE      A2,A0               ;
        MOVX      A3,A0               ;
        MOVE      A0,B2               ;DADDR = y1::x2
        CALL      B0                  ;fill line in top right
        MOVE      A3,B2               ;DADDR = y2::x2
        CALL      B0                  ;fill line in bottom right
* Move vertically to next fill line.
        ADDXY     A1,A2               ;++y1
        SUBXY     A1,A3               ;--y2
        ADD       A6,A10              ;v2A += k2A
        ADD       A10,A12             ;dA += v2A

        JRNN      PF8                 ;jump if dA >= 0
* Step in horizontal direction
PF7:
        SUBXY     A14,A2              ;--x1
        ADDK      1,B7                ;++wfill
        ADD       A4,A8               ;v1A += k1A
        ADD       A8,A12              ;dA += v1A
        JRN       PF7                 ;loop while dA < 0
PF8:
        ADD       A7,A11              ;v2B += k2B
        ADD       A11,A13             ;dB += v2B
        JRN       PF5                 ;loop again (dB < 0)
        JRUC      PF6                 ;(dB >= 0)
PF9:
*--- End of 2nd loop ---
        BTST      0,B1                ;is ycount odd ?
        JRZ       PFDONE              ;done if ycount is even
        MOVE      A2,B2               ;DADDR = y1::x1
        CALL      B0                  ;fill left middle of frame
        MOVE      A3,B2               ;DADDR = y2::x2
        CALL      B0                  ;fill right middle of frame

*-----------------------------------------------------------------------
* Restore registers and return.
PFDONE:
        MMFM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13,A14
        MMFM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        RETS      2                   ;return


*-----------------------------------------------------------------------
* Calculate control parameters k1, k2, v1, v2 and d for the ellipse fill
* algorithm, given width w and height h of the ellipse.
*      At call,               w  is in A0
*                             h  is in A1
*            ----------------------------------------------
*                             k1 is in A5
*      At return,             k2 is in A7
*                             v1 is in A9
*                             v2 is in A11
*                             d  is in A13
* The contents of registers A8, A12 and A14 are destroyed.  Registers
* A0, A1, A2, A3, A4, A6 and A8 are undisturbed; no B-file registers are
* disturbed.
*-----------------------------------------------------------------------
OVAL_PARAMS:
* Calculate k1 = 8*w*w and k2 = 8*h*h.
        SETF      16,0,1              ;field size = 16 for multiply
        MOVE      A1,A5               ;copy h
        MPYU      A5,A5               ;
        SLL       3,A5                ;k1 = 8*h*h
        MOVE      A0,A7               ;copy w
        MPYU      A7,A7               ;
        SLL       3,A7                ;k2 = 8*w*w
        SETF      32,0,1              ;restore field size to 32
* Calculate 32*h*w*w to 64 bits as a precaution against overflow.
        MOVE      A1,A10              ;copy h
        SLL       2,A10               ;calculate 4*h
        MPYU      A7,A10              ;compute 32*h*w*w to 64 bits
* Is ellipse's width or height more likely to cause arithmetic overflow?
        CMP       A1,A0               ;is w >= h?
        JRLT      FO1                 ;jump if w < h
* w >= h:  Will quantity 32*h*w*w overflow 32-bit register?
        LMO       A10,A14             ;measure amount of overflow
        JRZ       FO3                 ;jump if no overflow
        JRUC      FO2                 ;need to prescale parameters
* w < h:  Will quantity 32*w*h*h overflow 32-bit register?
FO1:
        MOVE      A0,A12              ;copy w
        SLL       2,A12               ;calculate 4*w
        MPYU      A5,A12              ;compute 32*w*h*h to 64 bits
        LMO       A12,A14             ;measure amount of overflow
        JRZ       FO3                 ;jump if no overflow
* Prescale all loop constants and variables by the same amount.
FO2:
        SLL       A14,A10             ;prescale 32*h*w*w
        SRL       A14,A11             ;
        OR        A10,A11             ;
        SRL       A14,A5              ;prescale k1 = 8*h*h
        SRL       A14,A7              ;prescale k2 = 8*w*w
* Calculate initial values of loop variables v1, v2 and d.  Initially
* v2 = -4*h*w*w.  If w is even, v1 = 0 and d = h*h+w*w-2*h*w*w.
* If w is odd, v1 = 4*h*h and d = 4*h*h+w*w-2*h*w*w.
FO3:
        CLR       A9                  ;v1 = 0
        SRL       1,A11               ;
        NEG       A11                 ;-16*h*w*w
        MOVE      A11,A13             ;
        SRA       2,A11               ;v2 = -4*h*w*w
        ADD       A5,A13              ;
        ADD       A7,A13              ;8*d = 8*h*h+8*w*w-16*h*w*w
        BTST      0,A0                ;is w odd?
        JRZ       WEVEN               ;jump if w even
; w is odd--
        MOVE      A5,A9               ;
        SRL       1,A9                ;v1 = 4*h*h
        SUB       A5,A13              ;8*w*w-16*h*w*w
WEVEN:
        SRA       3,A13               ;
        ADD       A9,A13              ;initial d
        RETS      0                   ;
        .end

        .end

