Implement a flood fill.

A flood fill is a way of filling an area using color banks to define the contained area or a target color which "determines" the area (the valley that can be flooded; Wikipedia uses the term target color). It works almost like a water flooding from a point towards the banks (or: inside the valley): if there's a hole in the banks, the flood is not contained and all the image (or all the "connected valleys") get filled.

To accomplish the task, you need to implement just one of the possible algorithms (examples are on Wikipedia). Variations on the theme are allowed (e.g. adding a tolerance parameter or argument for color-matching of the banks or target color).

 
Testing: the basic algorithm is not suitable for truecolor images; a possible test image is the one shown on the right box; you can try to fill the white area, or the black inner circle.

INCLUDE "H6:RGBCIRCL.ACT" ;from task Midpoint circle algorithm
 
RGB black,white,yellow,blue
 
DEFINE PTR="CARD"
TYPE PointB=[BYTE px,py]
TYPE Queue=[PTR qfront,qrear,qdata INT capacity]
 
PROC QueueInit(Queue POINTER q)
  DEFINE MAXSIZE="500"
  CARD ARRAY a(MAXSIZE)
 
  q.qfront=0
  q.qrear=0
  q.capacity=MAXSIZE
  q.qdata=a
RETURN
 
BYTE FUNC IsQueueEmpty(Queue POINTER q)
  IF q.qfront=q.qrear THEN
    RETURN (1)
  FI
RETURN (0)
 
PROC QueuePush(Queue POINTER q PointB POINTER p)
  PTR rear
  PointB POINTER tmp
 
  rear=q.qrear+1
  IF rear=q.capacity THEN
    rear=0
  FI
  IF rear=q.qfront THEN
    Break()
  FI
  tmp=q.qdata+q.qrear*2
  tmp.px=p.px
  tmp.py=p.py
  q.qrear=rear
RETURN
 
PROC QueuePop(Queue POINTER q PointB POINTER p)
  PointB POINTER tmp
 
  IF IsQueueEmpty(q) THEN
    Break()
  FI
  tmp=q.qdata+q.qfront*2
  p.px=tmp.px
  p.py=tmp.py
  q.qfront==+1
  IF q.qfront=q.capacity THEN
    q.qfront=0
  FI
RETURN
 
PROC DrawImage(RgbImage POINTER img BYTE x,y)
  RGB POINTER p
  BYTE i,j
 
  p=img.data
  FOR j=0 TO img.h-1
  DO
    FOR i=0 TO img.w-1
    DO
      IF RgbEqual(p,yellow) THEN
        Color=1
      ELSEIF RgbEqual(p,white) THEN
        Color=2
      ELSEIF RgbEqual(p,blue) THEN
        Color=3
      ELSE
        Color=0
      FI
      Plot(x+i,y+j)
      p==+RGBSIZE
    OD
  OD  
RETURN
 
PROC FloodFill(RgbImage POINTER img BYTE x0,y0 RGB POINTER col)
  Queue q
  RGB c,tmp
  PointB p
 
  GetRgbPixel(img,x0,y0,c)
  IF RgbEqual(c,col) THEN
    RETURN
  FI
  p.px=x0 p.py=y0
  QueueInit(q)
  QueuePush(q,p)
  WHILE IsQueueEmpty(q)=0
  DO
    QueuePop(q,p)
    x0=p.px y0=p.py
 
    GetRgbPixel(img,x0,y0,tmp)
    IF RgbEqual(tmp,c) THEN
      SetRgbPixel(img,x0,y0,col)
 
      IF x0>0 THEN
        GetRgbPixel(img,x0-1,y0,tmp)
        IF RgbEqual(tmp,c) THEN
          p.px=x0-1 p.py=y0
          QueuePush(q,p)
        FI
      FI
      IF x0<img.w-1 THEN
        GetRgbPixel(img,x0+1,y0,tmp)
        IF RgbEqual(tmp,c) THEN
          p.px=x0+1 p.py=y0
          QueuePush(q,p)
        FI
      FI
      IF y0>0 THEN
        GetRgbPixel(img,x0,y0-1,tmp)
        IF RgbEqual(tmp,c) THEN
          p.px=x0 p.py=y0-1
          QueuePush(q,p)
        FI
      FI
      IF y0<img.h-1 THEN
        GetRgbPixel(img,x0,y0+1,tmp)
        IF RgbEqual(tmp,c) THEN
          p.px=x0 p.py=y0+1
          QueuePush(q,p)
        FI
      FI
    FI
  OD
RETURN
 
PROC Main()
  RgbImage img
  BYTE CH=$02FC,size=[40]
  BYTE ARRAY p(4800)
  BYTE n
  INT x,y
  RGB POINTER col
 
  Graphics(7+16)
  SetColor(0,13,12) ;yellow
  SetColor(1,0,14)  ;white
  SetColor(2,8,6)   ;blue
  SetColor(4,0,0)   ;black
 
  RgbBlack(black)
  RgbYellow(yellow)
  RgbWhite(white)
  RgbBlue(blue)
 
  InitRgbImage(img,size,size,p)
  FillRgbImage(img,black)
 
  RgbCircle(img,size/2,size/2,size/2-1,white)
  RgbCircle(img,2*size/5,2*size/5,size/5,white)
  DrawImage(img,0,(96-size)/2)
 
  FloodFill(img,3*size/5,3*size/5,white)
  DrawImage(img,size,(96-size)/2)
 
  FloodFill(img,2*size/5,2*size/5,blue)
  DrawImage(img,2*size,(96-size)/2)
 
  FloodFill(img,3*size/5,3*size/5,yellow)
  DrawImage(img,3*size,(96-size)/2)
 
  DO UNTIL CH#$FF OD
  CH=$FF
RETURN