;-------------------------------------------------------------------------;
;                                  TIGA                                   ;
;        Copyright (c) 1987-1990  Texas Instruments Incorporated.         ;
;			   All Rights Reserved				  ;
;-------------------------------------------------------------------------;
;   TIGA - Graphics Manager Extension                                     ;
;-------------------------------------------------------------------------;
;                                                                         ;
; seed_fill and seed_patnfill functions                                   ;
;                                                                         ;
;   Performs a seed fill of a connected region consisting of pixels of    ;
;   the same color, given the coordinates (x,y) of a seed point (or       ;
;   starting pixel) within the region.  In the case of the seed_fill      ;
;   function, pixels in the connected region are replaced by the color 1  ;
;   value.  In the case of the seed_patnfill function, pixels in the      ;
;   connected region are replaced by a pattern rendered in the color 0    ;
;   and color 1 values.  A pixel is considered part of the connected      ;
;   region if it has a horizontally or vertically adjacent neighbor       ;
;   pixel that is part of the region.  (A diagonally adjacent neighbor    ;
;   is not sufficient.)                                                   ;
;                                                                         ;
;   An array buffer[] is included as an argument; this array is used as   ;
;   working storage during the seed fill.  The size of the buffer[]       ;
;   array is also included as an argument.  More complex connected        ;
;   regions tend to require greater working storage.  The seed fill       ;
;   function will abort if the specified buffer size is too small.        ;
;                                                                         ;
;   The seed_fill function aborts (returns immediately) if any of the     ;
;   three conditions below is detected:                                   ;
;     (1) if at any point the storage buffer space specified in           ;
;         the third and fourth input arguments is insufficient to         ;
;         continue                                                        ;
;     (2) the starting pixel (or seed pixel) lies outside the current     ;
;         window (also called "visibility region")                        ;
;     (3) the starting pixel value is the same as color 1.                ;
;   The seed_patnfill function aborts under similar conditions, except    ;
;   that condition 3 above is modified as follows:                        ;
;     (3) the starting pixel value is the same as either color 1 or       ;
;         color 0.                                                        ;
;----------------------------------------------------------------------   ;
; Usage:  long x, y;                                                      ;
;         short buffer[];                                                 ;
;         long size;                                                      ;
;         seed_fill(x, y, buffer, size);                                  ;
;         seed_patnfill(x, y, buffer, size);                              ;
;                                                                         ;
; Description of the arguments:                                           ;
;         x, y = seed point coordinates                                   ;
;         buffer = address of buffer for use by seed_fill                 ;
;         size = size of the buffer in bytes                              ;
;                                                                         ;
; Returned in register A8:  void (undefined).                             ;
;                                                                         ;
; Registers altered:  A8                                                  ;
;                                                                         ;
; Notes: - Seed_fill will abort if buffer size is too small.              ;
;        - This function is pixel size independent.                       ;
;-------------------------------------------------------------------------;
; Revision history:                                                       ;
;   2/19/87...Original version written....................J.G.Littleton   ;
;   3/19/87...Modified to do pattern fill as well.........J. Van Aken     ;
;   5/05/87...Fixed bug that set initial fill line........JGL             ;
;   8/15/87...Local variables now allocate temp stack.....JGL             ;
;   9/12/87...Fixed potential problem due to piped writes.JGL             ;
;             (Inserted delay after MOVE @CONVDP,@CONVSP,0)               ;
;  12/02/87...Missed end of valid right run by 1..........JGL             ;
;  09/18/88...Added TIGA dm, globals and dstbm............Graham Short    ;
;  07/31/89...Added support for the 34020.................A. Sharp        ;
;  08/22/89...Added use of temp register in '20 code......A. Sharp per JVA;
;  11/24/89...Moved FILTYP into local space to free up....Graham Short    ;
;             SPTCH for the 34020, added MOVE DPTCH,SPTCH                 ;
;-------------------------------------------------------------------------;
;
        .title    'seed fill'
        .file     'seedfill.asm'
;
;  Include GSP definitions and assembly language macros
        .include   gspreg.inc
        .include   gspglobs.inc          
        .include   gsptypes.inc
        .include   oem.inc
;
; Global function declarations
        .globl    _seed_fill, _dm_seed_fill
        .globl    _seed_patnfill, _dm_seed_patnfill
