        .width    132
        .title    'frame a circular hole'

*----------------------------------------------------------------------
*                                    TIGA
*          Copyright (C) 1987-1990  Texas Instruments Incorporated.
*                            All Rights Reserved
*----------------------------------------------------------------------
* frame_hole function
*
*   Draw a square with a circular hole cut out of it.  Only the portion
*   of the square lying outside the circle is filled.  The square and
*   circular hole share the same center and diameter.  The circular hole
*   is specified in terms of its radius r, and center point coordinates
*   (xc, yc).
*----------------------------------------------------------------------
* Usage:  frame_hole(r, xc, yc);
*
* Stack parameters:
*     long r;       /* radius of filled circle */
*     long xc, yc;  /* coordinates of center of circle */
*
* Returned in A8:  void (undefined)
*
* Registers altered:  A8
*----------------------------------------------------------------------
* Revision history:
*   06/18/87...Original version written..................Jerry Van Aken
*----------------------------------------------------------------------
;
;
;     DECLARE GLOBAL FUNCTION NAME
;
        .globl    _frame_hole
;
;
;     DECLARE EXTERNAL GLOBALS
;
        .globl    _xyorigin           ;position of origin on screen
;
;
;     DEFINE CONSTANTS

OCT0    .set      A0                  ;xy address in octant 0
OCT1    .set      A1                  ;xy address in octant 1
OCT2    .set      A2                  ;xy address in octant 2
OCT3    .set      A3                  ;xy address in octant 3
OCT4    .set      A4                  ;xy address in octant 4
OCT5    .set      A5                  ;xy address in octant 5
OCT6    .set      A6                  ;xy address in octant 6
OCT7    .set      A7                  ;xy address in octant 7
D       .set      A8                  ;decision variable D
P       .set      A9                  ;D increment if square step
Q       .set      A10                 ;D increment if diagonal step
INC1    .set      A11                 ;xy address increment  0::+1
INC2    .set      A12                 ;xy address increment +1:: 0
INC3    .set      A13                 ;xy address increment +1::+1
INC4    .set      A14                 ;xy address increment +1::-1
STK     .set      A14                 ;C program stack pointer
WIN     .set      B0                  ;inner fill width
WOUT    .set      B1                  ;outer fill width
DADDR   .set      B2                  ;dest'n address pointer for fills
DYDX    .set      B7                  ;fill width (fill height = 1)
COUNT   .set      B8                  ;xy step counter
BTEMP   .set      B10                 ;B-file temporary register
;
;
;     ENTRY POINT
;
_frame_hole:

        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      *-STK,D,1           ;get argument 'r'
        JRLE      DONE                ;jump if r <= 0
        MOVE      *-STK,OCT0,1        ;get argument 'x'
        MOVE      *-STK,OCT1,1        ;get argument 'y'
* Form XY address of circle's center point.
        SLL       16,OCT1             ;concatenate x and y
        MOVY      OCT1,OCT0           ;
        MOVE      @_xyorigin,OCT1,1   ;get xy origin displacement
        ADDXY     OCT1,OCT0           ;convert to screen coord's
* Set up XY increments for horizontal, vertical and diagonal moves.
        MOVK      1,INC1              ;deltay = 0, deltax = +1
        MOVK      1,INC2              ;
        SLL       16,INC2             ;deltay = +1, deltax = 0
        MOVE      INC2,INC3           ;
        INC       INC3                ;deltay = +1, deltax = +1
        MOVE      INC2,INC4           ;
        SUBXY     INC1,INC4           ;deltay = +1, deltax = -1
* Get XY addresses for arc starting points in all 8 octants.
        MOVE      OCT0,OCT3           ;copy y::x
        MOVE      OCT0,OCT6           ;copy y::x again
        MOVE      D,OCT1              ;
        SLL       16,OCT1             ;r::0
        SUBXY     OCT1,OCT6           ;y-r::x
        ADDXY     OCT0,OCT1           ;y+r::x
        ADDXY     D,OCT0              ;y::x+r
        SUBXY     D,OCT3              ;y::x-r
        MOVY      OCT1,OCT2           ;
        MOVX      OCT3,OCT2           ;y+r::x-r
        MOVE      OCT3,OCT4           ;y::x-r
        MOVX      OCT3,OCT5           ;
        MOVY      OCT6,OCT5           ;y-r::x-r
        MOVE      OCT0,OCT7           ;y::x+r
        SUBXY     INC2,OCT0           ;
        SUBXY     INC2,OCT1           ;
        SUBXY     INC2,OCT2           ;
        SUBXY     INC2,OCT3           ;
* Set up initial values for step counter and inside/outside fill widths.
        CLR       WIN                 ;initial inside fill width = 0
        MOVE      D,WOUT              ;initial outside fill width = r
        MOVE      D,COUNT             ;initial step counter = r
        MOVE      INC2,DYDX           ;DY = 1
