]> git.saurik.com Git - wxWidgets.git/blame - src/common/imagfill.cpp
part of Ictrl -> Iscntrl change I forgot to commit (not important, anyhow)
[wxWidgets.git] / src / common / imagfill.cpp
CommitLineData
7011cf13
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: imagfill.cpp
3// Purpose: FloodFill for wxImage
e3fed5c4 4// Author:
7011cf13 5// RCS-ID: $Id$
e3fed5c4 6// Copyright:
7011cf13
JS
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
7011cf13
JS
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
3a0a5ada
VS
18#include "wx/defs.h"
19
20#if wxUSE_IMAGE && !defined(__WXMSW__)
21// we have no use for this code in wxMSW...
7011cf13
JS
22
23#include "wx/image.h"
0fc5dbf5
VZ
24
25#ifndef WX_PRECOMP
26 #include "wx/brush.h"
3a0a5ada
VS
27 #include "wx/dc.h"
28 #include "wx/dcmemory.h"
0fc5dbf5 29#endif
7011cf13
JS
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
f5f05abf 36static bool LINKAGEMODE MatchPixel(wxImage *img, int x, int y, int w, int h, const wxColour& c)
7011cf13 37{
e3fed5c4 38 if ((x<0)||(x>=w)||(y<0)||(y>=h)) return FALSE;
7011cf13 39
3a0a5ada
VS
40 unsigned char r = img->GetRed(x,y);
41 unsigned char g = img->GetGreen(x,y);
42 unsigned char b = img->GetBlue(x,y);
7011cf13
JS
43 return c.Red() == r && c.Green() == g && c.Blue() == b ;
44}
45
f5f05abf 46static bool LINKAGEMODE MatchBoundaryPixel(wxImage *img, int x, int y, int w, int h, const wxColour & fill, const wxColour& bound)
7011cf13
JS
47{
48 if ((x<0)||(x>=w)||(y<0)||(y>=h)) return TRUE;
49
3a0a5ada
VS
50 unsigned char r = img->GetRed(x,y);
51 unsigned char g = img->GetGreen(x,y);
52 unsigned char b = img->GetBlue(x,y);
f5f05abf 53 if ( fill.Red() == r && fill.Green() == g && fill.Blue() == b )
3a0a5ada 54 return TRUE;
f5f05abf 55 if ( bound.Red() == r && bound.Green() == g && bound.Blue() == b )
3a0a5ada
VS
56 return TRUE;
57 return FALSE;
7011cf13
JS
58}
59
60
f5f05abf
DW
61static void LINKAGEMODE
62wxImageFloodFill(wxImage *image,
63 wxCoord x, wxCoord y, const wxBrush & fillBrush,
64 const wxColour& testColour, int style,
65 int LogicalFunction)
7011cf13
JS
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
3a0a5ada
VS
72 int width = image->GetWidth();
73 int height = image->GetHeight();
7011cf13
JS
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
3a0a5ada
VS
86 if ( image->GetRed(x,y) != r
87 || image->GetGreen(x,y) != g
88 || image->GetBlue (x,y) != b )
7011cf13
JS
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
3a0a5ada 111 image->SetRGB(xt,yt,r,g,b);
7011cf13
JS
112
113 //Main queue loop
114 while(qr!=qs)
115 {
116 //Add new members to queue
117 //Above current pixel
3a0a5ada 118 if(MatchPixel(image,xt,yt-1,width,height,testColour))
7011cf13
JS
119 {
120 *qs=xt;
121 qs++;
122 *qs=yt-1;
123 qs++;
3a0a5ada 124 image->SetRGB(xt,yt-1,r,g,b);
7011cf13
JS
125
126 //Loop back to beginning of queue
127 if(qs>=(qst+qSz)) qs=qst;
128 }
129
130 //Below current pixel
3a0a5ada 131 if(MatchPixel(image,xt,yt+1,width,height,testColour))
7011cf13
JS
132 {
133 *qs=xt;
134 qs++;
135 *qs=yt+1;
136 qs++;
3a0a5ada 137 image->SetRGB(xt,yt+1,r,g,b);
7011cf13
JS
138 if(qs>=(qst+qSz)) qs=qst;
139 }
140
141 //Left of current pixel
3a0a5ada 142 if(MatchPixel(image,xt-1,yt,width,height,testColour))
7011cf13
JS
143 {
144 *qs=xt-1;
145 qs++;
146 *qs=yt;
147 qs++;
3a0a5ada 148 image->SetRGB(xt-1,yt,r,g,b);
7011cf13
JS
149 if(qs>=(qst+qSz)) qs=qst;
150 }
151
152 //Right of current pixel
3a0a5ada 153 if(MatchPixel(image,xt+1,yt,width,height,testColour))
7011cf13
JS
154 {
155 *qs=xt+1;
156 qs++;
157 *qs=yt;
158 qs++;
3a0a5ada 159 image->SetRGB(xt+1,yt,r,g,b);
7011cf13
JS
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
3a0a5ada 174 delete[] qst;
7011cf13
JS
175 }
176 }
177 else
178 {
179 //style is wxFLOOD_BORDER
180 // fill up to testColor border - if already testColour don't do anything
3a0a5ada
VS
181 if ( image->GetRed(x,y) != testColour.Red()
182 || image->GetGreen(x,y) != testColour.Green()
183 || image->GetBlue(x,y) != testColour.Blue() )
184 {
7011cf13
JS
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
3a0a5ada 206 image->SetRGB(xt,yt,r,g,b);
7011cf13
JS
207
208 //Main queue loop
3a0a5ada 209 while (qr!=qs)
7011cf13
JS
210 {
211 //Add new members to queue
212 //Above current pixel
3a0a5ada 213 if(!MatchBoundaryPixel(image,xt,yt-1,width,height,fillColour,testColour))
7011cf13
JS
214 {
215 *qs=xt;
216 qs++;
217 *qs=yt-1;
218 qs++;
3a0a5ada 219 image->SetRGB(xt,yt-1,r,g,b);
7011cf13
JS
220
221 //Loop back to beginning of queue
222 if(qs>=(qst+qSz)) qs=qst;
223 }
224
225 //Below current pixel
3a0a5ada 226 if(!MatchBoundaryPixel(image,xt,yt+1,width,height,fillColour,testColour))
7011cf13
JS
227 {
228 *qs=xt;
229 qs++;
230 *qs=yt+1;
231 qs++;
3a0a5ada 232 image->SetRGB(xt,yt+1,r,g,b);
7011cf13
JS
233 if(qs>=(qst+qSz)) qs=qst;
234 }
235
236 //Left of current pixel
3a0a5ada 237 if(!MatchBoundaryPixel(image,xt-1,yt,width,height,fillColour,testColour))
7011cf13
JS
238 {
239 *qs=xt-1;
240 qs++;
241 *qs=yt;
242 qs++;
3a0a5ada 243 image->SetRGB(xt-1,yt,r,g,b);
7011cf13
JS
244 if(qs>=(qst+qSz)) qs=qst;
245 }
246
247 //Right of current pixel
3a0a5ada 248 if(!MatchBoundaryPixel(image,xt+1,yt,width,height,fillColour,testColour))
7011cf13
JS
249 {
250 *qs=xt+1;
251 qs++;
252 *qs=yt;
253 qs++;
3a0a5ada 254 image->SetRGB(xt+1,yt,r,g,b);
7011cf13
JS
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
3a0a5ada 269 delete[] qst;
7011cf13
JS
270 }
271 }
272 //all done,
273}
274
3a0a5ada 275
387ebd3e 276bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
3a0a5ada
VS
277 const wxColour& col, int style)
278{
279 if (dc->GetBrush().GetStyle() == wxTRANSPARENT)
387ebd3e 280 return TRUE;
3a0a5ada
VS
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...
3f4f90c2
VZ
287 wxCHECK_MSG(width >= 1 && height >= 1, FALSE,
288 wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC"));
3a0a5ada
VS
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();
f5f05abf 298 wxImageFloodFill(&image, x,y, dc->GetBrush(), col, style,
3a0a5ada
VS
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);
3f4f90c2 304
387ebd3e 305 return TRUE;
3a0a5ada
VS
306}
307
7011cf13
JS
308#endif // wxUSE_IMAGE
309