;
;   Local register usage
;
Rdir    .set      A0                  ;direction (up or down)
Rtmp    .set      A1
Rtmp1   .set      A2
Rbuf    .set      A3                  ;ptr to workspace buffer
Rorg    .set      A4
Rrgt    .set      A5
Rlft    .set      A6
Rsize   .set      A7                  ;size of workspace buffer
Rprgt   .set      A9                  ;right endpoint of parent run
Rplft   .set      A10                 ;left endpoint of parent run
Rnrgt   .set      A11
Rnlft   .set      A12
;
Rfiltyp .set      B0                  ;indicates fill type (solid or pattern)
Rruns   .set      B0                  ;(used to count number of runs in buffer)
;
;  Local Variables
LOCALSIZE .set    32+32+16+32         ;stack space to reserve for locals
L_SLFT   .set      0h                 ;long
L_SRGT   .set     20h                 ;long
L_CONVSP .set     40h                 ;short
L_FILTYP .set     50h                 ;long
;
;     C-PACKET ENTRY POINTS
;
_seed_fill:
        mmtm      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13
        mmtm      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        clr       Rfiltyp             ;0 flag for solid fill
        jruc      cp_ep
;
_seed_patnfill:
        mmtm      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13
        mmtm      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        move      @_pattern+PATTERN_HSRV,Rfiltyp,1   ;subroutine for pattern fill
;
cp_ep:
        setf      16,0,0
        move      *-A14,A8,1               ;pop X
        move      *-A14,Rorg,1             ;pop Y
        sll       16,Rorg
        movx      A8,Rorg                  ;Y:X
        move      *-A14,Rbuf,1             ;pop buffer address
        move      *-A14,Rsize,1            ;pop buffer size
        jruc      common_ep
;
;     DIRECT-MODE ENTRY POINTS
;
_dm_seed_fill:
        mmtm      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13
        mmtm      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        clr       Rfiltyp             ;0 flag for solid fill
        jruc      dm_ep
;
_dm_seed_patnfill:
        mmtm      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A12,A13
        mmtm      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        move      @_pattern+PATTERN_HSRV,Rfiltyp,1   ;subroutine for pattern fill
;
dm_ep:
        setf      16,0,0
        move      *-A14,A8,1               ;get pointer to data area
        move      *A8+,Rorg,1              ;get y::x
        move      *A8+,Rbuf,1              ;get buffer address
        move      *A8,Rsize,0              ;get buffer size
;
;     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      abort                     ; if zero, dstbm is set to screen
;
;     MAIN ALGORITHM
;
;  Reserve Room for local variables
        move      @_env+ENVIRONMENT_XYORIGIN,A8,1
        addxy     A8,Rorg
        move      STK,FP
        addi      LOCALSIZE,STK
;
        move      Rfiltyp,Rtmp
        move      Rtmp,*FP(L_FILTYP),1 ;save solid fill or pattern fill?
        clr       Rruns
        move      @CONVSP,Rtmp,0
        move      Rtmp,*FP(L_CONVSP),0 ;save CONVSP
        move      DPTCH,SPTCH
        move      @CONVDP,@CONVSP,0
        move      *A8,A8,0
;  Read color of seed point
        pixt      *Rorg.XY,A8
;  If it's the same as the floodfill color, then exit
        move      @PSIZE,Rtmp1,0      ;get pixel size
        movi      -1,Rtmp
        srl       Rtmp1,Rtmp          ;Rtmp -> pixel mask
        move      COLOR1,Rtmp1        ;get floodfill color
        and       Rtmp,Rtmp1          ;mask off 1 pixel
        xor       A8,Rtmp1            ;is seed color == floodfill col or?
        jrz       exit_seedfill       ;yes... exit
        move      *FP(L_FILTYP),Rtmp1,1 ;solid fill or pattern fill?
        jrz       skipcheck           ;jump if solid fill
        move      COLOR0,Rtmp1        ;get floodfill color
        and       Rtmp,Rtmp1          ;mask off 1 pixel
        xor       A8,Rtmp1            ;is seed color == floodfill col or?
        jrz       exit_seedfill       ;yes... exit
skipcheck:
        cpw       Rorg,Rtmp           ;is seed point in window
        jrv       exit_seedfill       ;no... exit
;  Find leftmost X in starting run
        move      Rorg,Rlft
        move      Rorg,Rtmp
find_slft:
;
        .if     GSP_34010 ; Code used if the processor is a 34010
        subk      1,Rtmp
        cpw       Rtmp,Rtmp1
        jrv       found_slft
        pixt      *Rtmp.XY,Rtmp1      ;check first before setting up fpixne
        xor       A8,Rtmp1
        dsjeq     Rlft,find_slft
        .endif
