.module FloodFill ;------------------------------------------------------------------------------- ;@doc:routine ; ; === Graphics.FloodFill.AllocMem === ; ; Allocates memory for the flood-filler. You MUST call this immediately before ; using any of the flood-filling routines. The memory is not marked as being ; reserved so you do not need to free it afterwards. ; ; OUTPUTS: ; REGISTERS ; * F - Carry flag set if there is not enough free memory. ; ; DESTROYS: ; REGISTERS ; * HL, DE, AF. ; ;@doc:end ;------------------------------------------------------------------------------- AllocMem ld hl,($A0E4) ; HIMEM ld de,($A0E2) ; Free memory after heap. or a sbc hl,de ; HL = amount of free space between top of heap and HIMEM ld de,768*2+256 ; Minimum amount of free RAM to fill. or a sbc hl,de ret c ld hl,($A0E2) ld (FillQueue),hl inc h inc h inc h ld (FillQueueEnd),hl ld (FillToColourBuffer),hl or a ret ;------------------------------------------------------------------------------- ;@doc:routine ; ; === Graphics.FloodFill.FillToColour === ; ; Flood-fills a region of the screen buffer with a pattern. ; ; INPUTS: ; REGISTERS ; * IXH - X co-ordinate to start filling from. ; * IXL - Y co-ordinate to start filling from. ; MEMORY ; * Graphics.PatternBuffer - Pattern to fill with. ; * Graphics.Bounds - Graphic viewport boundaries. ; ; ;@doc:end ;------------------------------------------------------------------------------- FillToColour ld a,ixl ld l,a ld a,ixh call GetPixelInfo and (hl) push af jr z,+ ld hl,(Lcd.Buffer) ld bc,3 - ld a,(hl) cpl ld (hl),a inc hl djnz - dec c jr nz,- + ld hl,(Lcd.Buffer) ld de,(FillToColourBuffer) ld bc,768 ldir call Fill ld hl,(FillToColourBuffer) ld de,(Lcd.Buffer) ld ix,PatternBuffer pop af jr z,FillToColourWhite FillToColourBlack di push iy ld c,64 -- ld b,12 - ld a,(de) ld iyl,a ld a,(ix+0) cpl and iyl or (hl) cpl ld (de),a inc hl inc de djnz - inc ix ld a,c dec a and 7 jr nz,+ ld ix,PatternBuffer + dec c jr nz,-- pop iy ei ret FillToColourWhite ld c,64 -- ld b,12 - ld a,(de) and (ix+0) or (hl) ld (de),a inc hl inc de djnz - inc ix ld a,c dec a and 7 jr nz,+ ld ix,PatternBuffer + dec c jr nz,-- ret ;------------------------------------------------------------------------------- ;@doc:routine ; ; === Graphics.FloodFill.Fill === ; ; Flood-fills a white region of the screen buffer black. ; ; INPUTS: ; REGISTERS ; * IXH - X co-ordinate to start filling from. ; * IXL - Y co-ordinate to start filling from. ; MEMORY ; * Graphics.Bounds - Graphic viewport boundaries. ; ;@doc:end ;------------------------------------------------------------------------------- Fill ld de,0 ld (FillQueueLength),de ld de,(FillQueue) ld (FillQueueReadPointer),de ld (FillQueueWritePointer),de ld a,ixl ld l,a ld a,ixh call GetPixelInfo and (hl) ret nz call Enqueue FillLoop ; Check if the queue is empty. ld hl,(FillQueueLength) ld a,h or l jp z,FinishedFilling ; So, there's something worth checking to fill. call Dequeue ld a,ixl ld l,a ld a,ixh call GetPixelInfo ; Is this point fillable? ld c,a ld a,(hl) and c jr nz,FillLoop ld a,c ; At this point, we need to find the lower and upper bounds to fill. push hl ; \_ Save these for tracing West. push af ; / ld d,a ; d = pixel mask. ld b,ixh ; b = x - ld a,(Bounds+0) cp b jr z,HitLeftViewportBound dec b rlc d jr nc,+ dec hl + ld a,(hl) and d jr z,- inc b HitLeftViewportBound ; b = left bound. pop af ; \_ Restore these for tracing East. pop hl ; / ld d,a ; d = pixel mask. ld c,ixh ; c = x - ld a,(Bounds+1) cp c jr z,HitRightViewportBound inc c rrc d jr nc,+ inc hl + ld a,(hl) and d jr z,- dec c HitRightViewportBound ; c = right bound. push bc ; We'll need these bounds in a minute. ld a,ixl call FloodFillScanline pop bc ; That's one scanline handled. We need to check the scanline above us and below us! ld a,c sub b inc a ld c,b ; c = lower bound. ld b,a ; b = number of pixels on filled scanline. push ix ; Save current coordinates. push bc ; Save start of scanline and pixel count data. dec ixl ld a,ixl ld l,a ld a,(Bounds+2) dec a cp l jr z,HitTopViewportBound ld ixh,c ld a,c ; Lower bound. push bc call GetPixelInfo pop bc ld c,a ; c = pixel mask. - ld a,(hl) and c jr nz,+ call Enqueue + inc ixh ; Move X along. rrc c jr nc,+ inc hl + djnz - HitTopViewportBound pop bc ; Restore start of scanline and pixel count data. pop ix ; Restore current coordinates. inc ixl ld a,ixl ld l,a ld a,(Bounds+3) inc a cp l jr z,HitBottomViewportBound ld ixh,c ld a,c ; Lower bound. push bc call GetPixelInfo pop bc ld c,a ; c = pixel mask. - ld a,(hl) and c jr nz,+ call Enqueue + inc ixh ; Move X along. rrc c jr nc,+ inc hl + djnz - HitBottomViewportBound ; Loop! jp FillLoop FinishedFilling ret Enqueue push hl ; ++length ld hl,(FillQueueLength) inc hl ld (FillQueueLength),hl ld hl,(FillQueueWritePointer) ld de,(FillQueueEnd) or a sbc hl,de ld hl,(FillQueue) jr z,WrappedEnqueue ld hl,(FillQueueWritePointer) WrappedEnqueue ld a,ixh ld (hl),a inc hl ld a,ixl ld (hl),a inc hl ld (FillQueueWritePointer),hl pop hl ret Dequeue push hl ; --length ld hl,(FillQueueLength) dec hl ld (FillQueueLength),hl ld hl,(FillQueueReadPointer) ld de,(FillQueueEnd) or a sbc hl,de ld hl,(FillQueue) jr z,WrappedDequeue ld hl,(FillQueueReadPointer) WrappedDequeue ld a,(hl) inc hl ld ixh,a ld a,(hl) inc hl ld ixl,a ld (FillQueueReadPointer),hl pop hl ret ;------------------------------------------------------------------------------- ;@doc:routine ; ; === FloodFillScanline === ; ; Fills a horizontal line segment with black. ; ; INPUTS: ; ; REGISTERS ; * A - Y co-ordinate ; * B - Line x1 (pixel offset from DE) ; * C - Line x2 (pixel offset from DE) ; ;@doc:end ;------------------------------------------------------------------------------- FloodFillScanline ;------------------------------------------------------------------- ; Calculate A * 12 and offset into canvas ;------------------------------------------------------------------- push bc ld l,a add a,a add a,l ld l,a ld h,0 add hl,hl add hl,hl ld de,(Lcd.Buffer) add hl,de ex de, hl ;------------------------------------------------------------------- ; Calculate the starting byte offset and add to DE. ;------------------------------------------------------------------- ld a,b and ~7 rra rra rra add a,e ld e,a ld a,d adc a,0 ld d,a ;------------------------------------------------------------------- ; Calculate the width of the line and store the result in C. ;------------------------------------------------------------------- ld a,c sub b ld c,a ld a,b and 7 ld b,a ld l,hFillPlotMask add a,l ld l,a ld a,7 sub b sub c ld b,h ld h,hFillPlotMask >> 8 jp nc,FloodFillByteScanline ;------------------------------------------------------------------- ; Draw left edge of line [57] ;------------------------------------------------------------------- neg ld c,a ld l,(hl) ld a,(de) and l ld h,a ld a,l cpl or h ld (de),a ;------------------------------------------------------------------- ; Draw middle segment of line [45 + 26 per byte] ;------------------------------------------------------------------- ld a,c and ~7 jp z,FloodFillLineEnd rra rra rra ld b,a ld a,$FF - inc de ld (de),a djnz - ;------------------------------------------------------------------- ; Draw right edge of line [107] ;------------------------------------------------------------------- FloodFillLineEnd ld a,c and 7 jp z,FloodFillScanlineRet ld hl,hFillPlotMask add a,l ld l,a ld a,(hl) inc de ld a,(de) or (hl) ld (de),a FloodFillScanlineRet pop bc ret ;------------------------------------------------------------------- ; This code is to handle the special case of x1 and x2 both ; residing in the same byte of screen RAM. ;------------------------------------------------------------------- FloodFillByteScanline ld a,c inc a add a,l ld c,(hl) ld l,a ld a,(hl) xor c ld h,a ;and b ld l,a ld a,h cpl ex de,hl and (hl) or e ld (hl),a pop bc ret .endmodule