fill tool

Blitz3D Forums/Blitz3D Programming/fill tool

Picklesworth(Posted 2004) [#1]
okay, let's say I'm making a paint program (I'm not actually, it's a texture system, but this is easier to explain if I leave you in the dark about everything).
Now, I'm designing a function like a fill tool. It just fills black into an area within surrounding lines, no matter what their shape, as long as they form an enclosed area. How can I make this work?
In other words, How can I make a paint bucket tool function? (like in paint, photoshop, and all other drawing programs)


Shambler(Posted 2004) [#2]
In C++ but fairly readable http://www.codeproject.com/gdi/QuickFill.asp

Also a good explanation of some of the simpler methods http://www.cs.unc.edu/~mcmillan/comp136/Lecture8/areaFills.html


BlackJumper(Posted 2004) [#3]
OT:

I remember reading somewhere that in the early days at Micro$oft some hotshot programmer started to pull the 'Fill' code in the early version of Paint apart... saying how badly coded it was... what a moron the original programmer must be to write such poorly optimised code. Turned out that good old Bill had written that routine himself. Caused a bit of a frosty relationship.

Moral: choose a good 'Fill' example or only hire people who are less smart than you are ;-)


ShadowTurtle(Posted 2004) [#4]
Hoi

Heres many routines:

Graphics 640, 480, 32, 2
rgbalt% = 0
rgbneu% = 255*$10000 + 100*$100 + 50
Color 255, 255, 255
Oval 0, 0, 200, 200, 0
WaitKey()
LockBuffer FrontBuffer()
fuellen_rekursiv(100, 100, FrontBuffer(), 640, 480, rgbalt%, rgbneu%)
UnlockBuffer FrontBuffer()
Flip
WaitKey()
End


Function fuellen_rekursiv(x%, y%, buffer%, breite%, hoehe%, rgbalt%, rgbneu%)   
   ;x%, y% -> Koordinaten des Pixels
   ;buffer% -> Identität des Buffers, in dem gearbeitet wird
   ;breite%, hoehe% -> Größe des Buffers
   ;rgbalt% -> RGB-Wert der Farbe, die geändert werden soll
   ;rgbneu% -> RGB-Wert der Farbe, die das Pixel annehmen soll
   ;      => rgb = r*$10000 + g*$100 + b
   If (ReadPixelFast(x%, y%, buffer%)And $FFFFFF)=rgbalt% Then
      WritePixelFast(x%, y%, rgbneu%, buffer%)
      If (x% + 1)<breite% Then fuellen_rekursiv((x% + 1), y%, buffer%, breite%, hoehe%, rgbalt%, rgbneu%)
      If (x% - 1)>=0 Then fuellen_rekursiv((x% - 1), y%, buffer%, breite%, hoehe%, rgbalt%, rgbneu%)
      If (y% + 1)<hoehe% Then fuellen_rekursiv(x%, (y% + 1), buffer%, breite%, hoehe%, rgbalt%, rgbneu%)
      If (y% - 1)>=0 Then fuellen_rekursiv(x%, (y% - 1), buffer%, breite%, hoehe%, rgbalt%, rgbneu%)
   EndIf
End Function


; Kreisfunktion

Graphics 640, 480, 16, 2
AppTitle "Kreisfunktion"

Print "Press any key to start"
WaitKey

Start = MilliSecs()
 Kreis(320,240,100,1,255,0,0) ; Kreis(X, Y, Radius, Füllung, r,g,b)
Zeit = MilliSecs() - Start

Color 255,255,255
Print "Benötigte Zeit: " + Zeit + "ms"

WaitKey
End


Function Kreis(PosX, PosY, Radius, Fill, r, g, b)

 LockBuffer FrontBuffer() 
  If Fill = 0
   For grad# = 0 To 360 Step .05
    x = ((Sin (grad#) * radius) + PosX)
    y = ((Cos (grad#) * radius) + PosY)
    WritePixelFast x, y, a*$1000000 + r*$10000 + g*$100 + b
   Next
  EndIf

  If Fill = 1 Then
   For rad = radius To 0 Step -1
    For grad# = 0 To 360 Step .3
     x = ((Sin (grad#) * rad) + PosX)
     y = ((Cos (grad#) * rad) + PosY)   
     WritePixelFast x, y, a*$1000000 + r*$10000 + g*$100 + b
    Next
   Next
  EndIf
 UnlockBuffer FrontBuffer()

End Function


Graphics 800,600,32
SeedRnd MilliSecs()

Global x1,y1,NeueFarbe,AlteFarbe
Global xstart,xend,ystart,yend

xstart=100
xend=400
ystart=100
yend=400

NeueFarbe=$ff0000ff
AlteFarbe=$ffff0000

While Not KeyHit(1)

  Cls
  Color 255,0,0
  Oval 100,100,Rand(100,300),Rand(100,300),1
  Color 255,255,0
  Rect 200,90,Rand(10,60),Rand(100,400)
  h#=MilliSecs()
   LockBuffer FrontBuffer()
     Flood_Fill_Now 150,150,AlteFarbe,NeueFarbe
   UnlockBuffer FrontBuffer()
  Text 100,500,MilliSecs()-h+" ms"
  Delay 1000

Wend

WaitKey
End


Function Flood_Fill_Now (Xpos,Ypos,AlteFarbe,NeueFarbe)
     LeftX=Xpos
     RightX=Xpos
     WritePixel Xpos,Ypos,NeueFarbe
     While (LeftX>xstart)
       rgb=ReadPixel(LeftX-1,Ypos)
       If rgb=AlteFarbe LeftX=LeftX-1 WritePixel LeftX,Ypos,NeueFarbe Else Exit
     Wend

     While (RightX<xend)
        rgb=ReadPixel(RightX+1,Ypos) 
        If rgb=AlteFarbe RightX=RightX+1 WritePixel RightX,Ypos,NeueFarbe Else Exit
     Wend

    If Ypos>ystart Then
        For i=LeftX To RightX
          rgb=ReadPixel(i,Ypos-1)
          If rgb=AlteFarbe Flood_Fill_Now i,Ypos-1,AlteFarbe,NeueFarbe
        Next
    End If

    If Ypos<yend Then
        For i=LeftX To RightX
          rgb=ReadPixel(i,Ypos+1)
          If rgb=AlteFarbe Flood_Fill_Now i, Ypos+1,AlteFarbe,NeueFarbe
        Next
    End If
End Function


cu


Picklesworth(Posted 2004) [#5]
thanks a lot. That's less work for me :D
Looks like a bit of code from myself will finally be coming as soon as I stop planning for my other stuff.


big10p(Posted 2004) [#6]
In my experience I wouldn't use a recursive fill routine. You'll blow the stack with any 'complicated' fill.


Picklesworth(Posted 2004) [#7]
hm. I may just use it for referance then. I'm planning to set up files for the images to be filled containing x and y positions for spots within the same lines.

I'm using the bottom example for now though, so I'm just wondering what AlteFarbe and NeueFarbe is? (all I know is that it is some kind of colour thing) I'm kind of guessing right now. Also, when I right click to draw the fill it only fills in a little bit, then I have to drag the mouse to fill more. What am I doing wrong with the function?

;includes
;the flood fill function
Include "FloodFill.bb"

;graphics setup
Graphics 800,600,16,2

;double buffer setup
SetBuffer BackBuffer()

While Not KeyDown(1)

;the line drawing stuff

;uh, me being lazy
CursorX=MouseX()
CursorY=MouseY()
;end me being lazy and not bothering to fix my lame code

If MouseDown(1)
	
	If linebefore=0
		lastmouseX=CursorX
		lastmouseY=CursorY
		linebefore=1
	EndIf

	Line lastmouseX,lastmouseY,CursorX,CursorY
	lastmouseX=CursorX
	lastmouseY=CursorY
EndIf

;flood fill function

If MouseDown(2)
	;lock buffer for speed up
	LockBuffer FrontBuffer()
	flood_fill_now(MouseX(),MouseY(),$ff000000,$ff0000ff)
	;unlock buffer
	UnlockBuffer FrontBuffer()
EndIf

;double buffering
Flip

Wend



ShadowTurtle(Posted 2004) [#8]
Hoi

AlteFarbe = Old color, NeueFarbe = New color.


Here is my best way :\
Graphics 800,600,16,2

Global x1,y1,NeueFarbe,AlteFarbe
Global xstart,xend,ystart,yend

BGimage = CreateImage(800, 600)


;double buffer setup
SetBuffer BackBuffer()

While Not KeyDown(1)
;the line drawing stuff
;uh, me being lazy
CursorX=MouseX()
CursorY=MouseY()
;end me being lazy and not bothering to fix my lame code
If MouseDown(1)
	If linebefore=0
		lastmouseX=CursorX
		lastmouseY=CursorY
		linebefore=1
	EndIf

    SetBuffer ImageBuffer(BGimage)
	Line lastmouseX,lastmouseY,CursorX,CursorY
	lastmouseX=CursorX
	lastmouseY=CursorY
EndIf



;flood fill function
If MouseDown(2)
	;lock buffer for speed up
	LockBuffer ImageBuffer(BGimage)
	colorfill(MouseX(),MouseY(),ImageBuffer(BGimage),GraphicsWidth(),GraphicsHeight(),$ff000000,$ff0000ff)
	;unlock buffer
	UnlockBuffer ImageBuffer(BGimage)
EndIf

SetBuffer BackBuffer()
Cls
DrawBlock BGimage, 0, 0


;double buffering
Flip
Wend

Function colorfill(x%, y%, buffer%, breite%, hoehe%, rgbalt%, rgbneu%)
   If (ReadPixelFast(x%, y%, buffer%) )=rgbalt% Then
      WritePixelFast(x%, y%, rgbneu%, buffer%)
      If (x% - 1)>=0 Then colorfill((x% - 1), y%, buffer%, breite%, hoehe%, rgbalt%, rgbneu%)
      If (x% + 1)<breite% Then colorfill((x% + 1), y%, buffer%, breite%, hoehe%, rgbalt%, rgbneu%)
      If (y% + 1)<hoehe% Then colorfill(x%, (y% + 1), buffer%, breite%, hoehe%, rgbalt%, rgbneu%)
      If (y% - 1)>=0 Then colorfill(x%, (y% - 1), buffer%, breite%, hoehe%, rgbalt%, rgbneu%)
   EndIf
End Function