;
        .if     GSP_34020 ; Code used if the processor is a 34020
        MOVE      B8,Rtmp1
        MOVE      Rtmp,B11            ;set up max pixel count
        SUBXY     B5,B11
        INC       B11
        ZEXT      B11,0
        NEG       B11                 ;search left
        MOVE      Rtmp,B10            ;set up linear start address
        CVXYL     B10,B10
        MOVE      A8,B8               ;set up pixel
        RPIX      B8
        FPIXNE
        ADDXY     B5,B11              ;convert residual count to x address
        MOVE      B11,Rtmp
        MOVX      Rtmp,Rlft
        MOVE      Rtmp1,B8
        .endif
;
found_slft:
;  Find rightmost X in starting run
        move      Rorg,Rrgt
        move      Rorg,Rtmp
find_srgt:
        addk      1,Rtmp
;
        .if     GSP_34010 ; Code used if the processor is a 34010
        cpw       Rtmp,Rtmp1
        jrv       found_srgt
        pixt      *Rtmp.XY,Rtmp1
        xor       A8,Rtmp1
        jrnz      found_srgt
        addk      1,Rrgt
        jruc      find_srgt
        .endif
;
        .if     GSP_34020 ; Code used if the processor is a 34020
        MOVE      B8,A4
        MOVE      Rtmp,B10            ;set up max pixel count
        MOVE      B6,B11
        SUBXY     B10,B11             ;window x - start point x
        ADDK      2,B11
        ZEXT      B11,0
        MOVE      Rtmp,B10            ;set up linear start address
        CVXYL     B10,B10
        MOVE      A8,B8               ;set up pixel
        RPIX      B8
        FPIXNE
        MOVE      B6,B10              ;convert residual count to x address
        SUBXY     B11,B10
        MOVE      B10,Rtmp
        MOVX      Rtmp,Rrgt
        MOVE      A4,B8
        .endif
;
found_srgt:
;  Fill starting run
        move      Rlft,DADDR
        move      Rrgt,DYDX
        subxy     DADDR,DYDX
        addk      1,DYDX
        zext      DYDX,0
        ori       10000h,DYDX

        move      *FP(L_FILTYP),Rtmp,1 ;solid fill or pattern fill?
        jrnz      pfill0              ;jump if pattern fill
        FILL      XY                  ;do solid filled horiz line
        jruc      fend0               ;
pfill0:
        call      Rtmp                ;do pattern filled horiz line

fend0:

;  Call recursive fill with run above
        move      Rlft,*FP(L_SLFT),1
        move      Rrgt,*FP(L_SRGT),1
        move      Rlft,Rtmp
        movi      10000h,Rtmp1
        subxy     Rtmp1,Rtmp
        move      Rtmp,*Rbuf+,1       ;push lft
        move      Rrgt,*Rbuf+,0       ;push rgt
        move      Rlft,*Rbuf+,0       ;push parent_lft
        move      Rrgt,*Rbuf+,0       ;push parent_rgt
        movk      1,Rdir
        move      Rdir,*Rbuf+,0       ;push direction
        addk      1,Rruns
        callr     recursive_fill
;  Call recursive fill with run below
        move      *FP(L_SLFT),Rlft,1
        move      *FP(L_SRGT),Rrgt,1
        move      Rlft,Rtmp
        movi      10000h,Rtmp1
        addxy     Rtmp1,Rtmp
        move      Rtmp,*Rbuf+,1       ;push lft
        move      Rrgt,*Rbuf+,0       ;push rgt
        move      Rlft,*Rbuf+,0       ;push parent_lft
        move      Rrgt,*Rbuf+,0       ;push parent_rgt
        movi      -1,Rdir
        move      Rdir,*Rbuf+,0       ;push direction
        addk      1,Rruns
        callr     recursive_fill
        movk      1,A8                ;normal return (return TRUE, A8 <> 0)
        jruc      restore_regs
;
;  error exit
; 
exit_seedfill:
        clrs      A8                  ;error return (return FALSE, A8 == 0)
;
restore_regs:
        move      *FP(L_CONVSP),Rtmp,0 ;restore source pitch
        move      Rtmp,@CONVSP,0
        subi      LOCALSIZE,STK
abort:  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
        MOVE      *SP(32),A14,1       ;restore program stack pointer
        rets      2

abort_seedfill:
        addk      32,SP               ;ditch return address
        jruc      exit_seedfill
