home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / imagfill.cpp < prev    next >
C/C++ Source or Header  |  2002-04-17  |  9KB  |  310 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        imagfill.cpp
  3. // Purpose:     FloodFill for wxImage
  4. // Author:
  5. // RCS-ID:      $Id: imagfill.cpp,v 1.9 2002/04/17 14:16:36 VZ Exp $
  6. // Copyright:
  7. // Licence:     wxWindows licence
  8. /////////////////////////////////////////////////////////////////////////////
  9.  
  10.  
  11. // For compilers that support precompilation, includes "wx.h".
  12. #include "wx/wxprec.h"
  13.  
  14. #ifdef __BORLANDC__
  15.     #pragma hdrstop
  16. #endif
  17.  
  18. #include "wx/defs.h"
  19.  
  20. #if wxUSE_IMAGE && !defined(__WXMSW__)
  21. // we have no use for this code in wxMSW...
  22.  
  23. #include "wx/image.h"
  24.  
  25. #ifndef WX_PRECOMP
  26.     #include "wx/brush.h"
  27.     #include "wx/dc.h"
  28.     #include "wx/dcmemory.h"
  29. #endif
  30.  
  31. // DoFloodFill
  32. // Fills with the colour extracted from fillBrush, starting at x,y until either
  33. // a color different from the start pixel is reached (wxFLOOD_SURFACE)
  34. // or fill color is reached (wxFLOOD_BORDER)
  35.  
  36. static bool LINKAGEMODE MatchPixel(wxImage *img, int x, int y, int w, int h, const wxColour& c)
  37. {
  38.     if ((x<0)||(x>=w)||(y<0)||(y>=h)) return FALSE;
  39.  
  40.     unsigned char r = img->GetRed(x,y);
  41.     unsigned char g = img->GetGreen(x,y);
  42.     unsigned char b = img->GetBlue(x,y);
  43.     return c.Red() == r && c.Green() == g && c.Blue() == b ;
  44. }
  45.  
  46. static bool LINKAGEMODE MatchBoundaryPixel(wxImage *img, int x, int y, int w, int h, const wxColour & fill, const wxColour& bound)
  47. {
  48.     if ((x<0)||(x>=w)||(y<0)||(y>=h)) return TRUE;
  49.  
  50.     unsigned char r = img->GetRed(x,y);
  51.     unsigned char g = img->GetGreen(x,y);
  52.     unsigned char b = img->GetBlue(x,y);
  53.     if ( fill.Red() == r && fill.Green() == g && fill.Blue() == b )
  54.         return TRUE;
  55.     if ( bound.Red() == r && bound.Green() == g && bound.Blue() == b )
  56.         return TRUE;
  57.     return FALSE;
  58. }
  59.  
  60.  
  61. static void LINKAGEMODE
  62. wxImageFloodFill(wxImage *image,
  63.                  wxCoord x, wxCoord y, const wxBrush & fillBrush,
  64.                  const wxColour& testColour, int style,
  65.                 int LogicalFunction)
  66. {
  67.     /* A diamond flood-fill using a circular queue system.
  68.     Each pixel surrounding the current pixel is added to
  69.     the queue if it meets the criteria, then is retrieved in
  70.     its turn.  Code originally based on http://www.drawit.co.nz/Developers.htm */
  71.  
  72.     int width = image->GetWidth();
  73.     int height = image->GetHeight();
  74.  
  75.     //Draw using a pen made from the current brush colour
  76.     //Potentially allows us to use patterned flood fills in future code
  77.     wxColour fillColour = fillBrush.GetColour();
  78.     unsigned char r = fillColour.Red();
  79.     unsigned char g = fillColour.Green();
  80.     unsigned char b = fillColour.Blue();
  81.  
  82.     //initial test :
  83.     if (style == wxFLOOD_SURFACE)
  84.     {
  85.        //if wxFLOOD_SURFACE, if fill colour is same as required, we don't do anything
  86.        if (     image->GetRed(x,y)   != r
  87.              || image->GetGreen(x,y) != g
  88.              || image->GetBlue (x,y) != b   )
  89.         {
  90.         //prepare memory for queue
  91.         //queue save, start, read
  92.         size_t *qs, *qst, *qr;
  93.  
  94.         //queue size (physical)
  95.         long qSz= height * width * 2;
  96.         qst = new size_t [qSz];
  97.  
  98.         //temporary x and y locations
  99.         int xt, yt;
  100.  
  101.         for (int i=0; i < qSz; i++)
  102.             qst[i] = 0;
  103.  
  104.         // start queue
  105.         qs=qr=qst;
  106.         *qs=xt=x;
  107.         qs++;
  108.         *qs=yt=y;
  109.         qs++;
  110.  
  111.         image->SetRGB(xt,yt,r,g,b);
  112.  
  113.         //Main queue loop
  114.         while(qr!=qs)
  115.         {
  116.             //Add new members to queue
  117.             //Above current pixel
  118.             if(MatchPixel(image,xt,yt-1,width,height,testColour))
  119.             {
  120.                 *qs=xt;
  121.                 qs++;
  122.                 *qs=yt-1;
  123.                 qs++;
  124.                 image->SetRGB(xt,yt-1,r,g,b);
  125.  
  126.                 //Loop back to beginning of queue
  127.                 if(qs>=(qst+qSz)) qs=qst;
  128.             }
  129.  
  130.             //Below current pixel
  131.             if(MatchPixel(image,xt,yt+1,width,height,testColour))
  132.             {
  133.                 *qs=xt;
  134.                 qs++;
  135.                 *qs=yt+1;
  136.                 qs++;
  137.                 image->SetRGB(xt,yt+1,r,g,b);
  138.                 if(qs>=(qst+qSz)) qs=qst;
  139.             }
  140.  
  141.             //Left of current pixel
  142.             if(MatchPixel(image,xt-1,yt,width,height,testColour))
  143.             {
  144.                 *qs=xt-1;
  145.                 qs++;
  146.                 *qs=yt;
  147.                 qs++;
  148.                 image->SetRGB(xt-1,yt,r,g,b);
  149.                 if(qs>=(qst+qSz)) qs=qst;
  150.             }
  151.  
  152.             //Right of current pixel
  153.             if(MatchPixel(image,xt+1,yt,width,height,testColour))
  154.             {
  155.                 *qs=xt+1;
  156.                 qs++;
  157.                 *qs=yt;
  158.                 qs++;
  159.                 image->SetRGB(xt+1,yt,r,g,b);
  160.                 if(qs>=(qst+qSz)) qs=qst;
  161.             }
  162.  
  163.             //Retrieve current queue member
  164.             qr+=2;
  165.  
  166.             //Loop back to the beginning
  167.             if(qr>=(qst+qSz)) qr=qst;
  168.             xt=*qr;
  169.             yt=*(qr+1);
  170.  
  171.         //Go Back to beginning of loop
  172.         }
  173.  
  174.         delete[] qst;
  175.         }
  176.     }
  177.     else
  178.     {
  179.     //style is wxFLOOD_BORDER
  180.     // fill up to testColor border - if already testColour don't do anything
  181.     if (  image->GetRed(x,y)   != testColour.Red()
  182.           || image->GetGreen(x,y) != testColour.Green()
  183.           || image->GetBlue(x,y)  != testColour.Blue() )
  184.     {
  185.         //prepare memory for queue
  186.         //queue save, start, read
  187.         size_t *qs, *qst, *qr;
  188.  
  189.         //queue size (physical)
  190.         long qSz= height * width * 2;
  191.         qst = new size_t [qSz];
  192.  
  193.         //temporary x and y locations
  194.         int xt, yt;
  195.  
  196.         for (int i=0; i < qSz; i++)
  197.             qst[i] = 0;
  198.  
  199.         // start queue
  200.         qs=qr=qst;
  201.         *qs=xt=x;
  202.         qs++;
  203.         *qs=yt=y;
  204.         qs++;
  205.  
  206.         image->SetRGB(xt,yt,r,g,b);
  207.  
  208.         //Main queue loop
  209.         while (qr!=qs)
  210.         {
  211.             //Add new members to queue
  212.             //Above current pixel
  213.             if(!MatchBoundaryPixel(image,xt,yt-1,width,height,fillColour,testColour))
  214.             {
  215.                 *qs=xt;
  216.                 qs++;
  217.                 *qs=yt-1;
  218.                 qs++;
  219.                 image->SetRGB(xt,yt-1,r,g,b);
  220.  
  221.                 //Loop back to beginning of queue
  222.                 if(qs>=(qst+qSz)) qs=qst;
  223.             }
  224.  
  225.             //Below current pixel
  226.             if(!MatchBoundaryPixel(image,xt,yt+1,width,height,fillColour,testColour))
  227.             {
  228.                 *qs=xt;
  229.                 qs++;
  230.                 *qs=yt+1;
  231.                 qs++;
  232.                 image->SetRGB(xt,yt+1,r,g,b);
  233.                 if(qs>=(qst+qSz)) qs=qst;
  234.             }
  235.  
  236.             //Left of current pixel
  237.             if(!MatchBoundaryPixel(image,xt-1,yt,width,height,fillColour,testColour))
  238.             {
  239.                 *qs=xt-1;
  240.                 qs++;
  241.                 *qs=yt;
  242.                 qs++;
  243.                 image->SetRGB(xt-1,yt,r,g,b);
  244.                 if(qs>=(qst+qSz)) qs=qst;
  245.             }
  246.  
  247.             //Right of current pixel
  248.             if(!MatchBoundaryPixel(image,xt+1,yt,width,height,fillColour,testColour))
  249.             {
  250.                 *qs=xt+1;
  251.                 qs++;
  252.                 *qs=yt;
  253.                 qs++;
  254.                 image->SetRGB(xt+1,yt,r,g,b);
  255.                 if(qs>=(qst+qSz)) qs=qst;
  256.             }
  257.  
  258.             //Retrieve current queue member
  259.             qr+=2;
  260.  
  261.             //Loop back to the beginning
  262.             if(qr>=(qst+qSz)) qr=qst;
  263.             xt=*qr;
  264.             yt=*(qr+1);
  265.  
  266.         //Go Back to beginning of loop
  267.         }
  268.  
  269.         delete[] qst;
  270.         }
  271.     }
  272.     //all done,
  273. }
  274.  
  275.  
  276. bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
  277.                    const wxColour& col, int style)
  278. {
  279.     if (dc->GetBrush().GetStyle() == wxTRANSPARENT)
  280.         return TRUE;
  281.  
  282.     int height = 0;
  283.     int width  = 0;
  284.     dc->GetSize(&width, &height);
  285.  
  286.     //it would be nice to fail if we don't get a sensible size...
  287.     wxCHECK_MSG(width >= 1 && height >= 1, FALSE,
  288.                 wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC"));
  289.  
  290.     //this is much faster than doing the individual pixels
  291.     wxMemoryDC memdc;
  292.     wxBitmap bitmap(width, height);
  293.     memdc.SelectObject(bitmap);
  294.     memdc.Blit(0, 0, width, height, dc, 0, 0);
  295.     memdc.SelectObject(wxNullBitmap);
  296.  
  297.     wxImage image = bitmap.ConvertToImage();
  298.     wxImageFloodFill(&image, x,y, dc->GetBrush(), col, style,
  299.                      dc->GetLogicalFunction());
  300.     bitmap = wxBitmap(image);
  301.     memdc.SelectObject(bitmap);
  302.     dc->Blit(0, 0, width, height, &memdc, 0, 0);
  303.     memdc.SelectObject(wxNullBitmap);
  304.  
  305.     return TRUE;
  306. }
  307.  
  308. #endif // wxUSE_IMAGE
  309.  
  310.