home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-386-Vol-2of3.iso / b / bgi256-3.zip / SFLOOD.INC < prev    next >
Text File  |  1993-01-03  |  25KB  |  845 lines

  1.  
  2. ;SFLOOD.INC - Copyright 1991,1992 Knight Software
  3. ;   History:
  4. ;       25 May 1991 - first release
  5. ;       22 Nov 1992 - adapted for protected mode operation
  6. ;    19 Dec 1992 - fixed floodfill so it works now
  7. ;                      also added lots of options (see description)
  8. ;       03 Jan 1993 - corrected lockup with inverted floodfills
  9. ;
  10. ;===============================================================
  11. ;Floodfill can handle seed fill, or border fill methods.
  12. ;This is selected by the SetWriteMode command.
  13. ;Normally, the floodfill will select the best fill mode to use. 
  14. ;For simple move type fills, a fast fill is selected. For complex fills, 
  15. ;it would be the complex (slow) mode. The complex mode uses a border 
  16. ;tracer and saves all information on the internal XY stack. The stack 
  17. ;is not released until the fill is done. This allows us to know where 
  18. ;we've been so that multiple overfills don't happen. This is required 
  19. ;for fills that do read/modify/write cycles such as XOR, AND, OR, and NOT.  
  20. ;The simplex (fast) fill allows overwrites to happen. It does this by 
  21. ;popping unused scan segments from the XY stack. This makes XY stack usage 
  22. ;more efficient. Also, the simplex fill method doesn't search the stack 
  23. ;for used scan segments (which is why overwrites can happen). 
  24. ;A border fill fills everything that is not the border color. 
  25. ;A seed fill fills everything that is not the seed color. 
  26. ;In compressed mode, the stack storage is reduced by 33%. It does this by 
  27. ;not saving the right side of the scan segment. Instead, the right side is 
  28. ;recreated at the time the segment is drawn. This slows things down, 
  29. ;but it reduces stack usage thus allowing for more complex fills. 
  30. ;
  31. ; flood fill type bits
  32. ;bit
  33. ; 0: 0=border fill, 1=seed fill
  34. ; 1: 0 <reserved>
  35. ; 2: 0=auto fill, 1=complex fill
  36. ; 3: 0=normal stack, 1=compressed stack
  37. ; 4: 0=draw during search, 1=draw after search (if no error)
  38. ; 5: 0=no tracer during scan, 1=show tracer during scan
  39. ; 6: 0 (not used)
  40. ; 7: 0=fast, 1=slow  (computed by floodfill routine)
  41.  
  42. XYStackBeg EQU 2*4  ;start pos of XY stack on the main stack
  43.             ;also marks the end of the prev loc check array
  44.  
  45. FALSE    EQU 0
  46. TRUE    EQU 0FFH
  47. DEBUG    EQU FALSE
  48.  
  49.      MAKEFILE EQU FALSE
  50.      SHOWLOC  EQU FALSE
  51.      IF DEBUG
  52.     INCLUDE DEBFILE.INC
  53.      ENDIF
  54.  
  55. ;-------------------------------------------------------------
  56. ;Do a floodfill in the current color using the specified X,Y address 
  57. ;in AX, BX as the seed point. CL has the border color.
  58. ;if FloodFillMode is zero, border fill is done (fill up to border).
  59. ;if FloodFillMode is non-zero, seed fill is done (fill only seed color area).
  60. ;Assume:  DS = data segment
  61. ;Entry:   AX = Seed X
  62. ;         BX = Seed Y
  63. ;         CL = Border color
  64. ;Return:  AL = 0FFH on error, 00H if went ok
  65. ;Destroy: AH
  66.  
  67. DoFloodFill PROC NEAR
  68.     PUSH    ES
  69.     PUSH    BP
  70.     PUSH    DI
  71.     PUSH    SI
  72.     PUSH    DX
  73.     PUSH    CX
  74.     PUSH    BX
  75.  
  76.     MOV    DS:[PixelX],AX        ;save seed addr
  77.     MOV    DS:[PixelY],BX
  78.     MOV    DS:[BorderColor],CL    ;save border color
  79.     CALL    GetPixelAddress
  80.     CALL    ReadPixel        ;get seed color
  81.     MOV    DS:[SeedColor],AL    ;save it for later
  82.     MOV    byte ptr DS:[StatBlock.stat],0 ;init error flag
  83.     MOV    word ptr DS:[XYStackPeak],0    ;init XY stack peak cnt
  84.     MOV    word ptr DS:[XYStackFree],0    ;init XY stack free
  85.  
  86.     MOV    AH,DS:[FloodFillType]    ;get current control flags
  87.     OR    AH,SlowFill        ;default to slow fill
  88.     TEST    AH,ComplexFill        ;if forced complex fill,
  89.     JNZ    @DoFloodFill1        ;ignore this
  90.     MOV    AL,DS:[FillPixelWriteMode] ;check fill write mode
  91.     AND    AL,17H            ;if read/modify/write
  92.     JNZ    @DoFloodFill1        ;we have to do it in slow mode
  93.     LEA    SI,[FillPattern]
  94.     MOV    CX,8
  95. @DoFloodFill0:
  96.     CMP    byte ptr DS:[SI],0FFH    ;simplex fill requires 
  97.     JNZ    @DoFloodFill1        ;forground fill color only
  98.     INC    SI            ;no pattern or background
  99.     LOOP    @DoFloodFill0        ;filling allowed
  100.  
  101.     ;if we made it this far, it is a simplex fill, so allow for it
  102.     AND    AH,0FFH-(DelayedDraw+SlowFill) ;clr draw and slow fill
  103.  
  104. @DoFloodFill1:
  105.     MOV    AL,DS:[SeedColor]
  106.     MOV    DS:[FloodFillFlags],AH  ;save operating control flags
  107.     TEST    AH,SeedFill
  108.     JNZ    @DoFloodFill2
  109.     CMP    AL,DS:[BorderColor]    ;if border fill
  110.     JNZ    @DoFloodFIll3        ;we are done if 
  111.     JMP    @FloodFillExit        ;seed is border color
  112. @DoFloodFill2:
  113.     TEST    AH,SlowFIll        ;if slow fill, we accept
  114.     JNZ    @DoFloodFill3        ;any kind of seed fill
  115.     CMP    AL,DS:[FillForeColor]    ;if fast seed fill
  116.     JNZ    @DoFloodFill3        ;we are done if 
  117.     JMP    @FloodFillExit        ;seed is fill color
  118.  
  119. @DoFloodFill3:
  120.     MOV    word ptr DS:[FillFlipX1],-1 ;init tracer addr
  121.     MOV    word ptr DS:[FillFlipX2],-1
  122.     MOV    word ptr DS:[FillFlipY],-1
  123.     MOV    word ptr DS:[XYStackAdj],6  ;init stack control var
  124.     TEST    byte ptr DS:[FloodFillFlags],StackCompress
  125.     JZ    @DoFloodFill5
  126.     MOV    word ptr DS:[XYStackAdj],4
  127. @DoFloodFill5:
  128.  
  129.      IF MAKEFILE
  130.     CALL OPENFILE
  131.      ENDIF
  132.  
  133.     MOV    AX,DS:[StatBlock.BytesPerScanLine] ;alloc whole scan line
  134.     ADD    AX,1000        ;allow 1000 extra sp bytes for interrupts
  135.     CMP    SP,AX        ;Hows the stack doing?
  136.     JNC    @FloodStackOK    ;lots of room yet!
  137.  
  138.     MOV    byte ptr DS:[StatBlock.stat],grNoFloodMem ;ack! no room! 
  139.     JMP    @FloodFillExit                     ;mark error and exit
  140.  
  141. @FloodStackOK:
  142.     SUB    SP,DS:[StatBlock.BytesPerScanLine] ;alloc whole scan line
  143.     MOV    SI,SS        ;ES:SI points to scan line buffer
  144.     MOV    ES,SI
  145.     MOV    SI,SP
  146.  
  147.     MOV    BP,XYStackBeg          ;init XY stack pointer
  148.     MOV    DS:[XYStackIndex],BP   ;init XY stack R/W pointer
  149.     MOV    DI,0        ;init the prev stack with -1
  150.     MOV    AX,-1        ;in each of the prev stack records
  151.     MOV    CX,XYStackBeg    ;(never visited location)
  152.     REP    STOSW        ;assumes ES:DI points at stack
  153.     MOV    word ptr DS:[PrevStackIndex],0  ;init prev stack index
  154.  
  155.     MOV    DX,DS:[PixelY]    ;start at seed XY point
  156.     MOV    BX,DS:[PixelX]
  157.     MOV    CX,BX
  158.     MOV    DI,0C000H    ;scan in both directions on start
  159.     CALL    FloodScan    ;scan it for stuff to do
  160.     CALL    FloodProc    ;just do it
  161.     JC    @FloodFillDone    ;don't draw if error
  162.  
  163.     TEST    byte ptr DS:[FloodFillFlags],DelayedDraw
  164.     JZ    @FloodFillDone    ;if delayed draw enabled, 
  165.     CALL    DrawXYStack    ;it is now time to draw the XY stack
  166.  
  167. @FloodFillDone:
  168.     ADD    SP,DS:[StatBlock.BytesPerScanLine] ;deallocate XY stack
  169.  
  170. @FloodFillExit:
  171.     XOR    AL,AL    ;default to no error
  172.     CMP    byte ptr DS:[StatBlock.stat],0
  173.     JZ    @FloodExitOK
  174.     MOV    AL,0FFH    ;return error flag
  175. @FloodExitOK:
  176.  
  177.      IF MAKEFILE
  178.     CALL CLOSEFILE
  179.      ENDIF
  180.  
  181.     POP    BX
  182.     POP    CX
  183.     POP    DX
  184.     POP    SI
  185.     POP    DI
  186.     POP    BP
  187.     POP    ES
  188.     RET
  189. DoFloodFill ENDP
  190.  
  191.  
  192. ;-------------------------------------------------------------
  193. ;Main flood fill procedure
  194. ;Assume:  DS = data segment
  195. ;Enter:   ES:SI = ScanLine - points to scan line buffer
  196. ;Return:  if error, returns 0F9H in [StatBlock.stat] 
  197. ;         flags = C - carray set on error
  198. ;         NC - carry clear if all ok 
  199. ;Destroy: AX,BX,CX,DX,DI,BP
  200.  
  201. FloodProc PROC NEAR
  202.     CALL    GetFlood    ;get a flood segment from the stack
  203.     JC    @FloodProcDone    ;Nothing left to do
  204.  
  205.     TEST    byte ptr DS:[FloodFillFlags],TracerOn
  206.     JZ    @FloodProc3    ;if tracer is on,
  207.     CALL    UnFlipFillScan    ;remove trace from screen
  208. @FloodProc3:
  209.     TEST    byte ptr DS:[FloodFillFlags],StackCompress
  210.     JZ    @FloodProc4    ;if stack is compressed, we have to
  211.     CALL    FindRightEdge    ;go find the right scan edge first
  212. @FloodProc4:
  213.     TEST    byte ptr DS:[FloodFillFlags],DelayedDraw
  214.     JNZ    @FloodProc5    ;if immediate drawing, 
  215.     CALL    DrawFloodLine    ;draw the flood segment
  216. @FloodProc5:
  217.     TEST    byte ptr DS:[FloodFillFlags],TracerOn ;if tracer is on,
  218.     JZ    @FloodProc6                  ;show where we are
  219.     CALL    FlipFillScan    ;BX=LeftX, CX=RightX, DX=LineY, DI=Dir
  220.  
  221. @FloodProc6:
  222.      IF SHOWLOC
  223.     CALL    WHEREXY
  224.      ENDIF
  225.  
  226.     TEST    DI,4000H    ;seek upward moving scan?
  227.     JZ    @FloodProc8    ;no, try for downward scan
  228.     DEC    DX
  229.     CMP    DX,DS:[ClipY1]    ;out of bounds?
  230.     JL    @FloodProc7    ;yes, do do this
  231.     PUSH    DI
  232.     MOV    DI,4000H    ;mark as upward scan direction
  233.     CALL    FloodScan    ;scan it for stuff to do
  234.     POP    DI
  235. @FloodProc7:
  236.     INC    DX
  237.  
  238. @FloodProc8:
  239.     TEST    DI,8000H    ;seek downward moving scan?
  240.     JZ    @FloodProc9    ;nope, so we're done
  241.     INC    DX
  242.     CMP    DX,DS:[ClipY2]    ;out of bounds?
  243.     JG    @FloodProc9    ;yes, don't do this
  244.     PUSH    DI
  245.     MOV    DI,8000H    ;mark as upward scan direction
  246.     CALL    FloodScan    ;scan it for stuff to do
  247.     POP    DI
  248. @FloodProc9:
  249.     JMP    FloodProc    ;keep on truckin'
  250.  
  251. @FloodProcDone:
  252.     TEST    byte ptr DS:[FloodFillFlags],TracerOn
  253.     JZ    @FloodProcNoTrace ;if tracer is on,
  254.     CALL    UnFlipFillScan      ;unflip the last pixel
  255.     MOV    word ptr DS:[FillFlipX1],-1
  256.     MOV    word ptr DS:[FillFlipX2],-1 ;init tracer addr
  257.     MOV    word ptr DS:[FillFlipY],-1
  258. @FloodProcNoTrace:
  259.     CMP    byte ptr DS:[StatBlock.stat],0
  260.     JZ    @FloodProcExit
  261.     STC            ;return error flag
  262. @FloodProcExit:
  263.     RET
  264.  
  265. FloodProc ENDP
  266.  
  267.  
  268. ;---------------------------------------------------------
  269. ;Scan the next flood line for stuff to do
  270. ;Assume:  DS = data segment
  271. ;Enter:   BX = LeftX       - current left edge of flood scan 
  272. ;         CX = RightX      - current right edge of flood scan 
  273. ;         DX = LineY       - current scan line
  274. ;         DI = Dir         - current Y search direction 
  275. ;      ES:SI = ScanLinePtr - pointer to scan line buffer
  276. ;
  277. ;Return:  New floodfill segments to draw on stack
  278. ;Destroy: nothing
  279.  
  280. FloodScan PROC NEAR
  281.     PUSH    BX
  282.     PUSH    CX
  283.     MOV    DS:[LeftX],BX    ;save leftX pos
  284.     MOV    DS:[RightX],CX    ;save rightX pos
  285.     CALL    ReadScanStart    ;get the inital scan read
  286.     MOV    CX,BX        ;save current pos in CX
  287.     CALL    Fillable    ;if fillable, go find left edge 
  288.     JZ    @FloodScan2    ;to the left otherwise try right
  289. @FloodScan1:
  290.     INC    BX
  291.     CMP    BX,DS:[RightX]    ;if over boundry, nothing here
  292.     JG    @FloodScanExit
  293.     CALL    Fillable    ;keep trying until something happens
  294.     JNZ    @FloodScan1
  295.     MOV    CX,BX
  296.     JMP    @FloodScanRight    ;CX and BX now has left edge of scan
  297.  
  298. ;let's try to find the left edge of the scan segment
  299. @FloodScan2:
  300.     DEC    BX
  301.     CMP    BX,DS:[ClipX1]    ;if at left edge,
  302.     JL    @FloodScan3    ;go find right edge
  303.     CALL    ReadScanLeft    ;make sure we have it in memory
  304.     CALL    Fillable    ;scan until we find edge
  305.     JZ    @FloodScan2    ;CX still has last good right pos
  306. @FloodScan3:
  307.     INC    BX        ;restore BX back to valid pixel
  308.  
  309. ;ok, we got a valid left pixel, now find the right pixel of the scan
  310. @FloodScanRight:
  311.     XCHG    BX,CX        ;Swap CX/BX and search for right edge
  312. @FloodScan4:
  313.     INC    BX
  314.     CMP    BX,DS:[RightX]    ;if we bump into master edge
  315.     JG    @FloodScan6    ;go handle seperately
  316.     CALL    Fillable
  317.     JZ    @FloodScan4    ;keep going until full segment found
  318.     DEC    BX        ;make BX valid
  319.     XCHG    BX,CX        ;swap the regs back to normal
  320.     CALL    FloodPush    ;save it on the stack
  321.     INC    CX
  322.     MOV    BX,CX        ;start new search at right edge +1
  323.     JMP    @FloodScan1    ;go find the next left edge
  324.  
  325. @FloodScan6:
  326.     CMP    BX,DS:[ClipX2]    ;are we at the right limit?
  327.     JG    @FloodScan8    ;yup, so go save it and we're done
  328.     CALL    ReadScanRight    ;make sure we have it in memory
  329.     CALL    Fillable    ;if not fillable
  330.     JNZ    @FloodScan8    ;go save it and we're done
  331.     INC    BX
  332.     JMP    @FloodScan6    ;keep a tryin'
  333.  
  334. @FloodScan8:
  335.     DEC    BX        ;make BX valid
  336.     XCHG    CX,BX        ;swap the regs back to normal
  337.     CALL    FloodPush    ;save the scan segment
  338. @FloodScanExit:
  339.     POP    CX
  340.     POP    BX
  341.     RET
  342. FloodScan ENDP
  343.  
  344.  
  345. ;---------------------------------------------------------
  346. ;Assume:  DS    = data segment
  347. ;Enter:   ES:SI = points to scan line buffer
  348. ;         BX    = buffer index (X) 
  349. ;      DX    = scan line number (Y)
  350. ;Return:  flags = Z - ok to write,  NZ - not ok to write
  351. ;Destory: Nothing
  352.  
  353. Fillable PROC NEAR
  354.     PUSH    AX
  355.     TEST    byte ptr DS:[FloodFillFlags],SeedFill
  356.     JNZ    @SeedFillCheck          ;seed file type?
  357.  
  358.     MOV    AL,ES:[SI+BX]          ;is this a border color?
  359.     CMP    AL,DS:[BorderColor]
  360.     JZ    @NotFillable
  361.     TEST    byte ptr DS:[FloodFillFlags],SlowFill
  362.     JNZ    @IsFillable
  363.     CMP    AL,DS:[FillForeColor] ;how about the fill color?
  364.     JZ    @NotFillable
  365. @IsFillable:
  366.     XOR    AL,AL              ;nope, so ok to fill it
  367.     POP    AX
  368.     RET
  369.  
  370. @NotFillable:
  371.     OR    AL,0FFH              ;its not a fillable pixel
  372.     POP    AX
  373.     RET
  374.  
  375. @SeedFillCheck:
  376.     MOV    AL,ES:[SI+BX]
  377.     CMP    AL,DS:[SeedColor]      ;is this a seed color?
  378.     POP    AX
  379.     RET
  380. Fillable ENDP
  381.  
  382.  
  383.  
  384. ;-----------------------------------------------------------
  385. ;Push a flood line segment on the XY stack
  386. ;Assume:  DS = data segment
  387. ;Enter:   BP = XY stack - index into XY flood stack
  388. ;         BX = LeftX    - left edge of scan line flood segment
  389. ;         CX = RightX   - right edge of scan line flood segment
  390. ;      DX = LineY    - scan line number
  391. ;      DI = Dir      - direction of Y movement : 4000H=up, 8000H=down
  392. ;Return:  BP = XY stack - new XY flood stack index 
  393. ;      flags = NC - values pushed on stack ok
  394. ;              C  - nothing pushed (stack overflow)
  395. ;Destroy: nothing
  396.  
  397. FloodPush PROC NEAR
  398.     ADD    BP,1000        ;check on stack condition
  399.     CMP    SP,BP        ;allow 1000 bytes for interrupts
  400.     JNC    @FloodPushStart    ;it's ok, so go push the data
  401.     MOV    byte ptr DS:[StatBlock.stat],grNoFloodMem ;ack! no room! 
  402.     SUB    BP,1000        ;restore XY stack pointer
  403.     STC            ;return carry set on error
  404.     RET
  405.  
  406. @FloodPushStart:
  407.     SUB    BP,1000        ;restore XY stack ptr to normal
  408.     PUSH    DI        ;presume default dir search
  409.     CMP    BX,DS:[LeftX]    ;over left edge?
  410.     JL    @FloodPush1    ;if so, search both dir
  411.     CMP    CX,DS:[RightX]    ;over right edge?
  412.     JLE    @FloodPush2    ;if so, search both dir
  413. @FloodPush1:
  414.     MOV    DI,0C000H    ;0C000H = both dir search
  415. @FloodPush2:
  416.     CALL    PushCheck    ;Have we been here before?
  417.     JZ    @FloodPushExit    ;yes, so don't do this
  418.     PUSH    DX
  419.     OR    DX,DI        ;mix dir with LineY to save stack space
  420.     MOV    SS:[BP+0],DX    ;save XL,XR,Y,Dir on the stack
  421.     MOV    SS:[BP+2],BX    ;BX=LeftX    CX=RightX
  422.     TEST    byte ptr DS:[FloodFillFlags],StackCompress
  423.     JNZ    @FloodPush4    ;DX=LineY    DI=Dir
  424.     MOV    SS:[BP+4],CX    ;don't push CX if compressed
  425. @FloodPush4:
  426.      IF MAKEFILE
  427.     CALL WRITEFILE        ;copy stack info to file for debugging
  428.      ENDIF
  429.     POP    DX
  430.     ADD    BP,DS:[XYStackAdj] ;adjust stack up
  431.     MOV    DS:[XYStackIndex],BP
  432.     CMP    BP,DS:[XYStackPeak]
  433.     JC    @FloodPushExit
  434.     MOV    DS:[XYStackPeak],BP ;save peak stack level
  435.     MOV    DI,SP
  436.     SUB    DI,1000
  437.     SUB    DI,BP
  438.     MOV    DS:[XYStackFree],DI ;save stack free space
  439. @FloodPushExit:
  440.     POP    DI
  441.     OR    DI,DI        ;make sure carry flag is clear
  442.     RET            ;for good return
  443. FloodPush ENDP
  444.  
  445.  
  446. ;------------------------------------------------------------
  447. ;check if we've been to this scan before. For fast fill, we
  448. ;use a short previous stack to prevent lockups. For slow fill
  449. ;we have to track everything, so we watch the XY stack instead.
  450. ;Enter:  BX = LeftX - left edge of scan line flood segment
  451. ;     DX = LineY - scan line number
  452. ;        DI = Dir   - direction of Y movement : 4000H=up, 8000H=down
  453. ;Return: flags:  Z= we've been there
  454. ;        NZ= never seen that one before
  455. ;Destroy: nothing
  456.  
  457. PushCheck PROC NEAR
  458.     TEST    byte ptr DS:[FloodFillFlags],SlowFill
  459.     JNZ    StackCheck     ;check XY stack if slow fill
  460.     OR    DI,DI         ;non-direction scan, so don't push it
  461.     RET             ;rets NZ if directional, Z if not
  462.  
  463. StackCheck:
  464.     PUSH    BP           ;slow stack check 
  465.     PUSH    AX
  466.  
  467. @StackCheckNext:
  468.     SUB    BP,DS:[XYStackAdj] ;check if anything 
  469.     CMP    BP,XYStackBeg       ;is on the XY stack
  470.     JC    @StackCheckDone       ;nope, so we're done
  471. @StackCheckLoop:
  472.     CMP    SS:[BP+2],BX       ;ScanX - have we been here?
  473.     JNZ    @StackCheckNext       ;nope, so try next pos
  474.     MOV    AX,SS:[BP+0]       ;LineY - have we been here?
  475.     AND    AX,03FFFH       ;if so, we're done
  476.     CMP    AX,DX           ;else try the next pos
  477.     JNZ    @StackCheckNext       ;nope, so try next pos
  478.  
  479. @StackCheckExit:
  480.     XOR    AX,AX           ;we found something so ret Z
  481.     POP    AX
  482.     POP    BP
  483.     RET
  484.  
  485. @StackCheckDone:
  486.     OR    AX,1           ;nothing found so ret NZ
  487.     POP    AX
  488.     POP    BP
  489.     RET
  490.  
  491. PushCheck ENDP
  492.  
  493.  
  494. ;-----------------------------------------------------------
  495. ;Get a flood line segment from the XY stack
  496. ;Assume:  DS = data segment
  497. ;Enter:   BP = XY stack  - index into XY flood stack
  498. ;      [XYStackIndex] - read index into XY stack
  499. ;Return:  BX = LeftX     - left edge of flood scan line 
  500. ;      CX = RightX    - right edge of flood scan line (uncompressed) 
  501. ;      DX = LineY     - flood scan line 
  502. ;      DI = Dir       - direction of Y movement to search
  503. ;      BP = XY stack  - new XY flood stack index 
  504. ;      [XYStackIndex] - new XY stack read index 
  505. ;      flags = NC - valid value returned
  506. ;              C  - nothing returned (stack is empty)
  507. ;Destroy: nothing (in compressed CX is invalid)
  508.  
  509. GetFlood PROC NEAR
  510.     TEST    byte ptr DS:[FloodFillFlags],SlowFill
  511.     JZ    FloodPop
  512.  
  513. ;Read the stack, but leave it intact (slow fill mode)
  514. XYStackRead:
  515.     PUSH    SI
  516.     MOV    SI,DS:[XYStackIndex]
  517. @XYStackLoop1:
  518.     SUB    SI,DS:[XYStackAdj] ;check on condition of XY stack
  519.     CMP    SI,XYStackBeg
  520.     JC    @XYStackReadExit ;its empty Jim
  521.     MOV    DX,SS:[SI+0]     ;DX=LineY     DI=Dir
  522.     MOV    DI,DX         ;DI = Dir - direction of Y movement
  523.     AND    DI,0C000H     ;8000H = downward, 0C000H = both dir
  524.     JZ    @XYStackLoop1     ;4000H = seek upward movement, 0=neither
  525.     MOV    DS:[XYStackIndex],SI ;update stack read index
  526.     AND    DX,3FFFH
  527.     MOV    SS:[SI+0],DX     ;update dir flags on stack
  528.     MOV    BX,SS:[SI+2]      ;pop XL,XR,Y,Dir off the stack
  529.     MOV    CX,SS:[SI+4]     ;BX=LeftX     CX=RightX
  530. @XYStackReadExit:
  531.     POP    SI
  532.     RET             ;returns carry set on empty stack
  533.  
  534. ;pop a level off the stack - adjs stack ptr (fast fill mode)
  535. FloodPop:
  536.     SUB    BP,DS:[XYStackAdj] ;check on condition of XY stack
  537.     CMP    BP,XYStackBeg
  538.     JC    @FloodPopExit    ;its empty Jim
  539.     MOV    CX,SS:[BP+4]     ;pop XL,XR,Y,Dir off the stack
  540.     MOV    BX,SS:[BP+2]    ;BX=LeftX     CX=RightX
  541.     MOV    DX,SS:[BP+0]    ;DX=LineY     DI=Dir
  542.     MOV    DI,DX        ;DI = Dir - direction of Y movement
  543.     AND    DX,3FFFH    ;4000H = seek upward movement
  544.     AND    DI,0C000H    ;8000H = downward, 0C000H = both dir
  545. @FloodPopExit:
  546.     RET            ;returns carry set on empty stack
  547.  
  548. GetFlood ENDP
  549.  
  550. ;-----------------------------------------------------------
  551. ;find the right edge of the flood scan line
  552. ;Assume:  DS = data segment
  553. ;Enter:   BX = LeftX  - left edge of flood scan line 
  554. ;      DX = LineY  - scan line to read 
  555. ;Return:  BX = LeftX  - left edge of flood scan line 
  556. ;      CX = RightX - right edge of flood scan line
  557. ;      flags = NC - no carry if data found 
  558. ;               C - carry set on error
  559. ;Destroy: nothing
  560.  
  561. FindRightEdge PROC NEAR
  562.     MOV    CX,BX
  563.     CALL    ReadScanStart    ;init right scan pos
  564.     CALL    Fillable
  565.     JZ    @FindRightEdge1
  566.     STC
  567.     RET
  568.  
  569. @FindRightEdge1:
  570.     INC    BX         ;we presume at least one pixel here
  571.     CMP    BX,DS:[ClipX2]     ;if at left edge we're done
  572.     JG    @FindRightEdge2
  573.     CALL    ReadScanRight     ;make sure data is in buffer
  574.     CALL    Fillable     ;if fillable, go find right edge 
  575.     JZ    @FindRightEdge1  ;else we are done
  576. @FindRightEdge2:
  577.     DEC    BX         ;restore BX
  578.     XCHG    BX,CX         ;swap regs to proper places
  579.     RET
  580. FindRightEdge ENDP
  581.  
  582.  
  583. ;---------------------------------------------------------
  584. ;Read an initial scan line segment from the display 
  585. ;Assume:  DS = data segment
  586. ;Enter:      BX = LextX  - left edge of scan segment
  587. ;      CX = RightX - right edge of scan segment
  588. ;      DX = LineY  - scan line to read 
  589. ;Return:  Scan line buffer is updated with new scan line data
  590. ;Destroy: nothing
  591.  
  592. ReadScanStart PROC NEAR
  593.     CALL    ReadScan          ;read the indicated segment
  594.     MOV    DS:[ScanLeftX],BX     ;mark which segment we have read
  595.     MOV    DS:[ScanRightX],CX
  596.     RET
  597. ReadScanStart ENDP
  598.  
  599.  
  600. ;---------------------------------------------------------
  601. ;Read a scan line segment from the display to the left of normal
  602. ;Assume:  DS = data segment
  603. ;Enter:      BX = LextX - left edge of scan segment
  604. ;      DX = LineY - scan line to read 
  605. ;Return:  Scan line buffer is updated with new scan line data
  606. ;Destroy: nothing
  607.  
  608. ReadScanLeft PROC NEAR
  609.     CMP    BX,DS:[ScanLeftX]    ;is it in memory already?
  610.     JGE    @ReadScanLeftExit    ;yep, so no need to get it
  611.     PUSH    CX
  612.     PUSH    BX
  613.     MOV    CX,DS:[ScanLeftX]    ;gotta go get the data
  614.     SUB    BX,8            ;grab it in eight pixel chunks
  615.     CMP    BX,DS:[ClipX1]        ;or to the left limit
  616.     JGE    @ReadScanLeft2        ;whichever is first
  617.     MOV    BX,DS:[ClipX1]
  618. @ReadScanLeft2:
  619.     CALL    ReadScan        ;go read the additional data
  620.     MOV    DS:[ScanLeftX],BX    ;save new location
  621.     POP    BX
  622.     POP    CX
  623. @ReadScanLeftExit:
  624.     RET
  625. ReadScanLeft ENDP
  626.  
  627.  
  628. ;---------------------------------------------------------
  629. ;Read a scan line segment from the display to the right of normal
  630. ;Assume:  DS = data segment
  631. ;Enter:      BX = RightX - right edge of scan segment
  632. ;      DX = LineY  - scan line to read 
  633. ;Return:  Scan line buffer is updated with new scan line data
  634. ;Destroy: nothing
  635.  
  636. ReadScanRight PROC NEAR
  637.     CMP    BX,DS:[ScanRightX]    ;is it in memory already?
  638.     JLE    @ReadScanRightExit    ;yep, so no need to get it
  639.     PUSH    CX
  640.     PUSH    BX
  641.     MOV    CX,BX
  642.     MOV    BX,DS:[ScanRightX]    ;gotta go get the data
  643.     ADD    CX,8            ;grab it in eight pixel chunks
  644.     CMP    CX,DS:[ClipX2]        ;or to the left limit
  645.     JLE    @ReadScanRight2        ;whichever is first
  646.     MOV    CX,DS:[ClipX2]
  647. @ReadScanRight2:
  648.     CALL    ReadScan        ;go read the additional data
  649.     MOV    DS:[ScanRightX],CX    ;save new location
  650.     POP    BX
  651.     POP    CX
  652. @ReadScanRightExit:
  653.     RET
  654. ReadScanRight ENDP
  655.  
  656.  
  657. ;---------------------------------------------------------
  658. ;Read a scan line segment from the display 
  659. ;Assume:  DS = data segment
  660. ;Enter:      BX = LextX  - left edge of scan segment
  661. ;      CX = RightX - right edge of scan segment
  662. ;      DX = LineY  - scan line to read 
  663. ;Return:  Scan line buffer is updated with new scan line data
  664. ;Destroy: nothing
  665.  
  666. ReadScan PROC NEAR
  667.     PUSH    SI
  668.     PUSH    DI
  669.     PUSH    CX
  670.     PUSH    BX
  671.     PUSH    AX
  672.     ADD    SI,BX             ;index into the scan buffer
  673.     SUB    CX,BX             ;determine how many pixels to read
  674.     INC    CX
  675.     MOV    AX,CX                 ;set the length
  676.     MOV    CX,BX             ;start at LeftX position
  677.     MOV    BX,1             ;read only one scan line
  678.     LEA    DI,ReadBitMap         ;on scan line Y (reg DX)
  679.     CALL    DoBitMap          ;returns scan line in ES:SI
  680.     POP    AX
  681.     POP    BX
  682.     POP    CX
  683.     POP    DI
  684.     POP    SI
  685.     RET
  686. ReadScan ENDP
  687.  
  688.  
  689. ;---------------------------------------------------------
  690. ;Draw flood fill line on screen
  691. ;Assume:  DS = data segment
  692. ;Enter:      BX = LeftX     - left edge of scan line to be drawn
  693. ;      CX = RightX    - right edge of scan line to be drawn
  694. ;      DX = LineY     - current scan line to draw 
  695. ;Return:  nothing
  696. ;Destroy: nothing
  697.  
  698. DrawFloodLine PROC NEAR
  699.     PUSH    DI
  700.     PUSH    BX
  701.     PUSH    CX
  702.     SUB    CX,BX         ;write between BX and CX
  703.     INC    CX
  704.     MOV    AX,CX         ;AX = width 
  705.     MOV    CX,BX         ;start at left edge mark
  706.     MOV    BX,1         ;write only one scan line
  707.     LEA    DI,WriteFillLine ;on scan line Y (reg DX)
  708.     CALL    DoBitMap
  709.     POP    CX
  710.     POP    BX
  711.     POP    DI
  712.     RET
  713. DrawFloodLine ENDP
  714.  
  715.  
  716. ;---------------------------------------------------------
  717. ;Draw flood fill segments sitting on the XY stack
  718. ;Assume:  DS = data segment
  719. ;Enter:      flood fill segment list is on the XY stack
  720. ;Return:  nothing
  721. ;Destroy: nothing
  722.  
  723. DrawXYStack PROC NEAR
  724.     CALL    FloodPop     ;get a scan segment from stack 
  725.     JC    @DrawXYStackDone ;stack is empty
  726.     TEST    byte ptr DS:[FloodFillFlags],StackCompress
  727.     JZ    @DrawXYStack1    ;if stack is compressed, we have to
  728.     CALL    FindRightEdge    ;go find the right scan edge first
  729. @DrawXYStack1:
  730.     CALL    DrawFloodLine     ;draw the segment
  731.     JMP    DrawXYStack     ;do it until it hurts
  732. @DrawXYStackDone:
  733.     RET
  734. DrawXYStack ENDP
  735.  
  736.  
  737. ;------------------------------------------------------------
  738. ;Flip the pixel at the address passed. Used by Tracer
  739. ;to show tracing pixel while searching the display.
  740. ;Assume:  DS = data segment
  741. ;Enter:   BX = LextX  - left edge of scan segment being processed
  742. ;      CX = RightX - right edge of scan segment
  743. ;      DX = LineY  - scan line being processed 
  744. ;Return:  (screen pixel in inverted)
  745. ;Destroy: nothing
  746.  
  747. FlipFillScan PROC NEAR
  748.     PUSH    AX
  749.     PUSH    BX
  750.     MOV    DS:[FillFlipY],DX
  751.     MOV    DS:[FillFlipX1],BX
  752.     MOV    DS:[FillFlipX2],CX
  753.     MOV    DS:[PixelY],DX
  754.     MOV    DS:[PixelX],BX
  755.     CALL    GetPixelAddress
  756.     CALL    ReadPixel
  757.     MOV    byte ptr DS:[OldFlipColors],AL
  758.     NOT    AL
  759.     CALL    WritePixel
  760.  
  761.     CMP    BX,CX
  762.     JZ    @FlipFillScan1
  763.     INC    word ptr DS:[PixelX]
  764.     CALL    GetPixelAddress
  765.     CALL    ReadPixel
  766.     MOV    byte ptr DS:[OldFlipColors+1],AL
  767.     NOT    AL
  768.     CALL    WritePixel
  769. @FlipFillScan1:
  770.  
  771.     POP    BX
  772.     POP    AX
  773.     RET
  774. FlipFillScan ENDP
  775.  
  776.  
  777. ;------------------------------------------------------------
  778. ;UnFlip the pixel at the address passed. Used by Tracer
  779. ;to restore old pixel before writing new one.
  780. ;Assume:  DS = data segment
  781. ;Enter:   nothing
  782. ;Return:  (old pixel is restored)
  783. ;Destroy: nothing
  784.  
  785. UnFlipFillScan PROC NEAR
  786.     PUSH    AX
  787.     PUSH    BX
  788.     MOV    BX,DS:[FillFlipX1]
  789.     CMP    BX,-1        ;if never used, don't unflip
  790.     JZ    @UnFlipFillExit
  791.     MOV    DS:[PixelX],BX
  792.     MOV    BX,DS:[FillFlipY]
  793.     MOV    DS:[PixelY],BX
  794.     CALL    GetPixelAddress
  795.     MOV    AL,byte ptr DS:[OldFlipColors]
  796.     CALL    WritePixel
  797.  
  798.     MOV    BX,DS:[FillFlipX2]
  799.     CMP    BX,DS:[FillFlipX1]
  800.     JZ    @UnFlipFillExit
  801.     INC    word ptr DS:[PixelX]
  802.     CALL    GetPixelAddress
  803.     MOV    AL,byte ptr DS:[OldFlipColors+1]
  804.     CALL    WritePixel
  805. @UnFlipFillExit:
  806.     POP    BX
  807.     POP    AX
  808.     RET
  809. UnFlipFillScan ENDP
  810.  
  811.  
  812. ;------------------------------------------------------------
  813.  
  814.  
  815. ;@PushCheck1:
  816. ;    PUSH    SI         ;used by fast fill
  817. ;    PUSH    DI         ;check the prev loc stack 
  818. ;    MOV    DI,0         ;to see if we've been here recently
  819. ;@PushCheckLoop:
  820. ;    CMP    SS:[DI+0],DX
  821. ;    JNZ    @PushCheckNext     ;lineY the same?
  822. ;    CMP    SS:[DI+2],BX
  823. ;    JZ    @PushCheckExit     ;ScanX the same?
  824. ;@PushCheckNext:
  825. ;    ADD    DI,4         ;not the same
  826. ;    CMP    DI,XYStackBeg     ;so adj the stack and try again
  827. ;    JC    @PushCheckLoop     ;nothing found, so we're done
  828. ;
  829. ;    MOV    DI,DS:[PrevStackIndex]
  830. ;    ADD    DI,4         ;adjust prev stack pointer
  831. ;    CMP    DI,XYStackBeg
  832. ;    JC    @PushCheckStuff     ;if stack overflowed
  833. ;    MOV    DI,0         ;wrap pointer to zero
  834. ;@PushCheckStuff:
  835. ;    MOV    DS:[PrevStackIndex],DI
  836. ;    MOV    SS:[DI+0],DX     ;stuff current location 
  837. ;    MOV    SS:[DI+2],BX     ;onto the prev stack
  838. ;    INC    DI
  839. ;@PushCheckExit:
  840. ;    POP    DI
  841. ;    POP    SI
  842. ;    RET
  843.  
  844.  
  845.