;
recursive_fill:
        move      *-Rbuf,Rdir,0       ;direction
        sext      Rdir,0
        move      *-Rbuf,Rprgt,0      ;parent right
        move      *-Rbuf,Rplft,0      ;parent left
        move      *-Rbuf,Rrgt,0       ;right x
        move      *-Rbuf,Rlft,1       ;left x
        movy      Rlft,Rrgt
        movy      Rlft,Rprgt
        movy      Rlft,Rplft
        subk      1,Rruns             ;decrement run count
        addk      12,Rsize
;  If the leftmost point is equal to seedcolor, then search left
;  for the leftmost point in the unfilled run. If not equal, then
;  search right for the beginning of a run.
        move      Rlft,Rnlft          ;left -> nextleft
search_run:
        pixt      *Rnlft.XY,Rtmp      ;read pixel
        xor       A8,Rtmp             ;seedcolor?
        jrnz      find_start_run      ;no, look to the right
        move      Rnlft,Rnrgt         ;nextleftx -> nextright
        move      Rnlft,Rtmp
find_lftmost:
;
        .if     GSP_34010 ; Code used if the processor is a 34010
        subk      1,Rtmp
        cpw       Rtmp,Rtmp1
        jrv       found_lftmost
        pixt      *Rtmp.XY,Rtmp1      ;check 1st before setting up fpixne
        xor       A8,Rtmp1
        dsjeq     Rnlft,find_lftmost
        .endif
;
        .if     GSP_34020 ; Code used if the processor is a 34020
        MOVE      B8,A4
        MOVE      Rtmp,B11            ;set up max pixel count
        SUBXY     B5,B11
        INC       B11
        ZEXT      B11,0
        NEG       B11                 ;search left
        MOVE      Rtmp,B10            ;set up linear start address
        CVXYL     B10,B10
        MOVE      A8,B8               ;set up pixel
        RPIX      B8
        FPIXNE
        ADDXY     B5,B11              ;convert residual count to x address
        MOVE      B11,Rtmp
        MOVX      Rtmp,Rnlft
        MOVE      A4,B8
        .endif
;
found_lftmost:
        jruc      find_rgtmost
;  Search right until we find the beginning of an unfilled run
find_start_run:
        inc       Rnlft
find_start_lp:
        cmpxy     Rrgt,Rnlft          ;is nextleft <= Rrgt?
        jrxgt     found_start_run     ;no, exit
        cpw       Rnlft,Rtmp1
        jrv       found_start_run
        pixt      *Rnlft.XY,Rtmp1     ;read pixel
        xor       A8,Rtmp1            ;is it start of run?
        jrz       found_start_run     ;yes
;
        .if     GSP_34010 ; Code used if the processor is a 34010
        addk      1,Rnlft
        jruc      find_start_lp
        .endif
        .if     GSP_34020 ; Code used if the processor is a 34020
        MOVE      B8,A4
        MOVE      Rnlft,B10            ;set up max pixel count
        MOVE      B6,B11
        SUBXY     B10,B11             ;window x - start point x
        ZEXT      B11,0
        MOVE      Rnlft,B10            ;set up linear start address
        CVXYL     B10,B10
        MOVE      A8,B8               ;set up pixel
        RPIX      B8
        FPIXEQ
        MOVE      B6,B10              ;convert residual count to x address
        SUBXY     B11,B10
        DEC       B10
        MOVE      B10,Rtmp1
        MOVX      Rtmp1,Rnlft
        MOVE      A4,B8
        .endif
;
found_start_run:
        move      Rnlft,Rnrgt
;  A starting left point in the current shadow run has been found.
;  Search for the rightmost point.
find_rgtmost:
        cmpxy     Rrgt,Rnlft          ;is nextleft <= Rrgt?
        jrxgt     rundone             ;no, exit
        move      Rnrgt,Rtmp
frmost:
        addk      1,Rtmp
;
        .if     GSP_34010 ; Code used if the processor is a 34010
        cpw       Rtmp,Rtmp1
        jrv       found_rgtmost
        pixt      *Rtmp.XY,Rtmp1
        xor       A8,Rtmp1
        jrnz      found_rgtmost
        addk      1,Rnrgt
        jruc      frmost
        .endif