* Set up initial values for loop count, and outside/inside fill widths.
        SLL       1,D                 ;2*r
        NEG       D                   ;-2*r
        MOVE      D,Q                 ;copy -2*r
        ADD       D,Q                 ;initially q = -4*r
        CLR       P                   ;initially p = 0
        INC       D                   ;initially d = 1 - 2*r
*----------BEGIN INNER LOOP OF CIRCLE ALGORITHM-------------
* Take a square (horizontal or vertical) step in all 8 octants.
SQUARE:
        MOVE      WIN,WIN             ;check inside_width
        JRZ       WINZERO             ;jump if inside_width = 0
        MOVX      WIN,DYDX            ;DX = inside_width
        MOVE      OCT0,DADDR          ;copy octant 0 pointer
        FILL      XY                  ;
        MOVE      OCT3,DADDR          ;copy octant 3 pointer
        FILL      XY                  ;
        MOVE      OCT4,DADDR          ;copy octant 4 pointer
        FILL      XY                  ;
        MOVE      OCT7,DADDR          ;copy octant 7 pointer
        FILL      XY                  ;
WINZERO:
        ADDXY     INC2,OCT0           ;increment octant 0 pointer
        ADDXY     INC1,OCT1           ;increment octant 1 pointer
        ADDXY     INC2,OCT3           ;increment octant 3 pointer
        SUBXY     INC2,OCT4           ;increment octant 4 pointer
        ADDXY     INC1,OCT6           ;increment octant 6 pointer
        SUBXY     INC2,OCT7           ;increment octant 7 pointer
        DEC       WOUT                ;decrement outside_width
        DEC       COUNT               ;decrement loop count by 1
        JRLE      OUT                 ;jump if at end of octant
        ADDK      4,P                 ;p += 4
        ADDK      4,Q                 ;q += 4
        ADD       P,D                 ;d += p
        JRN       SQUARE              ;jump if d < 0 (square step)

* Take a diagonal step in all 8 octants.
DIAG:
        MOVX      WIN,DYDX            ;DX = inside_width
        MOVE      OCT0,DADDR          ;copy octant 0 pointer
        FILL      XY                  ;
        MOVE      OCT3,DADDR          ;copy octant 3 pointer
        FILL      XY                  ;
        MOVE      OCT4,DADDR          ;copy octant 4 pointer
        FILL      XY                  ;
        MOVE      OCT7,DADDR          ;copy octant 7 pointer
        FILL      XY                  ;
        MOVX      WOUT,DYDX           ;copy outside_width
        MOVE      OCT1,DADDR          ;copy octant 1 pointer
        FILL      XY                  ;
        MOVE      OCT2,DADDR          ;copy octant 2 pointer
        FILL      XY                  ;
        MOVE      OCT5,DADDR          ;copy octant 5 pointer
        FILL      XY                  ;
        MOVE      OCT6,DADDR          ;copy octant 6 pointer
        FILL      XY                  ;
        ADDXY     INC4,OCT0           ;increment octant 0 pointer
        SUBXY     INC4,OCT1           ;increment octant 1 pointer
        SUBXY     INC2,OCT2           ;increment octant 2 pointer
        ADDXY     INC2,OCT3           ;increment octant 3 pointer
        SUBXY     INC2,OCT4           ;increment octant 4 pointer
        ADDXY     INC2,OCT5           ;increment octant 5 pointer
        ADDXY     INC3,OCT6           ;increment octant 6 pointer
        SUBXY     INC3,OCT7           ;increment octant 7 pointer
        DEC       WOUT                ;increment outside_width
        INC       WIN                 ;decrement inside_width
        SUBK      2,COUNT             ;decrement loop count by 2
        JRLE      OUT                 ;jump if at end of octant
        ADDK      4,P                 ;p += 4
        ADDK      8,Q                 ;q += 8
        ADD       Q,D                 ;d += q
        JRN       SQUARE              ;jump if d < 0
        JRUC      DIAG                ;jump if d >= 0

* Check whether 4 final horizontal lines are needed to finish circle.
OUT:
        JRNZ      DONE                ;jump if arcs already touch
        MOVX      WOUT,DYDX           ;copy outside_width
        MOVE      OCT1,DADDR          ;copy octant 1 pointer
        FILL      XY                  ;
        MOVE      OCT2,DADDR          ;copy octant 2 pointer
        FILL      XY                  ;
        MOVE      OCT5,DADDR          ;copy octant 5 pointer
        FILL      XY                  ;
        MOVE      OCT6,DADDR          ;copy octant 6 pointer
        FILL      XY                  ;
* All done.  Restore registers and return to calling routine.
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
        MOVE      *SP(32),A14,1       ;update STK pointer
        RETS      2                   ;
        .end