;
        .if     GSP_34020 ; Code used if the processor is a 34020
        MOVE      B8,A4
        MOVE      Rnrgt,B10            ;set up max pixel count
        MOVE      B6,B11
        SUBXY     B10,B11             ;window x - start point x
        ADDK      2,B11
        ZEXT      B11,0
        MOVE      Rnrgt,B10            ;set up linear start address
        CVXYL     B10,B10
        MOVE      A8,B8               ;set up pixel
        RPIX      B8
        FPIXNE
        MOVE      B6,B10              ;convert residual count to x address
        SUBXY     B11,B10
        MOVE      B10,Rtmp1
        MOVX      Rtmp1,Rnrgt
        MOVE      A4,B8
        .endif
;
found_rgtmost:
;     Fill shadow run
        move      Rnlft,DADDR
        move      Rnrgt,DYDX
        subxy     DADDR,DYDX
        jrv       rundone
        addk      1,DYDX
        zext      DYDX,0
        ori       10000h,DYDX

        move      *FP(L_FILTYP),Rtmp,1 ;solid fill or pattern fill?
        jrnz      pfill1              ;jump if pattern fill
        FILL      XY                  ;do solid filled horiz line
af:     jruc      fend1               ;
pfill1:
        call      Rtmp                ;do pattern filled horiz line
fend1:

;  Push shadow run into buffer
        move      Rdir,Rtmp
        sll       16,Rtmp
        move      Rnlft,Rtmp1
        subxy     Rtmp,Rtmp1
        cpw       Rtmp1,Rtmp
        jrv       rundone
        move      Rtmp1,*Rbuf+,1      ;push y-dir:nextlft
        move      Rnrgt,*Rbuf+,0      ;push nextrgt
        move      Rnlft,*Rbuf+,0      ;push parent left
        move      Rnrgt,*Rbuf+,0      ;push parent right
        move      Rdir,*Rbuf+,0       ;push direction
        addk      1,Rruns
        subk      12,Rsize
        jrn       abort_seedfill
;  Is there a valid left shadow?
        movk      2,Rtmp
        move      Rplft,Rtmp1
        subxy     Rtmp,Rtmp1          ;plft - 2
        cmpxy     Rtmp1,Rnlft         ;is nextlft <= pleft-2
        jrxgt     nextrec             ;no...
;  Push valid left shadow into buffer
        move      Rtmp1,B10           ;save (plft - 2)
        move      Rdir,Rtmp
        sll       16,Rtmp
        move      Rnlft,Rtmp1
        addxy     Rtmp,Rtmp1          ;y+dir:nlft
        cpw       Rtmp1,Rtmp
        jrv       rundone
        move      Rtmp1,*Rbuf+,1      ;push y+dir:nextlft
        move      B10,Rtmp1
        move      Rtmp1,*Rbuf+,0      ;push parent left - 2
        move      Rnlft,*Rbuf+,0      ;push nextlft
        move      Rnrgt,*Rbuf+,0      ;push nextrgt
        move      Rdir,Rtmp
        neg       Rtmp
        move      Rtmp,*Rbuf+,0       ;push -dir
        addk      1,Rruns
        subk      12,Rsize
        jrn       abort_seedfill
;  Is there a valid right shadow?
nextrec:
        movk      2,Rtmp
        move      Rprgt,Rtmp1
        addxy     Rtmp,Rtmp1
        cmpxy     Rnrgt,Rtmp1         ;is pright+2 <= nextright
        jrxgt     skipnl              ;no...
;  Push valid right shadow into buffer
        move      Rdir,Rtmp
        sll       16,Rtmp
        addxy     Rtmp,Rtmp1
        cpw       Rtmp1,Rtmp
        jrv       rundone
        move      Rtmp1,*Rbuf+,1      ;y+dir:prgt+2
        move      Rnrgt,*Rbuf+,0      ;push nrgt
        move      Rnlft,*Rbuf+,0      ;push nextleftx
        move      Rnrgt,*Rbuf+,0      ;push nextrightx
        move      Rdir,Rtmp
        neg       Rtmp
        move      Rtmp,*Rbuf+,0       ;push -dir
        addk      1,Rruns
        subk      12,Rsize
        jrn       abort_seedfill
;  Skip to next possible leftmost x
skipnl:
        move      Rnrgt,Rnlft         ;nextleft = nextright+2
        addk      2,Rnlft
;  Check to see if we have hit the end of the run, if not
;  continue to search the run for unfilled segments.
        cmpxy     Rrgt,Rnlft          ;is nextleft < right
        jrxle     search_run          ;yes, continue searching run
rundone:
        move      Rruns,Rruns         ;any runs left in buffer?
        jrgt      recursive_fill      ;yes.. keep going
        rets      0
        .end

